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
19 #include "pulse_audio_service_adapter_impl.h"
20
21 #include <sstream>
22 #include <unistd.h>
23 #include <thread>
24
25 #include "audio_errors.h"
26 #include "audio_log.h"
27 #include "hisysevent.h"
28 #include <set>
29
30 using namespace std;
31
32 namespace OHOS {
33 namespace AudioStandard {
34 static unique_ptr<AudioServiceAdapterCallback> g_audioServiceAdapterCallback;
35 std::unordered_map<uint32_t, uint32_t> PulseAudioServiceAdapterImpl::sinkIndexSessionIDMap;
36 std::unordered_map<uint32_t, uint32_t> PulseAudioServiceAdapterImpl::sourceIndexSessionIDMap;
37 int32_t g_playbackCapturerSourceOutputIndex = -1;
38
39 std::set<uint32_t> g_wakeupCapturerSourceOutputIndexs;
40
41 static const unordered_map<std::string, AudioStreamType> STREAM_TYPE_STRING_ENUM_MAP = {
42 {"voice_call", STREAM_VOICE_CALL},
43 {"music", STREAM_MUSIC},
44 {"ring", STREAM_RING},
45 {"media", STREAM_MEDIA},
46 {"voice_assistant", STREAM_VOICE_ASSISTANT},
47 {"system", STREAM_SYSTEM},
48 {"alarm", STREAM_ALARM},
49 {"notification", STREAM_NOTIFICATION},
50 {"bluetooth_sco", STREAM_BLUETOOTH_SCO},
51 {"enforced_audible", STREAM_ENFORCED_AUDIBLE},
52 {"dtmf", STREAM_DTMF},
53 {"tts", STREAM_TTS},
54 {"accessibility", STREAM_ACCESSIBILITY},
55 {"recording", STREAM_RECORDING},
56 {"movie", STREAM_MOVIE},
57 {"game", STREAM_GAME},
58 {"speech", STREAM_SPEECH},
59 {"system_enforced", STREAM_SYSTEM_ENFORCED},
60 {"ultrasonic", STREAM_ULTRASONIC},
61 {"wakeup", STREAM_WAKEUP},
62 {"voice_message", STREAM_VOICE_MESSAGE},
63 {"navigation", STREAM_NAVIGATION}
64 };
65
66 AudioServiceAdapter::~AudioServiceAdapter() = default;
67 PulseAudioServiceAdapterImpl::~PulseAudioServiceAdapterImpl() = default;
68
CreateAudioAdapter(unique_ptr<AudioServiceAdapterCallback> cb)69 unique_ptr<AudioServiceAdapter> AudioServiceAdapter::CreateAudioAdapter(unique_ptr<AudioServiceAdapterCallback> cb)
70 {
71 if (!cb) {
72 AUDIO_ERR_LOG("CreateAudioAdapter cb is nullptr!");
73 return nullptr;
74 }
75 return make_unique<PulseAudioServiceAdapterImpl>(cb);
76 }
77
PulseAudioServiceAdapterImpl(unique_ptr<AudioServiceAdapterCallback> & cb)78 PulseAudioServiceAdapterImpl::PulseAudioServiceAdapterImpl(unique_ptr<AudioServiceAdapterCallback> &cb)
79 {
80 g_audioServiceAdapterCallback = move(cb);
81 }
82
Connect()83 bool PulseAudioServiceAdapterImpl::Connect()
84 {
85 mMainLoop = pa_threaded_mainloop_new();
86 if (!mMainLoop) {
87 AUDIO_ERR_LOG("[PulseAudioServiceAdapterImpl] MainLoop creation failed");
88 return false;
89 }
90
91 if (pa_threaded_mainloop_start(mMainLoop) < 0) {
92 AUDIO_ERR_LOG("[PulseAudioServiceAdapterImpl] Failed to start mainloop");
93 pa_threaded_mainloop_free(mMainLoop);
94 return false;
95 }
96
97 pa_threaded_mainloop_lock(mMainLoop);
98
99 while (true) {
100 pa_context_state_t state;
101
102 if (mContext != nullptr) {
103 state = pa_context_get_state(mContext);
104 if (state == PA_CONTEXT_READY) {
105 break;
106 }
107 // if pulseaudio is ready, retry connect to pulseaudio. before retry wait for sometime. reduce sleep later
108 usleep(PA_CONNECT_RETRY_SLEEP_IN_MICRO_SECONDS);
109 }
110
111 bool result = ConnectToPulseAudio();
112 if (!result || !PA_CONTEXT_IS_GOOD(pa_context_get_state(mContext))) {
113 continue;
114 }
115
116 AUDIO_DEBUG_LOG("pa context not ready... wait");
117
118 // Wait for the context to be ready
119 pa_threaded_mainloop_wait(mMainLoop);
120 }
121
122 pa_threaded_mainloop_unlock(mMainLoop);
123
124 return true;
125 }
126
ConnectToPulseAudio()127 bool PulseAudioServiceAdapterImpl::ConnectToPulseAudio()
128 {
129 if (mContext != nullptr) {
130 AUDIO_INFO_LOG("context is not null, disconnect first!");
131 pa_context_disconnect(mContext);
132 pa_context_set_state_callback(mContext, nullptr, nullptr);
133 pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
134 pa_context_unref(mContext);
135 }
136
137 swapStatus = 0;
138 pa_proplist *proplist = pa_proplist_new();
139 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio Service");
140 pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.ohos.pulseaudio.service");
141 pa_proplist_sets(proplist, "device.swap.status", "0");
142 mContext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mMainLoop), nullptr, proplist);
143 pa_proplist_free(proplist);
144
145 if (mContext == nullptr) {
146 AUDIO_ERR_LOG("creating pa context failed");
147 return false;
148 }
149
150 pa_context_set_state_callback(mContext, PulseAudioServiceAdapterImpl::PaContextStateCb, this);
151 if (pa_context_connect(mContext, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) {
152 if (pa_context_errno(mContext) == PA_ERR_INVALID) {
153 AUDIO_ERR_LOG("pa context connect failed: %{public}s",
154 pa_strerror(pa_context_errno(mContext)));
155 goto Fail;
156 }
157 }
158
159 return true;
160
161 Fail:
162 /* Make sure we don't get any further callbacks */
163 pa_context_set_state_callback(mContext, nullptr, nullptr);
164 pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
165 pa_context_unref(mContext);
166 return false;
167 }
168
OpenAudioPort(string audioPortName,string moduleArgs)169 uint32_t PulseAudioServiceAdapterImpl::OpenAudioPort(string audioPortName, string moduleArgs)
170 {
171 lock_guard<mutex> lock(lock_);
172
173 unique_ptr<UserData> userData = make_unique<UserData>();
174 userData->thiz = this;
175
176 pa_threaded_mainloop_lock(mMainLoop);
177 if (mContext == nullptr) {
178 AUDIO_ERR_LOG("[OpenAudioPort] mContext is nullptr");
179 pa_threaded_mainloop_unlock(mMainLoop);
180 return ERROR;
181 }
182
183 pa_operation *operation = pa_context_load_module(mContext, audioPortName.c_str(), moduleArgs.c_str(),
184 PaModuleLoadCb, reinterpret_cast<void*>(userData.get()));
185 if (operation == nullptr) {
186 AUDIO_ERR_LOG("pa_context_load_module returned nullptr");
187 pa_threaded_mainloop_unlock(mMainLoop);
188 return PA_INVALID_INDEX;
189 }
190
191 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
192 pa_threaded_mainloop_wait(mMainLoop);
193 }
194
195 pa_operation_unref(operation);
196 pa_threaded_mainloop_unlock(mMainLoop);
197
198 if (userData->idx == PA_INVALID_INDEX) {
199 AUDIO_ERR_LOG("OpenAudioPort returned invalid index");
200 return PA_INVALID_INDEX;
201 }
202
203 return userData->idx;
204 }
205
CloseAudioPort(int32_t audioHandleIndex)206 int32_t PulseAudioServiceAdapterImpl::CloseAudioPort(int32_t audioHandleIndex)
207 {
208 lock_guard<mutex> lock(lock_);
209
210 pa_threaded_mainloop_lock(mMainLoop);
211 if (mContext == nullptr) {
212 AUDIO_ERR_LOG("[CloseAudioPort] mContext is nullptr");
213 pa_threaded_mainloop_unlock(mMainLoop);
214 return ERROR;
215 }
216
217 pa_operation *operation = pa_context_unload_module(mContext, audioHandleIndex, nullptr, nullptr);
218 if (operation == nullptr) {
219 AUDIO_ERR_LOG("pa_context_unload_module returned nullptr!");
220 pa_threaded_mainloop_unlock(mMainLoop);
221 return ERROR;
222 }
223
224 pa_operation_unref(operation);
225 pa_threaded_mainloop_unlock(mMainLoop);
226 return SUCCESS;
227 }
228
SuspendAudioDevice(string & audioPortName,bool isSuspend)229 int32_t PulseAudioServiceAdapterImpl::SuspendAudioDevice(string &audioPortName, bool isSuspend)
230 {
231 AUDIO_INFO_LOG("SuspendAudioDevice: [%{public}s] : [%{public}d]", audioPortName.c_str(), isSuspend);
232 pa_threaded_mainloop_lock(mMainLoop);
233 if (mContext == nullptr) {
234 AUDIO_ERR_LOG("[SuspendAudioDevice] mContext is nullptr");
235 pa_threaded_mainloop_unlock(mMainLoop);
236 return ERROR;
237 }
238
239 auto suspendFlag = isSuspend ? 1 : 0;
240 pa_operation *operation = pa_context_suspend_sink_by_name(mContext, audioPortName.c_str(), suspendFlag,
241 nullptr, nullptr);
242 if (operation == nullptr) {
243 AUDIO_ERR_LOG("pa_context_suspend_sink_by_name failed!");
244 pa_threaded_mainloop_unlock(mMainLoop);
245 return ERR_OPERATION_FAILED;
246 }
247
248 pa_operation_unref(operation);
249 pa_threaded_mainloop_unlock(mMainLoop);
250
251 return SUCCESS;
252 }
253
SetSinkMute(const std::string & sinkName,bool isMute)254 bool PulseAudioServiceAdapterImpl::SetSinkMute(const std::string &sinkName, bool isMute)
255 {
256 AUDIO_INFO_LOG("MuteAudioDevice: [%{public}s] : [%{public}d]", sinkName.c_str(), isMute);
257 pa_threaded_mainloop_lock(mMainLoop);
258
259 int muteFlag = isMute ? 1 : 0;
260 pa_operation *operation = pa_context_set_sink_mute_by_name(mContext, sinkName.c_str(), muteFlag, nullptr, nullptr);
261 if (operation == nullptr) {
262 AUDIO_ERR_LOG("pa_context_suspend_sink_by_name failed!");
263 pa_threaded_mainloop_unlock(mMainLoop);
264 return false;
265 }
266
267 pa_operation_unref(operation);
268 pa_threaded_mainloop_unlock(mMainLoop);
269
270 return true;
271 }
272
SetDefaultSink(string name)273 int32_t PulseAudioServiceAdapterImpl::SetDefaultSink(string name)
274 {
275 pa_threaded_mainloop_lock(mMainLoop);
276 if (mContext == nullptr) {
277 AUDIO_ERR_LOG("[SetDefaultSink] mContext is nullptr");
278 pa_threaded_mainloop_unlock(mMainLoop);
279 return ERROR;
280 }
281
282 pa_operation *operation = pa_context_set_default_sink(mContext, name.c_str(), nullptr, nullptr);
283 if (operation == nullptr) {
284 AUDIO_ERR_LOG("pa_context_set_default_sink failed!");
285 pa_threaded_mainloop_unlock(mMainLoop);
286 return ERR_OPERATION_FAILED;
287 }
288 isSetDefaultSink_ = true;
289 pa_operation_unref(operation);
290 pa_threaded_mainloop_unlock(mMainLoop);
291
292 return SUCCESS;
293 }
294
SetDefaultSource(string name)295 int32_t PulseAudioServiceAdapterImpl::SetDefaultSource(string name)
296 {
297 pa_threaded_mainloop_lock(mMainLoop);
298 if (mContext == nullptr) {
299 AUDIO_ERR_LOG("[SetDefaultSource] mContext is nullptr");
300 pa_threaded_mainloop_unlock(mMainLoop);
301 return ERROR;
302 }
303
304 pa_operation *operation = pa_context_set_default_source(mContext, name.c_str(), nullptr, nullptr);
305 if (operation == nullptr) {
306 AUDIO_ERR_LOG("pa_context_set_default_source failed!");
307 pa_threaded_mainloop_unlock(mMainLoop);
308 return ERR_OPERATION_FAILED;
309 }
310 isSetDefaultSource_ = true;
311 pa_operation_unref(operation);
312 pa_threaded_mainloop_unlock(mMainLoop);
313
314 return SUCCESS;
315 }
316
PaGetSinksCb(pa_context * c,const pa_sink_info * i,int eol,void * userdata)317 void PulseAudioServiceAdapterImpl::PaGetSinksCb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
318 {
319 UserData *userData = reinterpret_cast<UserData *>(userdata);
320 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
321 if (eol < 0) {
322 AUDIO_ERR_LOG("[PaGetSinksCb] Failed to get sink information: %{public}s",
323 pa_strerror(pa_context_errno(c)));
324 return;
325 }
326
327 if (eol) {
328 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
329 return;
330 }
331
332 if (i->proplist == nullptr) {
333 AUDIO_ERR_LOG("[PaGetSinksCb] Invalid Proplist for sink (%{public}d).", i->index);
334 return;
335 }
336
337 const char *adapterCStr = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_STRING);
338 if (adapterCStr == nullptr) {
339 adapterCStr = "";
340 }
341 AUDIO_DEBUG_LOG("[PaGetSinksCb] sink[%{public}d] device[%{public}s] name[%{public}s]", i->index, adapterCStr,
342 i->name);
343 std::string sinkDeviceName(adapterCStr);
344 std::string sinkName(i->name);
345 SinkInfo sinkInfo = {};
346 sinkInfo.sinkId = i->index;
347 sinkInfo.sinkName = sinkName;
348 sinkInfo.adapterName = sinkDeviceName;
349 userData->sinkInfos.push_back(sinkInfo);
350 }
351
GetAllSinks()352 std::vector<SinkInfo> PulseAudioServiceAdapterImpl::GetAllSinks()
353 {
354 AUDIO_INFO_LOG("GetAllSinks enter.");
355 lock_guard<mutex> lock(lock_);
356 unique_ptr<UserData> userData = make_unique<UserData>();
357 userData->thiz = this;
358 userData->sinkInfos = {};
359
360 if (mContext == nullptr) {
361 AUDIO_ERR_LOG("GetAllSinks mContext is nullptr");
362 return userData->sinkInfos;
363 }
364
365 pa_threaded_mainloop_lock(mMainLoop);
366
367 pa_operation *operation = pa_context_get_sink_info_list(mContext,
368 PulseAudioServiceAdapterImpl::PaGetSinksCb, reinterpret_cast<void*>(userData.get()));
369 if (operation == nullptr) {
370 AUDIO_ERR_LOG("GetAllSinks pa_context_get_sink_info_list returned nullptr");
371 pa_threaded_mainloop_unlock(mMainLoop);
372 return userData->sinkInfos;
373 }
374
375 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
376 pa_threaded_mainloop_wait(mMainLoop);
377 }
378
379 pa_operation_unref(operation);
380 pa_threaded_mainloop_unlock(mMainLoop);
381
382 AUDIO_DEBUG_LOG("GetAllSinks end, get [%{public}zu] sinks.", userData->sinkInfos.size());
383 return userData->sinkInfos;
384 }
385
GetTargetSinks(std::string adapterName)386 std::vector<uint32_t> PulseAudioServiceAdapterImpl::GetTargetSinks(std::string adapterName)
387 {
388 std::vector<SinkInfo> sinkInfos = GetAllSinks();
389 std::vector<uint32_t> targetSinkIds = {};
390 for (size_t i = 0; i < sinkInfos.size(); i++) {
391 if (sinkInfos[i].adapterName == adapterName) {
392 targetSinkIds.push_back(sinkInfos[i].sinkId);
393 }
394 }
395 return targetSinkIds;
396 }
397
SetLocalDefaultSink(std::string name)398 int32_t PulseAudioServiceAdapterImpl::SetLocalDefaultSink(std::string name)
399 {
400 std::vector<SinkInput> allSinkInputs = GetAllSinkInputs();
401
402 std::string remoteDevice = "remote";
403 std::vector<uint32_t> remoteSinks = GetTargetSinks(remoteDevice);
404
405 // filter sink-inputs which are not connected with remote sinks.
406 for (auto sinkInput : allSinkInputs) {
407 uint32_t sink = sinkInput.deviceSinkId;
408 // the sink inputs connected to remote device remain the same
409 if (std::find(remoteSinks.begin(), remoteSinks.end(), sink) != remoteSinks.end()) {
410 AUDIO_INFO_LOG("[SetLocalDefaultSink] sink-input[%{public}d] connects with remote device[%{public}d]",
411 sinkInput.paStreamId, sinkInput.deviceSinkId);
412 continue;
413 }
414 // move the remaining sink inputs to the default sink
415 uint32_t invalidSinkId = PA_INVALID_INDEX;
416 MoveSinkInputByIndexOrName(sinkInput.paStreamId, invalidSinkId, name);
417 }
418
419 return SUCCESS;
420 }
421
MoveSinkInputByIndexOrName(uint32_t sinkInputId,uint32_t sinkIndex,std::string sinkName)422 int32_t PulseAudioServiceAdapterImpl::MoveSinkInputByIndexOrName(uint32_t sinkInputId, uint32_t sinkIndex,
423 std::string sinkName)
424 {
425 lock_guard<mutex> lock(lock_);
426
427 unique_ptr<UserData> userData = make_unique<UserData>();
428 userData->thiz = this;
429
430 if (mContext == nullptr) {
431 AUDIO_ERR_LOG("[MoveSinkInputByIndexOrName] SetVolume mContext is nullptr");
432 return ERROR;
433 }
434 pa_threaded_mainloop_lock(mMainLoop);
435 pa_operation *operation = nullptr;
436 if (sinkName.empty()) {
437 operation = pa_context_move_sink_input_by_index(mContext, sinkInputId, sinkIndex,
438 PulseAudioServiceAdapterImpl::PaMoveSinkInputCb, reinterpret_cast<void *>(userData.get()));
439 } else {
440 operation = pa_context_move_sink_input_by_name(mContext, sinkInputId, sinkName.c_str(),
441 PulseAudioServiceAdapterImpl::PaMoveSinkInputCb, reinterpret_cast<void *>(userData.get()));
442 }
443
444 if (operation == nullptr) {
445 AUDIO_ERR_LOG("pa_context_get_sink_input_info_list nullptr");
446 pa_threaded_mainloop_unlock(mMainLoop);
447 return ERROR;
448 }
449 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
450 pa_threaded_mainloop_wait(mMainLoop);
451 }
452 pa_operation_unref(operation);
453 pa_threaded_mainloop_unlock(mMainLoop);
454
455 int result = userData->moveResult;
456 AUDIO_DEBUG_LOG("move result:[%{public}d]", result);
457
458 return SUCCESS;
459 }
460
MoveSourceOutputByIndexOrName(uint32_t sourceOutputId,uint32_t sourceIndex,std::string sourceName)461 int32_t PulseAudioServiceAdapterImpl::MoveSourceOutputByIndexOrName(uint32_t sourceOutputId, uint32_t sourceIndex,
462 std::string sourceName)
463 {
464 lock_guard<mutex> lock(lock_);
465
466 unique_ptr<UserData> userData = make_unique<UserData>();
467 userData->thiz = this;
468
469 if (mContext == nullptr) {
470 AUDIO_ERR_LOG("[MoveSourceOutputByIndexOrName] SetVolume mContext is nullptr");
471 return ERROR;
472 }
473 pa_threaded_mainloop_lock(mMainLoop);
474 pa_operation *operation = nullptr;
475 if (sourceName.empty()) {
476 operation = pa_context_move_source_output_by_index(mContext, sourceOutputId, sourceIndex,
477 PulseAudioServiceAdapterImpl::PaMoveSourceOutputCb, reinterpret_cast<void *>(userData.get()));
478 } else {
479 operation = pa_context_move_source_output_by_name(mContext, sourceOutputId, sourceName.c_str(),
480 PulseAudioServiceAdapterImpl::PaMoveSourceOutputCb, reinterpret_cast<void *>(userData.get()));
481 }
482
483 if (operation == nullptr) {
484 AUDIO_ERR_LOG("[MoveSourceOutputByIndexOrName] pa_context_get_sink_input_info_list nullptr");
485 pa_threaded_mainloop_unlock(mMainLoop);
486 return ERROR;
487 }
488 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
489 pa_threaded_mainloop_wait(mMainLoop);
490 }
491 pa_operation_unref(operation);
492 pa_threaded_mainloop_unlock(mMainLoop);
493
494 int result = userData->moveResult;
495 AUDIO_DEBUG_LOG("move result:[%{public}d]", result);
496
497 return SUCCESS;
498 }
499
SetVolumeDb(AudioStreamType streamType,float volumeDb)500 int32_t PulseAudioServiceAdapterImpl::SetVolumeDb(AudioStreamType streamType, float volumeDb)
501 {
502 lock_guard<mutex> lock(lock_);
503
504 unique_ptr<UserData> userData = make_unique<UserData>();
505 if (userData == nullptr) {
506 AUDIO_ERR_LOG("SetVolumeDb userData memory alloc failed");
507 return ERROR;
508 }
509
510 userData->thiz = this;
511 userData->volume = volumeDb;
512 userData->streamType = streamType;
513
514 if (mContext == nullptr) {
515 AUDIO_ERR_LOG("SetVolumeDb mContext is nullptr");
516 return ERROR;
517 }
518 pa_threaded_mainloop_lock(mMainLoop);
519 pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
520 PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb, reinterpret_cast<void*>(userData.get()));
521 if (operation == nullptr) {
522 AUDIO_ERR_LOG("SetVolumeDb pa_context_get_sink_input_info_list nullptr");
523 pa_threaded_mainloop_unlock(mMainLoop);
524 return ERROR;
525 }
526 userData.release();
527
528 pa_threaded_mainloop_accept(mMainLoop);
529
530 pa_operation_unref(operation);
531 pa_threaded_mainloop_unlock(mMainLoop);
532
533 return SUCCESS;
534 }
535
SetSourceOutputMute(int32_t uid,bool setMute)536 int32_t PulseAudioServiceAdapterImpl::SetSourceOutputMute(int32_t uid, bool setMute)
537 {
538 if (mContext == nullptr) {
539 AUDIO_ERR_LOG("[SetSourceOutputMute] mContext is nullptr");
540 return ERROR;
541 }
542 vector<SourceOutput> sourOutputs = GetAllSourceOutputs();
543 lock_guard<mutex> lock(lock_);
544 int32_t streamSet = 0;
545 for (uint32_t i = 0; i < sourOutputs.size(); i ++) {
546 if (sourOutputs[i].uid == uid) {
547 pa_operation_unref(pa_context_set_source_output_mute(mContext, sourOutputs[i].paStreamId, (setMute ? 1 : 0),
548 nullptr, nullptr));
549 AUDIO_DEBUG_LOG("[SetSourceOutputMute] set source output Mute : %{public}s for stream :uid %{public}d",
550 (setMute ? "true" : "false"), sourOutputs[i].uid);
551 streamSet++;
552 }
553 }
554 AUDIO_INFO_LOG("[SetSourceOutputMute] set %{public}d %{public}s", streamSet, (setMute ? "mute" : "unmuted"));
555 return streamSet;
556 }
557
IsStreamActive(AudioStreamType streamType)558 bool PulseAudioServiceAdapterImpl::IsStreamActive(AudioStreamType streamType)
559 {
560 lock_guard<mutex> lock(lock_);
561 if (!isSetDefaultSink_) {
562 AUDIO_ERR_LOG("IsStreamActive: not SetDefaultSink first");
563 return false;
564 }
565
566 unique_ptr<UserData> userData = make_unique<UserData>();
567 userData->thiz = this;
568 userData->streamType = streamType;
569 userData->isCorked = true;
570
571 if (mContext == nullptr) {
572 AUDIO_ERR_LOG("IsStreamActive: mContext is nullptr");
573 return false;
574 }
575
576 pa_threaded_mainloop_lock(mMainLoop);
577
578 pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
579 PulseAudioServiceAdapterImpl::PaGetSinkInputInfoCorkStatusCb, reinterpret_cast<void*>(userData.get()));
580 if (operation == nullptr) {
581 AUDIO_ERR_LOG("IsStreamActive: pa_context_get_sink_input_info_list returned nullptr");
582 pa_threaded_mainloop_unlock(mMainLoop);
583 return false;
584 }
585
586 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
587 pa_threaded_mainloop_wait(mMainLoop);
588 }
589
590 pa_operation_unref(operation);
591 pa_threaded_mainloop_unlock(mMainLoop);
592
593 AUDIO_DEBUG_LOG("IsStreamActive: streamType: %{puiblic}d, isCorked: %{puiblic}d", streamType, userData->isCorked);
594
595 return (userData->isCorked) ? false : true;
596 }
597
GetAllSinkInputs()598 vector<SinkInput> PulseAudioServiceAdapterImpl::GetAllSinkInputs()
599 {
600 AUDIO_INFO_LOG("GetAllSinkInputs enter");
601 unique_ptr<UserData> userData = make_unique<UserData>();
602 userData->thiz = this;
603 userData->sinkInfos = GetAllSinks();
604
605 lock_guard<mutex> lock(lock_);
606 if (mContext == nullptr) {
607 AUDIO_ERR_LOG("GetAllSinkInputs mContext is nullptr");
608 return userData->sinkInputList;
609 }
610
611 pa_threaded_mainloop_lock(mMainLoop);
612
613 pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
614 PulseAudioServiceAdapterImpl::PaGetAllSinkInputsCb, reinterpret_cast<void*>(userData.get()));
615 if (operation == nullptr) {
616 AUDIO_ERR_LOG("[GetAllSinkInputs] pa_context_get_sink_input_info_list returned nullptr");
617 pa_threaded_mainloop_unlock(mMainLoop);
618 return userData->sinkInputList;
619 }
620
621 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
622 pa_threaded_mainloop_wait(mMainLoop);
623 }
624
625 pa_operation_unref(operation);
626 pa_threaded_mainloop_unlock(mMainLoop);
627
628 AUDIO_DEBUG_LOG("GetAllSinkInputs get:[%{public}zu]", userData->sinkInputList.size());
629 return userData->sinkInputList;
630 }
631
GetAllSourceOutputs()632 vector<SourceOutput> PulseAudioServiceAdapterImpl::GetAllSourceOutputs()
633 {
634 lock_guard<mutex> lock(lock_);
635
636 unique_ptr<UserData> userData = make_unique<UserData>();
637 userData->thiz = this;
638
639 if (mContext == nullptr) {
640 AUDIO_ERR_LOG("GetAllSourceOutputs mContext is nullptr");
641 return userData->sourceOutputList;
642 }
643
644 if (!isSetDefaultSource_) {
645 AUDIO_ERR_LOG("default source has not been set.");
646 return userData->sourceOutputList;
647 }
648
649 pa_threaded_mainloop_lock(mMainLoop);
650
651 pa_operation *operation = pa_context_get_source_output_info_list(mContext,
652 PulseAudioServiceAdapterImpl::PaGetAllSourceOutputsCb, reinterpret_cast<void*>(userData.get()));
653 if (operation == nullptr) {
654 AUDIO_ERR_LOG("[GetAllSourceOutputs] pa_context_get_source_output_info_list returned nullptr");
655 pa_threaded_mainloop_unlock(mMainLoop);
656 return userData->sourceOutputList;
657 }
658
659 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
660 pa_threaded_mainloop_wait(mMainLoop);
661 }
662
663 pa_operation_unref(operation);
664 pa_threaded_mainloop_unlock(mMainLoop);
665
666 return userData->sourceOutputList;
667 }
668
Disconnect()669 void PulseAudioServiceAdapterImpl::Disconnect()
670 {
671 if (mContext != nullptr) {
672 AUDIO_INFO_LOG("disconnect context!");
673 pa_context_disconnect(mContext);
674 /* Make sure we don't get any further callbacks */
675 pa_context_set_state_callback(mContext, nullptr, nullptr);
676 pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
677 pa_context_unref(mContext);
678 }
679
680 if (mMainLoop != nullptr) {
681 pa_threaded_mainloop_stop(mMainLoop);
682 pa_threaded_mainloop_free(mMainLoop);
683 }
684 }
685
GetIdByStreamType(string streamType)686 AudioStreamType PulseAudioServiceAdapterImpl::GetIdByStreamType(string streamType)
687 {
688 AudioStreamType stream = STREAM_MUSIC;
689 if (STREAM_TYPE_STRING_ENUM_MAP.find(streamType) != STREAM_TYPE_STRING_ENUM_MAP.end()) {
690 stream = STREAM_TYPE_STRING_ENUM_MAP.at(streamType);
691 } else {
692 AUDIO_ERR_LOG("GetIdByStreamType: Invalid stream type [%{public}s]. Use default type", streamType.c_str());
693 }
694 return stream;
695 }
696
PaMoveSinkInputCb(pa_context * c,int success,void * userdata)697 void PulseAudioServiceAdapterImpl::PaMoveSinkInputCb(pa_context *c, int success, void *userdata)
698 {
699 UserData *userData = reinterpret_cast<UserData *>(userdata);
700
701 AUDIO_INFO_LOG("[PaMoveSinkInputCb] result[%{public}d]", success);
702 userData->moveResult = success;
703
704 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
705
706 return;
707 }
708
PaMoveSourceOutputCb(pa_context * c,int success,void * userdata)709 void PulseAudioServiceAdapterImpl::PaMoveSourceOutputCb(pa_context *c, int success, void *userdata)
710 {
711 UserData *userData = reinterpret_cast<UserData *>(userdata);
712
713 AUDIO_INFO_LOG("[PaMoveSourceOutputCb] result[%{public}d]", success);
714 userData->moveResult = success;
715
716 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
717
718 return;
719 }
720
PaContextStateCb(pa_context * c,void * userdata)721 void PulseAudioServiceAdapterImpl::PaContextStateCb(pa_context *c, void *userdata)
722 {
723 PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
724
725 switch (pa_context_get_state(c)) {
726 case PA_CONTEXT_UNCONNECTED:
727 case PA_CONTEXT_CONNECTING:
728 case PA_CONTEXT_AUTHORIZING:
729 case PA_CONTEXT_SETTING_NAME:
730 break;
731
732 case PA_CONTEXT_READY: {
733 pa_context_set_subscribe_callback(c, PulseAudioServiceAdapterImpl::PaSubscribeCb, thiz);
734
735 pa_operation *operation = pa_context_subscribe(c, (pa_subscription_mask_t)
736 (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE |
737 PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT |
738 PA_SUBSCRIPTION_MASK_CARD), nullptr, nullptr);
739 if (operation == nullptr) {
740 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
741 return;
742 }
743 pa_operation_unref(operation);
744 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
745 break;
746 }
747
748 case PA_CONTEXT_FAILED:
749 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
750 return;
751
752 case PA_CONTEXT_TERMINATED:
753 default:
754 return;
755 }
756 }
757
PaModuleLoadCb(pa_context * c,uint32_t idx,void * userdata)758 void PulseAudioServiceAdapterImpl::PaModuleLoadCb(pa_context *c, uint32_t idx, void *userdata)
759 {
760 UserData *userData = reinterpret_cast<UserData*>(userdata);
761 if (idx == PA_INVALID_INDEX) {
762 AUDIO_ERR_LOG("PaModuleLoadCb Failure: %{public}s", pa_strerror(pa_context_errno(c)));
763 userData->idx = PA_INVALID_INDEX;
764 } else {
765 userData->idx = idx;
766 }
767 pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
768
769 return;
770 }
771
772 template <typename T>
CastValue(T & a,const char * raw)773 inline void CastValue(T &a, const char *raw)
774 {
775 if (raw == nullptr) {
776 return;
777 }
778 std::stringstream valueStr;
779 valueStr << raw;
780 valueStr >> a;
781 }
782
PaGetSinkInputInfoVolumeCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)783 void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol,
784 void *userdata)
785 {
786 UserData *userData = reinterpret_cast<UserData*>(userdata);
787 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
788
789 AUDIO_DEBUG_LOG("GetSinkInputInfoVolumeCb");
790 if (eol < 0) {
791 delete userData;
792 AUDIO_ERR_LOG("Failed to get sink input information: %{public}s",
793 pa_strerror(pa_context_errno(c)));
794 return;
795 }
796
797 if (eol) {
798 pa_threaded_mainloop_signal(thiz->mMainLoop, 1);
799 delete userData;
800 return;
801 }
802
803 if (i->proplist == nullptr) {
804 AUDIO_ERR_LOG("Invalid Proplist for sink input (%{public}d).", i->index);
805 return;
806 }
807
808 const char *streamtype = pa_proplist_gets(i->proplist, "stream.type");
809 const char *streamVolume = pa_proplist_gets(i->proplist, "stream.volumeFactor");
810 const char *streamPowerVolume = pa_proplist_gets(i->proplist, "stream.powerVolumeFactor");
811 const char *sessionCStr = pa_proplist_gets(i->proplist, "stream.sessionID");
812 int32_t uid = -1;
813 int32_t pid = -1;
814 CastValue<int32_t>(uid, pa_proplist_gets(i->proplist, "stream.client.uid"));
815 CastValue<int32_t>(pid, pa_proplist_gets(i->proplist, "stream.client.pid"));
816 if ((streamtype == nullptr) || (streamVolume == nullptr) || (streamPowerVolume == nullptr) ||
817 (sessionCStr == nullptr)) {
818 AUDIO_DEBUG_LOG("Invalid Stream parameter info.");
819 return;
820 }
821
822 std::stringstream sessionStr;
823 uint32_t sessionID;
824 sessionStr << sessionCStr;
825 sessionStr >> sessionID;
826 AUDIO_INFO_LOG("PaGetSinkInputInfoVolumeCb sessionID %{public}u", sessionID);
827
828 sinkIndexSessionIDMap[i->index] = sessionID;
829
830 string streamType(streamtype);
831 float volumeFactor = atof(streamVolume);
832 float powerVolumeFactor = atof(streamPowerVolume);
833 AudioStreamType streamTypeID = thiz->GetIdByStreamType(streamType);
834 float volumeDbCb = g_audioServiceAdapterCallback->OnGetVolumeDbCb(streamTypeID);
835 float vol = volumeDbCb * volumeFactor * powerVolumeFactor;
836
837 pa_cvolume cv = i->volume;
838 uint32_t volume = pa_sw_volume_from_linear(vol);
839 pa_cvolume_set(&cv, i->channel_map.channels, volume);
840
841 if (streamTypeID == userData->streamType || userData->isSubscribingCb) {
842 pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, nullptr, nullptr));
843 }
844 AUDIO_DEBUG_LOG("volume %{public}f for stream uid %{public}d"\
845 ", volumeFactor %{public}f, volumeDbCb %{public}f", vol, uid, volumeFactor, volumeDbCb);
846 HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::AUDIO,
847 "VOLUME_CHANGE", HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
848 "ISOUTPUT", 1, "STREAMID", sessionID, "APP_UID", uid, "APP_PID", pid, "STREAMTYPE", streamTypeID, "VOLUME", vol,
849 "SYSVOLUME", volumeDbCb, "VOLUMEFACTOR", volumeFactor, "POWERVOLUMEFACTOR", powerVolumeFactor);
850 }
851
PaGetSinkInputInfoCorkStatusCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)852 void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoCorkStatusCb(pa_context *c, const pa_sink_input_info *i, int eol,
853 void *userdata)
854 {
855 UserData *userData = reinterpret_cast<UserData*>(userdata);
856 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
857
858 if (eol < 0) {
859 AUDIO_ERR_LOG("Failed to get sink input information: %{public}s",
860 pa_strerror(pa_context_errno(c)));
861 return;
862 }
863
864 if (eol) {
865 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
866 return;
867 }
868
869 if (i->proplist == nullptr) {
870 AUDIO_ERR_LOG("PaGetSinkInputInfoCorkStatusCb Invalid Proplist for sink input (%{public}d).", i->index);
871 return;
872 }
873
874 const char *streamtype = pa_proplist_gets(i->proplist, "stream.type");
875 if (streamtype == nullptr) {
876 AUDIO_DEBUG_LOG("PaGetSinkInputInfoCorkStatusCb Invalid StreamType.");
877 return;
878 }
879
880 string streamType(streamtype);
881 if (thiz->GetIdByStreamType(streamType) == userData->streamType) {
882 userData->isCorked = i->corked;
883 AUDIO_INFO_LOG("PaGetSinkInputInfoCorkStatusCb corked : %{public}d for stream : %{public}s",
884 userData->isCorked, i->name);
885 }
886 }
887
PaGetSourceOutputCb(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)888 void PulseAudioServiceAdapterImpl::PaGetSourceOutputCb(pa_context *c, const pa_source_output_info *i, int eol,
889 void *userdata)
890 {
891 AUDIO_INFO_LOG("in eol[%{public}d]", eol);
892 UserData *userData = reinterpret_cast<UserData*>(userdata);
893 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
894
895 if (eol < 0) {
896 delete userData;
897 AUDIO_ERR_LOG("Failed to get source output information: %{public}s",
898 pa_strerror(pa_context_errno(c)));
899 return;
900 }
901
902 if (eol) {
903 pa_threaded_mainloop_signal(thiz->mMainLoop, 1);
904 delete userData;
905 return;
906 }
907
908 if (i->proplist == nullptr) {
909 AUDIO_ERR_LOG("Invalid proplist for source output (%{public}d).", i->index);
910 return;
911 }
912
913 const char *streamSession = pa_proplist_gets(i->proplist, "stream.sessionID");
914 if (streamSession == nullptr) {
915 AUDIO_ERR_LOG("Invalid stream parameter:sessionID.");
916 return;
917 }
918
919 std::stringstream sessionStr;
920 uint32_t sessionID;
921 sessionStr << streamSession;
922 sessionStr >> sessionID;
923 AUDIO_INFO_LOG("sessionID %{public}u", sessionID);
924 sourceIndexSessionIDMap[i->index] = sessionID;
925
926 const char *captureFlag = pa_proplist_gets(i->proplist, "stream.isInnerCapturer");
927 if (captureFlag == nullptr) {
928 AUDIO_ERR_LOG("Invalid stream parameter:isInnerCapturer.");
929 } else {
930 int32_t flag = atoi(captureFlag);
931 if (flag == 1) {
932 g_playbackCapturerSourceOutputIndex = i->index;
933 }
934 }
935
936 auto isWakeup = pa_proplist_gets(i->proplist, "stream.isWakeupCapturer");
937 if (isWakeup && !strcmp("1", isWakeup)) {
938 g_wakeupCapturerSourceOutputIndexs.insert(i->index);
939 }
940 }
941
PaGetAllSinkInputsCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)942 void PulseAudioServiceAdapterImpl::PaGetAllSinkInputsCb(pa_context *c, const pa_sink_input_info *i, int eol,
943 void *userdata)
944 {
945 AUDIO_INFO_LOG("[PaGetAllSinkInputsCb] in eol[%{public}d]", eol);
946 UserData *userData = reinterpret_cast<UserData *>(userdata);
947 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
948
949 if (eol < 0) {
950 AUDIO_ERR_LOG("PaGetAllSinkInputsCb Failed to get sink input information: %{public}s",
951 pa_strerror(pa_context_errno(c)));
952 return;
953 }
954
955 if (eol) {
956 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
957 return;
958 }
959
960 if (i->proplist == nullptr) {
961 AUDIO_ERR_LOG("PaGetAllSinkInputsCb Invalid Proplist for sink input (%{public}d).", i->index);
962 return;
963 }
964
965 AudioStreamType audioStreamType = STREAM_DEFAULT;
966 const char *streamType = pa_proplist_gets(i->proplist, "stream.type");
967 if (streamType != nullptr) {
968 audioStreamType = thiz->GetIdByStreamType(streamType);
969 }
970
971 SinkInput sinkInput = {};
972 sinkInput.streamType = audioStreamType;
973
974 sinkInput.deviceSinkId = i->sink;
975 for (auto sinkInfo : userData->sinkInfos) {
976 if (sinkInput.deviceSinkId == sinkInfo.sinkId) {
977 sinkInput.sinkName = sinkInfo.sinkName;
978 break;
979 }
980 }
981 sinkInput.paStreamId = i->index;
982 CastValue<int32_t>(sinkInput.streamId, pa_proplist_gets(i->proplist, "stream.sessionID"));
983 CastValue<int32_t>(sinkInput.uid, pa_proplist_gets(i->proplist, "stream.client.uid"));
984 CastValue<int32_t>(sinkInput.pid, pa_proplist_gets(i->proplist, "stream.client.pid"));
985 CastValue<uint64_t>(sinkInput.startTime, pa_proplist_gets(i->proplist, "stream.startTime"));
986
987 userData->sinkInputList.push_back(sinkInput);
988 }
989
PaGetAllSourceOutputsCb(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)990 void PulseAudioServiceAdapterImpl::PaGetAllSourceOutputsCb(pa_context *c, const pa_source_output_info *i, int eol,
991 void *userdata)
992 {
993 AUDIO_DEBUG_LOG("[PaGetAllSourceOutputsCb] in eol[%{public}d]", eol);
994 UserData *userData = reinterpret_cast<UserData *>(userdata);
995 PulseAudioServiceAdapterImpl *thiz = userData->thiz;
996
997 if (eol < 0) {
998 AUDIO_ERR_LOG("[PaGetAllSourceOutputsCb] Failed to get source output information: %{public}s",
999 pa_strerror(pa_context_errno(c)));
1000 return;
1001 }
1002
1003 if (eol) {
1004 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
1005 return;
1006 }
1007
1008 if (i->proplist == nullptr) {
1009 AUDIO_ERR_LOG("[PaGetAllSourceOutputsCb] Invalid Proplist for source output (%{public}d).", i->index);
1010 return;
1011 }
1012
1013 uint32_t sessionID = 0;
1014 const char *sessionCStr = pa_proplist_gets(i->proplist, "stream.sessionID");
1015 if (sessionCStr != nullptr) {
1016 std::stringstream sessionStr;
1017 sessionStr << sessionCStr;
1018 sessionStr >> sessionID;
1019 }
1020
1021 AudioStreamType audioStreamType = STREAM_DEFAULT;
1022 const char *streamType = pa_proplist_gets(i->proplist, "stream.type");
1023 if (streamType != nullptr) {
1024 audioStreamType = thiz->GetIdByStreamType(streamType);
1025 }
1026
1027 SourceOutput sourceOutput = {};
1028 sourceOutput.streamId = sessionID;
1029 sourceOutput.streamType = audioStreamType;
1030
1031 sourceOutput.paStreamId = i->index;
1032 sourceOutput.deviceSourceId = i->source;
1033 CastValue<int32_t>(sourceOutput.uid, pa_proplist_gets(i->proplist, "stream.client.uid"));
1034 CastValue<int32_t>(sourceOutput.pid, pa_proplist_gets(i->proplist, "stream.client.pid"));
1035 CastValue<uint64_t>(sourceOutput.startTime, pa_proplist_gets(i->proplist, "stream.startTime"));
1036 userData->sourceOutputList.push_back(sourceOutput);
1037 }
1038
ProcessSourceOutputEvent(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)1039 void PulseAudioServiceAdapterImpl::ProcessSourceOutputEvent(pa_context *c, pa_subscription_event_type_t t, uint32_t idx,
1040 void *userdata)
1041 {
1042 unique_ptr<UserData> userData = make_unique<UserData>();
1043 PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
1044 userData->thiz = thiz;
1045 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
1046 pa_threaded_mainloop_lock(thiz->mMainLoop);
1047 pa_operation *operation = pa_context_get_source_output_info(c, idx,
1048 PulseAudioServiceAdapterImpl::PaGetSourceOutputCb, reinterpret_cast<void*>(userData.get()));
1049 if (operation == nullptr) {
1050 AUDIO_ERR_LOG("[ProcessSourceOutputEvent] pa_context_get_source_output_info nullptr");
1051 pa_threaded_mainloop_unlock(thiz->mMainLoop);
1052 return;
1053 }
1054 userData.release();
1055 pa_threaded_mainloop_accept(thiz->mMainLoop);
1056 pa_operation_unref(operation);
1057 pa_threaded_mainloop_unlock(thiz->mMainLoop);
1058 } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
1059 uint32_t sessionID = sourceIndexSessionIDMap[idx];
1060 AUDIO_ERR_LOG("[ProcessSourceOutputEvent] sessionID: %{public}d removed", sessionID);
1061 g_audioServiceAdapterCallback->OnSessionRemoved(sessionID);
1062 if (idx == g_playbackCapturerSourceOutputIndex) {
1063 g_audioServiceAdapterCallback->OnPlaybackCapturerStop();
1064 g_playbackCapturerSourceOutputIndex = -1;
1065 }
1066
1067 auto it = g_wakeupCapturerSourceOutputIndexs.find(idx);
1068 if (it != g_wakeupCapturerSourceOutputIndexs.end()) {
1069 g_wakeupCapturerSourceOutputIndexs.erase(it);
1070
1071 pa_threaded_mainloop_once_unlocked(thiz->mMainLoop,
1072 []([[maybe_unused]] pa_threaded_mainloop *m, void *userdata) {
1073 g_audioServiceAdapterCallback->OnWakeupCapturerStop();
1074 },
1075 nullptr);
1076 }
1077 }
1078 }
1079
PaSubscribeCb(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)1080 void PulseAudioServiceAdapterImpl::PaSubscribeCb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx,
1081 void *userdata)
1082 {
1083 unique_ptr<UserData> userData = make_unique<UserData>();
1084 PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
1085 userData->thiz = thiz;
1086 userData->isSubscribingCb = true;
1087 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
1088 case PA_SUBSCRIPTION_EVENT_SINK:
1089 break;
1090
1091 case PA_SUBSCRIPTION_EVENT_SOURCE:
1092 break;
1093
1094 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
1095 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
1096 pa_threaded_mainloop_lock(thiz->mMainLoop);
1097 pa_operation *operation = pa_context_get_sink_input_info(c, idx,
1098 PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb, reinterpret_cast<void*>(userData.get()));
1099 if (operation == nullptr) {
1100 AUDIO_ERR_LOG("PaSubscribeCb pa_context_get_sink_input_info_list nullptr");
1101 pa_threaded_mainloop_unlock(thiz->mMainLoop);
1102 return;
1103 }
1104 userData.release();
1105 pa_threaded_mainloop_accept(thiz->mMainLoop);
1106 pa_operation_unref(operation);
1107 pa_threaded_mainloop_unlock(thiz->mMainLoop);
1108 } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
1109 const uint32_t sessionID = sinkIndexSessionIDMap[idx];
1110 AUDIO_INFO_LOG("sessionID: %{public}d removed", sessionID);
1111
1112 std::thread threadOnSessionRemoved([sessionID] {
1113 g_audioServiceAdapterCallback->OnSessionRemoved(sessionID);
1114 });
1115 threadOnSessionRemoved.detach();
1116 }
1117 break;
1118
1119 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
1120 ProcessSourceOutputEvent(c, t, idx, userdata);
1121 break;
1122
1123 default:
1124 break;
1125 }
1126 }
1127
UpdateSwapDeviceStatus()1128 int32_t PulseAudioServiceAdapterImpl::UpdateSwapDeviceStatus()
1129 {
1130 if (mContext == nullptr) {
1131 AUDIO_ERR_LOG("UpdateClusterModule mContext is nullptr");
1132 return ERROR;
1133 }
1134 pa_threaded_mainloop_lock(mMainLoop);
1135
1136 swapStatus = 1 - swapStatus;
1137 pa_proplist *proplist = pa_proplist_new();
1138 pa_proplist_sets(proplist, "device.swap.status", std::to_string(swapStatus).c_str());
1139 pa_operation *operation = pa_context_proplist_update(mContext, PA_UPDATE_REPLACE, proplist, nullptr, nullptr);
1140 if (operation == nullptr) {
1141 AUDIO_ERR_LOG("UpdateClusterModule pa_context_proplist_update returned nullptr");
1142 pa_threaded_mainloop_unlock(mMainLoop);
1143 return ERROR;
1144 }
1145
1146 pa_operation_unref(operation);
1147 pa_threaded_mainloop_unlock(mMainLoop);
1148 return SUCCESS;
1149 }
1150 } // namespace AudioStandard
1151 } // namespace OHOS
1152
1153 #endif // ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
1154