PulseAudioWrappers.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * Copyright (c) 2023, Gregory Bertilson <zaggy1024@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "PulseAudioWrappers.h"
  7. #include <AK/WeakPtr.h>
  8. #include <LibThreading/Mutex.h>
  9. namespace Audio {
  10. ErrorOr<NonnullRefPtr<PulseAudioContext>> PulseAudioContext::instance()
  11. {
  12. // Use a weak pointer to allow the context to be shut down if we stop outputting audio.
  13. static WeakPtr<PulseAudioContext> the_instance;
  14. static Threading::Mutex instantiation_mutex;
  15. // Lock and unlock the mutex to ensure that the mutex is fully unlocked at application
  16. // exit.
  17. atexit([]() {
  18. instantiation_mutex.lock();
  19. instantiation_mutex.unlock();
  20. });
  21. auto instantiation_locker = Threading::MutexLocker(instantiation_mutex);
  22. RefPtr<PulseAudioContext> strong_instance_pointer = the_instance.strong_ref();
  23. if (strong_instance_pointer == nullptr) {
  24. auto* main_loop = pa_threaded_mainloop_new();
  25. if (main_loop == nullptr)
  26. return Error::from_string_literal("Failed to create PulseAudio main loop");
  27. auto* api = pa_threaded_mainloop_get_api(main_loop);
  28. if (api == nullptr)
  29. return Error::from_string_literal("Failed to get PulseAudio API");
  30. auto* context = pa_context_new(api, "Ladybird");
  31. if (context == nullptr)
  32. return Error::from_string_literal("Failed to get PulseAudio connection context");
  33. strong_instance_pointer = make_ref_counted<PulseAudioContext>(main_loop, api, context);
  34. // Set a callback to signal ourselves to wake when the state changes, so that we can
  35. // synchronously wait for the connection.
  36. pa_context_set_state_callback(
  37. context, [](pa_context*, void* user_data) {
  38. static_cast<PulseAudioContext*>(user_data)->signal_to_wake();
  39. },
  40. strong_instance_pointer.ptr());
  41. if (auto error = pa_context_connect(context, nullptr, PA_CONTEXT_NOFLAGS, nullptr); error < 0) {
  42. warnln("Starting PulseAudio context connection failed with error: {}", pulse_audio_error_to_string(static_cast<PulseAudioErrorCode>(-error)));
  43. return Error::from_string_literal("Error while starting PulseAudio daemon connection");
  44. }
  45. if (auto error = pa_threaded_mainloop_start(main_loop); error < 0) {
  46. warnln("Starting PulseAudio main loop failed with error: {}", pulse_audio_error_to_string(static_cast<PulseAudioErrorCode>(-error)));
  47. return Error::from_string_literal("Failed to start PulseAudio main loop");
  48. }
  49. {
  50. auto locker = strong_instance_pointer->main_loop_locker();
  51. while (true) {
  52. bool is_ready = false;
  53. switch (strong_instance_pointer->get_connection_state()) {
  54. case PulseAudioContextState::Connecting:
  55. case PulseAudioContextState::Authorizing:
  56. case PulseAudioContextState::SettingName:
  57. break;
  58. case PulseAudioContextState::Ready:
  59. is_ready = true;
  60. break;
  61. case PulseAudioContextState::Failed:
  62. warnln("PulseAudio server connection failed with error: {}", pulse_audio_error_to_string(strong_instance_pointer->get_last_error()));
  63. return Error::from_string_literal("Failed to connect to PulseAudio server");
  64. case PulseAudioContextState::Unconnected:
  65. case PulseAudioContextState::Terminated:
  66. VERIFY_NOT_REACHED();
  67. break;
  68. }
  69. if (is_ready)
  70. break;
  71. strong_instance_pointer->wait_for_signal();
  72. }
  73. pa_context_set_state_callback(context, nullptr, nullptr);
  74. }
  75. the_instance = strong_instance_pointer;
  76. }
  77. return strong_instance_pointer.release_nonnull();
  78. }
  79. PulseAudioContext::PulseAudioContext(pa_threaded_mainloop* main_loop, pa_mainloop_api* api, pa_context* context)
  80. : m_main_loop(main_loop)
  81. , m_api(api)
  82. , m_context(context)
  83. {
  84. }
  85. PulseAudioContext::~PulseAudioContext()
  86. {
  87. {
  88. auto locker = main_loop_locker();
  89. pa_context_disconnect(m_context);
  90. pa_context_unref(m_context);
  91. }
  92. pa_threaded_mainloop_stop(m_main_loop);
  93. pa_threaded_mainloop_free(m_main_loop);
  94. }
  95. bool PulseAudioContext::current_thread_is_main_loop_thread()
  96. {
  97. return static_cast<bool>(pa_threaded_mainloop_in_thread(m_main_loop));
  98. }
  99. void PulseAudioContext::lock_main_loop()
  100. {
  101. if (!current_thread_is_main_loop_thread())
  102. pa_threaded_mainloop_lock(m_main_loop);
  103. }
  104. void PulseAudioContext::unlock_main_loop()
  105. {
  106. if (!current_thread_is_main_loop_thread())
  107. pa_threaded_mainloop_unlock(m_main_loop);
  108. }
  109. void PulseAudioContext::wait_for_signal()
  110. {
  111. pa_threaded_mainloop_wait(m_main_loop);
  112. }
  113. void PulseAudioContext::signal_to_wake()
  114. {
  115. pa_threaded_mainloop_signal(m_main_loop, 0);
  116. }
  117. PulseAudioContextState PulseAudioContext::get_connection_state()
  118. {
  119. return static_cast<PulseAudioContextState>(pa_context_get_state(m_context));
  120. }
  121. bool PulseAudioContext::connection_is_good()
  122. {
  123. return PA_CONTEXT_IS_GOOD(pa_context_get_state(m_context));
  124. }
  125. PulseAudioErrorCode PulseAudioContext::get_last_error()
  126. {
  127. return static_cast<PulseAudioErrorCode>(pa_context_errno(m_context));
  128. }
  129. #define STREAM_SIGNAL_CALLBACK(stream) \
  130. [](auto*, int, void* user_data) { \
  131. static_cast<PulseAudioStream*>(user_data)->m_context->signal_to_wake(); \
  132. }, \
  133. (stream)
  134. ErrorOr<NonnullRefPtr<PulseAudioStream>> PulseAudioContext::create_stream(OutputState initial_state, u32 sample_rate, u8 channels, u32 target_latency_ms, PulseAudioDataRequestCallback write_callback)
  135. {
  136. auto locker = main_loop_locker();
  137. VERIFY(get_connection_state() == PulseAudioContextState::Ready);
  138. pa_sample_spec sample_specification {
  139. // FIXME: Support more audio sample types.
  140. __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ? PA_SAMPLE_FLOAT32LE : PA_SAMPLE_FLOAT32BE,
  141. sample_rate,
  142. channels,
  143. };
  144. // Check the sample specification and channel map here. These are also checked by stream_new(),
  145. // but we can return a more accurate error if we check beforehand.
  146. if (pa_sample_spec_valid(&sample_specification) == 0)
  147. return Error::from_string_literal("PulseAudio sample specification is invalid");
  148. pa_channel_map channel_map;
  149. if (pa_channel_map_init_auto(&channel_map, sample_specification.channels, PA_CHANNEL_MAP_DEFAULT) == 0) {
  150. warnln("Getting default PulseAudio channel map failed with error: {}", pulse_audio_error_to_string(get_last_error()));
  151. return Error::from_string_literal("Failed to get default PulseAudio channel map");
  152. }
  153. // Create the stream object and set a callback to signal ourselves to wake when the stream changes states,
  154. // allowing us to wait synchronously for it to become Ready or Failed.
  155. auto* stream = pa_stream_new_with_proplist(m_context, "Audio Stream", &sample_specification, &channel_map, nullptr);
  156. if (stream == nullptr) {
  157. warnln("Instantiating PulseAudio stream failed with error: {}", pulse_audio_error_to_string(get_last_error()));
  158. return Error::from_string_literal("Failed to create PulseAudio stream");
  159. }
  160. pa_stream_set_state_callback(
  161. stream, [](pa_stream*, void* user_data) {
  162. static_cast<PulseAudioContext*>(user_data)->signal_to_wake();
  163. },
  164. this);
  165. auto stream_wrapper = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) PulseAudioStream(NonnullRefPtr(*this), stream)));
  166. stream_wrapper->m_write_callback = move(write_callback);
  167. pa_stream_set_write_callback(
  168. stream, [](pa_stream* stream, size_t bytes_to_write, void* user_data) {
  169. auto& stream_wrapper = *static_cast<PulseAudioStream*>(user_data);
  170. VERIFY(stream_wrapper.m_stream == stream);
  171. stream_wrapper.on_write_requested(bytes_to_write);
  172. },
  173. stream_wrapper.ptr());
  174. // Borrowing logic from cubeb to set reasonable buffer sizes for a target latency:
  175. // https://searchfox.org/mozilla-central/rev/3b707c8fd7e978eebf24279ee51ccf07895cfbcb/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c#910-927
  176. pa_buffer_attr buffer_attributes;
  177. buffer_attributes.maxlength = -1;
  178. buffer_attributes.prebuf = -1;
  179. buffer_attributes.tlength = target_latency_ms * sample_rate / 1000;
  180. buffer_attributes.minreq = buffer_attributes.tlength / 4;
  181. buffer_attributes.fragsize = buffer_attributes.minreq;
  182. auto flags = static_cast<pa_stream_flags>(PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_RELATIVE_VOLUME);
  183. if (initial_state == OutputState::Suspended) {
  184. stream_wrapper->m_suspended = true;
  185. flags = static_cast<pa_stream_flags>(static_cast<u32>(flags) | PA_STREAM_START_CORKED);
  186. }
  187. // This is a workaround for an issue with starting the stream corked, see PulseAudioPlaybackStream::total_time_played().
  188. pa_stream_set_started_callback(
  189. stream, [](pa_stream* stream, void* user_data) {
  190. static_cast<PulseAudioStream*>(user_data)->m_started_playback = true;
  191. pa_stream_set_started_callback(stream, nullptr, nullptr);
  192. },
  193. stream_wrapper.ptr());
  194. pa_stream_set_underflow_callback(
  195. stream, [](pa_stream*, void* user_data) {
  196. auto& stream = *static_cast<PulseAudioStream*>(user_data);
  197. if (stream.m_underrun_callback)
  198. stream.m_underrun_callback();
  199. },
  200. stream_wrapper.ptr());
  201. if (auto error = pa_stream_connect_playback(stream, nullptr, &buffer_attributes, flags, nullptr, nullptr); error != 0) {
  202. warnln("Failed to start PulseAudio stream connection with error: {}", pulse_audio_error_to_string(static_cast<PulseAudioErrorCode>(error)));
  203. return Error::from_string_literal("Error while connecting the PulseAudio stream");
  204. }
  205. while (true) {
  206. bool is_ready = false;
  207. switch (stream_wrapper->get_connection_state()) {
  208. case PulseAudioStreamState::Creating:
  209. break;
  210. case PulseAudioStreamState::Ready:
  211. is_ready = true;
  212. break;
  213. case PulseAudioStreamState::Failed:
  214. warnln("PulseAudio stream connection failed with error: {}", pulse_audio_error_to_string(get_last_error()));
  215. return Error::from_string_literal("Failed to connect to PulseAudio daemon");
  216. case PulseAudioStreamState::Unconnected:
  217. case PulseAudioStreamState::Terminated:
  218. VERIFY_NOT_REACHED();
  219. break;
  220. }
  221. if (is_ready)
  222. break;
  223. wait_for_signal();
  224. }
  225. return stream_wrapper;
  226. }
  227. PulseAudioStream::~PulseAudioStream()
  228. {
  229. pa_stream_unref(m_stream);
  230. }
  231. PulseAudioStreamState PulseAudioStream::get_connection_state()
  232. {
  233. return static_cast<PulseAudioStreamState>(pa_stream_get_state(m_stream));
  234. }
  235. bool PulseAudioStream::connection_is_good()
  236. {
  237. return PA_STREAM_IS_GOOD(pa_stream_get_state(m_stream));
  238. }
  239. void PulseAudioStream::set_underrun_callback(Function<void()> callback)
  240. {
  241. auto locker = m_context->main_loop_locker();
  242. m_underrun_callback = move(callback);
  243. }
  244. u32 PulseAudioStream::sample_rate()
  245. {
  246. return pa_stream_get_sample_spec(m_stream)->rate;
  247. }
  248. size_t PulseAudioStream::sample_size()
  249. {
  250. return pa_sample_size(pa_stream_get_sample_spec(m_stream));
  251. }
  252. size_t PulseAudioStream::frame_size()
  253. {
  254. return pa_frame_size(pa_stream_get_sample_spec(m_stream));
  255. }
  256. u8 PulseAudioStream::channel_count()
  257. {
  258. return pa_stream_get_sample_spec(m_stream)->channels;
  259. }
  260. void PulseAudioStream::on_write_requested(size_t bytes_to_write)
  261. {
  262. VERIFY(m_write_callback);
  263. if (m_suspended)
  264. return;
  265. while (bytes_to_write > 0) {
  266. auto buffer = begin_write(bytes_to_write).release_value_but_fixme_should_propagate_errors();
  267. auto frame_size = this->frame_size();
  268. VERIFY(buffer.size() % frame_size == 0);
  269. auto written_buffer = m_write_callback(*this, buffer, buffer.size() / frame_size);
  270. if (written_buffer.size() == 0) {
  271. cancel_write().release_value_but_fixme_should_propagate_errors();
  272. break;
  273. }
  274. bytes_to_write -= written_buffer.size();
  275. write(written_buffer).release_value_but_fixme_should_propagate_errors();
  276. }
  277. }
  278. ErrorOr<Bytes> PulseAudioStream::begin_write(size_t bytes_to_write)
  279. {
  280. void* data_pointer;
  281. size_t data_size = bytes_to_write;
  282. if (pa_stream_begin_write(m_stream, &data_pointer, &data_size) != 0 || data_pointer == nullptr)
  283. return Error::from_string_literal("Failed to get the playback stream's write buffer from PulseAudio");
  284. return Bytes { data_pointer, data_size };
  285. }
  286. ErrorOr<void> PulseAudioStream::write(ReadonlyBytes data)
  287. {
  288. if (pa_stream_write(m_stream, data.data(), data.size(), nullptr, 0, PA_SEEK_RELATIVE) != 0)
  289. return Error::from_string_literal("Failed to write data to PulseAudio playback stream");
  290. return {};
  291. }
  292. ErrorOr<void> PulseAudioStream::cancel_write()
  293. {
  294. if (pa_stream_cancel_write(m_stream) != 0)
  295. return Error::from_string_literal("Failed to get the playback stream's write buffer from PulseAudio");
  296. return {};
  297. }
  298. bool PulseAudioStream::is_suspended() const
  299. {
  300. return m_suspended;
  301. }
  302. StringView pulse_audio_error_to_string(PulseAudioErrorCode code)
  303. {
  304. if (code < PulseAudioErrorCode::OK || code >= PulseAudioErrorCode::Sentinel)
  305. return "Unknown error code"sv;
  306. char const* string = pa_strerror(static_cast<int>(code));
  307. return StringView { string, strlen(string) };
  308. }
  309. ErrorOr<void> PulseAudioStream::wait_for_operation(pa_operation* operation, StringView error_message)
  310. {
  311. while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
  312. m_context->wait_for_signal();
  313. if (!m_context->connection_is_good() || !this->connection_is_good()) {
  314. auto pulse_audio_error_name = pulse_audio_error_to_string(m_context->get_last_error());
  315. warnln("Encountered stream error: {}", pulse_audio_error_name);
  316. return Error::from_string_view(error_message);
  317. }
  318. pa_operation_unref(operation);
  319. return {};
  320. }
  321. ErrorOr<void> PulseAudioStream::drain_and_suspend()
  322. {
  323. auto locker = m_context->main_loop_locker();
  324. if (m_suspended)
  325. return {};
  326. m_suspended = true;
  327. if (pa_stream_is_corked(m_stream) > 0)
  328. return {};
  329. TRY(wait_for_operation(pa_stream_drain(m_stream, STREAM_SIGNAL_CALLBACK(this)), "Draining PulseAudio stream failed"sv));
  330. TRY(wait_for_operation(pa_stream_cork(m_stream, 1, STREAM_SIGNAL_CALLBACK(this)), "Corking PulseAudio stream after drain failed"sv));
  331. return {};
  332. }
  333. ErrorOr<void> PulseAudioStream::flush_and_suspend()
  334. {
  335. auto locker = m_context->main_loop_locker();
  336. if (m_suspended)
  337. return {};
  338. m_suspended = true;
  339. if (pa_stream_is_corked(m_stream) > 0)
  340. return {};
  341. TRY(wait_for_operation(pa_stream_flush(m_stream, STREAM_SIGNAL_CALLBACK(this)), "Flushing PulseAudio stream failed"sv));
  342. TRY(wait_for_operation(pa_stream_cork(m_stream, 1, STREAM_SIGNAL_CALLBACK(this)), "Corking PulseAudio stream after flush failed"sv));
  343. return {};
  344. }
  345. ErrorOr<void> PulseAudioStream::resume()
  346. {
  347. auto locker = m_context->main_loop_locker();
  348. if (!m_suspended)
  349. return {};
  350. m_suspended = false;
  351. TRY(wait_for_operation(pa_stream_cork(m_stream, 0, STREAM_SIGNAL_CALLBACK(this)), "Uncorking PulseAudio stream failed"sv));
  352. // Defer a write to the playback buffer on the PulseAudio main loop. Otherwise, playback will not
  353. // begin again, despite the fact that we uncorked.
  354. // NOTE: We ref here and then unref in the callback so that this stream will not be deleted until
  355. // it finishes.
  356. ref();
  357. pa_mainloop_api_once(
  358. m_context->m_api, [](pa_mainloop_api*, void* user_data) {
  359. auto& stream = *static_cast<PulseAudioStream*>(user_data);
  360. // NOTE: writable_size() returns -1 in case of an error. However, the value is still safe
  361. // since begin_write() will interpret -1 as a default parameter and choose a good size.
  362. auto bytes_to_write = pa_stream_writable_size(stream.m_stream);
  363. stream.on_write_requested(bytes_to_write);
  364. stream.unref();
  365. },
  366. this);
  367. return {};
  368. }
  369. ErrorOr<Duration> PulseAudioStream::total_time_played()
  370. {
  371. auto locker = m_context->main_loop_locker();
  372. // NOTE: This is a workaround for a PulseAudio issue. When a stream is started corked,
  373. // the time smoother doesn't seem to be aware of it, so it will return the time
  374. // since the stream was connected. Once the playback actually starts, the time
  375. // resets back to zero. However, since we request monotonically-increasing time,
  376. // this means that the smoother will register that it had a larger time before,
  377. // and return that time instead, until we reach a timestamp greater than the
  378. // last-returned time. If we never call pa_stream_get_time() until after giving
  379. // the stream its first samples, the issue never occurs.
  380. if (!m_started_playback)
  381. return Duration::zero();
  382. pa_usec_t time = 0;
  383. auto error = pa_stream_get_time(m_stream, &time);
  384. if (error == -PA_ERR_NODATA)
  385. return Duration::zero();
  386. if (error != 0)
  387. return Error::from_string_literal("Failed to get time from PulseAudio stream");
  388. if (time > NumericLimits<i64>::max()) {
  389. warnln("WARNING: Audio time is too large!");
  390. time -= NumericLimits<i64>::max();
  391. }
  392. return Duration::from_microseconds(static_cast<i64>(time));
  393. }
  394. ErrorOr<void> PulseAudioStream::set_volume(double volume)
  395. {
  396. auto locker = m_context->main_loop_locker();
  397. auto index = pa_stream_get_index(m_stream);
  398. if (index == PA_INVALID_INDEX)
  399. return Error::from_string_literal("Failed to get PulseAudio stream index while setting volume");
  400. auto pulse_volume = pa_sw_volume_from_linear(volume);
  401. pa_cvolume per_channel_volumes;
  402. pa_cvolume_set(&per_channel_volumes, channel_count(), pulse_volume);
  403. auto* operation = pa_context_set_sink_input_volume(m_context->m_context, index, &per_channel_volumes, STREAM_SIGNAL_CALLBACK(this));
  404. return wait_for_operation(operation, "Failed to set PulseAudio stream volume"sv);
  405. }
  406. }