1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
17 #define ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
18 #ifndef LOG_TAG
19 #define LOG_TAG "PulseAudioServiceAdapterImpl"
20 #endif
21
22 #include "pulse_audio_service_adapter_impl.h"
23
24 #include <sstream>
25 #include <unistd.h>
26 #include <thread>
27
28 #include "audio_errors.h"
29 #include "audio_common_log.h"
30 #include "audio_info.h"
31 #include "audio_utils.h"
32 #include "hisysevent.h"
33 #include <set>
34 #include <unordered_map>
35
36 #include "media_monitor_manager.h"
37 #include "event_bean.h"
38 #include "pa_adapter_tools.h"
39
40 using namespace std;
41
42 namespace OHOS {
43 namespace AudioStandard {
44 static unique_ptr<AudioServiceAdapterCallback> g_audioServiceAdapterCallback;
45 SafeMap<uint32_t, uint32_t> PulseAudioServiceAdapterImpl::sourceIndexSessionIDMap;
46
47 static const int32_t PA_SERVICE_IMPL_TIMEOUT = 10; // 10s is better
48 static const unordered_map<std::string, AudioStreamType> STREAM_TYPE_STRING_ENUM_MAP = {
49 {"voice_call", STREAM_VOICE_CALL},
50 {"voice_call_assistant", STREAM_VOICE_CALL_ASSISTANT},
51 {"music", STREAM_MUSIC},
52 {"ring", STREAM_RING},
53 {"media", STREAM_MEDIA},
54 {"voice_assistant", STREAM_VOICE_ASSISTANT},
55 {"system", STREAM_SYSTEM},
56 {"alarm", STREAM_ALARM},
57 {"notification", STREAM_NOTIFICATION},
58 {"bluetooth_sco", STREAM_BLUETOOTH_SCO},
59 {"enforced_audible", STREAM_ENFORCED_AUDIBLE},
60 {"dtmf", STREAM_DTMF},
61 {"tts", STREAM_TTS},
62 {"accessibility", STREAM_ACCESSIBILITY},
63 {"recording", STREAM_RECORDING},
64 {"movie", STREAM_MOVIE},
65 {"game", STREAM_GAME},
66 {"speech", STREAM_SPEECH},
67 {"system_enforced", STREAM_SYSTEM_ENFORCED},
68 {"ultrasonic", STREAM_ULTRASONIC},
69 {"wakeup", STREAM_WAKEUP},
70 {"voice_message", STREAM_VOICE_MESSAGE},
71 {"navigation", STREAM_NAVIGATION},
72 {"camcorder", STREAM_CAMCORDER}
73 };
74
75 AudioServiceAdapter::~AudioServiceAdapter() = default;
76 PulseAudioServiceAdapterImpl::~PulseAudioServiceAdapterImpl() = default;
77
CreateAudioAdapter(unique_ptr<AudioServiceAdapterCallback> cb)78 unique_ptr<AudioServiceAdapter> AudioServiceAdapter::CreateAudioAdapter(unique_ptr<AudioServiceAdapterCallback> cb)
79 {
80 CHECK_AND_RETURN_RET_LOG(cb != nullptr, nullptr, "CreateAudioAdapter cb is nullptr!");
81 return make_unique<PulseAudioServiceAdapterImpl>(cb);
82 }
83
PulseAudioServiceAdapterImpl(unique_ptr<AudioServiceAdapterCallback> & cb)84 PulseAudioServiceAdapterImpl::PulseAudioServiceAdapterImpl(unique_ptr<AudioServiceAdapterCallback> &cb)
85 {
86 g_audioServiceAdapterCallback = move(cb);
87 }
88
Connect()89 bool PulseAudioServiceAdapterImpl::Connect()
90 {
91 mMainLoop = pa_threaded_mainloop_new();
92 CHECK_AND_RETURN_RET_LOG(mMainLoop, false, "MainLoop creation failed");
93 pa_threaded_mainloop_set_name(mMainLoop, "OS_AudioML");
94 if (pa_threaded_mainloop_start(mMainLoop) < 0) {
95 AUDIO_ERR_LOG("Failed to start mainloop");
96 pa_threaded_mainloop_free(mMainLoop);
97 return false;
98 }
99 int32_t XcollieFlag = (1 | 2); // flag 1 generate log file, flag 2 die when timeout, restart server
100
101 PaLockGuard palock(mMainLoop);
102 Trace trace("PulseAudioServiceAdapterImpl::Connect");
103
104 while (true) {
105 pa_context_state_t state;
106
107 if (mContext != nullptr) {
108 state = pa_context_get_state(mContext);
109 if (state == PA_CONTEXT_READY) {
110 break;
111 }
112 // if pulseaudio is ready, retry connect to pulseaudio. before retry wait for sometime. reduce sleep later
113 usleep(PA_CONNECT_RETRY_SLEEP_IN_MICRO_SECONDS);
114 }
115
116 bool result = ConnectToPulseAudio();
117 if (!result || !PA_CONTEXT_IS_GOOD(pa_context_get_state(mContext))) {
118 continue;
119 }
120
121 AUDIO_DEBUG_LOG("pa context not ready... wait");
122
123 // Wait for the context to be ready
124 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::Connect", PA_SERVICE_IMPL_TIMEOUT,
125 [](void *) {
126 AUDIO_ERR_LOG("Connect timeout");
127 }, nullptr, XcollieFlag);
128 pa_threaded_mainloop_wait(mMainLoop);
129 }
130
131 return true;
132 }
133
ConnectToPulseAudio()134 bool PulseAudioServiceAdapterImpl::ConnectToPulseAudio()
135 {
136 if (mContext != nullptr) {
137 AUDIO_DEBUG_LOG("context is not null, disconnect first!");
138 pa_context_disconnect(mContext);
139 pa_context_set_state_callback(mContext, nullptr, nullptr);
140 pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
141 pa_context_unref(mContext);
142 mContext = nullptr;
143 }
144 pa_proplist *proplist = pa_proplist_new();
145 if (proplist == nullptr) {
146 AUDIO_ERR_LOG("Connect to pulseAudio and new proplist return nullptr!");
147 return false;
148 }
149 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio Service");
150 pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.ohos.pulseaudio.service");
151 mContext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mMainLoop), nullptr, proplist);
152 pa_proplist_free(proplist);
153
154 CHECK_AND_RETURN_RET_LOG(mContext != nullptr, false, "creating pa context failed");
155
156 pa_context_set_state_callback(mContext, PulseAudioServiceAdapterImpl::PaContextStateCb, this);
157 if (pa_context_connect(mContext, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) {
158 if (pa_context_errno(mContext) == PA_ERR_INVALID) {
159 AUDIO_ERR_LOG("pa context connect failed: %{public}s",
160 pa_strerror(pa_context_errno(mContext)));
161 goto Fail;
162 }
163 }
164
165 return true;
166
167 Fail:
168 /* Make sure we don't get any further callbacks */
169 pa_context_set_state_callback(mContext, nullptr, nullptr);
170 pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
171 pa_context_unref(mContext);
172 mContext = nullptr;
173 return false;
174 }
175
OpenAudioPort(string audioPortName,string moduleArgs)176 uint32_t PulseAudioServiceAdapterImpl::OpenAudioPort(string audioPortName, string moduleArgs)
177 {
178 AUDIO_PRERELEASE_LOGI("OpenAudioPort enter.");
179 int32_t XcollieFlag = (1 | 2); // flag 1 generate log file, flag 2 die when timeout, restart server
180 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::OpenAudioPort", PA_SERVICE_IMPL_TIMEOUT,
181 [](void *) {
182 AUDIO_ERR_LOG("OpenAudioPort timeout");
183 }, nullptr, XcollieFlag);
184 lock_guard<mutex> lock(lock_);
185
186 unique_ptr<UserData> userData = make_unique<UserData>();
187 userData->thiz = this;
188
189 PaLockGuard palock(mMainLoop);
190 Trace trace("PulseAudioServiceAdapterImpl::OpenAudioPort");
191 if (mContext == nullptr) {
192 AUDIO_ERR_LOG("mContext is nullptr");
193 return ERROR;
194 }
195
196 pa_operation *operation = pa_context_load_module(mContext, audioPortName.c_str(), moduleArgs.c_str(),
197 PaModuleLoadCb, reinterpret_cast<void*>(userData.get()));
198 if (operation == nullptr) {
199 AUDIO_ERR_LOG("pa_context_load_module returned nullptr");
200 return PA_INVALID_INDEX;
201 }
202
203 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
204 pa_threaded_mainloop_wait(mMainLoop);
205 }
206
207 pa_operation_unref(operation);
208
209 CHECK_AND_RETURN_RET_LOG(userData->idx != PA_INVALID_INDEX, PA_INVALID_INDEX,
210 "OpenAudioPort returned invalid index");
211
212 return userData->idx;
213 }
214
CloseAudioPort(int32_t audioHandleIndex)215 int32_t PulseAudioServiceAdapterImpl::CloseAudioPort(int32_t audioHandleIndex)
216 {
217 lock_guard<mutex> lock(lock_);
218
219 PaLockGuard palock(mMainLoop);
220 if (mContext == nullptr) {
221 AUDIO_ERR_LOG("mContext is nullptr");
222 return ERROR;
223 }
224
225 pa_operation *operation = pa_context_unload_module(mContext, audioHandleIndex, nullptr, nullptr);
226 if (operation == nullptr) {
227 AUDIO_ERR_LOG("pa_context_unload_module returned nullptr!");
228 return ERROR;
229 }
230
231 pa_operation_unref(operation);
232 return SUCCESS;
233 }
234
SuspendAudioDevice(string & audioPortName,bool isSuspend)235 int32_t PulseAudioServiceAdapterImpl::SuspendAudioDevice(string &audioPortName, bool isSuspend)
236 {
237 AUDIO_INFO_LOG("[%{public}s] : [%{public}d]", audioPortName.c_str(), isSuspend);
238 PaLockGuard palock(mMainLoop);
239 if (mContext == nullptr) {
240 AUDIO_ERR_LOG("mContext is nullptr");
241 return ERROR;
242 }
243
244 auto suspendFlag = isSuspend ? 1 : 0;
245 pa_operation *operation = pa_context_suspend_sink_by_name(mContext, audioPortName.c_str(), suspendFlag,
246 nullptr, nullptr);
247 if (operation == nullptr) {
248 AUDIO_ERR_LOG("pa_context_suspend_sink_by_name failed!");
249 return ERR_OPERATION_FAILED;
250 }
251
252 pa_operation_unref(operation);
253
254 return SUCCESS;
255 }
256
SetSinkMute(const std::string & sinkName,bool isMute,bool isSync)257 bool PulseAudioServiceAdapterImpl::SetSinkMute(const std::string &sinkName, bool isMute, bool isSync)
258 {
259 AUDIO_DEBUG_LOG("MuteAudioDevice: [%{public}s] : [%{public}d]", sinkName.c_str(), isMute);
260 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::SetSinkMute", PA_SERVICE_IMPL_TIMEOUT,
261 [](void *) {
262 AUDIO_ERR_LOG("SetSinkMute timeout");
263 }, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
264 unique_ptr<UserData> userData = make_unique<UserData>();
265 userData->thiz = this;
266
267 PaLockGuard palock(mMainLoop);
268 Trace trace("PulseAudioServiceAdapterImpl::SetSinkMute");
269
270 int muteFlag = isMute ? 1 : 0;
271
272 pa_operation *operation = nullptr;
273 if (isSync) {
274 operation = pa_context_set_sink_mute_by_name(mContext, sinkName.c_str(), muteFlag,
275 PulseAudioServiceAdapterImpl::PaSinkMuteCb, reinterpret_cast<void *>(userData.get()));
276 } else {
277 operation = pa_context_set_sink_mute_by_name(mContext, sinkName.c_str(), muteFlag,
278 nullptr, nullptr);
279 }
280
281 if (operation == nullptr) {
282 AUDIO_ERR_LOG("pa_context_suspend_sink_by_name failed!");
283 return false;
284 }
285
286 if (isSync) {
287 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
288 pa_threaded_mainloop_wait(mMainLoop);
289 }
290 }
291
292 pa_operation_unref(operation);
293
294 return true;
295 }
296
SetDefaultSink(string name)297 int32_t PulseAudioServiceAdapterImpl::SetDefaultSink(string name)
298 {
299 PaLockGuard palock(mMainLoop);
300 if (mContext == nullptr) {
301 AUDIO_ERR_LOG("mContext is nullptr");
302 return ERROR;
303 }
304
305 pa_operation *operation = pa_context_set_default_sink(mContext, name.c_str(), nullptr, nullptr);
306 if (operation == nullptr) {
307 AUDIO_ERR_LOG("pa_context_set_default_sink failed!");
308 return ERR_OPERATION_FAILED;
309 }
310 isSetDefaultSink_ = true;
311 pa_operation_unref(operation);
312
313 return SUCCESS;
314 }
315
SetDefaultSource(string name)316 int32_t PulseAudioServiceAdapterImpl::SetDefaultSource(string name)
317 {
318 PaLockGuard palock(mMainLoop);
319 if (mContext == nullptr) {
320 AUDIO_ERR_LOG("mContext is nullptr");
321 return ERROR;
322 }
323
324 pa_operation *operation = pa_context_set_default_source(mContext, name.c_str(), nullptr, nullptr);
325 if (operation == nullptr) {
326 AUDIO_ERR_LOG("pa_context_set_default_source failed!");
327 return ERR_OPERATION_FAILED;
328 }
329 isSetDefaultSource_ = true;
330 pa_operation_unref(operation);
331
332 return SUCCESS;
333 }
334
PaGetSinksCb(pa_context * c,const pa_sink_info * i,int eol,void * userdata)335 void PulseAudioServiceAdapterImpl::PaGetSinksCb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
336 {
337 UserData *userData = reinterpret_cast<UserData *>(userdata);
338 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
339
340 if (eol < 0) {
341 AUDIO_ERR_LOG("Failed to get sink information: %{public}s", pa_strerror(pa_context_errno(c)));
342 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
343 return;
344 }
345
346 if (eol) {
347 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
348 return;
349 }
350
351 CHECK_AND_RETURN_LOG(i->proplist != nullptr, "Invalid Proplist for sink (%{public}d).", i->index);
352
353 const char *adapterCStr = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_STRING);
354 if (adapterCStr == nullptr) {
355 adapterCStr = "";
356 }
357 AUDIO_DEBUG_LOG("sink[%{public}d] device[%{public}s] name[%{public}s]", i->index, adapterCStr,
358 i->name);
359 std::string sinkDeviceName(adapterCStr);
360 std::string sinkName(i->name);
361 SinkInfo sinkInfo = {};
362 sinkInfo.sinkId = i->index;
363 sinkInfo.sinkName = sinkName;
364 sinkInfo.adapterName = sinkDeviceName;
365 userData->sinkInfos.push_back(sinkInfo);
366 }
367
GetAllSinks()368 std::vector<SinkInfo> PulseAudioServiceAdapterImpl::GetAllSinks()
369 {
370 AUDIO_PRERELEASE_LOGI("GetAllSinks enter.");
371 int32_t XcollieFlag = (1 | 2); // flag 1 generate log file, flag 2 die when timeout, restart server
372 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::GetAllSinks", PA_SERVICE_IMPL_TIMEOUT,
373 [](void *) {
374 AUDIO_ERR_LOG("GetAllSinks timeout");
375 }, nullptr, XcollieFlag);
376 lock_guard<mutex> lock(lock_);
377 unique_ptr<UserData> userData = make_unique<UserData>();
378 userData->thiz = this;
379 userData->sinkInfos = {};
380
381 CHECK_AND_RETURN_RET_LOG(mContext != nullptr, userData->sinkInfos, "mContext is nullptr");
382
383 PaLockGuard palock(mMainLoop);
384 Trace trace("PulseAudioServiceAdapterImpl::GetAllSinks");
385
386 pa_operation *operation = pa_context_get_sink_info_list(mContext,
387 PulseAudioServiceAdapterImpl::PaGetSinksCb, reinterpret_cast<void*>(userData.get()));
388 if (operation == nullptr) {
389 AUDIO_ERR_LOG("pa_context_get_sink_info_list returned nullptr");
390 return userData->sinkInfos;
391 }
392
393 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
394 pa_threaded_mainloop_wait(mMainLoop);
395 }
396
397 pa_operation_unref(operation);
398
399 AUDIO_DEBUG_LOG("end, get [%{public}zu] sinks.", userData->sinkInfos.size());
400 return userData->sinkInfos;
401 }
402
GetTargetSinks(std::string adapterName)403 std::vector<uint32_t> PulseAudioServiceAdapterImpl::GetTargetSinks(std::string adapterName)
404 {
405 std::vector<SinkInfo> sinkInfos = GetAllSinks();
406 std::vector<uint32_t> targetSinkIds = {};
407 for (size_t i = 0; i < sinkInfos.size(); i++) {
408 if (sinkInfos[i].adapterName == adapterName) {
409 targetSinkIds.push_back(sinkInfos[i].sinkId);
410 }
411 }
412 return targetSinkIds;
413 }
414
SetLocalDefaultSink(std::string name)415 int32_t PulseAudioServiceAdapterImpl::SetLocalDefaultSink(std::string name)
416 {
417 std::vector<SinkInput> allSinkInputs = GetAllSinkInputs();
418
419 std::string remoteDevice = "remote";
420 std::vector<uint32_t> remoteSinks = GetTargetSinks(remoteDevice);
421
422 // filter sink-inputs which are not connected with remote sinks.
423 for (auto sinkInput : allSinkInputs) {
424 uint32_t sink = sinkInput.deviceSinkId;
425 // the sink inputs connected to remote device remain the same
426 CHECK_AND_CONTINUE_LOG(std::find(remoteSinks.begin(), remoteSinks.end(), sink) == remoteSinks.end(),
427 "sink-input[%{public}d] connects with remote device[%{public}d]",
428 sinkInput.paStreamId, sinkInput.deviceSinkId);
429 // move the remaining sink inputs to the default sink
430 uint32_t invalidSinkId = PA_INVALID_INDEX;
431 MoveSinkInputByIndexOrName(sinkInput.paStreamId, invalidSinkId, name);
432 }
433
434 return SUCCESS;
435 }
436
MoveSinkInputByIndexOrName(uint32_t sinkInputId,uint32_t sinkIndex,std::string sinkName)437 int32_t PulseAudioServiceAdapterImpl::MoveSinkInputByIndexOrName(uint32_t sinkInputId, uint32_t sinkIndex,
438 std::string sinkName)
439 {
440 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::MoveSinkInputByIndexOrName", PA_SERVICE_IMPL_TIMEOUT,
441 [](void *) {
442 AUDIO_ERR_LOG("MoveSinkInputByIndexOrName timeout");
443 }, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
444 lock_guard<mutex> lock(lock_);
445 Trace trace("PulseAudioServiceAdapterImpl::MoveSinkInputByIndexOrName:id:" + std::to_string(sinkInputId) +
446 +":index:" + std::to_string(sinkIndex) + ":name:" + sinkName);
447
448 unique_ptr<UserData> userData = make_unique<UserData>();
449 userData->thiz = this;
450
451 CHECK_AND_RETURN_RET_LOG(mContext != nullptr, ERROR, "mContext is nullptr");
452 PaLockGuard palock(mMainLoop);
453 pa_operation *operation = nullptr;
454 if (sinkName.empty()) {
455 operation = pa_context_move_sink_input_by_index(mContext, sinkInputId, sinkIndex,
456 PulseAudioServiceAdapterImpl::PaMoveSinkInputCb, reinterpret_cast<void *>(userData.get()));
457 } else {
458 operation = pa_context_move_sink_input_by_name(mContext, sinkInputId, sinkName.c_str(),
459 PulseAudioServiceAdapterImpl::PaMoveSinkInputCb, reinterpret_cast<void *>(userData.get()));
460 }
461
462 if (operation == nullptr) {
463 AUDIO_ERR_LOG("pa_context_get_sink_input_info_list nullptr");
464 return ERROR;
465 }
466 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
467 pa_threaded_mainloop_wait(mMainLoop);
468 }
469 pa_operation_unref(operation);
470
471 int result = userData->moveResult;
472 AUDIO_DEBUG_LOG("move result:[%{public}d]", result);
473
474 return SUCCESS;
475 }
476
MoveSourceOutputByIndexOrName(uint32_t sourceOutputId,uint32_t sourceIndex,std::string sourceName)477 int32_t PulseAudioServiceAdapterImpl::MoveSourceOutputByIndexOrName(uint32_t sourceOutputId, uint32_t sourceIndex,
478 std::string sourceName)
479 {
480 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::MoveSourceOutputByIndexOrName",
481 PA_SERVICE_IMPL_TIMEOUT, [](void *) {
482 AUDIO_ERR_LOG("MoveSourceOutputByIndexOrName timeout");
483 }, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
484 lock_guard<mutex> lock(lock_);
485 Trace trace("PulseAudioServiceAdapterImpl::MoveSourceOutputByIndexOrName:id:" + std::to_string(sourceOutputId) +
486 +":index:" + std::to_string(sourceIndex) + ":name:" + sourceName);
487
488 unique_ptr<UserData> userData = make_unique<UserData>();
489 userData->thiz = this;
490
491 if (mContext == nullptr) {
492 AUDIO_ERR_LOG("mContext is nullptr");
493 return ERROR;
494 }
495 PaLockGuard palock(mMainLoop);
496 pa_operation *operation = nullptr;
497 if (sourceName.empty()) {
498 operation = pa_context_move_source_output_by_index(mContext, sourceOutputId, sourceIndex,
499 PulseAudioServiceAdapterImpl::PaMoveSourceOutputCb, reinterpret_cast<void *>(userData.get()));
500 } else {
501 operation = pa_context_move_source_output_by_name(mContext, sourceOutputId, sourceName.c_str(),
502 PulseAudioServiceAdapterImpl::PaMoveSourceOutputCb, reinterpret_cast<void *>(userData.get()));
503 }
504
505 if (operation == nullptr) {
506 AUDIO_ERR_LOG("pa_context_get_sink_input_info_list nullptr");
507 return ERROR;
508 }
509 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
510 pa_threaded_mainloop_wait(mMainLoop);
511 }
512 pa_operation_unref(operation);
513
514 int result = userData->moveResult;
515 AUDIO_DEBUG_LOG("move result:[%{public}d]", result);
516
517 return SUCCESS;
518 }
519
SetSourceOutputMute(int32_t uid,bool setMute)520 int32_t PulseAudioServiceAdapterImpl::SetSourceOutputMute(int32_t uid, bool setMute)
521 {
522 CHECK_AND_RETURN_RET_LOG(mContext != nullptr, ERROR, "mContext is nullptr");
523 vector<SourceOutput> sourOutputs = GetAllSourceOutputs();
524 lock_guard<mutex> lock(lock_);
525 int32_t streamSet = 0;
526 for (uint32_t i = 0; i < sourOutputs.size(); i ++) {
527 if (sourOutputs[i].uid == uid) {
528 PaLockGuard palock(mMainLoop);
529 pa_operation *operation = pa_context_set_source_output_mute(mContext, sourOutputs[i].paStreamId,
530 (setMute ? 1 : 0), nullptr, nullptr);
531 if (operation == nullptr) {
532 AUDIO_ERR_LOG("pa_context_set_source_output_mute nullptr");
533 return ERROR;
534 }
535 pa_operation_unref(operation);
536 AUDIO_DEBUG_LOG("set source output Mute : %{public}s for stream :uid %{public}d",
537 (setMute ? "true" : "false"), sourOutputs[i].uid);
538 streamSet++;
539 }
540 }
541 AUDIO_INFO_LOG("set %{public}d %{public}s", streamSet, (setMute ? "mute" : "unmuted"));
542 return streamSet;
543 }
544
GetAllSinkInputs()545 vector<SinkInput> PulseAudioServiceAdapterImpl::GetAllSinkInputs()
546 {
547 AUDIO_PRERELEASE_LOGI("GetAllSinkInputs enter");
548 unique_ptr<UserData> userData = make_unique<UserData>();
549 userData->thiz = this;
550 userData->sinkInfos = GetAllSinks();
551
552 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::GetAllSinkInputs", PA_SERVICE_IMPL_TIMEOUT,
553 [](void *) {
554 AUDIO_ERR_LOG("GetAllSinkInputs timeout");
555 }, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
556 lock_guard<mutex> lock(lock_);
557 CHECK_AND_RETURN_RET_LOG(mContext != nullptr, userData->sinkInputList, "mContext is nullptr");
558
559 PaLockGuard palock(mMainLoop);
560 Trace trace("PulseAudioServiceAdapterImpl::GetAllSinkInputs");
561
562 pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
563 PulseAudioServiceAdapterImpl::PaGetAllSinkInputsCb, reinterpret_cast<void*>(userData.get()));
564 if (operation == nullptr) {
565 AUDIO_ERR_LOG("pa_context_get_sink_input_info_list returned nullptr");
566 return userData->sinkInputList;
567 }
568
569 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
570 pa_threaded_mainloop_wait(mMainLoop);
571 }
572
573 pa_operation_unref(operation);
574
575 AUDIO_DEBUG_LOG("get:[%{public}zu]", userData->sinkInputList.size());
576 return userData->sinkInputList;
577 }
578
GetAllSourceOutputs()579 vector<SourceOutput> PulseAudioServiceAdapterImpl::GetAllSourceOutputs()
580 {
581 AudioXCollie audioXCollie("PulseAudioServiceAdapterImpl::GetAllSourceOutputs", PA_SERVICE_IMPL_TIMEOUT,
582 [](void *) {
583 AUDIO_ERR_LOG("GetAllSourceOutputs timeout");
584 }, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
585 lock_guard<mutex> lock(lock_);
586 Trace trace("PulseAudioServiceAdapterImpl::GetAllSourceOutputs");
587
588 unique_ptr<UserData> userData = make_unique<UserData>();
589 userData->thiz = this;
590
591 CHECK_AND_RETURN_RET_LOG(mContext != nullptr, userData->sourceOutputList, "mContext is nullptr");
592
593 CHECK_AND_RETURN_RET_LOG(isSetDefaultSource_, userData->sourceOutputList, "default source has not been set.");
594
595 PaLockGuard palock(mMainLoop);
596
597 pa_operation *operation = pa_context_get_source_output_info_list(mContext,
598 PulseAudioServiceAdapterImpl::PaGetAllSourceOutputsCb, reinterpret_cast<void*>(userData.get()));
599 if (operation == nullptr) {
600 AUDIO_ERR_LOG("pa_context_get_source_output_info_list returned nullptr");
601 return userData->sourceOutputList;
602 }
603
604 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
605 pa_threaded_mainloop_wait(mMainLoop);
606 }
607
608 pa_operation_unref(operation);
609
610 return userData->sourceOutputList;
611 }
612
Disconnect()613 void PulseAudioServiceAdapterImpl::Disconnect()
614 {
615 if (mContext != nullptr) {
616 AUDIO_WARNING_LOG("disconnect context! should not happen");
617 pa_context_disconnect(mContext);
618 /* Make sure we don't get any further callbacks */
619 pa_context_set_state_callback(mContext, nullptr, nullptr);
620 pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
621 pa_context_unref(mContext);
622 mContext = nullptr;
623 }
624
625 if (mMainLoop != nullptr) {
626 AUDIO_WARNING_LOG("disconnect mainloop! should not happen");
627 pa_threaded_mainloop_stop(mMainLoop);
628 pa_threaded_mainloop_free(mMainLoop);
629 mMainLoop = nullptr;
630 }
631 }
632
GetIdByStreamType(string streamType)633 AudioStreamType PulseAudioServiceAdapterImpl::GetIdByStreamType(string streamType)
634 {
635 AudioStreamType stream = STREAM_MUSIC;
636 if (STREAM_TYPE_STRING_ENUM_MAP.find(streamType) != STREAM_TYPE_STRING_ENUM_MAP.end()) {
637 stream = STREAM_TYPE_STRING_ENUM_MAP.at(streamType);
638 } else {
639 AUDIO_WARNING_LOG("Invalid stream type [%{public}s]. Use default type", streamType.c_str());
640 }
641 return stream;
642 }
643
PaMoveSinkInputCb(pa_context * c,int success,void * userdata)644 void PulseAudioServiceAdapterImpl::PaMoveSinkInputCb(pa_context *c, int success, void *userdata)
645 {
646 UserData *userData = reinterpret_cast<UserData *>(userdata);
647
648 AUDIO_DEBUG_LOG("result[%{public}d]", success);
649 userData->moveResult = success;
650
651 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
652
653 return;
654 }
655
PaMoveSourceOutputCb(pa_context * c,int success,void * userdata)656 void PulseAudioServiceAdapterImpl::PaMoveSourceOutputCb(pa_context *c, int success, void *userdata)
657 {
658 UserData *userData = reinterpret_cast<UserData *>(userdata);
659
660 AUDIO_INFO_LOG("result[%{public}d]", success);
661 userData->moveResult = success;
662
663 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
664
665 return;
666 }
667
PaSinkMuteCb(pa_context * c,int success,void * userdata)668 void PulseAudioServiceAdapterImpl::PaSinkMuteCb(pa_context *c, int success, void *userdata)
669 {
670 UserData *userData = reinterpret_cast<UserData *>(userdata);
671 AUDIO_DEBUG_LOG("result[%{public}d]", success);
672 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
673 }
674
PaContextStateCb(pa_context * c,void * userdata)675 void PulseAudioServiceAdapterImpl::PaContextStateCb(pa_context *c, void *userdata)
676 {
677 PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
678
679 switch (pa_context_get_state(c)) {
680 case PA_CONTEXT_UNCONNECTED:
681 case PA_CONTEXT_CONNECTING:
682 case PA_CONTEXT_AUTHORIZING:
683 case PA_CONTEXT_SETTING_NAME:
684 break;
685
686 case PA_CONTEXT_READY: {
687 pa_context_set_subscribe_callback(c, PulseAudioServiceAdapterImpl::PaSubscribeCb, thiz);
688
689 pa_operation *operation = pa_context_subscribe(c, (pa_subscription_mask_t)
690 (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE |
691 PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT |
692 PA_SUBSCRIPTION_MASK_CARD), nullptr, nullptr);
693 if (operation == nullptr) {
694 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
695 return;
696 }
697 pa_operation_unref(operation);
698 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
699 break;
700 }
701
702 case PA_CONTEXT_FAILED:
703 case PA_CONTEXT_TERMINATED:
704 AUDIO_ERR_LOG("state is PA_CONTEXT_FAILED or PA_CONTEXT_TERMINATED");
705 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
706 return;
707
708 default:
709 return;
710 }
711 }
712
PaModuleLoadCb(pa_context * c,uint32_t idx,void * userdata)713 void PulseAudioServiceAdapterImpl::PaModuleLoadCb(pa_context *c, uint32_t idx, void *userdata)
714 {
715 UserData *userData = reinterpret_cast<UserData*>(userdata);
716 if (idx == PA_INVALID_INDEX) {
717 AUDIO_ERR_LOG("Failure: %{public}s", pa_strerror(pa_context_errno(c)));
718 userData->idx = PA_INVALID_INDEX;
719 } else {
720 userData->idx = idx;
721 }
722 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
723
724 return;
725 }
726
727 template <typename T>
CastValue(T & a,const char * raw)728 inline void CastValue(T &a, const char *raw)
729 {
730 if (raw == nullptr) {
731 return;
732 }
733 std::stringstream valueStr;
734 valueStr << raw;
735 valueStr >> a;
736 }
737
PaGetSourceOutputNoSignalCb(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)738 void PulseAudioServiceAdapterImpl::PaGetSourceOutputNoSignalCb(pa_context *c, const pa_source_output_info *i,
739 int eol, void *userdata)
740 {
741 AUDIO_INFO_LOG("in eol[%{public}d]", eol);
742 UserData *userData = reinterpret_cast<UserData*>(userdata);
743
744 if (eol < 0) {
745 delete userData;
746 AUDIO_ERR_LOG("Failed to get source output information: %{public}s",
747 pa_strerror(pa_context_errno(c)));
748 return;
749 }
750
751 if (eol) {
752 delete userData;
753 return;
754 }
755
756 CHECK_AND_RETURN_LOG(i->proplist != nullptr, "Invalid proplist for source output (%{public}d).", i->index);
757
758 const char *streamSession = pa_proplist_gets(i->proplist, "stream.sessionID");
759 CHECK_AND_RETURN_LOG(streamSession != nullptr, "Invalid stream parameter:sessionID.");
760
761 std::stringstream sessionStr;
762 uint32_t sessionID;
763 sessionStr << streamSession;
764 sessionStr >> sessionID;
765 AUDIO_INFO_LOG("sessionID %{public}u", sessionID);
766 sourceIndexSessionIDMap.Insert(i->index, sessionID);
767 }
768
PaGetAllSinkInputsCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)769 void PulseAudioServiceAdapterImpl::PaGetAllSinkInputsCb(pa_context *c, const pa_sink_input_info *i, int eol,
770 void *userdata)
771 {
772 AUDIO_DEBUG_LOG("in eol[%{public}d]", eol);
773 UserData *userData = reinterpret_cast<UserData *>(userdata);
774 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
775
776 if (eol < 0) {
777 AUDIO_ERR_LOG("Failed to get sink input information: %{public}s", pa_strerror(pa_context_errno(c)));
778 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
779 return;
780 }
781
782 if (eol) {
783 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
784 return;
785 }
786
787 CHECK_AND_RETURN_LOG(i->proplist != nullptr,
788 "Invalid Proplist for sink input (%{public}d).", i->index);
789
790 const char *streamMode = pa_proplist_gets(i->proplist, "stream.mode");
791 if (streamMode != nullptr && streamMode == DUP_STREAM) { return; }
792
793 AudioStreamType audioStreamType = STREAM_DEFAULT;
794 const char *streamType = pa_proplist_gets(i->proplist, "stream.type");
795 if (streamType != nullptr) {
796 audioStreamType = thiz->GetIdByStreamType(streamType);
797 }
798
799 SinkInput sinkInput = {};
800 sinkInput.streamType = audioStreamType;
801
802 sinkInput.deviceSinkId = i->sink;
803 for (auto sinkInfo : userData->sinkInfos) {
804 if (sinkInput.deviceSinkId == sinkInfo.sinkId) {
805 sinkInput.sinkName = sinkInfo.sinkName;
806 break;
807 }
808 }
809 sinkInput.paStreamId = i->index;
810 CastValue<int32_t>(sinkInput.streamId, pa_proplist_gets(i->proplist, "stream.sessionID"));
811 CastValue<int32_t>(sinkInput.uid, pa_proplist_gets(i->proplist, "stream.client.uid"));
812 CastValue<int32_t>(sinkInput.pid, pa_proplist_gets(i->proplist, "stream.client.pid"));
813 CastValue<uint64_t>(sinkInput.startTime, pa_proplist_gets(i->proplist, "stream.startTime"));
814
815 userData->sinkInputList.push_back(sinkInput);
816 }
817
PaGetAllSourceOutputsCb(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)818 void PulseAudioServiceAdapterImpl::PaGetAllSourceOutputsCb(pa_context *c, const pa_source_output_info *i, int eol,
819 void *userdata)
820 {
821 AUDIO_INFO_LOG("in eol[%{public}d]", eol);
822 UserData *userData = reinterpret_cast<UserData *>(userdata);
823 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
824
825 if (eol < 0) {
826 AUDIO_ERR_LOG("Failed to get source output information: %{public}s", pa_strerror(pa_context_errno(c)));
827 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
828 return;
829 }
830
831 if (eol) {
832 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
833 return;
834 }
835
836 CHECK_AND_RETURN_LOG(i->proplist != nullptr,
837 "Invalid Proplist for source output (%{public}d).", i->index);
838
839 int32_t sessionID = 0;
840 const char *sessionCStr = pa_proplist_gets(i->proplist, "stream.sessionID");
841 if (sessionCStr != nullptr) {
842 std::stringstream sessionStr;
843 sessionStr << sessionCStr;
844 sessionStr >> sessionID;
845 }
846
847 AudioStreamType audioStreamType = STREAM_DEFAULT;
848 const char *streamType = pa_proplist_gets(i->proplist, "stream.type");
849 if (streamType != nullptr) {
850 audioStreamType = thiz->GetIdByStreamType(streamType);
851 }
852
853 SourceOutput sourceOutput = {};
854 sourceOutput.streamId = sessionID;
855 sourceOutput.streamType = audioStreamType;
856
857 sourceOutput.paStreamId = i->index;
858 sourceOutput.deviceSourceId = i->source;
859 CastValue<int32_t>(sourceOutput.uid, pa_proplist_gets(i->proplist, "stream.client.uid"));
860 CastValue<int32_t>(sourceOutput.pid, pa_proplist_gets(i->proplist, "stream.client.pid"));
861 CastValue<uint64_t>(sourceOutput.startTime, pa_proplist_gets(i->proplist, "stream.startTime"));
862 userData->sourceOutputList.push_back(sourceOutput);
863 }
864
ProcessSourceOutputEvent(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)865 void PulseAudioServiceAdapterImpl::ProcessSourceOutputEvent(pa_context *c, pa_subscription_event_type_t t, uint32_t idx,
866 void *userdata)
867 {
868 unique_ptr<UserData> userData = make_unique<UserData>();
869 PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
870 userData->thiz = thiz;
871 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
872 pa_operation *operation = pa_context_get_source_output_info(c, idx,
873 PulseAudioServiceAdapterImpl::PaGetSourceOutputNoSignalCb, reinterpret_cast<void*>(userData.get()));
874 if (operation == nullptr) {
875 AUDIO_ERR_LOG("pa_context_get_source_output_info nullptr");
876 return;
877 }
878 userData.release();
879 pa_operation_unref(operation);
880 } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
881 uint32_t sessionID = 0;
882 if (sourceIndexSessionIDMap.Find(idx, sessionID) == true) {
883 AUDIO_ERR_LOG("sessionID: %{public}d removed", sessionID);
884 g_audioServiceAdapterCallback->OnAudioStreamRemoved(sessionID);
885 sourceIndexSessionIDMap.Erase(idx);
886 } else {
887 AUDIO_ERR_LOG("cannot find sessionID in sourceIndexSessionIDMap");
888 }
889 }
890 }
891
PaSubscribeCb(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)892 void PulseAudioServiceAdapterImpl::PaSubscribeCb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx,
893 void *userdata)
894 {
895 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
896 case PA_SUBSCRIPTION_EVENT_SINK:
897 break;
898
899 case PA_SUBSCRIPTION_EVENT_SOURCE:
900 break;
901
902 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
903 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
904 AUDIO_INFO_LOG("PA_SUBSCRIPTION_EVENT_NEW");
905 g_audioServiceAdapterCallback->OnSetVolumeDbCb();
906 } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
907 AUDIO_INFO_LOG("PA_SUBSCRIPTION_EVENT_REMOVE");
908 }
909 break;
910
911 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
912 ProcessSourceOutputEvent(c, t, idx, userdata);
913 break;
914
915 default:
916 break;
917 }
918 }
919 } // namespace AudioStandard
920 } // namespace OHOS
921
922 #endif // ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
923