/* * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "a2dp_encoding" #include "a2dp_encoding_aidl.h" #include "a2dp_transport.h" #include "audio_aidl_interfaces.h" #include "btif/include/btif_common.h" #include "codec_status_aidl.h" #include "transport_instance.h" namespace bluetooth { namespace audio { namespace aidl { namespace a2dp { namespace { using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; using ::aidl::android::hardware::bluetooth::audio::ChannelMode; using ::aidl::android::hardware::bluetooth::audio::CodecConfiguration; using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; using ::aidl::android::hardware::bluetooth::audio::SessionType; using ::bluetooth::audio::aidl::BluetoothAudioCtrlAck; using ::bluetooth::audio::aidl::BluetoothAudioSinkClientInterface; using ::bluetooth::audio::aidl::codec::A2dpAacToHalConfig; using ::bluetooth::audio::aidl::codec::A2dpAptxToHalConfig; using ::bluetooth::audio::aidl::codec::A2dpCodecToHalBitsPerSample; using ::bluetooth::audio::aidl::codec::A2dpCodecToHalChannelMode; using ::bluetooth::audio::aidl::codec::A2dpCodecToHalSampleRate; using ::bluetooth::audio::aidl::codec::A2dpLdacToHalConfig; using ::bluetooth::audio::aidl::codec::A2dpSbcToHalConfig; /*** * * A2dpTransport functions and variables * ***/ tA2DP_CTRL_CMD A2dpTransport::a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE; uint16_t A2dpTransport::remote_delay_report_ = 0; A2dpTransport::A2dpTransport(SessionType sessionType) : IBluetoothSinkTransportInstance(sessionType, (AudioConfiguration){}), total_bytes_read_(0), data_position_({}) { a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE; remote_delay_report_ = 0; } BluetoothAudioCtrlAck A2dpTransport::StartRequest(bool is_low_latency) { // Check if a previous request is not finished if (a2dp_pending_cmd_ == A2DP_CTRL_CMD_START) { LOG(INFO) << __func__ << ": A2DP_CTRL_CMD_START in progress"; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING); } else if (a2dp_pending_cmd_ != A2DP_CTRL_CMD_NONE) { LOG(WARNING) << __func__ << ": busy in pending_cmd=" << a2dp_pending_cmd_; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE); } // Don't send START request to stack while we are in a call if (!bluetooth::headset::IsCallIdle()) { LOG(ERROR) << __func__ << ": call state is busy"; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_INCALL_FAILURE); } if (btif_av_stream_started_ready()) { // Already started, ACK back immediately. return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS); } if (btif_av_stream_ready()) { /* * Post start event and wait for audio path to open. * If we are the source, the ACK will be sent after the start * procedure is completed, othewise send it now. */ a2dp_pending_cmd_ = A2DP_CTRL_CMD_START; btif_av_stream_start(); if (btif_av_get_peer_sep() != AVDT_TSEP_SRC) { LOG(INFO) << __func__ << ": accepted"; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING); } a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE; invoke_switch_codec_cb(is_low_latency); return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS); } LOG(ERROR) << __func__ << ": AV stream is not ready to start"; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE); } BluetoothAudioCtrlAck A2dpTransport::SuspendRequest() { // Previous request is not finished if (a2dp_pending_cmd_ == A2DP_CTRL_CMD_SUSPEND) { LOG(INFO) << __func__ << ": A2DP_CTRL_CMD_SUSPEND in progress"; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING); } else if (a2dp_pending_cmd_ != A2DP_CTRL_CMD_NONE) { LOG(WARNING) << __func__ << ": busy in pending_cmd=" << a2dp_pending_cmd_; return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE); } // Local suspend if (btif_av_stream_started_ready()) { LOG(INFO) << __func__ << ": accepted"; a2dp_pending_cmd_ = A2DP_CTRL_CMD_SUSPEND; btif_av_stream_suspend(); return BluetoothAudioCtrlAck::PENDING; } /* If we are not in started state, just ack back ok and let * audioflinger close the channel. This can happen if we are * remotely suspended, clear REMOTE SUSPEND flag. */ btif_av_clear_remote_suspend_flag(); return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS); } void A2dpTransport::StopRequest() { if (btif_av_get_peer_sep() == AVDT_TSEP_SNK && !btif_av_stream_started_ready()) { btif_av_clear_remote_suspend_flag(); return; } LOG(INFO) << __func__ << ": handling"; a2dp_pending_cmd_ = A2DP_CTRL_CMD_STOP; btif_av_stream_stop(RawAddress::kEmpty); } bool A2dpTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_read, timespec* data_position) { *remote_delay_report_ns = remote_delay_report_ * 100000u; *total_bytes_read = total_bytes_read_; *data_position = data_position_; VLOG(2) << __func__ << ": delay=" << remote_delay_report_ << "/10ms, data=" << total_bytes_read_ << " byte(s), timestamp=" << data_position_.tv_sec << "." << data_position_.tv_nsec << "s"; return true; } void A2dpTransport::SourceMetadataChanged( const source_metadata_t& source_metadata) { auto track_count = source_metadata.track_count; auto tracks = source_metadata.tracks; VLOG(1) << __func__ << ": " << track_count << " track(s) received"; while (track_count) { VLOG(2) << __func__ << ": usage=" << tracks->usage << ", content_type=" << tracks->content_type << ", gain=" << tracks->gain; --track_count; ++tracks; } } void A2dpTransport::SinkMetadataChanged(const sink_metadata_t&) {} tA2DP_CTRL_CMD A2dpTransport::GetPendingCmd() const { return a2dp_pending_cmd_; } void A2dpTransport::ResetPendingCmd() { a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE; } void A2dpTransport::ResetPresentationPosition() { remote_delay_report_ = 0; total_bytes_read_ = 0; data_position_ = {}; } void A2dpTransport::LogBytesRead(size_t bytes_read) { if (bytes_read != 0) { total_bytes_read_ += bytes_read; clock_gettime(CLOCK_MONOTONIC, &data_position_); } } /*** * * Global functions and variables * ***/ // delay reports from AVDTP is based on 1/10 ms (100us) void A2dpTransport::SetRemoteDelay(uint16_t delay_report) { remote_delay_report_ = delay_report; } // Common interface to call-out into Bluetooth Audio HAL BluetoothAudioSinkClientInterface* software_hal_interface = nullptr; BluetoothAudioSinkClientInterface* offloading_hal_interface = nullptr; BluetoothAudioSinkClientInterface* active_hal_interface = nullptr; // Save the value if the remote reports its delay before this interface is // initialized uint16_t remote_delay = 0; bool btaudio_a2dp_disabled = false; bool is_configured = false; bool is_low_latency_mode_allowed = false; BluetoothAudioCtrlAck a2dp_ack_to_bt_audio_ctrl_ack(tA2DP_CTRL_ACK ack) { switch (ack) { case A2DP_CTRL_ACK_SUCCESS: return BluetoothAudioCtrlAck::SUCCESS_FINISHED; case A2DP_CTRL_ACK_PENDING: return BluetoothAudioCtrlAck::PENDING; case A2DP_CTRL_ACK_INCALL_FAILURE: return BluetoothAudioCtrlAck::FAILURE_BUSY; case A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS: return BluetoothAudioCtrlAck::FAILURE_DISCONNECTING; case A2DP_CTRL_ACK_UNSUPPORTED: /* Offloading but resource failure */ return BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED; case A2DP_CTRL_ACK_FAILURE: return BluetoothAudioCtrlAck::FAILURE; default: return BluetoothAudioCtrlAck::FAILURE; } } bool a2dp_get_selected_hal_codec_config(CodecConfiguration* codec_config) { A2dpCodecConfig* a2dp_config = bta_av_get_a2dp_current_codec(); if (a2dp_config == nullptr) { LOG(WARNING) << __func__ << ": failure to get A2DP codec config"; return false; } btav_a2dp_codec_config_t current_codec = a2dp_config->getCodecConfig(); switch (current_codec.codec_type) { case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC: [[fallthrough]]; case BTAV_A2DP_CODEC_INDEX_SINK_SBC: { if (!A2dpSbcToHalConfig(codec_config, a2dp_config)) { return false; } break; } case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC: [[fallthrough]]; case BTAV_A2DP_CODEC_INDEX_SINK_AAC: { if (!A2dpAacToHalConfig(codec_config, a2dp_config)) { return false; } break; } case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX: [[fallthrough]]; case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD: { if (!A2dpAptxToHalConfig(codec_config, a2dp_config)) { return false; } break; } case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC: { if (!A2dpLdacToHalConfig(codec_config, a2dp_config)) { return false; } break; } case BTAV_A2DP_CODEC_INDEX_MAX: [[fallthrough]]; default: LOG(ERROR) << __func__ << ": Unknown codec_type=" << current_codec.codec_type; return false; } codec_config->encodedAudioBitrate = a2dp_config->getTrackBitRate(); // Obtain the MTU RawAddress peer_addr = btif_av_source_active_peer(); tA2DP_ENCODER_INIT_PEER_PARAMS peer_param; bta_av_co_get_peer_params(peer_addr, &peer_param); int effectiveMtu = bta_av_co_get_encoder_effective_frame_size(); if (effectiveMtu > 0 && effectiveMtu < peer_param.peer_mtu) { codec_config->peerMtu = effectiveMtu; } else { codec_config->peerMtu = peer_param.peer_mtu; } if (current_codec.codec_type == BTAV_A2DP_CODEC_INDEX_SOURCE_SBC && codec_config->config.get() .maxBitpool <= A2DP_SBC_BITPOOL_MIDDLE_QUALITY) { codec_config->peerMtu = MAX_2MBPS_AVDTP_MTU; } else if (codec_config->peerMtu > MAX_3MBPS_AVDTP_MTU) { codec_config->peerMtu = MAX_3MBPS_AVDTP_MTU; } LOG(INFO) << __func__ << ": CodecConfiguration=" << codec_config->toString(); return true; } bool a2dp_get_selected_hal_pcm_config(PcmConfiguration* pcm_config) { if (pcm_config == nullptr) return false; A2dpCodecConfig* a2dp_codec_configs = bta_av_get_a2dp_current_codec(); if (a2dp_codec_configs == nullptr) { LOG(WARNING) << __func__ << ": failure to get A2DP codec config"; *pcm_config = BluetoothAudioSinkClientInterface::kInvalidPcmConfiguration; return false; } btav_a2dp_codec_config_t current_codec = a2dp_codec_configs->getCodecConfig(); pcm_config->sampleRateHz = A2dpCodecToHalSampleRate(current_codec); pcm_config->bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec); pcm_config->channelMode = A2dpCodecToHalChannelMode(current_codec); return (pcm_config->sampleRateHz > 0 && pcm_config->bitsPerSample > 0 && pcm_config->channelMode != ChannelMode::UNKNOWN); } // Checking if new bluetooth_audio is supported bool is_hal_force_disabled() { if (!is_configured) { btaudio_a2dp_disabled = osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false); is_configured = true; } return btaudio_a2dp_disabled; } } // namespace bool update_codec_offloading_capabilities( const std::vector& framework_preference) { return ::bluetooth::audio::aidl::codec::UpdateOffloadingCapabilities( framework_preference); } // Checking if new bluetooth_audio is enabled bool is_hal_enabled() { return active_hal_interface != nullptr; } // Check if new bluetooth_audio is running with offloading encoders bool is_hal_offloading() { if (!is_hal_enabled()) { return false; } return active_hal_interface->GetTransportInstance()->GetSessionType() == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH; } // Initialize BluetoothAudio HAL: openProvider bool init(bluetooth::common::MessageLoopThread* message_loop) { LOG(INFO) << __func__; if (is_hal_force_disabled()) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is disabled"; return false; } if (!BluetoothAudioClientInterface::is_aidl_available()) { LOG(ERROR) << __func__ << ": BluetoothAudio AIDL implementation does not exist"; return false; } auto a2dp_sink = new A2dpTransport(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH); software_hal_interface = new BluetoothAudioSinkClientInterface(a2dp_sink, message_loop); if (!software_hal_interface->IsValid()) { LOG(WARNING) << __func__ << ": BluetoothAudio HAL for A2DP is invalid?!"; delete software_hal_interface; software_hal_interface = nullptr; delete a2dp_sink; return false; } if (btif_av_is_a2dp_offload_enabled()) { a2dp_sink = new A2dpTransport(SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH); offloading_hal_interface = new BluetoothAudioSinkClientInterface(a2dp_sink, message_loop); if (!offloading_hal_interface->IsValid()) { LOG(FATAL) << __func__ << ": BluetoothAudio HAL for A2DP offloading is invalid?!"; delete offloading_hal_interface; offloading_hal_interface = nullptr; delete a2dp_sink; a2dp_sink = static_cast( software_hal_interface->GetTransportInstance()); delete software_hal_interface; software_hal_interface = nullptr; delete a2dp_sink; return false; } } active_hal_interface = (offloading_hal_interface != nullptr ? offloading_hal_interface : software_hal_interface); if (remote_delay != 0) { LOG(INFO) << __func__ << ": restore DELAY " << static_cast(remote_delay / 10.0) << " ms"; static_cast(active_hal_interface->GetTransportInstance()) ->SetRemoteDelay(remote_delay); remote_delay = 0; } return true; } // Clean up BluetoothAudio HAL void cleanup() { if (!is_hal_enabled()) return; end_session(); auto a2dp_sink = active_hal_interface->GetTransportInstance(); static_cast(a2dp_sink)->ResetPendingCmd(); static_cast(a2dp_sink)->ResetPresentationPosition(); active_hal_interface = nullptr; a2dp_sink = software_hal_interface->GetTransportInstance(); delete software_hal_interface; software_hal_interface = nullptr; delete a2dp_sink; if (offloading_hal_interface != nullptr) { a2dp_sink = offloading_hal_interface->GetTransportInstance(); delete offloading_hal_interface; offloading_hal_interface = nullptr; delete a2dp_sink; } remote_delay = 0; } // Set up the codec into BluetoothAudio HAL bool setup_codec() { if (!is_hal_enabled()) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return false; } CodecConfiguration codec_config{}; if (!a2dp_get_selected_hal_codec_config(&codec_config)) { LOG(ERROR) << __func__ << ": Failed to get CodecConfiguration"; return false; } bool should_codec_offloading = bluetooth::audio::aidl::codec::IsCodecOffloadingEnabled(codec_config); if (should_codec_offloading && !is_hal_offloading()) { LOG(WARNING) << __func__ << ": Switching BluetoothAudio HAL to Hardware"; end_session(); active_hal_interface = offloading_hal_interface; } else if (!should_codec_offloading && is_hal_offloading()) { LOG(WARNING) << __func__ << ": Switching BluetoothAudio HAL to Software"; end_session(); active_hal_interface = software_hal_interface; } AudioConfiguration audio_config{}; if (active_hal_interface->GetTransportInstance()->GetSessionType() == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { audio_config.set(codec_config); } else { PcmConfiguration pcm_config{}; if (!a2dp_get_selected_hal_pcm_config(&pcm_config)) { LOG(ERROR) << __func__ << ": Failed to get PcmConfiguration"; return false; } audio_config.set(pcm_config); } return active_hal_interface->UpdateAudioConfig(audio_config); } void start_session() { if (!is_hal_enabled()) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return; } active_hal_interface->SetLowLatencyModeAllowed(is_low_latency_mode_allowed); active_hal_interface->StartSession(); } void end_session() { if (!is_hal_enabled()) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return; } active_hal_interface->EndSession(); static_cast(active_hal_interface->GetTransportInstance()) ->ResetPendingCmd(); static_cast(active_hal_interface->GetTransportInstance()) ->ResetPresentationPosition(); } void ack_stream_started(const tA2DP_CTRL_ACK& ack) { auto ctrl_ack = a2dp_ack_to_bt_audio_ctrl_ack(ack); LOG(INFO) << __func__ << ": result=" << ctrl_ack; auto a2dp_sink = static_cast(active_hal_interface->GetTransportInstance()); auto pending_cmd = a2dp_sink->GetPendingCmd(); if (pending_cmd == A2DP_CTRL_CMD_START) { active_hal_interface->StreamStarted(ctrl_ack); } else { LOG(WARNING) << __func__ << ": pending=" << pending_cmd << " ignore result=" << ctrl_ack; return; } if (ctrl_ack != BluetoothAudioCtrlAck::PENDING) { a2dp_sink->ResetPendingCmd(); } } void ack_stream_suspended(const tA2DP_CTRL_ACK& ack) { auto ctrl_ack = a2dp_ack_to_bt_audio_ctrl_ack(ack); LOG(INFO) << __func__ << ": result=" << ctrl_ack; auto a2dp_sink = static_cast(active_hal_interface->GetTransportInstance()); auto pending_cmd = a2dp_sink->GetPendingCmd(); if (pending_cmd == A2DP_CTRL_CMD_SUSPEND) { active_hal_interface->StreamSuspended(ctrl_ack); } else if (pending_cmd == A2DP_CTRL_CMD_STOP) { LOG(INFO) << __func__ << ": A2DP_CTRL_CMD_STOP result=" << ctrl_ack; } else { LOG(WARNING) << __func__ << ": pending=" << pending_cmd << " ignore result=" << ctrl_ack; return; } if (ctrl_ack != BluetoothAudioCtrlAck::PENDING) { a2dp_sink->ResetPendingCmd(); } } // Read from the FMQ of BluetoothAudio HAL size_t read(uint8_t* p_buf, uint32_t len) { if (!is_hal_enabled()) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return 0; } else if (is_hal_offloading()) { LOG(ERROR) << __func__ << ": session_type=" << toString(active_hal_interface->GetTransportInstance() ->GetSessionType()) << " is not A2DP_SOFTWARE_ENCODING_DATAPATH"; return 0; } return active_hal_interface->ReadAudioData(p_buf, len); } // Update A2DP delay report to BluetoothAudio HAL void set_remote_delay(uint16_t delay_report) { if (!is_hal_enabled()) { LOG(INFO) << __func__ << ": not ready for DelayReport " << static_cast(delay_report / 10.0) << " ms"; remote_delay = delay_report; return; } VLOG(1) << __func__ << ": DELAY " << static_cast(delay_report / 10.0) << " ms"; static_cast(active_hal_interface->GetTransportInstance()) ->SetRemoteDelay(delay_report); } // Set low latency buffer mode allowed or disallowed void set_low_latency_mode_allowed(bool allowed) { is_low_latency_mode_allowed = allowed; if (!is_hal_enabled()) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return; } active_hal_interface->SetLowLatencyModeAllowed(allowed); } } // namespace a2dp } // namespace aidl } // namespace audio } // namespace bluetooth