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 #include "audio_service_dump.h"
17
18 using namespace std;
19
20 namespace OHOS {
21 namespace AudioStandard {
AudioServiceDump()22 AudioServiceDump::AudioServiceDump() : mainLoop(nullptr),
23 api(nullptr),
24 context(nullptr),
25 isMainLoopStarted(false),
26 isContextConnected(false)
27 {
28 MEDIA_DEBUG_LOG("AudioServiceDump ctor");
29 }
30
~AudioServiceDump()31 AudioServiceDump::~AudioServiceDump()
32 {
33 ResetPAAudioDump();
34 }
35
ResetPAAudioDump()36 void AudioServiceDump::ResetPAAudioDump()
37 {
38 lock_guard<mutex> lock(ctrlMutex);
39 if (mainLoop && (isMainLoopStarted == true)) {
40 pa_threaded_mainloop_stop(mainLoop);
41 }
42
43 if (context) {
44 pa_context_set_state_callback(context, nullptr, nullptr);
45 if (isContextConnected == true) {
46 pa_context_disconnect(context);
47 }
48 pa_context_unref(context);
49 }
50
51 if (mainLoop) {
52 pa_threaded_mainloop_free(mainLoop);
53 }
54
55 isMainLoopStarted = false;
56 isContextConnected = false;
57 mainLoop = nullptr;
58 context = nullptr;
59 api = nullptr;
60 }
61
Initialize()62 int32_t AudioServiceDump::Initialize()
63 {
64 int error = PA_ERR_INTERNAL;
65 mainLoop = pa_threaded_mainloop_new();
66 if (mainLoop == nullptr) {
67 return AUDIO_DUMP_INIT_ERR;
68 }
69
70 api = pa_threaded_mainloop_get_api(mainLoop);
71 if (api == nullptr) {
72 ResetPAAudioDump();
73 return AUDIO_DUMP_INIT_ERR;
74 }
75
76 context = pa_context_new(api, "AudioServiceDump");
77 if (context == nullptr) {
78 ResetPAAudioDump();
79 return AUDIO_DUMP_INIT_ERR;
80 }
81
82 pa_context_set_state_callback(context, PAContextStateCb, mainLoop);
83
84 if (pa_context_connect(context, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) {
85 error = pa_context_errno(context);
86 MEDIA_ERR_LOG("context connect error: %{public}s", pa_strerror(error));
87 ResetPAAudioDump();
88 return AUDIO_DUMP_INIT_ERR;
89 }
90
91 isContextConnected = true;
92 pa_threaded_mainloop_lock(mainLoop);
93
94 if (pa_threaded_mainloop_start(mainLoop) < 0) {
95 MEDIA_ERR_LOG("Audio Service not started");
96 pa_threaded_mainloop_unlock(mainLoop);
97 ResetPAAudioDump();
98 return AUDIO_DUMP_INIT_ERR;
99 }
100
101 isMainLoopStarted = true;
102 while (true) {
103 pa_context_state_t state = pa_context_get_state(context);
104 if (state == PA_CONTEXT_READY) {
105 break;
106 }
107
108 if (!PA_CONTEXT_IS_GOOD(state)) {
109 error = pa_context_errno(context);
110 MEDIA_ERR_LOG("context bad state error: %{public}s", pa_strerror(error));
111 pa_threaded_mainloop_unlock(mainLoop);
112 ResetPAAudioDump();
113 return AUDIO_DUMP_INIT_ERR;
114 }
115
116 pa_threaded_mainloop_wait(mainLoop);
117 }
118
119 pa_threaded_mainloop_unlock(mainLoop);
120 return AUDIO_DUMP_SUCCESS;
121 }
122
OnTimeOut()123 void AudioServiceDump::OnTimeOut()
124 {
125 pa_threaded_mainloop_lock(mainLoop);
126 pa_threaded_mainloop_signal(mainLoop, 0);
127 pa_threaded_mainloop_unlock(mainLoop);
128 }
129
IsEndWith(const std::string & mainStr,const std::string & toMatch)130 bool AudioServiceDump::IsEndWith(const std::string &mainStr, const std::string &toMatch)
131 {
132 if (mainStr.size() >= toMatch.size() &&
133 mainStr.compare(mainStr.size() - toMatch.size(), toMatch.size(), toMatch) == 0) {
134 return true;
135 }
136 return false;
137 }
138
IsValidModule(const std::string moduleName)139 bool AudioServiceDump::IsValidModule(const std::string moduleName)
140 {
141 if (moduleName.rfind("fifo", 0) == SUCCESS) {
142 return false; // Module starts with fifo, Not valid module
143 }
144
145 if (IsEndWith(moduleName, "monitor")) {
146 return false; // Module ends with monitor, Not valid module
147 }
148 return true;
149 }
150
IsStreamSupported(AudioStreamType streamType)151 bool AudioServiceDump::IsStreamSupported(AudioStreamType streamType)
152 {
153 switch (streamType) {
154 case STREAM_MUSIC:
155 case STREAM_RING:
156 case STREAM_VOICE_CALL:
157 case STREAM_VOICE_ASSISTANT:
158 return true;
159 default:
160 return false;
161 }
162 }
163
GetStreamName(AudioStreamType audioType)164 const std::string AudioServiceDump::GetStreamName(AudioStreamType audioType)
165 {
166 string name;
167 switch (audioType) {
168 case STREAM_VOICE_ASSISTANT:
169 name = "VOICE_ASSISTANT";
170 break;
171 case STREAM_VOICE_CALL:
172 name = "VOICE_CALL";
173 break;
174 case STREAM_SYSTEM:
175 name = "SYSTEM";
176 break;
177 case STREAM_RING:
178 name = "RING";
179 break;
180 case STREAM_MUSIC:
181 name = "MUSIC";
182 break;
183 case STREAM_ALARM:
184 name = "ALARM";
185 break;
186 case STREAM_NOTIFICATION:
187 name = "NOTIFICATION";
188 break;
189 case STREAM_BLUETOOTH_SCO:
190 name = "BLUETOOTH_SCO";
191 break;
192 case STREAM_DTMF:
193 name = "DTMF";
194 break;
195 case STREAM_TTS:
196 name = "TTS";
197 break;
198 default:
199 name = "UNKNOWN";
200 }
201
202 const string streamName = name;
203 return streamName;
204 }
205
GetStreamUsgaeName(StreamUsage streamUsage)206 const std::string AudioServiceDump::GetStreamUsgaeName(StreamUsage streamUsage)
207 {
208 string usage;
209 switch (streamUsage) {
210 case STREAM_USAGE_MEDIA:
211 usage = "MEDIA";
212 break;
213 case STREAM_USAGE_VOICE_COMMUNICATION:
214 usage = "VOICE_COMMUNICATION";
215 break;
216 case STREAM_USAGE_NOTIFICATION_RINGTONE:
217 usage = "NOTIFICATION_RINGTONE";
218 break;
219 case STREAM_USAGE_VOICE_ASSISTANT:
220 usage = "VOICE_ASSISTANT";
221 break;
222 default:
223 usage = "STREAM_USAGE_UNKNOWN";
224 }
225
226 const string streamUsageName = usage;
227 return streamUsageName;
228 }
229
GetContentTypeName(ContentType contentType)230 const std::string AudioServiceDump::GetContentTypeName(ContentType contentType)
231 {
232 string content;
233 switch (contentType) {
234 case CONTENT_TYPE_SPEECH:
235 content = "SPEECH";
236 break;
237 case CONTENT_TYPE_MUSIC:
238 content = "MUSIC";
239 break;
240 case CONTENT_TYPE_MOVIE:
241 content = "MOVIE";
242 break;
243 case CONTENT_TYPE_SONIFICATION:
244 content = "SONIFICATION";
245 break;
246 case CONTENT_TYPE_RINGTONE:
247 content = "RINGTONE";
248 break;
249 default:
250 content = "UNKNOWN";
251 }
252
253 const string contentTypeName = content;
254 return contentTypeName;
255 }
256
GetDeviceTypeName(DeviceType deviceType)257 const std::string AudioServiceDump::GetDeviceTypeName(DeviceType deviceType)
258 {
259 string device;
260 switch (deviceType) {
261 case DEVICE_TYPE_SPEAKER:
262 device = "SPEAKER";
263 break;
264 case DEVICE_TYPE_WIRED_HEADSET:
265 device = "WIRED_HEADSET";
266 break;
267 case DEVICE_TYPE_WIRED_HEADPHONES:
268 device = "WIRED_HEADPHONES";
269 break;
270 case DEVICE_TYPE_BLUETOOTH_SCO:
271 device = "BLUETOOTH_SCO";
272 break;
273 case DEVICE_TYPE_BLUETOOTH_A2DP:
274 device = "BLUETOOTH_A2DP";
275 break;
276 case DEVICE_TYPE_MIC:
277 device = "MIC";
278 break;
279 case DEVICE_TYPE_NONE:
280 device = "NONE";
281 break;
282 case DEVICE_TYPE_INVALID:
283 device = "INVALID";
284 break;
285 default:
286 device = "UNKNOWN";
287 }
288
289 const string deviceTypeName = device;
290 return deviceTypeName;
291 }
292
PlaybackStreamDump(std::string & dumpString)293 void AudioServiceDump::PlaybackStreamDump(std::string &dumpString)
294 {
295 char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
296
297 dumpString += "Audio Data Dump:\n\n";
298 dumpString += "Playback Streams\n";
299
300 AppendFormat(dumpString, "%d Playback stream (s) available:\n\n", audioData_.streamData.sinkInputs.size());
301
302 for (auto it = audioData_.streamData.sinkInputs.begin(); it != audioData_.streamData.sinkInputs.end(); it++) {
303 InputOutputInfo sinkInputInfo = *it;
304
305 AppendFormat(dumpString, "Stream Id: %s\n", (sinkInputInfo.sessionId).c_str());
306 AppendFormat(dumpString, "Application Name: %s\n", ((sinkInputInfo.applicationName).c_str()));
307 AppendFormat(dumpString, "Process Id: %s\n", (sinkInputInfo.processId).c_str());
308 AppendFormat(dumpString, "User Id: %d\n", sinkInputInfo.userId);
309
310 char *inputSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sinkInputInfo.sampleSpec));
311 AppendFormat(dumpString, "Stream Configuration: %s\n", inputSampleSpec);
312 dumpString += "Status:";
313 dumpString += (sinkInputInfo.corked) ? "STOPPED/PAUSED" : "RUNNING";
314 AppendFormat(dumpString, "\nStream Start Time: %s\n", (sinkInputInfo.sessionStartTime).c_str());
315 dumpString += "\n";
316 }
317 }
318
RecordStreamDump(std::string & dumpString)319 void AudioServiceDump::RecordStreamDump(std::string &dumpString)
320 {
321 char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
322 dumpString += "Record Streams \n";
323 AppendFormat(dumpString, "%d Record stream (s) available:\n\n", audioData_.streamData.sourceOutputs.size());
324
325 for (auto it = audioData_.streamData.sourceOutputs.begin(); it != audioData_.streamData.sourceOutputs.end(); it++) {
326 InputOutputInfo sourceOutputInfo = *it;
327 AppendFormat(dumpString, "Stream Id: %s\n", (sourceOutputInfo.sessionId).c_str());
328 AppendFormat(dumpString, "Application Name: %s\n", (sourceOutputInfo.applicationName).c_str());
329 AppendFormat(dumpString, "Process Id: %s\n", sourceOutputInfo.processId.c_str());
330 AppendFormat(dumpString, "User Id: %d\n", sourceOutputInfo.userId);
331
332 char *outputSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sourceOutputInfo.sampleSpec));
333 AppendFormat(dumpString, "Stream Configuration: %s\n", outputSampleSpec);
334 dumpString += "Status:";
335 dumpString += (sourceOutputInfo.corked) ? "STOPPED/PAUSED" : "RUNNING";
336 AppendFormat(dumpString, "\nStream Start Time: %s\n", (sourceOutputInfo.sessionStartTime).c_str());
337 dumpString += "\n";
338 }
339 }
340
HDFModulesDump(std::string & dumpString)341 void AudioServiceDump::HDFModulesDump(std::string &dumpString)
342 {
343 char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
344
345 dumpString += "\nHDF Input Modules\n";
346 AppendFormat(dumpString, "%d HDF Input Modules (s) available:\n\n", audioData_.streamData.sourceDevices.size());
347
348 for (auto it = audioData_.streamData.sourceDevices.begin(); it != audioData_.streamData.sourceDevices.end(); it++) {
349 SinkSourceInfo sourceInfo = *it;
350
351 AppendFormat(dumpString, "Module Name: %s\n", (sourceInfo.name).c_str());
352 char *hdfOutSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sourceInfo.sampleSpec));
353 AppendFormat(dumpString, "Module Configuration: %s\n\n", hdfOutSampleSpec);
354 }
355
356 dumpString += "HDF Output Modules\n";
357 AppendFormat(dumpString, "%d HDF Output Modules (s) available:\n\n", audioData_.streamData.sinkDevices.size());
358
359 for (auto it = audioData_.streamData.sinkDevices.begin(); it != audioData_.streamData.sinkDevices.end(); it++) {
360 SinkSourceInfo sinkInfo = *it;
361 AppendFormat(dumpString, "Module Name: %s\n", (sinkInfo.name).c_str());
362 char *hdfInSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sinkInfo.sampleSpec));
363 AppendFormat(dumpString, "Module Configuration: %s\n\n", hdfInSampleSpec);
364 }
365 }
366
CallStatusDump(std::string & dumpString)367 void AudioServiceDump::CallStatusDump(std::string &dumpString)
368 {
369 dumpString += "\nAudio Scene:";
370 switch (audioData_.policyData.callStatus) {
371 case AUDIO_SCENE_DEFAULT:
372 dumpString += "DEFAULT";
373 break;
374 case AUDIO_SCENE_RINGING:
375 dumpString += "RINGING";
376 break;
377 case AUDIO_SCENE_PHONE_CALL:
378 dumpString += "PHONE_CALL";
379 break;
380 case AUDIO_SCENE_PHONE_CHAT:
381 dumpString += "PHONE_CHAT";
382 break;
383 default:
384 dumpString += "UNKNOWN";
385 }
386 dumpString += "\n";
387 }
388
RingerModeDump(std::string & dumpString)389 void AudioServiceDump::RingerModeDump(std::string &dumpString)
390 {
391 dumpString += "Ringer Mode:";
392 switch (audioData_.policyData.ringerMode) {
393 case RINGER_MODE_NORMAL:
394 dumpString += "NORMAL";
395 break;
396 case RINGER_MODE_SILENT:
397 dumpString += "SILENT";
398 break;
399 case RINGER_MODE_VIBRATE:
400 dumpString += "VIBRATE";
401 break;
402 default:
403 dumpString += "UNKNOWN";
404 }
405 dumpString += "\n";
406 }
407
StreamVolumesDump(string & dumpString)408 void AudioServiceDump::StreamVolumesDump (string &dumpString)
409 {
410 dumpString += "\nStream: Volumes\n";
411 for (auto it = audioData_.policyData.streamVolumes.cbegin(); it != audioData_.policyData.streamVolumes.cend();
412 ++it) {
413 AppendFormat(dumpString, "%s: %d\n", GetStreamName(it->first).c_str(), it->second);
414 }
415 }
416
AudioFocusInfoDump(string & dumpString)417 void AudioServiceDump::AudioFocusInfoDump(string &dumpString)
418 {
419 dumpString += "\nAudio In Focus Info:\n";
420 uint32_t invalidSessionID = static_cast<uint32_t>(-1);
421
422 if (audioData_.policyData.audioFocusInfo.sessionID == invalidSessionID) {
423 MEDIA_DEBUG_LOG("No streams in focus");
424 dumpString += "Not available\n";
425 return;
426 }
427
428 AppendFormat(dumpString, "Stream Id: %d\n", audioData_.policyData.audioFocusInfo.sessionID);
429 AppendFormat(dumpString, "Stream Usage: %s\n",
430 GetStreamUsgaeName(audioData_.policyData.audioFocusInfo.streamUsage).c_str());
431 AppendFormat(dumpString, "Content Type: %s\n",
432 GetContentTypeName(audioData_.policyData.audioFocusInfo.contentType).c_str());
433 AppendFormat(dumpString, "Stream Name: %s\n",
434 GetStreamName(audioData_.policyData.audioFocusInfo.streamType).c_str());
435
436 return;
437 }
438
DevicesInfoDump(string & dumpString)439 void AudioServiceDump::DevicesInfoDump(string &dumpString)
440 {
441 dumpString += "\nInput Devices:\n";
442 AppendFormat(dumpString, "%d Input Devices (s) available :\n\n", audioData_.policyData.inputDevices.size());
443
444 for (auto it = audioData_.policyData.inputDevices.begin(); it != audioData_.policyData.inputDevices.end(); it++) {
445 DevicesInfo devicesInfo = *it;
446 AppendFormat(dumpString, "%s\n", GetDeviceTypeName(devicesInfo.deviceType).c_str());
447 }
448
449 dumpString += "\nOutput Devices:\n";
450 AppendFormat(dumpString, "%d Output Devices (s) available :\n\n", audioData_.policyData.outputDevices.size());
451
452 for (auto it = audioData_.policyData.outputDevices.begin(); it != audioData_.policyData.outputDevices.end(); it++) {
453 DevicesInfo devicesInfo = *it;
454 AppendFormat(dumpString, "%s\n", GetDeviceTypeName(devicesInfo.deviceType).c_str());
455 }
456 }
457
DataDump(string & dumpString)458 void AudioServiceDump::DataDump(string &dumpString)
459 {
460 PlaybackStreamDump(dumpString);
461 RecordStreamDump(dumpString);
462 HDFModulesDump(dumpString);
463 DevicesInfoDump(dumpString);
464 CallStatusDump(dumpString);
465 RingerModeDump(dumpString);
466 StreamVolumesDump(dumpString);
467 AudioFocusInfoDump(dumpString);
468 }
469
AudioDataDump(PolicyData & policyData,string & dumpString)470 void AudioServiceDump::AudioDataDump(PolicyData &policyData, string &dumpString)
471 {
472 if (mainLoop == nullptr || context == nullptr) {
473 MEDIA_ERR_LOG("Audio Service Not running");
474 return;
475 }
476
477 pa_threaded_mainloop_lock(mainLoop);
478 pa_operation *operation = nullptr;
479 operation = pa_context_get_sink_info_list(context, AudioServiceDump::PASinkInfoCallback, (void *)(this));
480
481 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
482 pa_threaded_mainloop_wait(mainLoop);
483 }
484
485 pa_operation_unref(operation);
486 operation = pa_context_get_sink_input_info_list(context, AudioServiceDump::PASinkInputInfoCallback, (void *)this);
487
488 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
489 pa_threaded_mainloop_wait(mainLoop);
490 }
491
492 pa_operation_unref(operation);
493 operation = pa_context_get_source_info_list(context, AudioServiceDump::PASourceInfoCallback, (void *)this);
494
495 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
496 pa_threaded_mainloop_wait(mainLoop);
497 }
498
499 pa_operation_unref(operation);
500 operation = pa_context_get_source_output_info_list(context,
501 AudioServiceDump::PASourceOutputInfoCallback, (void *)this);
502
503 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
504 pa_threaded_mainloop_wait(mainLoop);
505 }
506
507 pa_operation_unref(operation);
508 pa_threaded_mainloop_unlock(mainLoop);
509
510 audioData_.policyData = policyData;
511 DataDump(dumpString);
512
513 return;
514 }
515
PAContextStateCb(pa_context * context,void * userdata)516 void AudioServiceDump::PAContextStateCb(pa_context *context, void *userdata)
517 {
518 pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *)userdata;
519
520 switch (pa_context_get_state(context)) {
521 case PA_CONTEXT_READY:
522 case PA_CONTEXT_TERMINATED:
523 case PA_CONTEXT_FAILED:
524 pa_threaded_mainloop_signal(mainLoop, 0);
525 break;
526
527 case PA_CONTEXT_UNCONNECTED:
528 case PA_CONTEXT_CONNECTING:
529 case PA_CONTEXT_AUTHORIZING:
530 case PA_CONTEXT_SETTING_NAME:
531 default:
532 break;
533 }
534 return;
535 }
536
PASinkInfoCallback(pa_context * c,const pa_sink_info * i,int eol,void * userdata)537 void AudioServiceDump::PASinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
538 {
539 AudioServiceDump *asDump = (AudioServiceDump *)userdata;
540 if (asDump == nullptr) {
541 MEDIA_ERR_LOG("Failed to get sink information");
542 return;
543 }
544
545 pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *)asDump->mainLoop;
546
547 if (eol < 0) {
548 MEDIA_ERR_LOG("Failed to get sink information: %{public}s", pa_strerror(pa_context_errno(c)));
549 return;
550 }
551
552 if (eol) {
553 pa_threaded_mainloop_signal(mainLoop, 0);
554 return;
555 }
556
557 SinkSourceInfo sinkInfo;
558
559 if (i->name != nullptr) {
560 string sinkName(i->name);
561 if (IsValidModule(sinkName)) {
562 (sinkInfo.name).assign(sinkName);
563 sinkInfo.sampleSpec = i->sample_spec;
564 asDump->audioData_.streamData.sinkDevices.push_back(sinkInfo);
565 }
566 }
567 }
568
PASinkInputInfoCallback(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)569 void AudioServiceDump::PASinkInputInfoCallback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
570 {
571 AudioServiceDump *asDump = (AudioServiceDump *)userdata;
572 if (asDump == nullptr) {
573 MEDIA_ERR_LOG("Failed to get sink input information");
574 return;
575 }
576
577 pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *)asDump->mainLoop;
578
579 if (eol < 0) {
580 MEDIA_ERR_LOG("Failed to get sink input information: %{public}s", pa_strerror(pa_context_errno(c)));
581 return;
582 }
583
584 if (eol) {
585 pa_threaded_mainloop_signal(mainLoop, 0);
586 return;
587 }
588
589 InputOutputInfo sinkInputInfo;
590
591 sinkInputInfo.sampleSpec = i->sample_spec;
592 sinkInputInfo.corked = i->corked;
593
594 if (i->proplist !=nullptr) {
595 const char *applicationname = pa_proplist_gets(i->proplist, "application.name");
596 const char *processid = pa_proplist_gets(i->proplist, "application.process.id");
597 const char *user = pa_proplist_gets(i->proplist, "application.process.user");
598 const char *sessionid = pa_proplist_gets(i->proplist, "stream.sessionID");
599 const char *sessionstarttime = pa_proplist_gets(i->proplist, "stream.startTime");
600
601 if (applicationname != nullptr) {
602 string applicationName(applicationname);
603 (sinkInputInfo.applicationName).assign(applicationName);
604 }
605
606 if (processid != nullptr) {
607 string processId(processid);
608 (sinkInputInfo.processId).assign(processId);
609 }
610
611 if (user != nullptr) {
612 struct passwd *p;
613 if ((p = getpwnam(user)) != nullptr) {
614 sinkInputInfo.userId = uint32_t(p->pw_uid);
615 }
616 }
617
618 if (sessionid != nullptr) {
619 string sessionId(sessionid);
620 (sinkInputInfo.sessionId).assign(sessionId);
621 }
622
623 if (sessionstarttime != nullptr) {
624 string sessionStartTime(sessionstarttime);
625 (sinkInputInfo.sessionStartTime).assign(sessionStartTime);
626 }
627 }
628 asDump->audioData_.streamData.sinkInputs.push_back(sinkInputInfo);
629 }
630
PASourceInfoCallback(pa_context * c,const pa_source_info * i,int eol,void * userdata)631 void AudioServiceDump::PASourceInfoCallback(pa_context *c, const pa_source_info *i, int eol, void *userdata)
632 {
633 AudioServiceDump *asDump = (AudioServiceDump *)userdata;
634 if (asDump == nullptr) {
635 MEDIA_ERR_LOG("Failed to get source information");
636 return;
637 }
638
639 pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *)asDump->mainLoop;
640
641 if (eol < 0) {
642 MEDIA_ERR_LOG("Failed to get source information: %{public}s", pa_strerror(pa_context_errno(c)));
643 return;
644 }
645
646 if (eol) {
647 pa_threaded_mainloop_signal(mainLoop, 0);
648 return;
649 }
650
651 SinkSourceInfo sourceInfo;
652
653 if (i->name != nullptr) {
654 string sourceName(i->name);
655 if (IsValidModule(sourceName)) {
656 (sourceInfo.name).assign(sourceName);
657 sourceInfo.sampleSpec = i->sample_spec;
658 asDump->audioData_.streamData.sourceDevices.push_back(sourceInfo);
659 }
660 }
661 }
662
PASourceOutputInfoCallback(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)663 void AudioServiceDump::PASourceOutputInfoCallback(pa_context *c, const pa_source_output_info *i, int eol,
664 void *userdata)
665 {
666 AudioServiceDump *asDump = (AudioServiceDump *)userdata;
667 if (asDump == nullptr) {
668 MEDIA_ERR_LOG("Failed to get source output information");
669 return;
670 }
671
672 pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *)asDump->mainLoop;
673
674 if (eol < 0) {
675 MEDIA_ERR_LOG("Failed to get source output information: %{public}s", pa_strerror(pa_context_errno(c)));
676 return;
677 }
678
679 if (eol) {
680 pa_threaded_mainloop_signal(mainLoop, 0);
681 return;
682 }
683
684 InputOutputInfo sourceOutputInfo;
685 sourceOutputInfo.sampleSpec = i->sample_spec;
686 sourceOutputInfo.corked = i->corked;
687
688 if (i->proplist !=nullptr) {
689 const char *applicationname = pa_proplist_gets(i->proplist, "application.name");
690 const char *processid = pa_proplist_gets(i->proplist, "application.process.id");
691 const char *user = pa_proplist_gets(i->proplist, "application.process.user");
692 const char *sessionid = pa_proplist_gets(i->proplist, "stream.sessionID");
693 const char *sessionstarttime = pa_proplist_gets(i->proplist, "stream.startTime");
694
695 if (applicationname != nullptr) {
696 string applicationName(applicationname);
697 (sourceOutputInfo.applicationName).assign(applicationName);
698 }
699
700 if (processid != nullptr) {
701 string processId(processid);
702 (sourceOutputInfo.processId).assign(processId);
703 }
704
705 if (user != nullptr) {
706 struct passwd *p;
707 if ((p = getpwnam(user)) != nullptr) {
708 sourceOutputInfo.userId = uint32_t(p->pw_uid);
709 }
710 }
711
712 if (sessionid != nullptr) {
713 string sessionId(sessionid);
714 (sourceOutputInfo.sessionId).assign(sessionId);
715 }
716
717 if (sessionstarttime != nullptr) {
718 string sessionStartTime(sessionstarttime);
719 (sourceOutputInfo.sessionStartTime).assign(sessionStartTime);
720 }
721 }
722 asDump->audioData_.streamData.sourceOutputs.push_back(sourceOutputInfo);
723 }
724 } // namespace AudioStandard
725 } // namespace OHOS
726