• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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