1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "le_audio_utils.h"
18
19 #include "bta/le_audio/content_control_id_keeper.h"
20 #include "gd/common/strings.h"
21 #include "le_audio_types.h"
22 #include "osi/include/log.h"
23
24 using bluetooth::common::ToString;
25 using le_audio::types::AudioContexts;
26 using le_audio::types::LeAudioContextType;
27
28 namespace le_audio {
29 namespace utils {
30
31 /* The returned LeAudioContextType should have its entry in the
32 * AudioSetConfigurationProvider's ContextTypeToScenario mapping table.
33 * Otherwise the AudioSetConfigurationProvider will fall back
34 * to default scenario.
35 */
AudioContentToLeAudioContext(audio_content_type_t content_type,audio_usage_t usage)36 LeAudioContextType AudioContentToLeAudioContext(
37 audio_content_type_t content_type, audio_usage_t usage) {
38 /* Check audio attribute usage of stream */
39 switch (usage) {
40 case AUDIO_USAGE_MEDIA:
41 return LeAudioContextType::MEDIA;
42 case AUDIO_USAGE_ASSISTANT:
43 return LeAudioContextType::VOICEASSISTANTS;
44 case AUDIO_USAGE_VOICE_COMMUNICATION:
45 case AUDIO_USAGE_CALL_ASSISTANT:
46 return LeAudioContextType::CONVERSATIONAL;
47 case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
48 if (content_type == AUDIO_CONTENT_TYPE_SPEECH)
49 return LeAudioContextType::CONVERSATIONAL;
50 else
51 return LeAudioContextType::MEDIA;
52 case AUDIO_USAGE_GAME:
53 return LeAudioContextType::GAME;
54 case AUDIO_USAGE_NOTIFICATION:
55 return LeAudioContextType::NOTIFICATIONS;
56 case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
57 return LeAudioContextType::RINGTONE;
58 case AUDIO_USAGE_ALARM:
59 return LeAudioContextType::ALERTS;
60 case AUDIO_USAGE_EMERGENCY:
61 return LeAudioContextType::EMERGENCYALARM;
62 case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
63 return LeAudioContextType::INSTRUCTIONAL;
64 case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
65 return LeAudioContextType::SOUNDEFFECTS;
66 default:
67 break;
68 }
69
70 return LeAudioContextType::MEDIA;
71 }
72
usageToString(audio_usage_t usage)73 static std::string usageToString(audio_usage_t usage) {
74 switch (usage) {
75 case AUDIO_USAGE_UNKNOWN:
76 return "USAGE_UNKNOWN";
77 case AUDIO_USAGE_MEDIA:
78 return "USAGE_MEDIA";
79 case AUDIO_USAGE_VOICE_COMMUNICATION:
80 return "USAGE_VOICE_COMMUNICATION";
81 case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
82 return "USAGE_VOICE_COMMUNICATION_SIGNALLING";
83 case AUDIO_USAGE_ALARM:
84 return "USAGE_ALARM";
85 case AUDIO_USAGE_NOTIFICATION:
86 return "USAGE_NOTIFICATION";
87 case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
88 return "USAGE_NOTIFICATION_TELEPHONY_RINGTONE";
89 case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
90 return "USAGE_NOTIFICATION_COMMUNICATION_REQUEST";
91 case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
92 return "USAGE_NOTIFICATION_COMMUNICATION_INSTANT";
93 case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
94 return "USAGE_NOTIFICATION_COMMUNICATION_DELAYED";
95 case AUDIO_USAGE_NOTIFICATION_EVENT:
96 return "USAGE_NOTIFICATION_EVENT";
97 case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
98 return "USAGE_ASSISTANCE_ACCESSIBILITY";
99 case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
100 return "USAGE_ASSISTANCE_NAVIGATION_GUIDANCE";
101 case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
102 return "USAGE_ASSISTANCE_SONIFICATION";
103 case AUDIO_USAGE_GAME:
104 return "USAGE_GAME";
105 case AUDIO_USAGE_ASSISTANT:
106 return "USAGE_ASSISTANT";
107 case AUDIO_USAGE_CALL_ASSISTANT:
108 return "USAGE_CALL_ASSISTANT";
109 case AUDIO_USAGE_EMERGENCY:
110 return "USAGE_EMERGENCY";
111 case AUDIO_USAGE_SAFETY:
112 return "USAGE_SAFETY";
113 case AUDIO_USAGE_VEHICLE_STATUS:
114 return "USAGE_VEHICLE_STATUS";
115 case AUDIO_USAGE_ANNOUNCEMENT:
116 return "USAGE_ANNOUNCEMENT";
117 default:
118 return "unknown usage ";
119 }
120 }
121
contentTypeToString(audio_content_type_t content_type)122 static std::string contentTypeToString(audio_content_type_t content_type) {
123 switch (content_type) {
124 case AUDIO_CONTENT_TYPE_UNKNOWN:
125 return "CONTENT_TYPE_UNKNOWN";
126 case AUDIO_CONTENT_TYPE_SPEECH:
127 return "CONTENT_TYPE_SPEECH";
128 case AUDIO_CONTENT_TYPE_MUSIC:
129 return "CONTENT_TYPE_MUSIC";
130 case AUDIO_CONTENT_TYPE_MOVIE:
131 return "CONTENT_TYPE_MOVIE";
132 case AUDIO_CONTENT_TYPE_SONIFICATION:
133 return "CONTENT_TYPE_SONIFICATION";
134 default:
135 return "unknown content type ";
136 }
137 }
138
audioSourceToStr(audio_source_t source)139 static const char* audioSourceToStr(audio_source_t source) {
140 const char* strArr[] = {
141 "AUDIO_SOURCE_DEFAULT", "AUDIO_SOURCE_MIC",
142 "AUDIO_SOURCE_VOICE_UPLINK", "AUDIO_SOURCE_VOICE_DOWNLINK",
143 "AUDIO_SOURCE_VOICE_CALL", "AUDIO_SOURCE_CAMCORDER",
144 "AUDIO_SOURCE_VOICE_RECOGNITION", "AUDIO_SOURCE_VOICE_COMMUNICATION",
145 "AUDIO_SOURCE_REMOTE_SUBMIX", "AUDIO_SOURCE_UNPROCESSED",
146 "AUDIO_SOURCE_VOICE_PERFORMANCE"};
147
148 if (static_cast<uint32_t>(source) < (sizeof(strArr) / sizeof(strArr[0])))
149 return strArr[source];
150 return "UNKNOWN";
151 }
152
GetAllowedAudioContextsFromSourceMetadata(const std::vector<struct playback_track_metadata> & source_metadata,AudioContexts allowed_contexts)153 AudioContexts GetAllowedAudioContextsFromSourceMetadata(
154 const std::vector<struct playback_track_metadata>& source_metadata,
155 AudioContexts allowed_contexts) {
156 AudioContexts track_contexts;
157 for (auto& track : source_metadata) {
158 if (track.content_type == 0 && track.usage == 0) continue;
159
160 LOG_INFO("%s: usage=%s(%d), content_type=%s(%d), gain=%f", __func__,
161 usageToString(track.usage).c_str(), track.usage,
162 contentTypeToString(track.content_type).c_str(),
163 track.content_type, track.gain);
164
165 track_contexts.set(
166 AudioContentToLeAudioContext(track.content_type, track.usage));
167 }
168 track_contexts &= allowed_contexts;
169 LOG_INFO("%s: allowed context= %s", __func__,
170 track_contexts.to_string().c_str());
171
172 return track_contexts;
173 }
174
GetAllowedAudioContextsFromSinkMetadata(const std::vector<struct record_track_metadata> & sink_metadata,AudioContexts allowed_contexts)175 AudioContexts GetAllowedAudioContextsFromSinkMetadata(
176 const std::vector<struct record_track_metadata>& sink_metadata,
177 AudioContexts allowed_contexts) {
178 AudioContexts all_track_contexts;
179
180 for (auto& track : sink_metadata) {
181 if (track.source == AUDIO_SOURCE_INVALID) continue;
182 LeAudioContextType track_context;
183
184 LOG_DEBUG(
185 "source=%s(0x%02x), gain=%f, destination device=0x%08x, destination "
186 "device address=%.32s, allowed_contexts=%s",
187 audioSourceToStr(track.source), track.source, track.gain,
188 track.dest_device, track.dest_device_address,
189 bluetooth::common::ToString(allowed_contexts).c_str());
190
191 if ((track.source == AUDIO_SOURCE_MIC) &&
192 (allowed_contexts.test(LeAudioContextType::LIVE))) {
193 track_context = LeAudioContextType::LIVE;
194
195 } else if ((track.source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
196 (allowed_contexts.test(LeAudioContextType::CONVERSATIONAL))) {
197 track_context = LeAudioContextType::CONVERSATIONAL;
198
199 } else if (allowed_contexts.test(LeAudioContextType::VOICEASSISTANTS)) {
200 /* Fallback to voice assistant
201 * This will handle also a case when the device is
202 * AUDIO_SOURCE_VOICE_RECOGNITION
203 */
204 track_context = LeAudioContextType::VOICEASSISTANTS;
205 LOG_WARN(
206 "Could not match the recording track type to group available "
207 "context. Using context %s.",
208 ToString(track_context).c_str());
209 }
210
211 all_track_contexts.set(track_context);
212 }
213
214 if (all_track_contexts.none()) {
215 all_track_contexts = AudioContexts(
216 static_cast<std::underlying_type<LeAudioContextType>::type>(
217 LeAudioContextType::UNSPECIFIED));
218 LOG_DEBUG(
219 "Unable to find supported audio source context for the remote audio "
220 "sink device. This may result in voice back channel malfunction.");
221 }
222
223 LOG_DEBUG("Allowed contexts from sink metadata: %s (0x%08hx)",
224 bluetooth::common::ToString(all_track_contexts).c_str(),
225 all_track_contexts.value());
226 return all_track_contexts;
227 }
228
GetAllCcids(const AudioContexts & contexts)229 std::vector<uint8_t> GetAllCcids(const AudioContexts& contexts) {
230 auto ccid_keeper = ContentControlIdKeeper::GetInstance();
231 std::vector<uint8_t> ccid_vec;
232
233 for (LeAudioContextType context : types::kLeAudioContextAllTypesArray) {
234 if (!contexts.test(context)) continue;
235 using T = std::underlying_type<LeAudioContextType>::type;
236 auto ccid = ccid_keeper->GetCcid(static_cast<T>(context));
237 if (ccid != -1) {
238 ccid_vec.push_back(static_cast<uint8_t>(ccid));
239 }
240 }
241
242 return ccid_vec;
243 }
244
245 } // namespace utils
246 } // namespace le_audio
247