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