Loading android/app/jni/com_android_bluetooth_le_audio.cpp +30 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ using bluetooth::le_audio::LeAudioBroadcasterCallbacks; using bluetooth::le_audio::LeAudioBroadcasterInterface; using bluetooth::le_audio::LeAudioClientCallbacks; using bluetooth::le_audio::LeAudioClientInterface; using bluetooth::le_audio::UnicastMonitorModeStatus; namespace android { static jmethodID method_onInitialized; Loading @@ -53,6 +54,7 @@ static jmethodID method_onAudioGroupCurrentCodecConf; static jmethodID method_onAudioGroupSelectableCodecConf; static jmethodID method_onHealthBasedRecommendationAction; static jmethodID method_onHealthBasedGroupRecommendationAction; static jmethodID method_onUnicastMonitorModeStatus; static struct { jclass clazz; Loading Loading @@ -345,6 +347,19 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks { method_onHealthBasedGroupRecommendationAction, (jint)group_id, (jint)action); } void OnUnicastMonitorModeStatus(uint8_t direction, UnicastMonitorModeStatus status) override { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnicastMonitorModeStatus, (jint)direction, (jint)status); } }; static LeAudioClientCallbacksImpl sLeAudioClientCallbacks; Loading Loading @@ -681,6 +696,17 @@ static void setInCallNative(JNIEnv* /* env */, jobject /* object */, sLeAudioClientInterface->SetInCall(inCall); } static void setUnicastMonitorModeNative(JNIEnv* /* env */, jobject /* object */, jint direction, jboolean enable) { std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sLeAudioClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface"; return; } sLeAudioClientInterface->SetUnicastMonitorMode(direction, enable); } static void sendAudioProfilePreferencesNative( JNIEnv* /* env */, jint groupId, jboolean isOutputPreferenceLeAudio, jboolean isDuplexPreferenceLeAudio) { Loading Loading @@ -1548,6 +1574,8 @@ int register_com_android_bluetooth_le_audio(JNIEnv* env) { (void*)setCodecConfigPreferenceNative}, {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative}, {"setInCallNative", "(Z)V", (void*)setInCallNative}, {"setUnicastMonitorModeNative", "(IZ)V", (void*)setUnicastMonitorModeNative}, {"sendAudioProfilePreferencesNative", "(IZZ)V", (void*)sendAudioProfilePreferencesNative}, }; Loading Loading @@ -1582,6 +1610,8 @@ int register_com_android_bluetooth_le_audio(JNIEnv* env) { &method_onHealthBasedRecommendationAction}, {"onHealthBasedGroupRecommendationAction", "(II)V", &method_onHealthBasedGroupRecommendationAction}, {"onUnicastMonitorModeStatus", "(II)V", &method_onUnicastMonitorModeStatus}, }; GET_JAVA_METHODS(env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", javaMethods); Loading android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java +30 −0 Original line number Diff line number Diff line Loading @@ -258,6 +258,20 @@ public class LeAudioNativeInterface { } sendMessageToService(event); } @VisibleForTesting void onUnicastMonitorModeStatus(int direction, int status) { LeAudioStackEvent event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS); event.valueInt1 = direction; event.valueInt2 = status; if (DBG) { Log.d(TAG, "onUnicastMonitorModeStatus: " + event); } sendMessageToService(event); } /** * Initializes the native interface. * Loading Loading @@ -366,6 +380,20 @@ public class LeAudioNativeInterface { setInCallNative(inCall); } /** * Set unicast monitor mode flag. * * @param direction direction for which monitor mode should be used * @param enable true when LE Audio device should be listening for streaming status * on direction stream. false otherwise */ public void setUnicastMonitorMode(int direction, boolean enable) { if (DBG) { Log.d(TAG, "setUnicastMonitorMode enable: " + enable + ", direction : " + direction); } setUnicastMonitorModeNative(direction, enable); } /** * Sends the audio preferences for the groupId to the native stack. * Loading Loading @@ -398,6 +426,8 @@ public class LeAudioNativeInterface { BluetoothLeAudioCodecConfig outputCodecConfig); private native void setCcidInformationNative(int ccid, int contextType); private native void setInCallNative(boolean inCall); private native void setUnicastMonitorModeNative(int direction, boolean enable); /*package*/ private native void sendAudioProfilePreferencesNative(int groupId, boolean isOutputPreferenceLeAudio, boolean isDuplexPreferenceLeAudio); Loading android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java +35 −1 Original line number Diff line number Diff line Loading @@ -40,8 +40,9 @@ public class LeAudioStackEvent { public static final int EVENT_TYPE_NATIVE_INITIALIZED = 9; public static final int EVENT_TYPE_HEALTH_BASED_DEV_RECOMMENDATION = 10; public static final int EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION = 11; public static final int EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS = 12; // -------- DO NOT PUT ANY NEW UNICAST EVENTS BELOW THIS LINE------------- public static final int EVENT_TYPE_UNICAST_MAX = 12; public static final int EVENT_TYPE_UNICAST_MAX = 13; // Broadcast related events public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1; Loading Loading @@ -77,6 +78,17 @@ public class LeAudioStackEvent { static final int BROADCAST_STATE_STOPPING = 3; static final int BROADCAST_STATE_STREAMING = 4; // Do not modify without updating the HAL bt_le_audio.h files. // Match up with UnicastMonitorModeStatus enum of bt_le_audio.h static final int STATUS_LOCAL_STREAM_REQUESTED = 0; static final int STATUS_LOCAL_STREAM_STREAMING = 1; static final int STATUS_LOCAL_STREAM_SUSPENDED = 2; // Do not modify without updating le_audio_types.h // Match up with defines of le_audio_types.h static final int DIRECTION_SINK = 1; static final int DIRECTION_SOURCE = 2; public int type = EVENT_TYPE_NONE; public BluetoothDevice device; public int valueInt1 = 0; Loading Loading @@ -170,6 +182,8 @@ public class LeAudioStackEvent { return "EVENT_TYPE_HEALTH_BASED_DEV_RECOMMENDATION"; case EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION: return "EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION"; case EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS: return "EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS"; default: return "EVENT_TYPE_UNKNOWN:" + type; } Loading Loading @@ -223,6 +237,15 @@ public class LeAudioStackEvent { default: return "UNKNOWN"; } case EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS: switch (value) { case DIRECTION_SINK: return "DIRECTION_SINK"; case DIRECTION_SOURCE: return "DIRECTION_SOURCE"; default: return "UNKNOWN"; } default: break; } Loading Loading @@ -265,6 +288,17 @@ public class LeAudioStackEvent { default: return "UNKNOWN"; } case EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS: switch (value) { case STATUS_LOCAL_STREAM_REQUESTED: return "STATUS_LOCAL_STREAM_REQUESTED"; case STATUS_LOCAL_STREAM_STREAMING: return "STATUS_LOCAL_STREAM_STREAMING"; case STATUS_LOCAL_STREAM_SUSPENDED: return "STATUS_LOCAL_STREAM_SUSPENDED"; default: return "UNKNOWN"; } default: break; } Loading system/bta/include/bta_le_audio_api.h +1 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ class LeAudioClient { virtual void SetInCall(bool in_call) = 0; virtual bool IsInCall() = 0; virtual void SetInVoipCall(bool in_call) = 0; virtual void SetUnicastMonitorMode(uint8_t direction, bool enable) = 0; virtual bool IsInVoipCall() = 0; virtual void SendAudioProfilePreferences( const int group_id, bool is_output_preference_le_audio, Loading system/bta/le_audio/client.cc +81 −3 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ using bluetooth::le_audio::GroupNodeStatus; using bluetooth::le_audio::GroupStatus; using bluetooth::le_audio::GroupStreamStatus; using bluetooth::le_audio::LeAudioHealthBasedAction; using bluetooth::le_audio::UnicastMonitorModeStatus; using le_audio::CodecManager; using le_audio::ContentControlIdKeeper; using le_audio::DeviceConnectState; Loading Loading @@ -233,6 +234,8 @@ class LeAudioClientImpl : public LeAudioClient { audio_sender_state_(AudioState::IDLE), in_call_(false), in_voip_call_(false), sink_monitor_mode_(false), sink_monitor_notified_status_(std::nullopt), current_source_codec_config({0, 0, 0, 0}), current_sink_codec_config({0, 0, 0, 0}), le_audio_source_hal_client_(nullptr), Loading Loading @@ -1023,6 +1026,31 @@ class LeAudioClientImpl : public LeAudioClient { bool IsInVoipCall() override { return in_voip_call_; } void SetUnicastMonitorMode(uint8_t direction, bool enable) override { if (!IS_FLAG_ENABLED(leaudio_broadcast_audio_handover_policies)) { LOG_WARN("Monitor mode is disabled, Set Unicast Monitor mode is ignored"); return; } if (direction == le_audio::types::kLeAudioDirectionSink) { /* Cleanup Sink HAL client interface if listening mode is toggled off * before group activation (active group context would take care of * Sink HAL client cleanup). */ if (sink_monitor_mode_ && !enable && le_audio_sink_hal_client_ && active_group_id_ == bluetooth::groups::kGroupUnknown) { local_metadata_context_types_.sink.clear(); le_audio_sink_hal_client_->Stop(); le_audio_sink_hal_client_.reset(); } LOG_DEBUG("enable: %d", enable); sink_monitor_mode_ = enable; } else { LOG_ERROR("invalid direction: 0x%02x monitor mode set", direction); } } void SendAudioProfilePreferences( const int group_id, bool is_output_preference_le_audio, bool is_duplex_preference_le_audio) override { Loading Loading @@ -1137,6 +1165,7 @@ class LeAudioClientImpl : public LeAudioClient { } auto group_id_to_close = active_group_id_; active_group_id_ = bluetooth::groups::kGroupUnknown; sink_monitor_notified_status_ = std::nullopt; LOG_INFO("Group id: %d", group_id_to_close); if (alarm_is_scheduled(suspend_timeout_)) alarm_cancel(suspend_timeout_); Loading Loading @@ -1242,6 +1271,8 @@ class LeAudioClientImpl : public LeAudioClient { callbacks_->OnGroupStatus(previous_active_group, GroupStatus::INACTIVE); } /* Reset sink listener notified status */ sink_monitor_notified_status_ = std::nullopt; callbacks_->OnGroupStatus(active_group_id_, GroupStatus::ACTIVE); SendAudioGroupSelectableCodecConfigChanged(group); } Loading Loading @@ -3745,6 +3776,12 @@ class LeAudioClientImpl : public LeAudioClient { dprintf(fd, " local sink metadata context type mask: %s\n", local_metadata_context_types_.sink.to_string().c_str()); dprintf(fd, " TBS state: %s\n", in_call_ ? " In call" : "No calls"); dprintf(fd, " Sink listening mode: %s\n", sink_monitor_mode_ ? "true" : "false"); if (sink_monitor_notified_status_) { dprintf(fd, " Local sink notified state: %d\n", sink_monitor_notified_status_.value()); } dprintf(fd, " Start time: "); for (auto t : stream_start_history_queue_) { dprintf(fd, ", %d ms", static_cast<int>(t)); Loading @@ -3769,7 +3806,13 @@ class LeAudioClientImpl : public LeAudioClient { if (active_group_id_ != bluetooth::groups::kGroupUnknown) { /* Bluetooth turned off while streaming */ StopAudio(); SetUnicastMonitorMode(le_audio::types::kLeAudioDirectionSink, false); ClientAudioInterfaceRelease(); } else { /* There may be not stopped Sink HAL client due to set Listening mode */ if (sink_monitor_mode_) { SetUnicastMonitorMode(le_audio::types::kLeAudioDirectionSink, false); } } groupStateMachine_->Cleanup(); aseGroups_.Cleanup(); Loading Loading @@ -4221,6 +4264,16 @@ class LeAudioClientImpl : public LeAudioClient { .has_value(); } void notifyAudioLocalSink(UnicastMonitorModeStatus status) { if (sink_monitor_notified_status_ != status) { LOG_INFO("Stram monitoring status changed to: %d", static_cast<int>(status)); sink_monitor_notified_status_ = status; callbacks_->OnUnicastMonitorModeStatus( le_audio::types::kLeAudioDirectionSink, status); } } void OnLocalAudioSinkResume() { LOG_INFO( "active group_id: %d IN: audio_receiver_state_: %s, " Loading @@ -4233,6 +4286,14 @@ class LeAudioClientImpl : public LeAudioClient { "r_state: " + ToString(audio_receiver_state_) + ", s_state: " + ToString(audio_sender_state_)); if (active_group_id_ == bluetooth::groups::kGroupUnknown) { if (sink_monitor_mode_ && !sink_monitor_notified_status_) { notifyAudioLocalSink(UnicastMonitorModeStatus::STREAMING_REQUESTED); } CancelLocalAudioSinkStreamingRequest(); return; } /* Stop the VBC close watchdog if needed */ StopVbcCloseTimeout(); Loading Loading @@ -5463,6 +5524,12 @@ class LeAudioClientImpl : public LeAudioClient { LOG_INFO("Clear pending configuration flag for group %d", group->group_id_); group->ClearPendingConfiguration(); } else { if (sink_monitor_mode_) { callbacks_->OnUnicastMonitorModeStatus( le_audio::types::kLeAudioDirectionSink, UnicastMonitorModeStatus::STREAMING_SUSPENDED); } } } Loading Loading @@ -5537,6 +5604,10 @@ class LeAudioClientImpl : public LeAudioClient { /* Keep in call state. */ bool in_call_; bool in_voip_call_; /* Listen for streaming status on Sink stream */ bool sink_monitor_mode_; /* Status which has been notified to Service */ std::optional<UnicastMonitorModeStatus> sink_monitor_notified_status_; /* Reconnection mode */ tBTM_BLE_CONN_TYPE reconnection_mode_; Loading Loading @@ -5602,12 +5673,19 @@ class LeAudioClientImpl : public LeAudioClient { le_audio_source_hal_client_->Stop(); le_audio_source_hal_client_.reset(); } local_metadata_context_types_.sink.clear(); if (le_audio_sink_hal_client_) { /* Keep session set up to monitor streaming request. This is required if * there is another LE Audio device streaming (e.g. Broadcast) and via * the session callbacks special action from this Module would be * required e.g. to Unicast handover. */ if (!sink_monitor_mode_) { local_metadata_context_types_.sink.clear(); le_audio_sink_hal_client_->Stop(); le_audio_sink_hal_client_.reset(); } } local_metadata_context_types_.source.clear(); configuration_context_type_ = LeAudioContextType::UNINITIALIZED; Loading Loading
android/app/jni/com_android_bluetooth_le_audio.cpp +30 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ using bluetooth::le_audio::LeAudioBroadcasterCallbacks; using bluetooth::le_audio::LeAudioBroadcasterInterface; using bluetooth::le_audio::LeAudioClientCallbacks; using bluetooth::le_audio::LeAudioClientInterface; using bluetooth::le_audio::UnicastMonitorModeStatus; namespace android { static jmethodID method_onInitialized; Loading @@ -53,6 +54,7 @@ static jmethodID method_onAudioGroupCurrentCodecConf; static jmethodID method_onAudioGroupSelectableCodecConf; static jmethodID method_onHealthBasedRecommendationAction; static jmethodID method_onHealthBasedGroupRecommendationAction; static jmethodID method_onUnicastMonitorModeStatus; static struct { jclass clazz; Loading Loading @@ -345,6 +347,19 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks { method_onHealthBasedGroupRecommendationAction, (jint)group_id, (jint)action); } void OnUnicastMonitorModeStatus(uint8_t direction, UnicastMonitorModeStatus status) override { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnicastMonitorModeStatus, (jint)direction, (jint)status); } }; static LeAudioClientCallbacksImpl sLeAudioClientCallbacks; Loading Loading @@ -681,6 +696,17 @@ static void setInCallNative(JNIEnv* /* env */, jobject /* object */, sLeAudioClientInterface->SetInCall(inCall); } static void setUnicastMonitorModeNative(JNIEnv* /* env */, jobject /* object */, jint direction, jboolean enable) { std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sLeAudioClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface"; return; } sLeAudioClientInterface->SetUnicastMonitorMode(direction, enable); } static void sendAudioProfilePreferencesNative( JNIEnv* /* env */, jint groupId, jboolean isOutputPreferenceLeAudio, jboolean isDuplexPreferenceLeAudio) { Loading Loading @@ -1548,6 +1574,8 @@ int register_com_android_bluetooth_le_audio(JNIEnv* env) { (void*)setCodecConfigPreferenceNative}, {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative}, {"setInCallNative", "(Z)V", (void*)setInCallNative}, {"setUnicastMonitorModeNative", "(IZ)V", (void*)setUnicastMonitorModeNative}, {"sendAudioProfilePreferencesNative", "(IZZ)V", (void*)sendAudioProfilePreferencesNative}, }; Loading Loading @@ -1582,6 +1610,8 @@ int register_com_android_bluetooth_le_audio(JNIEnv* env) { &method_onHealthBasedRecommendationAction}, {"onHealthBasedGroupRecommendationAction", "(II)V", &method_onHealthBasedGroupRecommendationAction}, {"onUnicastMonitorModeStatus", "(II)V", &method_onUnicastMonitorModeStatus}, }; GET_JAVA_METHODS(env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", javaMethods); Loading
android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java +30 −0 Original line number Diff line number Diff line Loading @@ -258,6 +258,20 @@ public class LeAudioNativeInterface { } sendMessageToService(event); } @VisibleForTesting void onUnicastMonitorModeStatus(int direction, int status) { LeAudioStackEvent event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS); event.valueInt1 = direction; event.valueInt2 = status; if (DBG) { Log.d(TAG, "onUnicastMonitorModeStatus: " + event); } sendMessageToService(event); } /** * Initializes the native interface. * Loading Loading @@ -366,6 +380,20 @@ public class LeAudioNativeInterface { setInCallNative(inCall); } /** * Set unicast monitor mode flag. * * @param direction direction for which monitor mode should be used * @param enable true when LE Audio device should be listening for streaming status * on direction stream. false otherwise */ public void setUnicastMonitorMode(int direction, boolean enable) { if (DBG) { Log.d(TAG, "setUnicastMonitorMode enable: " + enable + ", direction : " + direction); } setUnicastMonitorModeNative(direction, enable); } /** * Sends the audio preferences for the groupId to the native stack. * Loading Loading @@ -398,6 +426,8 @@ public class LeAudioNativeInterface { BluetoothLeAudioCodecConfig outputCodecConfig); private native void setCcidInformationNative(int ccid, int contextType); private native void setInCallNative(boolean inCall); private native void setUnicastMonitorModeNative(int direction, boolean enable); /*package*/ private native void sendAudioProfilePreferencesNative(int groupId, boolean isOutputPreferenceLeAudio, boolean isDuplexPreferenceLeAudio); Loading
android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java +35 −1 Original line number Diff line number Diff line Loading @@ -40,8 +40,9 @@ public class LeAudioStackEvent { public static final int EVENT_TYPE_NATIVE_INITIALIZED = 9; public static final int EVENT_TYPE_HEALTH_BASED_DEV_RECOMMENDATION = 10; public static final int EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION = 11; public static final int EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS = 12; // -------- DO NOT PUT ANY NEW UNICAST EVENTS BELOW THIS LINE------------- public static final int EVENT_TYPE_UNICAST_MAX = 12; public static final int EVENT_TYPE_UNICAST_MAX = 13; // Broadcast related events public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1; Loading Loading @@ -77,6 +78,17 @@ public class LeAudioStackEvent { static final int BROADCAST_STATE_STOPPING = 3; static final int BROADCAST_STATE_STREAMING = 4; // Do not modify without updating the HAL bt_le_audio.h files. // Match up with UnicastMonitorModeStatus enum of bt_le_audio.h static final int STATUS_LOCAL_STREAM_REQUESTED = 0; static final int STATUS_LOCAL_STREAM_STREAMING = 1; static final int STATUS_LOCAL_STREAM_SUSPENDED = 2; // Do not modify without updating le_audio_types.h // Match up with defines of le_audio_types.h static final int DIRECTION_SINK = 1; static final int DIRECTION_SOURCE = 2; public int type = EVENT_TYPE_NONE; public BluetoothDevice device; public int valueInt1 = 0; Loading Loading @@ -170,6 +182,8 @@ public class LeAudioStackEvent { return "EVENT_TYPE_HEALTH_BASED_DEV_RECOMMENDATION"; case EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION: return "EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION"; case EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS: return "EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS"; default: return "EVENT_TYPE_UNKNOWN:" + type; } Loading Loading @@ -223,6 +237,15 @@ public class LeAudioStackEvent { default: return "UNKNOWN"; } case EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS: switch (value) { case DIRECTION_SINK: return "DIRECTION_SINK"; case DIRECTION_SOURCE: return "DIRECTION_SOURCE"; default: return "UNKNOWN"; } default: break; } Loading Loading @@ -265,6 +288,17 @@ public class LeAudioStackEvent { default: return "UNKNOWN"; } case EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS: switch (value) { case STATUS_LOCAL_STREAM_REQUESTED: return "STATUS_LOCAL_STREAM_REQUESTED"; case STATUS_LOCAL_STREAM_STREAMING: return "STATUS_LOCAL_STREAM_STREAMING"; case STATUS_LOCAL_STREAM_SUSPENDED: return "STATUS_LOCAL_STREAM_SUSPENDED"; default: return "UNKNOWN"; } default: break; } Loading
system/bta/include/bta_le_audio_api.h +1 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ class LeAudioClient { virtual void SetInCall(bool in_call) = 0; virtual bool IsInCall() = 0; virtual void SetInVoipCall(bool in_call) = 0; virtual void SetUnicastMonitorMode(uint8_t direction, bool enable) = 0; virtual bool IsInVoipCall() = 0; virtual void SendAudioProfilePreferences( const int group_id, bool is_output_preference_le_audio, Loading
system/bta/le_audio/client.cc +81 −3 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ using bluetooth::le_audio::GroupNodeStatus; using bluetooth::le_audio::GroupStatus; using bluetooth::le_audio::GroupStreamStatus; using bluetooth::le_audio::LeAudioHealthBasedAction; using bluetooth::le_audio::UnicastMonitorModeStatus; using le_audio::CodecManager; using le_audio::ContentControlIdKeeper; using le_audio::DeviceConnectState; Loading Loading @@ -233,6 +234,8 @@ class LeAudioClientImpl : public LeAudioClient { audio_sender_state_(AudioState::IDLE), in_call_(false), in_voip_call_(false), sink_monitor_mode_(false), sink_monitor_notified_status_(std::nullopt), current_source_codec_config({0, 0, 0, 0}), current_sink_codec_config({0, 0, 0, 0}), le_audio_source_hal_client_(nullptr), Loading Loading @@ -1023,6 +1026,31 @@ class LeAudioClientImpl : public LeAudioClient { bool IsInVoipCall() override { return in_voip_call_; } void SetUnicastMonitorMode(uint8_t direction, bool enable) override { if (!IS_FLAG_ENABLED(leaudio_broadcast_audio_handover_policies)) { LOG_WARN("Monitor mode is disabled, Set Unicast Monitor mode is ignored"); return; } if (direction == le_audio::types::kLeAudioDirectionSink) { /* Cleanup Sink HAL client interface if listening mode is toggled off * before group activation (active group context would take care of * Sink HAL client cleanup). */ if (sink_monitor_mode_ && !enable && le_audio_sink_hal_client_ && active_group_id_ == bluetooth::groups::kGroupUnknown) { local_metadata_context_types_.sink.clear(); le_audio_sink_hal_client_->Stop(); le_audio_sink_hal_client_.reset(); } LOG_DEBUG("enable: %d", enable); sink_monitor_mode_ = enable; } else { LOG_ERROR("invalid direction: 0x%02x monitor mode set", direction); } } void SendAudioProfilePreferences( const int group_id, bool is_output_preference_le_audio, bool is_duplex_preference_le_audio) override { Loading Loading @@ -1137,6 +1165,7 @@ class LeAudioClientImpl : public LeAudioClient { } auto group_id_to_close = active_group_id_; active_group_id_ = bluetooth::groups::kGroupUnknown; sink_monitor_notified_status_ = std::nullopt; LOG_INFO("Group id: %d", group_id_to_close); if (alarm_is_scheduled(suspend_timeout_)) alarm_cancel(suspend_timeout_); Loading Loading @@ -1242,6 +1271,8 @@ class LeAudioClientImpl : public LeAudioClient { callbacks_->OnGroupStatus(previous_active_group, GroupStatus::INACTIVE); } /* Reset sink listener notified status */ sink_monitor_notified_status_ = std::nullopt; callbacks_->OnGroupStatus(active_group_id_, GroupStatus::ACTIVE); SendAudioGroupSelectableCodecConfigChanged(group); } Loading Loading @@ -3745,6 +3776,12 @@ class LeAudioClientImpl : public LeAudioClient { dprintf(fd, " local sink metadata context type mask: %s\n", local_metadata_context_types_.sink.to_string().c_str()); dprintf(fd, " TBS state: %s\n", in_call_ ? " In call" : "No calls"); dprintf(fd, " Sink listening mode: %s\n", sink_monitor_mode_ ? "true" : "false"); if (sink_monitor_notified_status_) { dprintf(fd, " Local sink notified state: %d\n", sink_monitor_notified_status_.value()); } dprintf(fd, " Start time: "); for (auto t : stream_start_history_queue_) { dprintf(fd, ", %d ms", static_cast<int>(t)); Loading @@ -3769,7 +3806,13 @@ class LeAudioClientImpl : public LeAudioClient { if (active_group_id_ != bluetooth::groups::kGroupUnknown) { /* Bluetooth turned off while streaming */ StopAudio(); SetUnicastMonitorMode(le_audio::types::kLeAudioDirectionSink, false); ClientAudioInterfaceRelease(); } else { /* There may be not stopped Sink HAL client due to set Listening mode */ if (sink_monitor_mode_) { SetUnicastMonitorMode(le_audio::types::kLeAudioDirectionSink, false); } } groupStateMachine_->Cleanup(); aseGroups_.Cleanup(); Loading Loading @@ -4221,6 +4264,16 @@ class LeAudioClientImpl : public LeAudioClient { .has_value(); } void notifyAudioLocalSink(UnicastMonitorModeStatus status) { if (sink_monitor_notified_status_ != status) { LOG_INFO("Stram monitoring status changed to: %d", static_cast<int>(status)); sink_monitor_notified_status_ = status; callbacks_->OnUnicastMonitorModeStatus( le_audio::types::kLeAudioDirectionSink, status); } } void OnLocalAudioSinkResume() { LOG_INFO( "active group_id: %d IN: audio_receiver_state_: %s, " Loading @@ -4233,6 +4286,14 @@ class LeAudioClientImpl : public LeAudioClient { "r_state: " + ToString(audio_receiver_state_) + ", s_state: " + ToString(audio_sender_state_)); if (active_group_id_ == bluetooth::groups::kGroupUnknown) { if (sink_monitor_mode_ && !sink_monitor_notified_status_) { notifyAudioLocalSink(UnicastMonitorModeStatus::STREAMING_REQUESTED); } CancelLocalAudioSinkStreamingRequest(); return; } /* Stop the VBC close watchdog if needed */ StopVbcCloseTimeout(); Loading Loading @@ -5463,6 +5524,12 @@ class LeAudioClientImpl : public LeAudioClient { LOG_INFO("Clear pending configuration flag for group %d", group->group_id_); group->ClearPendingConfiguration(); } else { if (sink_monitor_mode_) { callbacks_->OnUnicastMonitorModeStatus( le_audio::types::kLeAudioDirectionSink, UnicastMonitorModeStatus::STREAMING_SUSPENDED); } } } Loading Loading @@ -5537,6 +5604,10 @@ class LeAudioClientImpl : public LeAudioClient { /* Keep in call state. */ bool in_call_; bool in_voip_call_; /* Listen for streaming status on Sink stream */ bool sink_monitor_mode_; /* Status which has been notified to Service */ std::optional<UnicastMonitorModeStatus> sink_monitor_notified_status_; /* Reconnection mode */ tBTM_BLE_CONN_TYPE reconnection_mode_; Loading Loading @@ -5602,12 +5673,19 @@ class LeAudioClientImpl : public LeAudioClient { le_audio_source_hal_client_->Stop(); le_audio_source_hal_client_.reset(); } local_metadata_context_types_.sink.clear(); if (le_audio_sink_hal_client_) { /* Keep session set up to monitor streaming request. This is required if * there is another LE Audio device streaming (e.g. Broadcast) and via * the session callbacks special action from this Module would be * required e.g. to Unicast handover. */ if (!sink_monitor_mode_) { local_metadata_context_types_.sink.clear(); le_audio_sink_hal_client_->Stop(); le_audio_sink_hal_client_.reset(); } } local_metadata_context_types_.source.clear(); configuration_context_type_ = LeAudioContextType::UNINITIALIZED; Loading