Loading system/audio_hal_interface/a2dp_encoding.h +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ enum class BluetoothAudioStatus { /// Implements callbacks for the BT Audio HAL to start, suspend and configure /// the audio stream. Completion of the requested operation is indicated /// by the methods ack_stream_started, ack_stream_suspended. /// /// The callbacks are always invoked from one of the binder threads. class BluetoothAudioPort { public: virtual ~BluetoothAudioPort() {} Loading system/btif/src/btif_a2dp_source.cc +46 −30 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ #include "stack/include/bt_hdr.h" #include "stack/include/btm_client_interface.h" #include "stack/include/btm_status.h" #include "stack/include/main_thread.h" #include "types/raw_address.h" using bluetooth::audio::a2dp::BluetoothAudioStatus; Loading Loading @@ -227,9 +228,14 @@ private: BtifA2dpSource::RunState state_; }; /// Source worker thread created to run the CPU heavy encoder calls. /// Exactly three functions are executed on this thread: /// - btif_a2dp_source_audio_handle_timer /// - btif_a2dp_source_read_callback /// - btif_a2dp_source_enqueue_callback static bluetooth::common::MessageLoopThread btif_a2dp_source_thread("bt_a2dp_source_worker_thread"); static BtifA2dpSource btif_a2dp_source_cb; static BtifA2dpSource btif_a2dp_source_cb; static uint8_t btif_a2dp_source_dynamic_audio_buffer_size = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ; static void btif_a2dp_source_init_delayed(void); Loading Loading @@ -313,12 +319,19 @@ static void btif_a2dp_source_accumulate_stats(BtifMediaStats* src, BtifMediaStat src->Reset(); } /// Select the thread to run a2dp source actions on (a2dp encoder excluded). static bluetooth::common::MessageLoopThread* local_thread() { return com::android::bluetooth::flags::a2dp_source_threading_fix() ? get_main_thread() : &btif_a2dp_source_thread; } bool btif_a2dp_source_init(void) { log::info(""); // Start A2DP Source media task btif_a2dp_source_thread.StartUp(); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed)); return true; } Loading Loading @@ -384,8 +397,7 @@ static void btif_a2dp_source_init_delayed(void) { // the provider needs to be initialized earlier in order to ensure // get_a2dp_configuration and parse_a2dp_configuration can be // invoked before the stream is started. bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port, btif_av_is_a2dp_offload_enabled()); bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled()); } static bool btif_a2dp_source_startup(void) { Loading @@ -401,7 +413,7 @@ static bool btif_a2dp_source_startup(void) { btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX); // Schedule the rest of the operations btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed)); return true; } Loading @@ -413,7 +425,7 @@ static void btif_a2dp_source_startup_delayed() { log::fatal("unable to enable real time scheduling"); #endif } if (!bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port, if (!bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled())) { log::warn("Failed to setup the bluetooth audio HAL"); } Loading @@ -426,7 +438,7 @@ bool btif_a2dp_source_start_session(const RawAddress& peer_address, btif_a2dp_source_audio_tx_flush_req(); if (btif_a2dp_source_thread.DoInThread( if (local_thread()->DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_start_session_delayed, peer_address, std::move(peer_ready_promise)))) { return true; Loading Loading @@ -491,8 +503,8 @@ bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address, bool btif_a2dp_source_end_session(const RawAddress& peer_address) { log::info("peer_address={} state={}", peer_address, btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address)); btif_a2dp_source_cleanup_codec(); return true; } Loading @@ -518,7 +530,7 @@ static void btif_a2dp_source_end_session_delayed(const RawAddress& peer_address) void btif_a2dp_source_allow_low_latency_audio(bool allowed) { log::info("allowed={}", allowed); btif_a2dp_source_thread.DoInThread( local_thread()->DoInThread( FROM_HERE, base::BindOnce(bluetooth::audio::a2dp::set_audio_low_latency_mode_allowed, allowed)); } Loading @@ -534,9 +546,8 @@ void btif_a2dp_source_shutdown(std::promise<void> shutdown_complete_promise) { /* Make sure no channels are restarted while shutting down */ btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateShuttingDown); btif_a2dp_source_thread.DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed, std::move(shutdown_complete_promise))); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed, std::move(shutdown_complete_promise))); } static void btif_a2dp_source_shutdown_delayed(std::promise<void> shutdown_complete_promise) { Loading Loading @@ -614,8 +625,9 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) { log::error("Cannot stream audio: cannot set active peer to {}", peer_address); return; } btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface(peer_address); if (btif_a2dp_source_cb.encoder_interface == nullptr) { const tA2DP_ENCODER_INTERFACE* encoder_interface = bta_av_co_get_encoder_interface(peer_address); if (encoder_interface == nullptr) { log::error("Cannot stream audio: no source encoder interface"); return; } Loading @@ -626,11 +638,11 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) { return; } btif_a2dp_source_cb.encoder_interface->encoder_init(&peer_params, a2dp_codec_config, btif_a2dp_source_read_callback, encoder_interface->encoder_init(&peer_params, a2dp_codec_config, btif_a2dp_source_read_callback, btif_a2dp_source_enqueue_callback); // Save a local copy of the encoder_interval_ms btif_a2dp_source_cb.encoder_interface = encoder_interface; btif_a2dp_source_cb.encoder_interval_ms = btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(); Loading @@ -645,8 +657,7 @@ static void btif_a2dp_source_cleanup_codec() { log::info("state={}", btif_a2dp_source_cb.StateStr()); // Must stop media task first before cleaning up the encoder btif_a2dp_source_stop_audio_req(); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed)); } static void btif_a2dp_source_cleanup_codec_delayed() { Loading @@ -660,15 +671,13 @@ static void btif_a2dp_source_cleanup_codec_delayed() { void btif_a2dp_source_start_audio_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_start_event)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_start_event)); } void btif_a2dp_source_stop_audio_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_stop_event)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_stop_event)); } void btif_a2dp_source_encoder_user_config_update_req( Loading @@ -677,7 +686,8 @@ void btif_a2dp_source_encoder_user_config_update_req( std::promise<void> peer_ready_promise) { log::info("peer_address={} state={} {} codec_preference(s)", peer_address, btif_a2dp_source_cb.StateStr(), codec_user_preferences.size()); if (!btif_a2dp_source_thread.DoInThread( if (!local_thread()->DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_encoder_user_config_update_event, peer_address, codec_user_preferences, std::move(peer_ready_promise)))) { Loading Loading @@ -723,9 +733,8 @@ static void btif_a2dp_source_encoder_user_config_update_event( void btif_a2dp_source_feeding_update_req(const btav_a2dp_codec_config_t& codec_audio_config) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, codec_audio_config)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, codec_audio_config)); } static void btif_a2dp_source_audio_feeding_update_event( Loading Loading @@ -885,6 +894,12 @@ static void btif_a2dp_source_audio_tx_stop_event(void) { } } /// Periodic task responsible for encoding the audio stream and forwarding /// to the remote device. It will read PCM samples from the HAL provided FMQ, /// encode them into audio frames. Runs on the source worker thread. /// /// The timer driving the periodic task is cancelled before any state cleanup /// when the stream is ended. static void btif_a2dp_source_audio_handle_timer(void) { uint64_t timestamp_us = bluetooth::common::time_get_audio_server_tick_us(); uint64_t stats_timestamp_us = bluetooth::common::time_get_os_boottime_us(); Loading @@ -911,6 +926,8 @@ static void btif_a2dp_source_audio_handle_timer(void) { btif_a2dp_source_cb.encoder_interval_ms * 1000); } /// Callback invoked by the encoder for reading PCM audio data from the /// Bluetooth Audio HAL. Runs on the source worker thread. static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) { if (!btif_a2dp_source_cb.sw_audio_is_encoding) { return 0; Loading Loading @@ -1030,8 +1047,7 @@ static void btif_a2dp_source_audio_tx_flush_event(void) { static bool btif_a2dp_source_audio_tx_flush_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_flush_event)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_flush_event)); return true; } Loading Loading
system/audio_hal_interface/a2dp_encoding.h +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ enum class BluetoothAudioStatus { /// Implements callbacks for the BT Audio HAL to start, suspend and configure /// the audio stream. Completion of the requested operation is indicated /// by the methods ack_stream_started, ack_stream_suspended. /// /// The callbacks are always invoked from one of the binder threads. class BluetoothAudioPort { public: virtual ~BluetoothAudioPort() {} Loading
system/btif/src/btif_a2dp_source.cc +46 −30 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ #include "stack/include/bt_hdr.h" #include "stack/include/btm_client_interface.h" #include "stack/include/btm_status.h" #include "stack/include/main_thread.h" #include "types/raw_address.h" using bluetooth::audio::a2dp::BluetoothAudioStatus; Loading Loading @@ -227,9 +228,14 @@ private: BtifA2dpSource::RunState state_; }; /// Source worker thread created to run the CPU heavy encoder calls. /// Exactly three functions are executed on this thread: /// - btif_a2dp_source_audio_handle_timer /// - btif_a2dp_source_read_callback /// - btif_a2dp_source_enqueue_callback static bluetooth::common::MessageLoopThread btif_a2dp_source_thread("bt_a2dp_source_worker_thread"); static BtifA2dpSource btif_a2dp_source_cb; static BtifA2dpSource btif_a2dp_source_cb; static uint8_t btif_a2dp_source_dynamic_audio_buffer_size = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ; static void btif_a2dp_source_init_delayed(void); Loading Loading @@ -313,12 +319,19 @@ static void btif_a2dp_source_accumulate_stats(BtifMediaStats* src, BtifMediaStat src->Reset(); } /// Select the thread to run a2dp source actions on (a2dp encoder excluded). static bluetooth::common::MessageLoopThread* local_thread() { return com::android::bluetooth::flags::a2dp_source_threading_fix() ? get_main_thread() : &btif_a2dp_source_thread; } bool btif_a2dp_source_init(void) { log::info(""); // Start A2DP Source media task btif_a2dp_source_thread.StartUp(); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed)); return true; } Loading Loading @@ -384,8 +397,7 @@ static void btif_a2dp_source_init_delayed(void) { // the provider needs to be initialized earlier in order to ensure // get_a2dp_configuration and parse_a2dp_configuration can be // invoked before the stream is started. bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port, btif_av_is_a2dp_offload_enabled()); bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled()); } static bool btif_a2dp_source_startup(void) { Loading @@ -401,7 +413,7 @@ static bool btif_a2dp_source_startup(void) { btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX); // Schedule the rest of the operations btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed)); return true; } Loading @@ -413,7 +425,7 @@ static void btif_a2dp_source_startup_delayed() { log::fatal("unable to enable real time scheduling"); #endif } if (!bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port, if (!bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled())) { log::warn("Failed to setup the bluetooth audio HAL"); } Loading @@ -426,7 +438,7 @@ bool btif_a2dp_source_start_session(const RawAddress& peer_address, btif_a2dp_source_audio_tx_flush_req(); if (btif_a2dp_source_thread.DoInThread( if (local_thread()->DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_start_session_delayed, peer_address, std::move(peer_ready_promise)))) { return true; Loading Loading @@ -491,8 +503,8 @@ bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address, bool btif_a2dp_source_end_session(const RawAddress& peer_address) { log::info("peer_address={} state={}", peer_address, btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address)); btif_a2dp_source_cleanup_codec(); return true; } Loading @@ -518,7 +530,7 @@ static void btif_a2dp_source_end_session_delayed(const RawAddress& peer_address) void btif_a2dp_source_allow_low_latency_audio(bool allowed) { log::info("allowed={}", allowed); btif_a2dp_source_thread.DoInThread( local_thread()->DoInThread( FROM_HERE, base::BindOnce(bluetooth::audio::a2dp::set_audio_low_latency_mode_allowed, allowed)); } Loading @@ -534,9 +546,8 @@ void btif_a2dp_source_shutdown(std::promise<void> shutdown_complete_promise) { /* Make sure no channels are restarted while shutting down */ btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateShuttingDown); btif_a2dp_source_thread.DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed, std::move(shutdown_complete_promise))); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed, std::move(shutdown_complete_promise))); } static void btif_a2dp_source_shutdown_delayed(std::promise<void> shutdown_complete_promise) { Loading Loading @@ -614,8 +625,9 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) { log::error("Cannot stream audio: cannot set active peer to {}", peer_address); return; } btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface(peer_address); if (btif_a2dp_source_cb.encoder_interface == nullptr) { const tA2DP_ENCODER_INTERFACE* encoder_interface = bta_av_co_get_encoder_interface(peer_address); if (encoder_interface == nullptr) { log::error("Cannot stream audio: no source encoder interface"); return; } Loading @@ -626,11 +638,11 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) { return; } btif_a2dp_source_cb.encoder_interface->encoder_init(&peer_params, a2dp_codec_config, btif_a2dp_source_read_callback, encoder_interface->encoder_init(&peer_params, a2dp_codec_config, btif_a2dp_source_read_callback, btif_a2dp_source_enqueue_callback); // Save a local copy of the encoder_interval_ms btif_a2dp_source_cb.encoder_interface = encoder_interface; btif_a2dp_source_cb.encoder_interval_ms = btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(); Loading @@ -645,8 +657,7 @@ static void btif_a2dp_source_cleanup_codec() { log::info("state={}", btif_a2dp_source_cb.StateStr()); // Must stop media task first before cleaning up the encoder btif_a2dp_source_stop_audio_req(); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed)); } static void btif_a2dp_source_cleanup_codec_delayed() { Loading @@ -660,15 +671,13 @@ static void btif_a2dp_source_cleanup_codec_delayed() { void btif_a2dp_source_start_audio_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_start_event)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_start_event)); } void btif_a2dp_source_stop_audio_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_stop_event)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_stop_event)); } void btif_a2dp_source_encoder_user_config_update_req( Loading @@ -677,7 +686,8 @@ void btif_a2dp_source_encoder_user_config_update_req( std::promise<void> peer_ready_promise) { log::info("peer_address={} state={} {} codec_preference(s)", peer_address, btif_a2dp_source_cb.StateStr(), codec_user_preferences.size()); if (!btif_a2dp_source_thread.DoInThread( if (!local_thread()->DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_encoder_user_config_update_event, peer_address, codec_user_preferences, std::move(peer_ready_promise)))) { Loading Loading @@ -723,9 +733,8 @@ static void btif_a2dp_source_encoder_user_config_update_event( void btif_a2dp_source_feeding_update_req(const btav_a2dp_codec_config_t& codec_audio_config) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, codec_audio_config)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, codec_audio_config)); } static void btif_a2dp_source_audio_feeding_update_event( Loading Loading @@ -885,6 +894,12 @@ static void btif_a2dp_source_audio_tx_stop_event(void) { } } /// Periodic task responsible for encoding the audio stream and forwarding /// to the remote device. It will read PCM samples from the HAL provided FMQ, /// encode them into audio frames. Runs on the source worker thread. /// /// The timer driving the periodic task is cancelled before any state cleanup /// when the stream is ended. static void btif_a2dp_source_audio_handle_timer(void) { uint64_t timestamp_us = bluetooth::common::time_get_audio_server_tick_us(); uint64_t stats_timestamp_us = bluetooth::common::time_get_os_boottime_us(); Loading @@ -911,6 +926,8 @@ static void btif_a2dp_source_audio_handle_timer(void) { btif_a2dp_source_cb.encoder_interval_ms * 1000); } /// Callback invoked by the encoder for reading PCM audio data from the /// Bluetooth Audio HAL. Runs on the source worker thread. static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) { if (!btif_a2dp_source_cb.sw_audio_is_encoding) { return 0; Loading Loading @@ -1030,8 +1047,7 @@ static void btif_a2dp_source_audio_tx_flush_event(void) { static bool btif_a2dp_source_audio_tx_flush_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_flush_event)); local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_flush_event)); return true; } Loading