From 94f3a3ac7aaeb75af5182654ee173998f8dee07b Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Thu, 2 May 2019 15:49:17 -0700 Subject: [PATCH] Add Delay reporting for Hearing Aids Use the RenderDelay parameter from the Hearing Aid devices to implement the Delay Reporting feature. This will helps in the lip-sync issues. Please note that this change will requires a re-pair of the Hearing Aids devices in order for the delay report to work well. Bug: 132115153 Test: Manual test Change-Id: If4bef049c18a3912817c2fa96b9bd890d5712c22 --- .../hearing_aid_software_encoding.cc | 41 ++++++++++++++++++++-- .../hearing_aid_software_encoding.h | 2 ++ bta/hearing_aid/hearing_aid.cc | 21 +++++++++-- bta/hearing_aid/hearing_aid_audio_source.cc | 4 ++- bta/include/bta_hearing_aid_api.h | 3 +- stack/gatt/gatt_main.cc | 3 +- 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/audio_hal_interface/hearing_aid_software_encoding.cc b/audio_hal_interface/hearing_aid_software_encoding.cc index 08922873c..0e348ed28 100644 --- a/audio_hal_interface/hearing_aid_software_encoding.cc +++ b/audio_hal_interface/hearing_aid_software_encoding.cc @@ -43,6 +43,7 @@ class HearingAidTransport : IBluetoothTransportInstance( SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH, {}), stream_cb_(std::move(stream_cb)), + remote_delay_report_ms_(0), total_bytes_read_(0), data_position_({}){}; @@ -79,10 +80,14 @@ class HearingAidTransport timespec* data_position) override { VLOG(2) << __func__ << ": data=" << total_bytes_read_ << " byte(s), timestamp=" << data_position_.tv_sec << "." - << data_position_.tv_nsec << "s"; - if (remote_delay_report_ns != nullptr) *remote_delay_report_ns = 0; + << data_position_.tv_nsec + << "s, delay report=" << remote_delay_report_ms_ << " msec."; + if (remote_delay_report_ns != nullptr) { + *remote_delay_report_ns = remote_delay_report_ms_ * 1000000u; + } if (total_bytes_read != nullptr) *total_bytes_read = total_bytes_read_; if (data_position != nullptr) *data_position = data_position_; + return true; } @@ -100,6 +105,8 @@ class HearingAidTransport } void ResetPresentationPosition() override { + VLOG(2) << __func__ << ": called."; + remote_delay_report_ms_ = 0; total_bytes_read_ = 0; data_position_ = {}; } @@ -111,8 +118,14 @@ class HearingAidTransport } } + void SetRemoteDelay(uint16_t delay_report_ms) { + LOG(INFO) << __func__ << ": delay_report=" << delay_report_ms << " msec"; + remote_delay_report_ms_ = delay_report_ms; + } + private: StreamCallbacks stream_cb_; + uint16_t remote_delay_report_ms_; uint64_t total_bytes_read_; timespec data_position_; }; @@ -134,6 +147,10 @@ bluetooth::audio::BluetoothAudioClientInterface* bool btaudio_hearing_aid_disabled = false; bool is_configured = false; +// Save the value if the remote reports its delay before hearing_aid_sink is +// initialized +uint16_t remote_delay_ms = 0; + bool is_hal_2_0_force_disabled() { if (!is_configured) { btaudio_hearing_aid_disabled = osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false); @@ -171,6 +188,13 @@ bool init(StreamCallbacks stream_cb, hearing_aid_sink = nullptr; return false; } + + if (remote_delay_ms != 0) { + LOG(INFO) << __func__ << ": restore DELAY " << remote_delay_ms << " ms"; + hearing_aid_sink->SetRemoteDelay(remote_delay_ms); + remote_delay_ms = 0; + } + return true; } @@ -182,6 +206,7 @@ void cleanup() { hearing_aid_hal_clientinterface = nullptr; delete hearing_aid_sink; hearing_aid_sink = nullptr; + remote_delay_ms = 0; } void start_session() { @@ -212,6 +237,18 @@ size_t read(uint8_t* p_buf, uint32_t len) { return hearing_aid_hal_clientinterface->ReadAudioData(p_buf, len); } +// Update Hearing Aids delay report to BluetoothAudio HAL +void set_remote_delay(uint16_t delay_report_ms) { + if (!is_hal_2_0_enabled()) { + LOG(INFO) << __func__ << ": not ready for DelayReport " << delay_report_ms + << " ms"; + remote_delay_ms = delay_report_ms; + return; + } + LOG(INFO) << __func__ << ": delay_report_ms=" << delay_report_ms << " ms"; + hearing_aid_sink->SetRemoteDelay(delay_report_ms); +} + } // namespace hearing_aid } // namespace audio } // namespace bluetooth diff --git a/audio_hal_interface/hearing_aid_software_encoding.h b/audio_hal_interface/hearing_aid_software_encoding.h index 5723033b1..8a64fcdaa 100644 --- a/audio_hal_interface/hearing_aid_software_encoding.h +++ b/audio_hal_interface/hearing_aid_software_encoding.h @@ -42,6 +42,8 @@ void cleanup(); void start_session(); void end_session(); +void set_remote_delay(uint16_t delay_report_ms); + // Read from the FMQ of BluetoothAudio HAL size_t read(uint8_t* p_buf, uint32_t len); diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc index 582b6a166..f5c34ca98 100644 --- a/bta/hearing_aid/hearing_aid.cc +++ b/bta/hearing_aid/hearing_aid.cc @@ -69,6 +69,13 @@ constexpr uint8_t AUDIOTYPE_UNKNOWN = 0x00; constexpr uint8_t OTHER_SIDE_NOT_STREAMING = 0x00; constexpr uint8_t OTHER_SIDE_IS_STREAMING = 0x01; +// This ADD_RENDER_DELAY_INTERVALS is the number of connection intervals when +// the audio data packet is send by Audio Engine to when the Hearing Aids device +// received it from the air. We assumed that there is 2 data buffer queued from +// audio subsystem to bluetooth chip. Then the estimated OTA delay is two +// connnection intervals. +constexpr uint16_t ADD_RENDER_DELAY_INTERVALS = 4; + namespace { // clang-format off @@ -975,7 +982,14 @@ class HearingAidImpl : public HearingAid { codec.bit_rate = 16; codec.data_interval_ms = default_data_interval_ms; - HearingAidAudioSource::Start(codec, audioReceiver); + uint16_t delay_report_ms = 0; + if (hearingDevice.render_delay != 0) { + delay_report_ms = + hearingDevice.render_delay + + (ADD_RENDER_DELAY_INTERVALS * default_data_interval_ms); + } + + HearingAidAudioSource::Start(codec, audioReceiver, delay_report_ms); } } @@ -1409,7 +1423,8 @@ class HearingAidImpl : public HearingAid { bool connected = hearingDevice->accepting_audio; LOG(INFO) << "GAP_EVT_CONN_CLOSED: " << hearingDevice->address - << ", playback_started=" << hearingDevice->playback_started; + << ", playback_started=" << hearingDevice->playback_started + << ", accepting_audio=" << hearingDevice->accepting_audio; hearingDevice->playback_started = false; @@ -1443,6 +1458,8 @@ class HearingAidImpl : public HearingAid { << loghex(conn_id); return; } + VLOG(2) << __func__ << ": conn_id=" << loghex(conn_id) + << ", reason=" << loghex(reason) << ", remote_bda=" << remote_bda; // Inform the other side (if any) of this disconnection std::vector inform_disconn_state( diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc index e966d0182..cd6d5fad5 100644 --- a/bta/hearing_aid/hearing_aid_audio_source.cc +++ b/bta/hearing_aid/hearing_aid_audio_source.cc @@ -367,7 +367,8 @@ bool hearing_aid_on_suspend_req() { } // namespace void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration, - HearingAidAudioReceiver* audioReceiver) { + HearingAidAudioReceiver* audioReceiver, + uint16_t remote_delay_ms) { localAudioReceiver = audioReceiver; VLOG(2) << "Hearing Aid UIPC Open"; @@ -379,6 +380,7 @@ void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration, if (bluetooth::audio::hearing_aid::is_hal_2_0_enabled()) { bluetooth::audio::hearing_aid::start_session(); + bluetooth::audio::hearing_aid::set_remote_delay(remote_delay_ms); } } diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h index 9f748bf39..f58401d67 100644 --- a/bta/include/bta_hearing_aid_api.h +++ b/bta/include/bta_hearing_aid_api.h @@ -236,7 +236,8 @@ struct CodecConfiguration { class HearingAidAudioSource { public: static void Start(const CodecConfiguration& codecConfiguration, - HearingAidAudioReceiver* audioReceiver); + HearingAidAudioReceiver* audioReceiver, + uint16_t remote_delay_ms); static void Stop(); static void Initialize(); static void CleanUp(); diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc index 62e2d1651..87bae6ebf 100644 --- a/stack/gatt/gatt_main.cc +++ b/stack/gatt/gatt_main.cc @@ -1022,7 +1022,8 @@ void gatt_proc_srv_chg(void) { void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) { if (!p_tcb) return; - VLOG(1) << __func__ << ": old=" << +p_tcb->ch_state << " new=" << ch_state; + VLOG(1) << __func__ << ": old=" << +p_tcb->ch_state + << " new=" << loghex(ch_state); p_tcb->ch_state = ch_state; } -- 2.11.0