• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
17 #define ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
18 
19 #include "pulse_audio_service_adapter_impl.h"
20 
21 #include <sstream>
22 #include <unistd.h>
23 
24 #include "audio_errors.h"
25 #include "media_log.h"
26 
27 using namespace std;
28 
29 namespace OHOS {
30 namespace AudioStandard {
31 static unique_ptr<AudioServiceAdapterCallback> g_audioServiceAdapterCallback;
32 std::unordered_map<uint32_t, uint32_t> PulseAudioServiceAdapterImpl::sinkIndexSessionIDMap;
33 
34 AudioServiceAdapter::~AudioServiceAdapter() = default;
35 PulseAudioServiceAdapterImpl::~PulseAudioServiceAdapterImpl() = default;
36 
CreateAudioAdapter(unique_ptr<AudioServiceAdapterCallback> cb)37 unique_ptr<AudioServiceAdapter> AudioServiceAdapter::CreateAudioAdapter(unique_ptr<AudioServiceAdapterCallback> cb)
38 {
39     return make_unique<PulseAudioServiceAdapterImpl>(cb);
40 }
41 
PulseAudioServiceAdapterImpl(unique_ptr<AudioServiceAdapterCallback> & cb)42 PulseAudioServiceAdapterImpl::PulseAudioServiceAdapterImpl(unique_ptr<AudioServiceAdapterCallback> &cb)
43 {
44     g_audioServiceAdapterCallback = move(cb);
45 }
46 
Connect()47 bool PulseAudioServiceAdapterImpl::Connect()
48 {
49     mMainLoop = pa_threaded_mainloop_new();
50     if (!mMainLoop) {
51         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] MainLoop creation failed");
52         return false;
53     }
54 
55     if (pa_threaded_mainloop_start(mMainLoop) < 0) {
56         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Failed to start mainloop");
57         pa_threaded_mainloop_free (mMainLoop);
58         return false;
59     }
60 
61     pa_threaded_mainloop_lock(mMainLoop);
62 
63     while (true) {
64         pa_context_state_t state;
65 
66         if (mContext != nullptr) {
67             state = pa_context_get_state(mContext);
68             if (state == PA_CONTEXT_READY) {
69                 break;
70             }
71             // if pulseaudio is ready, retry connect to pulseaudio. before retry wait for sometime. reduce sleep later
72             usleep(PA_CONNECT_RETRY_SLEEP_IN_MICRO_SECONDS);
73         }
74 
75         bool result = ConnectToPulseAudio();
76         if (!result || !PA_CONTEXT_IS_GOOD(pa_context_get_state(mContext))) {
77             continue;
78         }
79 
80         MEDIA_DEBUG_LOG("[PulseAudioServiceAdapterImpl] pa context not ready... wait");
81 
82         // Wait for the context to be ready
83         pa_threaded_mainloop_wait(mMainLoop);
84     }
85 
86     pa_threaded_mainloop_unlock(mMainLoop);
87 
88     return true;
89 }
90 
ConnectToPulseAudio()91 bool PulseAudioServiceAdapterImpl::ConnectToPulseAudio()
92 {
93     if (mContext != nullptr) {
94         pa_context_disconnect(mContext);
95         pa_context_set_state_callback(mContext, nullptr, nullptr);
96         pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
97         pa_context_unref(mContext);
98     }
99 
100     pa_proplist *proplist = pa_proplist_new();
101     pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio Service");
102     pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.ohos.pulseaudio.service");
103     mContext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mMainLoop), nullptr, proplist);
104     pa_proplist_free(proplist);
105 
106     if (mContext == nullptr) {
107         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] creating pa context failed");
108         return false;
109     }
110 
111     pa_context_set_state_callback(mContext,  PulseAudioServiceAdapterImpl::PaContextStateCb, this);
112     if (pa_context_connect(mContext, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) {
113         if (pa_context_errno(mContext) == PA_ERR_INVALID) {
114             MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa context connect failed: %{public}s",
115                 pa_strerror(pa_context_errno(mContext)));
116             goto Fail;
117         }
118     }
119 
120     return true;
121 
122 Fail:
123     /* Make sure we don't get any further callbacks */
124     pa_context_set_state_callback(mContext, nullptr, nullptr);
125     pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
126     pa_context_unref(mContext);
127     return false;
128 }
129 
OpenAudioPort(string audioPortName,string moduleArgs)130 uint32_t PulseAudioServiceAdapterImpl::OpenAudioPort(string audioPortName, string moduleArgs)
131 {
132     unique_ptr<UserData> userData = make_unique<UserData>();
133     userData->thiz = this;
134 
135     pa_threaded_mainloop_lock(mMainLoop);
136     pa_operation *operation = pa_context_load_module(mContext, audioPortName.c_str(), moduleArgs.c_str(),
137         PaModuleLoadCb, reinterpret_cast<void*>(userData.get()));
138     if (operation == nullptr) {
139         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_load_module returned nullptr");
140         pa_threaded_mainloop_unlock(mMainLoop);
141         return ERR_INVALID_HANDLE;
142     }
143 
144     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
145         pa_threaded_mainloop_wait(mMainLoop);
146     }
147 
148     pa_operation_unref(operation);
149     pa_threaded_mainloop_unlock(mMainLoop);
150 
151     if (userData->idx == PA_INVALID_INDEX) {
152         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] OpenAudioPort returned invalid index");
153         return ERR_OPERATION_FAILED;
154     }
155 
156     return userData->idx;
157 }
158 
CloseAudioPort(int32_t audioHandleIndex)159 int32_t PulseAudioServiceAdapterImpl::CloseAudioPort(int32_t audioHandleIndex)
160 {
161     pa_threaded_mainloop_lock(mMainLoop);
162 
163     pa_operation *operation = pa_context_unload_module(mContext, audioHandleIndex, nullptr, nullptr);
164     if (operation == nullptr) {
165         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_unload_module returned nullptr!");
166         pa_threaded_mainloop_unlock(mMainLoop);
167         return ERROR;
168     }
169 
170     pa_operation_unref(operation);
171     pa_threaded_mainloop_unlock(mMainLoop);
172     return SUCCESS;
173 }
174 
SuspendAudioDevice(string & audioPortName,bool isSuspend)175 int32_t PulseAudioServiceAdapterImpl::SuspendAudioDevice(string &audioPortName, bool isSuspend)
176 {
177     MEDIA_INFO_LOG("SuspendAudioDevice: [%{public}s] : [%{public}d]", audioPortName.c_str(), isSuspend);
178     pa_threaded_mainloop_lock(mMainLoop);
179 
180     auto suspendFlag = isSuspend ? 1 : 0;
181     pa_operation *operation = pa_context_suspend_sink_by_name(mContext, audioPortName.c_str(), suspendFlag,
182         nullptr, nullptr);
183     if (operation == nullptr) {
184         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_suspend_sink_by_name failed!");
185         pa_threaded_mainloop_unlock(mMainLoop);
186         return ERR_OPERATION_FAILED;
187     }
188 
189     pa_operation_unref(operation);
190     pa_threaded_mainloop_unlock(mMainLoop);
191 
192     return SUCCESS;
193 }
194 
SetDefaultSink(string name)195 int32_t PulseAudioServiceAdapterImpl::SetDefaultSink(string name)
196 {
197     pa_threaded_mainloop_lock(mMainLoop);
198     pa_operation *operation = pa_context_set_default_sink(mContext, name.c_str(), nullptr, nullptr);
199     if (operation == nullptr) {
200         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_set_default_sink failed!");
201         pa_threaded_mainloop_unlock(mMainLoop);
202         return ERR_OPERATION_FAILED;
203     }
204     pa_operation_unref(operation);
205     pa_threaded_mainloop_unlock(mMainLoop);
206 
207     return SUCCESS;
208 }
209 
SetDefaultSource(string name)210 int32_t PulseAudioServiceAdapterImpl::SetDefaultSource(string name)
211 {
212     pa_threaded_mainloop_lock(mMainLoop);
213     pa_operation *operation = pa_context_set_default_source(mContext, name.c_str(), nullptr, nullptr);
214     if (operation == nullptr) {
215         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_set_default_source failed!");
216         pa_threaded_mainloop_unlock(mMainLoop);
217         return ERR_OPERATION_FAILED;
218     }
219     pa_operation_unref(operation);
220     pa_threaded_mainloop_unlock(mMainLoop);
221 
222     return SUCCESS;
223 }
224 
SetVolume(AudioStreamType streamType,float volume)225 int32_t PulseAudioServiceAdapterImpl::SetVolume(AudioStreamType streamType, float volume)
226 {
227     lock_guard<mutex> lock(mMutex);
228 
229     unique_ptr<UserData> userData = make_unique<UserData>();
230     if (userData == nullptr) {
231         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] SetVolume UserData memory alloc failed");
232         return ERROR;
233     }
234 
235     userData->thiz = this;
236     userData->volume = volume;
237     userData->streamType = streamType;
238 
239     if (mContext == nullptr) {
240         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] SetVolume mContext is nullptr");
241         return ERROR;
242     }
243     pa_threaded_mainloop_lock(mMainLoop);
244     pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
245         PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb, reinterpret_cast<void*>(userData.get()));
246     if (operation == nullptr) {
247         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_get_sink_input_info_list nullptr");
248         pa_threaded_mainloop_unlock(mMainLoop);
249         return ERROR;
250     }
251     userData.release();
252 
253     pa_threaded_mainloop_accept(mMainLoop);
254 
255     pa_operation_unref(operation);
256     pa_threaded_mainloop_unlock(mMainLoop);
257 
258     return SUCCESS;
259 }
260 
SetMute(AudioStreamType streamType,bool mute)261 int32_t PulseAudioServiceAdapterImpl::SetMute(AudioStreamType streamType, bool mute)
262 {
263     lock_guard<mutex> lock(mMutex);
264 
265     unique_ptr<UserData> userData = make_unique<UserData>();
266     userData->thiz = this;
267     userData->mute = mute;
268     userData->streamType = streamType;
269 
270     if (mContext == nullptr) {
271         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] SetMute mContext is nullptr");
272         return ERROR;
273     }
274     pa_threaded_mainloop_lock(mMainLoop);
275 
276     pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
277         PulseAudioServiceAdapterImpl::PaGetSinkInputInfoMuteCb, reinterpret_cast<void*>(userData.get()));
278     if (operation == nullptr) {
279         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_get_sink_input_info_list returned nullptr");
280         pa_threaded_mainloop_unlock(mMainLoop);
281         return ERROR;
282     }
283 
284     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
285         pa_threaded_mainloop_wait(mMainLoop);
286     }
287 
288     pa_operation_unref(operation);
289     pa_threaded_mainloop_unlock(mMainLoop);
290 
291     return SUCCESS;
292 }
293 
IsMute(AudioStreamType streamType)294 bool PulseAudioServiceAdapterImpl::IsMute(AudioStreamType streamType)
295 {
296     lock_guard<mutex> lock(mMutex);
297 
298     unique_ptr<UserData> userData = make_unique<UserData>();
299     userData->thiz = this;
300     userData->streamType = streamType;
301     userData->mute = false;
302 
303     if (mContext == nullptr) {
304         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] IsMute mContext is nullptr");
305         return false;
306     }
307 
308     pa_threaded_mainloop_lock(mMainLoop);
309 
310     pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
311         PulseAudioServiceAdapterImpl::PaGetSinkInputInfoMuteStatusCb, reinterpret_cast<void*>(userData.get()));
312     if (operation == nullptr) {
313         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_get_sink_input_info_list returned nullptr");
314         pa_threaded_mainloop_unlock(mMainLoop);
315         return false;
316     }
317 
318     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
319         pa_threaded_mainloop_wait(mMainLoop);
320     }
321 
322     pa_operation_unref(operation);
323     pa_threaded_mainloop_unlock(mMainLoop);
324 
325     return (userData->mute) ? true : false;
326 }
327 
IsStreamActive(AudioStreamType streamType)328 bool PulseAudioServiceAdapterImpl::IsStreamActive(AudioStreamType streamType)
329 {
330     lock_guard<mutex> lock(mMutex);
331 
332     unique_ptr<UserData> userData = make_unique<UserData>();
333     userData->thiz = this;
334     userData->streamType = streamType;
335     userData->isCorked = true;
336 
337     if (mContext == nullptr) {
338         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] IsStreamActive mContext is nullptr");
339         return false;
340     }
341 
342     pa_threaded_mainloop_lock(mMainLoop);
343 
344     pa_operation *operation = pa_context_get_sink_input_info_list(mContext,
345         PulseAudioServiceAdapterImpl::PaGetSinkInputInfoCorkStatusCb, reinterpret_cast<void*>(userData.get()));
346     if (operation == nullptr) {
347         MEDIA_ERR_LOG("[IsStreamActive] pa_context_get_sink_input_info_list returned nullptr");
348         pa_threaded_mainloop_unlock(mMainLoop);
349         return false;
350     }
351 
352     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
353         pa_threaded_mainloop_wait(mMainLoop);
354     }
355 
356     pa_operation_unref(operation);
357     pa_threaded_mainloop_unlock(mMainLoop);
358 
359     MEDIA_INFO_LOG("[IsStreamActive] cork for stream %s : %d",
360         GetNameByStreamType(streamType).c_str(), userData->isCorked);
361 
362     return (userData->isCorked) ? false : true;
363 }
364 
Disconnect()365 void PulseAudioServiceAdapterImpl::Disconnect()
366 {
367     if (mContext != nullptr) {
368         pa_context_disconnect(mContext);
369         /* Make sure we don't get any further callbacks */
370         pa_context_set_state_callback(mContext, nullptr, nullptr);
371         pa_context_set_subscribe_callback(mContext, nullptr, nullptr);
372         pa_context_unref(mContext);
373     }
374 
375     if (mMainLoop != nullptr) {
376         pa_threaded_mainloop_stop(mMainLoop);
377         pa_threaded_mainloop_free(mMainLoop);
378     }
379 }
380 
GetNameByStreamType(AudioStreamType streamType)381 string PulseAudioServiceAdapterImpl::GetNameByStreamType(AudioStreamType streamType)
382 {
383     switch (streamType) {
384         case STREAM_MUSIC:
385             return "music";
386         case STREAM_RING:
387             return "ring";
388         case STREAM_SYSTEM:
389             return "system";
390         case STREAM_NOTIFICATION:
391             return "notification";
392         case STREAM_ALARM:
393             return "alarm";
394         case STREAM_DTMF:
395             return "dtmf";
396         case STREAM_VOICE_CALL:
397             return "voice_call";
398         case STREAM_VOICE_ASSISTANT:
399             return "voice_assistant";
400         default:
401             return "";
402     }
403 }
404 
GetIdByStreamType(string streamType)405 AudioStreamType PulseAudioServiceAdapterImpl::GetIdByStreamType(string streamType)
406 {
407     AudioStreamType stream;
408 
409     if (!streamType.compare(string("music"))) {
410         stream = STREAM_MUSIC;
411     } else if (!streamType.compare(string("ring"))) {
412         stream = STREAM_RING;
413     } else if (!streamType.compare(string("system"))) {
414         stream = STREAM_SYSTEM;
415     } else if (!streamType.compare(string("notification"))) {
416         stream = STREAM_NOTIFICATION;
417     } else if (!streamType.compare(string("alarm"))) {
418         stream = STREAM_ALARM;
419     } else if (!streamType.compare(string("voice_call"))) {
420         stream = STREAM_VOICE_CALL;
421     }  else if (!streamType.compare(string("voice_assistant"))) {
422         stream = STREAM_VOICE_ASSISTANT;
423     } else {
424         stream = STREAM_MUSIC;
425     }
426 
427     return stream;
428 }
429 
PaGetSinkInputInfoMuteStatusCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)430 void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoMuteStatusCb(pa_context *c, const pa_sink_input_info *i, int eol,
431     void *userdata)
432 {
433     UserData *userData = reinterpret_cast<UserData*>(userdata);
434     PulseAudioServiceAdapterImpl *thiz = userData->thiz;
435 
436     if (eol < 0) {
437         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Failed to get sink input information: %{public}s",
438             pa_strerror(pa_context_errno(c)));
439         return;
440     }
441 
442     if (eol) {
443         pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
444         return;
445     }
446 
447     if (i->proplist == nullptr) {
448         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid Proplist for sink input (%{public}d).", i->index);
449         return;
450     }
451 
452     const char *streamtype = pa_proplist_gets(i->proplist, "stream.type");
453     if (streamtype == nullptr) {
454         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid StreamType.");
455         return;
456     }
457 
458     string streamType(streamtype);
459     if (!streamType.compare(thiz->GetNameByStreamType(userData->streamType))) {
460         userData->mute = i->mute;
461         MEDIA_INFO_LOG("[PulseAudioServiceAdapterImpl] Mute : %{public}d for stream : %{public}s",
462             userData->mute, i->name);
463     }
464 
465     return;
466 }
467 
PaGetSinkInputInfoMuteCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)468 void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoMuteCb(pa_context *c, const pa_sink_input_info *i,
469     int eol, void *userdata)
470 {
471     UserData *userData = reinterpret_cast<UserData*>(userdata);
472     PulseAudioServiceAdapterImpl *thiz = userData->thiz;
473 
474     if (eol < 0) {
475         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Failed to get sink input information: %{public}s",
476             pa_strerror(pa_context_errno(c)));
477         return;
478     }
479 
480     if (eol) {
481         pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
482         return;
483     }
484 
485     if (i->proplist == nullptr) {
486         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid Proplist for sink input (%{public}d).", i->index);
487         return;
488     }
489 
490     const char *streamtype = pa_proplist_gets(i->proplist, "stream.type");
491     if (streamtype == nullptr) {
492         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid StreamType.");
493         return;
494     }
495 
496     string streamType(streamtype);
497     if (!streamType.compare(thiz->GetNameByStreamType(userData->streamType))) {
498         pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, (userData->mute) ? 1 : 0, nullptr, nullptr));
499         MEDIA_INFO_LOG("[PulseAudioServiceAdapterImpl] Applied Mute : %{public}d for stream : %{public}s",
500             userData->mute, i->name);
501     }
502 
503     return;
504 }
505 
PaContextStateCb(pa_context * c,void * userdata)506 void PulseAudioServiceAdapterImpl::PaContextStateCb(pa_context *c, void *userdata)
507 {
508     PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
509 
510     switch (pa_context_get_state(c)) {
511         case PA_CONTEXT_UNCONNECTED:
512         case PA_CONTEXT_CONNECTING:
513         case PA_CONTEXT_AUTHORIZING:
514         case PA_CONTEXT_SETTING_NAME:
515             break;
516 
517         case PA_CONTEXT_READY: {
518             pa_context_set_subscribe_callback(c, PulseAudioServiceAdapterImpl::PaSubscribeCb, thiz);
519 
520             pa_operation *operation = pa_context_subscribe(c, (pa_subscription_mask_t)
521                 (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE |
522                 PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT |
523                 PA_SUBSCRIPTION_MASK_CARD), nullptr, nullptr);
524             if (operation == nullptr) {
525                 pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
526                 return;
527             }
528             pa_operation_unref(operation);
529             pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
530             break;
531         }
532 
533         case PA_CONTEXT_FAILED:
534             pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
535             return;
536 
537         case PA_CONTEXT_TERMINATED:
538         default:
539             return;
540     }
541 }
542 
PaModuleLoadCb(pa_context * c,uint32_t idx,void * userdata)543 void PulseAudioServiceAdapterImpl::PaModuleLoadCb(pa_context *c, uint32_t idx, void *userdata)
544 {
545     UserData *userData = reinterpret_cast<UserData*>(userdata);
546     if (idx == PA_INVALID_INDEX) {
547         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Failure: %{public}s", pa_strerror(pa_context_errno(c)));
548         userData->idx = PA_INVALID_INDEX;
549     } else {
550         userData->idx = idx;
551     }
552     pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0);
553 
554     return;
555 }
556 
PaGetSinkInputInfoVolumeCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)557 void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol,
558     void *userdata)
559 {
560     UserData *userData = reinterpret_cast<UserData*>(userdata);
561     PulseAudioServiceAdapterImpl *thiz = userData->thiz;
562 
563     MEDIA_INFO_LOG("[PulseAudioServiceAdapterImpl] GetSinkInputInfoVolumeCb");
564     if (eol < 0) {
565         delete userData;
566         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Failed to get sink input information: %{public}s",
567             pa_strerror(pa_context_errno(c)));
568         return;
569     }
570 
571     if (eol) {
572         pa_threaded_mainloop_signal(thiz->mMainLoop, 1);
573         delete userData;
574         return;
575     }
576 
577     if (i->proplist == nullptr) {
578         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid Proplist for sink input (%{public}d).", i->index);
579         return;
580     }
581 
582     const char *streamtype = pa_proplist_gets(i->proplist, "stream.type");
583     const char *streamVolume = pa_proplist_gets(i->proplist, "stream.volumeFactor");
584     const char *sessionCStr = pa_proplist_gets(i->proplist, "stream.sessionID");
585     if ((streamtype == nullptr) || (streamVolume == nullptr) || (sessionCStr == nullptr)) {
586         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid StreamType or streamVolume or SessionID");
587         return;
588     }
589 
590     std::stringstream sessionStr;
591     uint32_t sessionID;
592     sessionStr << sessionCStr;
593     sessionStr >> sessionID;
594     MEDIA_INFO_LOG("PulseAudioServiceAdapterImpl: PaGetSinkInputInfoVolumeCb sessionID %{public}u", sessionID);
595 
596     sinkIndexSessionIDMap[i->index] = sessionID;
597 
598     string streamType(streamtype);
599     float volumeFactor = atof(streamVolume);
600     AudioStreamType streamID = thiz->GetIdByStreamType(streamType);
601     float volumeCb = g_audioServiceAdapterCallback->OnGetVolumeCb(streamtype);
602     float vol = volumeCb * volumeFactor;
603 
604     pa_cvolume cv = i->volume;
605     uint32_t volume = pa_sw_volume_from_linear(vol);
606     pa_cvolume_set(&cv, i->channel_map.channels, volume);
607     pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, nullptr, nullptr));
608 
609     if (streamID == userData->streamType) {
610         if (i->mute) {
611             pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, 0, nullptr, nullptr));
612         }
613     }
614     MEDIA_INFO_LOG("[PulseAudioServiceAdapterImpl]volume : %{public}f for stream : %{public}s, volumeInt%{public}d",
615         vol, i->name, volume);
616 }
617 
PaGetSinkInputInfoCorkStatusCb(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)618 void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoCorkStatusCb(pa_context *c, const pa_sink_input_info *i, int eol,
619     void *userdata)
620 {
621     UserData *userData = reinterpret_cast<UserData*>(userdata);
622     PulseAudioServiceAdapterImpl *thiz = userData->thiz;
623 
624     if (eol < 0) {
625         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Failed to get sink input information: %{public}s",
626             pa_strerror(pa_context_errno(c)));
627         return;
628     }
629 
630     if (eol) {
631         pa_threaded_mainloop_signal(thiz->mMainLoop, 0);
632         return;
633     }
634 
635     if (i->proplist == nullptr) {
636         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid Proplist for sink input (%{public}d).", i->index);
637         return;
638     }
639 
640     const char *streamtype = pa_proplist_gets(i->proplist, "stream.type");
641     if (streamtype == nullptr) {
642         MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] Invalid StreamType.");
643         return;
644     }
645 
646     string streamType(streamtype);
647     if (!streamType.compare(thiz->GetNameByStreamType(userData->streamType))) {
648         userData->isCorked = i->corked;
649         MEDIA_INFO_LOG("[PulseAudioServiceAdapterImpl] corked : %{public}d for stream : %{public}s",
650             userData->isCorked, i->name);
651     }
652 }
653 
PaSubscribeCb(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)654 void PulseAudioServiceAdapterImpl::PaSubscribeCb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx,
655     void *userdata)
656 {
657     unique_ptr<UserData> userData = make_unique<UserData>();
658     PulseAudioServiceAdapterImpl *thiz = reinterpret_cast<PulseAudioServiceAdapterImpl*>(userdata);
659     userData->thiz = thiz;
660     switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
661         case PA_SUBSCRIPTION_EVENT_SINK:
662             break;
663 
664         case PA_SUBSCRIPTION_EVENT_SOURCE:
665             break;
666 
667         case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
668             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
669                 pa_threaded_mainloop_lock(thiz->mMainLoop);
670                 pa_operation *operation = pa_context_get_sink_input_info(c, idx,
671                     PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb, reinterpret_cast<void*>(userData.get()));
672                 if (operation == nullptr) {
673                     MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] pa_context_get_sink_input_info_list nullptr");
674                     pa_threaded_mainloop_unlock(thiz->mMainLoop);
675                     return;
676                 }
677                 userData.release();
678                 pa_threaded_mainloop_accept(thiz->mMainLoop);
679                 pa_operation_unref(operation);
680                 pa_threaded_mainloop_unlock(thiz->mMainLoop);
681             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
682                 uint32_t sessionID = sinkIndexSessionIDMap[idx];
683                 MEDIA_ERR_LOG("[PulseAudioServiceAdapterImpl] sessionID: %{public}d  removed", sessionID);
684                 g_audioServiceAdapterCallback->OnSessionRemoved(sessionID);
685             }
686             break;
687 
688         case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
689             break;
690 
691         default:
692             break;
693     }
694 }
695 } // namespace AudioStandard
696 } // namespace OHOS
697 
698 #endif // ST_PULSEAUDIO_AUDIO_SERVICE_ADAPTER_IMPL_H
699