diff --git a/Userland/Services/AudioServer/Mixer.cpp b/Userland/Services/AudioServer/Mixer.cpp index 9138c010443..09a0ef6a73d 100644 --- a/Userland/Services/AudioServer/Mixer.cpp +++ b/Userland/Services/AudioServer/Mixer.cpp @@ -20,7 +20,7 @@ namespace AudioServer { -Mixer::Mixer(NonnullRefPtr config, NonnullOwnPtr device) +Mixer::Mixer(NonnullRefPtr config, OwnPtr device) : m_device(move(device)) , m_sound_thread(Threading::Thread::construct( [this] { @@ -95,7 +95,8 @@ void Mixer::mix() // Even though it's not realistic, the user expects no sound at 0%. if (m_muted || m_main_volume < 0.01) { - m_device->write_until_depleted(m_zero_filled_buffer).release_value_but_fixme_should_propagate_errors(); + if (m_device) + m_device->write_until_depleted(m_zero_filled_buffer).release_value_but_fixme_should_propagate_errors(); } else { FixedMemoryStream stream { m_stream_buffer.span() }; @@ -113,8 +114,9 @@ void Mixer::mix() auto buffered_bytes = MUST(stream.tell()); VERIFY(buffered_bytes == m_stream_buffer.size()); - m_device->write_until_depleted({ m_stream_buffer.data(), buffered_bytes }) - .release_value_but_fixme_should_propagate_errors(); + if (m_device) + m_device->write_until_depleted({ m_stream_buffer.data(), buffered_bytes }) + .release_value_but_fixme_should_propagate_errors(); } } } @@ -152,6 +154,9 @@ void Mixer::set_muted(bool muted) int Mixer::audiodevice_set_sample_rate(u32 sample_rate) { + if (!m_device) + return ENOENT; + int code = ioctl(m_device->fd(), SOUNDCARD_IOCTL_SET_SAMPLE_RATE, sample_rate); if (code != 0) dbgln("Error while setting sample rate to {}: ioctl error: {}", sample_rate, strerror(errno)); @@ -165,6 +170,11 @@ u32 Mixer::audiodevice_get_sample_rate() const { if (m_cached_sample_rate.has_value()) return m_cached_sample_rate.value(); + + // We pretend that a non-existent device has a common sample rate (instead of returning something like 0 that would break clients). + if (!m_device) + return 44100; + u32 sample_rate = 0; int code = ioctl(m_device->fd(), SOUNDCARD_IOCTL_GET_SAMPLE_RATE, &sample_rate); if (code != 0) diff --git a/Userland/Services/AudioServer/Mixer.h b/Userland/Services/AudioServer/Mixer.h index af80f6da6d9..cb14e9c2bb3 100644 --- a/Userland/Services/AudioServer/Mixer.h +++ b/Userland/Services/AudioServer/Mixer.h @@ -42,7 +42,12 @@ public: static ErrorOr> try_create(NonnullRefPtr config) { // FIXME: Allow AudioServer to use other audio channels as well - auto device = TRY(Core::File::open("/dev/audio/0"sv, Core::File::OpenMode::Write)); + auto maybe_device = Core::File::open("/dev/audio/0"sv, Core::File::OpenMode::Write); + OwnPtr device; + if (maybe_device.is_error()) + dbgln("Couldn't open first audio channel: {}", maybe_device.error()); + else + device = maybe_device.release_value(); return adopt_nonnull_ref_or_enomem(new (nothrow) Mixer(move(config), move(device))); } @@ -61,7 +66,7 @@ public: u32 audiodevice_get_sample_rate() const; private: - Mixer(NonnullRefPtr config, NonnullOwnPtr device); + Mixer(NonnullRefPtr config, OwnPtr device); void request_setting_sync(); @@ -69,7 +74,7 @@ private: Threading::Mutex m_pending_mutex; Threading::ConditionVariable m_mixing_necessary { m_pending_mutex }; - NonnullOwnPtr m_device; + OwnPtr m_device; mutable Optional m_cached_sample_rate {}; NonnullRefPtr m_sound_thread; diff --git a/Userland/Services/AudioServer/main.cpp b/Userland/Services/AudioServer/main.cpp index 186fd5cfd74..d93a593e4c4 100644 --- a/Userland/Services/AudioServer/main.cpp +++ b/Userland/Services/AudioServer/main.cpp @@ -19,7 +19,12 @@ ErrorOr serenity_main(Main::Arguments) auto config = TRY(Core::ConfigFile::open_for_app("Audio", Core::ConfigFile::AllowWriting::Yes)); TRY(Core::System::unveil(config->filename(), "rwc"sv)); - TRY(Core::System::unveil("/dev/audio", "wc")); + + auto audio_unveil_result = Core::System::unveil("/dev/audio", "wc"); + // System may not have audio devices, which we handle gracefully. + if (audio_unveil_result.is_error()) + dbgln("Couldn't unveil audio devices: {}", audio_unveil_result.error()); + TRY(Core::System::unveil(nullptr, nullptr)); Core::EventLoop event_loop;