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