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