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