2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <sound_manager.h>
18 #include <sound_manager_private.h>
22 #define PA_BUS_NAME "org.pulseaudio.Server"
23 #define PA_STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/StreamManager"
24 #define PA_STREAM_MANAGER_INTERFACE "org.pulseaudio.StreamManager"
25 #define PA_STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO "GetStreamInfo"
26 #define PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES "SetStreamRouteDevices"
27 #define PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION "SetStreamRouteOption"
28 #define PA_STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL "GetVolumeMaxLevel"
29 #define PA_STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL "GetVolumeLevel"
30 #define PA_STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL "SetVolumeLevel"
31 #define PA_STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE "GetCurrentVolumeType"
32 #define PA_STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH "GetCurrentMediaRoutingPath"
33 #define PA_STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS "UpdateFocusStatus"
34 #define VCONF_PATH_PREFIX_VOLUME "file/private/sound/volume/"
35 #define VCONF_PATH_MAX 64
37 extern _session_interrupt_info_s g_session_interrupt_cb_table;
38 extern _session_mode_e g_cached_session_mode;
39 extern int g_cached_voip_device_id;
40 extern _focus_watch_info_s focus_watch_info_arr[SOUND_STREAM_INFO_ARR_MAX];
41 sound_stream_info_s *sound_stream_info_arr[SOUND_STREAM_INFO_ARR_MAX];
42 sound_stream_info_s *g_voip_stream_info = NULL;
43 virtual_sound_stream_info_s *g_voip_vstream_h = NULL;
44 int g_stream_info_count = 0;
45 pthread_mutex_t g_stream_info_count_mutex = PTHREAD_MUTEX_INITIALIZER;
47 int _convert_sound_manager_error_code(const char *func, int code)
49 int ret = SOUND_MANAGER_ERROR_NONE;
50 char *errorstr = NULL;
53 case MM_ERROR_FILE_WRITE:
54 case MM_ERROR_INVALID_HANDLE:
55 case MM_ERROR_SOUND_INVALID_OPERATION:
56 ret = SOUND_MANAGER_ERROR_INVALID_OPERATION;
57 errorstr = "INVALID_OPERATION";
60 ret = SOUND_MANAGER_ERROR_NONE;
61 errorstr = "ERROR_NONE";
63 case MM_ERROR_INVALID_ARGUMENT:
64 case MM_ERROR_SOUND_INVALID_POINTER:
65 ret = SOUND_MANAGER_ERROR_INVALID_PARAMETER;
66 errorstr = "INVALID_PARAMETER";
68 case MM_ERROR_SOUND_PERMISSION_DENIED:
69 ret = SOUND_MANAGER_ERROR_PERMISSION_DENIED;
70 errorstr = "PERMISSION_DENIED";
72 case MM_ERROR_SOUND_NO_DATA:
73 ret = SOUND_MANAGER_ERROR_NO_DATA;
76 case MM_ERROR_SOUND_INTERNAL:
77 case MM_ERROR_SOUND_VOLUME_CAPTURE_ONLY:
78 case MM_ERROR_OUT_OF_MEMORY:
79 ret = SOUND_MANAGER_ERROR_INTERNAL;
80 errorstr = "INTERNAL";
82 case MM_ERROR_POLICY_DUPLICATED:
83 case MM_ERROR_POLICY_INTERNAL:
84 case MM_ERROR_POLICY_BLOCKED:
85 ret = SOUND_MANAGER_ERROR_POLICY;
88 case MM_ERROR_SOUND_VOLUME_NO_INSTANCE:
89 ret = SOUND_MANAGER_ERROR_NO_PLAYING_SOUND;
90 errorstr = "NO_PLAYING_SOUND";
92 case MM_ERROR_NOT_SUPPORT_API:
93 ret = SOUND_MANAGER_ERROR_NOT_SUPPORTED;
94 errorstr = "NOT_SUPPORTED";
96 case MM_ERROR_SOUND_INVALID_STATE:
97 ret = SOUND_MANAGER_ERROR_INVALID_STATE;
98 errorstr = "INVALID_STATE";
101 LOGW("it should not be reached here, this error(0x%x) should be defined.", code);
102 ret = SOUND_MANAGER_ERROR_INTERNAL;
103 errorstr = "INTERNAL";
107 LOGE("[%s] >> leave : %s(0x%08x), mm_error(0x%08x)", func, errorstr, ret, code);
109 LOGD("[%s] >> leave : %s(0x%08x)", func, errorstr, ret);
114 int _convert_stream_type(sound_stream_type_e stream_type_enum, char **stream_type)
116 int ret = MM_ERROR_NONE;
118 if (stream_type == NULL)
119 return MM_ERROR_INVALID_ARGUMENT;
121 switch (stream_type_enum) {
122 case SOUND_STREAM_TYPE_MEDIA:
123 *stream_type = "media";
125 case SOUND_STREAM_TYPE_SYSTEM:
126 *stream_type = "system";
128 case SOUND_STREAM_TYPE_ALARM:
129 *stream_type = "alarm";
131 case SOUND_STREAM_TYPE_NOTIFICATION:
132 *stream_type = "notification";
134 case SOUND_STREAM_TYPE_EMERGENCY:
135 *stream_type = "emergency";
137 case SOUND_STREAM_TYPE_VOICE_INFORMATION:
138 *stream_type = "voice-information";
140 case SOUND_STREAM_TYPE_VOICE_RECOGNITION:
141 *stream_type = "voice-recognition";
143 case SOUND_STREAM_TYPE_RINGTONE_VOIP:
144 *stream_type = "ringtone-voip";
146 case SOUND_STREAM_TYPE_VOIP:
147 *stream_type = "voip";
149 case SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY:
150 *stream_type = "ext-media";
153 LOGE("could not find the stream_type[%d] in this switch case statement", stream_type_enum);
154 ret = MM_ERROR_SOUND_INTERNAL;
157 LOGI("stream_type[%s]", *stream_type);
162 int _convert_stream_type_for_internal(sound_stream_type_internal_e stream_type_enum, char **stream_type)
164 int ret = MM_ERROR_NONE;
166 if (stream_type == NULL)
167 return MM_ERROR_INVALID_ARGUMENT;
169 switch (stream_type_enum) {
170 case SOUND_STREAM_TYPE_RINGTONE_CALL:
171 *stream_type = "ringtone-call";
173 case SOUND_STREAM_TYPE_RINGBACKTONE_CALL:
174 *stream_type = "ringbacktone-call";
176 case SOUND_STREAM_TYPE_VOICE_CALL:
177 *stream_type = "call-voice";
179 case SOUND_STREAM_TYPE_VIDEO_CALL:
180 *stream_type = "call-video";
182 case SOUND_STREAM_TYPE_RADIO:
183 *stream_type = "radio";
185 case SOUND_STREAM_TYPE_LOOPBACK:
186 *stream_type = "loopback";
188 case SOUND_STREAM_TYPE_LOOPBACK_MIRRORING:
189 *stream_type = "loopback-mirroring";
191 case SOUND_STREAM_TYPE_SOLO:
192 *stream_type = "solo";
195 LOGE("could not find the stream_type[%d] in this switch case statement", stream_type_enum);
196 ret = MM_ERROR_SOUND_INTERNAL;
199 LOGI("stream_type_for_internal[%s]", *stream_type);
204 void _set_focus_availability(sound_stream_info_s *stream_info)
206 if (stream_info == NULL || stream_info->stream_type == NULL) {
207 LOGE("invalid argument");
210 if (!strncmp(stream_info->stream_type, "solo", SOUND_STREAM_TYPE_LEN) ||
211 !strncmp(stream_info->stream_type, "radio", SOUND_STREAM_TYPE_LEN) ||
212 !strncmp(stream_info->stream_type, "loopback-mirroring", SOUND_STREAM_TYPE_LEN)) {
213 stream_info->is_focus_unavailable = true;
214 LOGI("this stream_type[%s] does not support focus", stream_info->stream_type);
220 int _convert_stream_type_to_change_reason(const char *stream_type, sound_stream_focus_change_reason_e *change_reason)
222 SM_NULL_ARG_CHECK_FOR_PRIV(stream_type);
223 SM_NULL_ARG_CHECK_FOR_PRIV(change_reason);
225 if (!strncmp(stream_type, "media", SOUND_STREAM_TYPE_LEN) ||
226 !strncmp(stream_type, "radio", SOUND_STREAM_TYPE_LEN) ||
227 !strncmp(stream_type, "loopback", SOUND_STREAM_TYPE_LEN)) {
228 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA;
230 } else if (!strncmp(stream_type, "system", SOUND_STREAM_TYPE_LEN)) {
231 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM;
233 } else if (!strncmp(stream_type, "alarm", SOUND_STREAM_TYPE_LEN)) {
234 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_ALARM;
236 } else if (!strncmp(stream_type, "notification", SOUND_STREAM_TYPE_LEN)) {
237 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION;
239 } else if (!strncmp(stream_type, "emergency", SOUND_STREAM_TYPE_LEN)) {
240 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY;
242 } else if (!strncmp(stream_type, "voice-information", SOUND_STREAM_TYPE_LEN)) {
243 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION;
245 } else if (!strncmp(stream_type, "voice-recognition", SOUND_STREAM_TYPE_LEN)) {
246 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION;
248 } else if (!strncmp(stream_type, "ringtone-voip", SOUND_STREAM_TYPE_LEN) ||
249 !strncmp(stream_type, "ringtone-call", SOUND_STREAM_TYPE_LEN) ||
250 !strncmp(stream_type, "ringbacktone-call", SOUND_STREAM_TYPE_LEN)) {
251 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE;
253 } else if (!strncmp(stream_type, "voip", SOUND_STREAM_TYPE_LEN)) {
254 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_VOIP;
256 } else if (!strncmp(stream_type, "call-voice", SOUND_STREAM_TYPE_LEN) ||
257 !strncmp(stream_type, "call-video", SOUND_STREAM_TYPE_LEN)) {
258 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_CALL;
260 } else if (!strncmp(stream_type, "ext-media", SOUND_STREAM_TYPE_LEN)) {
261 *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY;
264 LOGE("not supported stream_type(%s)", stream_type);
265 return MM_ERROR_INVALID_ARGUMENT;
268 return MM_ERROR_NONE;
271 static int _convert_stream_type_to_interrupt_reason(const char *stream_type, sound_session_interrupted_code_e *change_reason)
273 SM_NULL_ARG_CHECK_FOR_PRIV(stream_type);
274 SM_NULL_ARG_CHECK_FOR_PRIV(change_reason);
276 if (!strncmp(stream_type, "media", SOUND_STREAM_TYPE_LEN) ||
277 !strncmp(stream_type, "radio", SOUND_STREAM_TYPE_LEN) ||
278 !strncmp(stream_type, "system", SOUND_STREAM_TYPE_LEN) ||
279 !strncmp(stream_type, "voice-information", SOUND_STREAM_TYPE_LEN) ||
280 !strncmp(stream_type, "voice-recognition", SOUND_STREAM_TYPE_LEN) ||
281 !strncmp(stream_type, "loopback", SOUND_STREAM_TYPE_LEN) ||
282 !strncmp(stream_type, "ext-media", SOUND_STREAM_TYPE_LEN)) {
283 *change_reason = SOUND_SESSION_INTERRUPTED_BY_MEDIA;
285 } else if (!strncmp(stream_type, "alarm", SOUND_STREAM_TYPE_LEN)) {
286 *change_reason = SOUND_SESSION_INTERRUPTED_BY_ALARM;
288 } else if (!strncmp(stream_type, "notification", SOUND_STREAM_TYPE_LEN)) {
289 *change_reason = SOUND_SESSION_INTERRUPTED_BY_NOTIFICATION;
291 } else if (!strncmp(stream_type, "emergency", SOUND_STREAM_TYPE_LEN)) {
292 *change_reason = SOUND_SESSION_INTERRUPTED_BY_EMERGENCY;
294 } else if (!strncmp(stream_type, "ringtone-voip", SOUND_STREAM_TYPE_LEN) ||
295 !strncmp(stream_type, "ringtone-call", SOUND_STREAM_TYPE_LEN) ||
296 !strncmp(stream_type, "ringbacktone-call", SOUND_STREAM_TYPE_LEN) ||
297 !strncmp(stream_type, "voip", SOUND_STREAM_TYPE_LEN) ||
298 !strncmp(stream_type, "call-voice", SOUND_STREAM_TYPE_LEN) ||
299 !strncmp(stream_type, "call-video", SOUND_STREAM_TYPE_LEN)) {
300 *change_reason = SOUND_SESSION_INTERRUPTED_BY_CALL;
303 LOGE("not supported stream_type(%s)", stream_type);
304 return MM_ERROR_INVALID_ARGUMENT;
307 return MM_ERROR_NONE;
310 int _convert_sound_type(sound_type_e sound_type, const char **volume_type)
312 SM_NULL_ARG_CHECK_FOR_PRIV(volume_type);
314 switch (sound_type) {
315 case SOUND_TYPE_SYSTEM:
316 *volume_type = "system";
318 case SOUND_TYPE_NOTIFICATION:
319 *volume_type = "notification";
321 case SOUND_TYPE_ALARM:
322 *volume_type = "alarm";
324 case SOUND_TYPE_RINGTONE:
325 *volume_type = "ringtone";
327 case SOUND_TYPE_MEDIA:
328 *volume_type = "media";
330 case SOUND_TYPE_CALL:
331 *volume_type = "call";
333 case SOUND_TYPE_VOIP:
334 *volume_type = "voip";
336 case SOUND_TYPE_VOICE:
337 *volume_type = "voice";
340 LOGI("volume_type[%s]", *volume_type);
342 return MM_ERROR_NONE;
345 int _convert_sound_type_to_enum(const char *sound_type, sound_type_e *sound_type_enum)
347 SM_NULL_ARG_CHECK_FOR_PRIV(sound_type);
348 SM_NULL_ARG_CHECK_FOR_PRIV(sound_type_enum);
350 if (!strncmp(sound_type, "system", strlen(sound_type))) {
351 *sound_type_enum = SOUND_TYPE_SYSTEM;
352 } else if (!strncmp(sound_type, "notification", strlen(sound_type))) {
353 *sound_type_enum = SOUND_TYPE_NOTIFICATION;
354 } else if (!strncmp(sound_type, "alarm", strlen(sound_type))) {
355 *sound_type_enum = SOUND_TYPE_ALARM;
356 } else if (!strncmp(sound_type, "ringtone", strlen(sound_type))) {
357 *sound_type_enum = SOUND_TYPE_RINGTONE;
358 } else if (!strncmp(sound_type, "media", strlen(sound_type))) {
359 *sound_type_enum = SOUND_TYPE_MEDIA;
360 } else if (!strncmp(sound_type, "call", strlen(sound_type))) {
361 *sound_type_enum = SOUND_TYPE_CALL;
362 } else if (!strncmp(sound_type, "voip", strlen(sound_type))) {
363 *sound_type_enum = SOUND_TYPE_VOIP;
364 } else if (!strncmp(sound_type, "voice", strlen(sound_type))) {
365 *sound_type_enum = SOUND_TYPE_VOICE;
367 LOGE("not supported sound_type(%s)", sound_type);
368 return MM_ERROR_INVALID_ARGUMENT;
371 return MM_ERROR_NONE;
374 int _convert_device_type_enum_to_str(sound_device_type_e device_type, char **device_type_str)
376 SM_NULL_ARG_CHECK_FOR_PRIV(device_type_str);
378 switch (device_type) {
379 case SOUND_DEVICE_BUILTIN_SPEAKER:
380 *device_type_str = "builtin-speaker";
382 case SOUND_DEVICE_BUILTIN_RECEIVER:
383 *device_type_str = "builtin-receiver";
385 case SOUND_DEVICE_BUILTIN_MIC:
386 *device_type_str = "builtin-mic";
388 case SOUND_DEVICE_AUDIO_JACK:
389 *device_type_str = "audio-jack";
391 case SOUND_DEVICE_BLUETOOTH_MEDIA:
392 *device_type_str = "bt-a2dp";
394 case SOUND_DEVICE_BLUETOOTH_VOICE:
395 *device_type_str = "bt-sco";
397 case SOUND_DEVICE_HDMI:
398 *device_type_str = "hdmi";
400 case SOUND_DEVICE_USB_AUDIO:
401 *device_type_str = "usb-audio";
403 case SOUND_DEVICE_FORWARDING:
404 *device_type_str = "forwarding";
407 LOGE("could not find the device_type[%d] in this switch case statement", device_type);
408 return MM_ERROR_SOUND_INTERNAL;
411 LOGI("device_type[%s]", *device_type_str);
413 return MM_ERROR_NONE;
416 int _convert_device_type_str_to_enum(const char *device_type_str, sound_device_type_e *device_type)
418 SM_NULL_ARG_CHECK_FOR_PRIV(device_type_str);
419 SM_NULL_ARG_CHECK_FOR_PRIV(device_type);
421 if (!strncmp(device_type_str, "builtin-speaker", SOUND_DEVICE_TYPE_LEN)) {
422 *device_type = SOUND_DEVICE_BUILTIN_SPEAKER;
424 } else if (!strncmp(device_type_str, "builtin-receiver", SOUND_DEVICE_TYPE_LEN)) {
425 *device_type = SOUND_DEVICE_BUILTIN_RECEIVER;
427 } else if (!strncmp(device_type_str, "builtin-mic", SOUND_DEVICE_TYPE_LEN)) {
428 *device_type = SOUND_DEVICE_BUILTIN_MIC;
430 } else if (!strncmp(device_type_str, "audio-jack", SOUND_DEVICE_TYPE_LEN)) {
431 *device_type = SOUND_DEVICE_AUDIO_JACK;
433 } else if (!strncmp(device_type_str, "hdmi", SOUND_DEVICE_TYPE_LEN)) {
434 *device_type = SOUND_DEVICE_HDMI;
436 } else if (!strncmp(device_type_str, "usb-audio", SOUND_DEVICE_TYPE_LEN)) {
437 *device_type = SOUND_DEVICE_USB_AUDIO;
439 } else if (!strncmp(device_type_str, "bt-a2dp", SOUND_DEVICE_TYPE_LEN)) {
440 *device_type = SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION;
442 } else if (!strncmp(device_type_str, "bt-sco", SOUND_DEVICE_TYPE_LEN)) {
443 *device_type = SOUND_DEVICE_BLUETOOTH_VOICE;
446 LOGE("not supported device_type(%s)", device_type_str);
447 return MM_ERROR_INVALID_ARGUMENT;
450 return MM_ERROR_NONE;
453 int _convert_device_type(mm_sound_device_type_e device_type, sound_device_type_e *sound_device_type)
455 switch (device_type) {
456 case MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER:
457 *sound_device_type = SOUND_DEVICE_BUILTIN_SPEAKER;
459 case MM_SOUND_DEVICE_TYPE_BUILTIN_RECEIVER:
460 *sound_device_type = SOUND_DEVICE_BUILTIN_RECEIVER;
462 case MM_SOUND_DEVICE_TYPE_BUILTIN_MIC:
463 *sound_device_type = SOUND_DEVICE_BUILTIN_MIC;
465 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
466 *sound_device_type = SOUND_DEVICE_AUDIO_JACK;
468 case MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP:
469 *sound_device_type = SOUND_DEVICE_BLUETOOTH_MEDIA;
471 case MM_SOUND_DEVICE_TYPE_BLUETOOTH_SCO:
472 *sound_device_type = SOUND_DEVICE_BLUETOOTH_VOICE;
474 case MM_SOUND_DEVICE_TYPE_HDMI:
475 *sound_device_type = SOUND_DEVICE_HDMI;
477 case MM_SOUND_DEVICE_TYPE_USB_AUDIO:
478 *sound_device_type = SOUND_DEVICE_USB_AUDIO;
480 case MM_SOUND_DEVICE_TYPE_MIRRORING:
481 *sound_device_type = SOUND_DEVICE_FORWARDING;
485 return MM_ERROR_NONE;
488 int _convert_device_io_direction(mm_sound_device_io_direction_e io_direction, sound_device_io_direction_e *sound_io_direction)
490 SM_NULL_ARG_CHECK(sound_io_direction);
492 switch (io_direction) {
493 case MM_SOUND_DEVICE_IO_DIRECTION_IN:
494 *sound_io_direction = SOUND_DEVICE_IO_DIRECTION_IN;
496 case MM_SOUND_DEVICE_IO_DIRECTION_OUT:
497 *sound_io_direction = SOUND_DEVICE_IO_DIRECTION_OUT;
499 case MM_SOUND_DEVICE_IO_DIRECTION_BOTH:
500 *sound_io_direction = SOUND_DEVICE_IO_DIRECTION_BOTH;
504 return MM_ERROR_NONE;
507 const char* _convert_api_name(native_api_e api_name)
509 const char* name = NULL;
512 case NATIVE_API_SOUND_MANAGER:
513 name = "sound-manager";
515 case NATIVE_API_PLAYER:
518 case NATIVE_API_WAV_PLAYER:
521 case NATIVE_API_TONE_PLAYER:
522 name = "tone-player";
524 case NATIVE_API_AUDIO_IO:
527 case NATIVE_API_RECORDER:
535 void _focus_state_change_callback(int index, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason, int option, const char *extra_info, void *user_data)
537 int ret = MM_ERROR_NONE;
539 sound_stream_focus_change_reason_e change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA;
543 ret = _convert_stream_type_to_change_reason(reason, &change_reason);
545 LOGE("failed to _convert_stream_type_to_enum(), reason(%s), err(0x%08x)", reason, ret);
549 for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++) {
550 if (sound_stream_info_arr[i] && sound_stream_info_arr[i]->index == index) {
551 if (state == FOCUS_IS_RELEASED)
552 sound_stream_info_arr[i]->acquired_focus &= ~focus_type;
553 else if (state == FOCUS_IS_ACQUIRED)
554 sound_stream_info_arr[i]->acquired_focus |= focus_type;
556 LOGI("[FOCUS USER CALLBACK(%p) START]", sound_stream_info_arr[i]->user_cb);
557 sound_stream_info_arr[i]->user_cb((sound_stream_info_h)sound_stream_info_arr[i],
558 focus_type, state, change_reason, option, extra_info, sound_stream_info_arr[i]->user_data);
559 LOGI("[FOCUS USER CALLBACK(%p) END]", sound_stream_info_arr[i]->user_cb);
564 if (i == SOUND_STREAM_INFO_ARR_MAX)
565 LOGE("could not find index(%d), failed to call user callback", index);
573 void _focus_watch_callback(int index, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason, const char *extra_info, void *user_data)
575 int ret = MM_ERROR_NONE;
577 sound_stream_focus_change_reason_e change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA;
579 ret = _convert_stream_type_to_change_reason(reason, &change_reason);
581 LOGE("failed to _convert_stream_type_to_enum(), reason(%s), err(0x%08x)", reason, ret);
585 for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++) {
586 if ((focus_watch_info_arr[i].id > 0) && (focus_watch_info_arr[i].id == index)) {
587 LOGI("[FOCUS WATCH USER CALLBACK(%p, id:%d) START]", focus_watch_info_arr[i].user_cb, index);
588 focus_watch_info_arr[i].user_cb(index, focus_type, state, change_reason, extra_info, focus_watch_info_arr[i].user_data);
589 LOGI("[FOCUS WATCH USER CALLBACK(%p) END]", focus_watch_info_arr[i].user_cb);
593 if (i == SOUND_STREAM_INFO_ARR_MAX)
594 LOGE("could not find index(%d), failed to call user callback", index);
601 void _pa_context_state_cb(pa_context *c, void *userdata)
603 pa_context_state_t state;
604 sound_stream_info_s *stream_info_h = (sound_stream_info_s*)userdata;
608 state = pa_context_get_state(c);
609 LOGI("[%p] context state = [%d]", stream_info_h, state);
611 case PA_CONTEXT_READY:
612 case PA_CONTEXT_TERMINATED:
613 case PA_CONTEXT_FAILED:
614 pa_threaded_mainloop_signal(stream_info_h->pa_mainloop, 0);
616 case PA_CONTEXT_UNCONNECTED:
617 case PA_CONTEXT_CONNECTING:
618 case PA_CONTEXT_AUTHORIZING:
619 case PA_CONTEXT_SETTING_NAME:
626 void _pa_stream_state_cb(pa_stream *s, void * userdata)
628 pa_stream_state_t state;
629 virtual_sound_stream_info_s *vstream_h = (virtual_sound_stream_info_s*)userdata;
633 state = pa_stream_get_state(s);
634 LOGI("[%p] stream [%d] state = [%d]", vstream_h, pa_stream_get_index(s), state);
637 case PA_STREAM_READY:
638 case PA_STREAM_FAILED:
639 case PA_STREAM_TERMINATED:
640 pa_threaded_mainloop_signal(vstream_h->pa_mainloop, 0);
642 case PA_STREAM_UNCONNECTED:
643 case PA_STREAM_CREATING:
650 int _get_stream_conf_info(const char *stream_type, stream_conf_info_s *info)
652 int ret = MM_ERROR_NONE;
653 GVariant *result = NULL;
654 GVariant *child = NULL;
655 GDBusConnection *conn = NULL;
658 GVariant *item = NULL;
666 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
668 LOGE("g_bus_get_sync() error (%s)", err->message);
670 return MM_ERROR_SOUND_INTERNAL;
672 result = g_dbus_connection_call_sync(conn,
674 PA_STREAM_MANAGER_OBJECT_PATH,
675 PA_STREAM_MANAGER_INTERFACE,
676 PA_STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
677 g_variant_new("(s)", stream_type),
678 G_VARIANT_TYPE("(vvvvvv)"),
679 G_DBUS_CALL_FLAGS_NONE,
683 if (!result && err) {
684 LOGE("g_dbus_connection_call_sync() for GET_STREAM_INFO error (%s)", err->message);
686 ret = MM_ERROR_SOUND_INTERNAL;
691 child = g_variant_get_child_value(result, 0);
692 item = g_variant_get_variant(child);
693 info->priority = g_variant_get_int32(item);
694 g_variant_unref(item);
695 g_variant_unref(child);
696 LOGI("priority(%d)", info->priority);
699 child = g_variant_get_child_value(result, 1);
700 item = g_variant_get_variant(child);
701 info->route_type = g_variant_get_int32(item);
702 g_variant_unref(item);
703 g_variant_unref(child);
704 LOGI("route_type(%d)", info->route_type);
706 /* get volume types */
707 child = g_variant_get_child_value(result, 2);
708 item = g_variant_get_variant(child);
709 g_variant_iter_init(&iter, item);
710 while (g_variant_iter_loop(&iter, "&s", &name)) {
711 if (name && !strncmp(name, "none", strlen("none")))
713 /* we use volume type only for out direction */
715 LOGI(" volume-type : %s", name);
716 info->volume_type = strdup(name);
720 g_variant_unref(item);
721 g_variant_unref(child);
723 /* get availabe in-devices */
724 child = g_variant_get_child_value(result, 3);
725 item = g_variant_get_variant(child);
726 size = g_variant_n_children(item);
727 LOGI("num of avail-in-devices are %d", size);
728 g_variant_iter_init(&iter, item);
730 while (g_variant_iter_loop(&iter, "&s", &name)) {
731 if (size == 1 && !strncmp(name, "none", strlen("none"))) {
732 LOGI(" in-device is [%s], skip it", name);
735 LOGI(" in-device name : %s", name);
736 info->avail_in_devices[i++] = strdup(name);
738 g_variant_unref(item);
739 g_variant_unref(child);
741 /* get available out-devices */
742 child = g_variant_get_child_value(result, 4);
743 item = g_variant_get_variant(child);
744 size = g_variant_n_children(item);
745 LOGI("num of avail-out-devices are %d", size);
746 g_variant_iter_init(&iter, item);
748 while (g_variant_iter_loop(&iter, "&s", &name)) {
749 if (size == 1 && !strncmp(name, "none", strlen("none"))) {
750 LOGI(" out-device is [%s], skip it", name);
753 LOGI(" out-device name : %s", name);
754 info->avail_out_devices[i++] = strdup(name);
756 g_variant_unref(item);
757 g_variant_unref(child);
759 /* get available frameworks */
760 child = g_variant_get_child_value(result, 5);
761 item = g_variant_get_variant(child);
762 size = g_variant_n_children(item);
763 LOGI("num of avail-frameworks are %d", size);
764 g_variant_iter_init(&iter, item);
766 while (g_variant_iter_loop(&iter, "&s", &name)) {
767 if (size == 1 && !strncmp(name, "none", strlen("none"))) {
768 LOGI(" framework is [%s], skip it", name);
771 LOGI(" framework name : %s", name);
772 info->avail_frameworks[i++] = strdup(name);
774 g_variant_unref(item);
775 g_variant_unref(child);
776 g_variant_unref(result);
778 if (info->priority == -1) {
779 LOGE("could not find the info of stream type(%s)", stream_type);
780 ret = MM_ERROR_NOT_SUPPORT_API;
784 g_object_unref(conn);
789 int _set_manual_route_info(unsigned int index, manual_route_info_s *info)
791 int ret = MM_ERROR_NONE;
793 GVariantBuilder *builder_for_in_devices;
794 GVariantBuilder *builder_for_out_devices;
795 GVariant *result = NULL;
796 GDBusConnection *conn = NULL;
798 const gchar *dbus_ret = NULL;
802 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
804 LOGE("g_bus_get_sync() error (%s)", err->message);
806 return MM_ERROR_SOUND_INTERNAL;
809 LOGI("index(%u)", index);
811 builder_for_in_devices = g_variant_builder_new(G_VARIANT_TYPE("au"));
812 builder_for_out_devices = g_variant_builder_new(G_VARIANT_TYPE("au"));
813 if (!builder_for_in_devices || !builder_for_out_devices) {
814 LOGE("failed to g_variant_builder_new(), builder_for_in_devices(%p), builder_for_out_devices(%p)",
815 builder_for_in_devices, builder_for_out_devices);
816 ret = MM_ERROR_SOUND_INTERNAL;
819 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
820 if (!info->route_in_devices[i])
822 g_variant_builder_add(builder_for_in_devices, "u", info->route_in_devices[i]);
823 LOGI("[IN] device_id:%u", info->route_in_devices[i]);
825 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
826 if (!info->route_out_devices[i])
828 g_variant_builder_add(builder_for_out_devices, "u", info->route_out_devices[i]);
829 LOGI("[OUT] device_id:%u", info->route_out_devices[i]);
832 result = g_dbus_connection_call_sync(conn,
834 PA_STREAM_MANAGER_OBJECT_PATH,
835 PA_STREAM_MANAGER_INTERFACE,
836 PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
837 g_variant_new("(uauau)", index, builder_for_in_devices, builder_for_out_devices),
838 G_VARIANT_TYPE("(s)"),
839 G_DBUS_CALL_FLAGS_NONE,
844 LOGE("g_dbus_connection_call_sync() for SET_STREAM_ROUTE_DEVICES error (%s)", err->message);
846 ret = MM_ERROR_SOUND_INTERNAL;
850 g_variant_get(result, "(&s)", &dbus_ret);
851 LOGI("g_dbus_connection_call_sync() success, method return value is (%s)", dbus_ret);
852 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
853 ret = MM_ERROR_SOUND_INVALID_STATE;
857 g_variant_unref(result);
859 if (builder_for_in_devices)
860 g_variant_builder_unref(builder_for_in_devices);
861 if (builder_for_out_devices)
862 g_variant_builder_unref(builder_for_out_devices);
863 g_object_unref(conn);
868 int _set_route_option(unsigned int index, const char *name, int value)
870 int ret = MM_ERROR_NONE;
871 GVariant *result = NULL;
872 GDBusConnection *conn = NULL;
874 const gchar *dbus_ret = NULL;
878 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
880 LOGE("g_bus_get_sync() error (%s)", err->message);
882 return MM_ERROR_SOUND_INTERNAL;
885 LOGI("[OPTION] %s(%d)", name, value);
887 result = g_dbus_connection_call_sync(conn,
889 PA_STREAM_MANAGER_OBJECT_PATH,
890 PA_STREAM_MANAGER_INTERFACE,
891 PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
892 g_variant_new("(usi)", index, name, value),
893 G_VARIANT_TYPE("(s)"),
894 G_DBUS_CALL_FLAGS_NONE,
898 if (!result && err) {
899 LOGE("g_dbus_connection_call_sync() for SET_STREAM_ROUTE_OPTION error (%s)", err->message);
901 ret = MM_ERROR_SOUND_INTERNAL;
905 g_variant_get(result, "(&s)", &dbus_ret);
906 LOGI("g_dbus_connection_call_sync() success, method return value is (%s)", dbus_ret);
907 if (!strncmp("STREAM_MANAGER_RETURN_ERROR_NO_STREAM", dbus_ret, strlen(dbus_ret)))
908 ret = MM_ERROR_SOUND_INVALID_STATE;
909 else if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
910 ret = MM_ERROR_SOUND_INTERNAL;
912 g_variant_unref(result);
914 g_object_unref(conn);
919 int _get_volume_max_level(const char *direction, const char *volume_type, unsigned int *max_level)
921 int ret = MM_ERROR_NONE;
922 GVariant *result = NULL;
923 GDBusConnection *conn = NULL;
925 const gchar *dbus_ret = NULL;
931 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
933 LOGE("g_bus_get_sync() error (%s)", err->message);
935 return MM_ERROR_SOUND_INTERNAL;
938 result = g_dbus_connection_call_sync(conn,
940 PA_STREAM_MANAGER_OBJECT_PATH,
941 PA_STREAM_MANAGER_INTERFACE,
942 PA_STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
943 g_variant_new("(ss)", direction, volume_type),
944 G_VARIANT_TYPE("(us)"),
945 G_DBUS_CALL_FLAGS_NONE,
950 LOGE("g_dbus_connection_call_sync() for GET_VOLUME_MAX_LEVEL error (%s)", err->message);
952 ret = MM_ERROR_SOUND_INTERNAL;
956 g_variant_get(result, "(u&s)", max_level, &dbus_ret);
957 LOGI("g_dbus_connection_call_sync() success, method return value is (%u, %s)", *max_level, dbus_ret);
958 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
959 ret = MM_ERROR_SOUND_INTERNAL;
961 g_variant_unref(result);
963 g_object_unref(conn);
968 int _get_volume_level(const char *direction, const char *volume_type, unsigned int *level)
970 int ret = MM_ERROR_NONE;
971 GVariant *result = NULL;
972 GDBusConnection *conn = NULL;
974 const gchar *dbus_ret = NULL;
980 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
982 LOGE("g_bus_get_sync() error (%s)", err->message);
984 return MM_ERROR_SOUND_INTERNAL;
987 result = g_dbus_connection_call_sync(conn,
989 PA_STREAM_MANAGER_OBJECT_PATH,
990 PA_STREAM_MANAGER_INTERFACE,
991 PA_STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
992 g_variant_new("(ss)", direction, volume_type),
993 G_VARIANT_TYPE("(us)"),
994 G_DBUS_CALL_FLAGS_NONE,
999 LOGE("g_dbus_connection_call_sync() for GET_VOLUME_LEVEL error (%s)", err->message);
1001 ret = MM_ERROR_SOUND_INTERNAL;
1005 g_variant_get(result, "(u&s)", level, &dbus_ret);
1006 LOGI("g_dbus_connection_call_sync() success, method return value is (%u, %s)", *level, dbus_ret);
1007 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
1008 ret = MM_ERROR_SOUND_INTERNAL;
1010 g_variant_unref(result);
1012 g_object_unref(conn);
1017 int _set_volume_level(const char *direction, const char *volume_type, unsigned int level)
1019 int ret = MM_ERROR_NONE;
1020 GVariant *result = NULL;
1021 GDBusConnection *conn = NULL;
1023 const gchar *dbus_ret = NULL;
1025 char volume_path[VCONF_PATH_MAX] = {0,};
1028 assert(volume_type);
1030 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1032 LOGE("g_bus_get_sync() error (%s)", err->message);
1034 return MM_ERROR_SOUND_INTERNAL;
1037 result = g_dbus_connection_call_sync(conn,
1039 PA_STREAM_MANAGER_OBJECT_PATH,
1040 PA_STREAM_MANAGER_INTERFACE,
1041 PA_STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
1042 g_variant_new("(ssu)", direction, volume_type, level),
1043 G_VARIANT_TYPE("(s)"),
1044 G_DBUS_CALL_FLAGS_NONE,
1049 LOGE("g_dbus_connection_call_sync() for SET_VOLUME_LEVEL error (%s)", err->message);
1051 ret = MM_ERROR_SOUND_INTERNAL;
1055 g_variant_get(result, "(&s)", &dbus_ret);
1056 LOGI("g_dbus_connection_call_sync() success, method return value is (%s)", dbus_ret);
1057 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
1058 ret = MM_ERROR_SOUND_INTERNAL;
1060 /* Set volume value to VCONF */
1061 snprintf(volume_path, sizeof(volume_path)-1, "%s%s", VCONF_PATH_PREFIX_VOLUME, volume_type);
1062 if ((vret = vconf_set_int(volume_path, (int)level)))
1063 LOGE("vconf_set_int(%s) failed..ret[%d]\n", volume_path, vret);
1065 g_variant_unref(result);
1067 g_object_unref(conn);
1072 int _get_current_volume_type(const char *direction, char **volume_type)
1074 int ret = MM_ERROR_NONE;
1075 GVariant *result = NULL;
1076 GDBusConnection *conn = NULL;
1078 const gchar *dbus_volume_type = NULL;
1079 const gchar *dbus_ret = NULL;
1082 assert(volume_type);
1084 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1086 LOGE("g_bus_get_sync() error (%s)", err->message);
1088 return MM_ERROR_SOUND_INTERNAL;
1091 result = g_dbus_connection_call_sync(conn,
1093 PA_STREAM_MANAGER_OBJECT_PATH,
1094 PA_STREAM_MANAGER_INTERFACE,
1095 PA_STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
1096 g_variant_new("(s)", direction),
1097 G_VARIANT_TYPE("(ss)"),
1098 G_DBUS_CALL_FLAGS_NONE,
1103 LOGE("g_dbus_connection_call_sync() for GET_CURRENT_VOLUME_TYPE error (%s)", err->message);
1105 ret = MM_ERROR_SOUND_INTERNAL;
1109 g_variant_get(result, "(&s&s)", &dbus_volume_type, &dbus_ret);
1110 LOGI("g_dbus_connection_call_sync() success, method return value is (%s, %s)", dbus_volume_type, dbus_ret);
1111 if (!strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
1112 ret = MM_ERROR_NONE;
1113 *volume_type = strdup(dbus_volume_type);
1114 } else if (!strncmp("STREAM_MANAGER_RETURN_ERROR_NO_STREAM", dbus_ret, strlen(dbus_ret)))
1115 ret = MM_ERROR_SOUND_VOLUME_NO_INSTANCE;
1117 ret = MM_ERROR_SOUND_INTERNAL;
1119 g_variant_unref(result);
1121 g_object_unref(conn);
1126 int _get_current_media_routing_path(const char *direction, sound_device_type_e *device_type)
1128 int ret = MM_ERROR_NONE;
1129 GVariant *result = NULL;
1130 GDBusConnection *conn = NULL;
1132 const gchar *dbus_device_type = NULL;
1133 const gchar *dbus_ret = NULL;
1136 assert(device_type);
1138 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1140 LOGE("g_bus_get_sync() error (%s)", err->message);
1142 return MM_ERROR_SOUND_INTERNAL;
1145 result = g_dbus_connection_call_sync(conn,
1147 PA_STREAM_MANAGER_OBJECT_PATH,
1148 PA_STREAM_MANAGER_INTERFACE,
1149 PA_STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH,
1150 g_variant_new("(s)", direction),
1151 G_VARIANT_TYPE("(ss)"),
1152 G_DBUS_CALL_FLAGS_NONE,
1157 LOGE("g_dbus_connection_call_sync() for GET_CURRENT_MEDIA_ROUTING_PATH error (%s)", err->message);
1159 ret = MM_ERROR_SOUND_INTERNAL;
1163 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
1164 LOGI("g_dbus_connection_call_sync() success, method return value is (%s, %s)", dbus_device_type, dbus_ret);
1165 if (!strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
1166 ret = MM_ERROR_NONE;
1167 if (_convert_device_type_str_to_enum(dbus_device_type, device_type) < 0)
1168 ret = MM_ERROR_SOUND_INTERNAL;
1170 if (!strncmp("none", dbus_device_type, strlen(dbus_device_type)))
1171 ret = MM_ERROR_SOUND_NO_DATA;
1173 ret = MM_ERROR_SOUND_INTERNAL;
1176 g_variant_unref(result);
1178 g_object_unref(conn);
1183 void _update_focus_status(unsigned int index, unsigned int acquired_focus_status)
1185 GVariant *result = NULL;
1186 GDBusConnection *conn = NULL;
1188 const gchar *dbus_ret = NULL;
1190 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1192 LOGE("g_bus_get_sync() error (%s)", err->message);
1197 result = g_dbus_connection_call_sync(conn,
1199 PA_STREAM_MANAGER_OBJECT_PATH,
1200 PA_STREAM_MANAGER_INTERFACE,
1201 PA_STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS,
1202 g_variant_new("(uu)", index, acquired_focus_status),
1203 G_VARIANT_TYPE("(s)"),
1204 G_DBUS_CALL_FLAGS_NONE,
1209 LOGE("g_dbus_connection_call_sync() for UPDATE_FOCUS_STATUS error (%s)", err->message);
1213 g_variant_get(result, "(&s)", &dbus_ret);
1214 LOGI("g_dbus_connection_call_sync() success, method return value is (%s)", dbus_ret);
1215 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
1216 LOGE("failed to UPDATE_FOCUS_STATUS error (%s)", dbus_ret);
1218 g_variant_unref(result);
1220 g_object_unref(conn);
1225 void _focus_session_interrupt_cb(mm_sound_focus_state_e state, const char *reason, bool is_wcb, void *user_data)
1227 sound_session_interrupted_code_e e;
1228 LOGE("session interrupted by [%s]", reason);
1229 if (g_session_interrupt_cb_table.user_cb) {
1231 if (state == FOCUS_IS_RELEASED)
1232 e = SOUND_SESSION_INTERRUPTED_COMPLETED;
1234 _convert_stream_type_to_interrupt_reason(reason, &e);
1236 if (state == FOCUS_IS_ACQUIRED)
1237 e = SOUND_SESSION_INTERRUPTED_COMPLETED;
1239 _convert_stream_type_to_interrupt_reason(reason, &e);
1241 g_session_interrupt_cb_table.user_cb(e, g_session_interrupt_cb_table.user_data);
1247 void _device_connected_cb(sound_device_h device, bool is_connected, void *user_data)
1249 mm_sound_device_type_e type;
1250 if (mm_sound_get_device_type(device, &type) != MM_ERROR_NONE) {
1251 LOGE("getting device type failed");
1256 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
1257 case MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP:
1258 case MM_SOUND_DEVICE_TYPE_BLUETOOTH_SCO:
1259 case MM_SOUND_DEVICE_TYPE_HDMI:
1260 case MM_SOUND_DEVICE_TYPE_MIRRORING:
1261 case MM_SOUND_DEVICE_TYPE_USB_AUDIO:
1262 if (!is_connected) {
1263 LOGI("sound device unplugged");
1264 g_session_interrupt_cb_table.user_cb(SOUND_SESSION_INTERRUPTED_BY_EARJACK_UNPLUG, g_session_interrupt_cb_table.user_data);
1274 /* This is an internal callback for the VOIP SESSION */
1275 void _voip_focus_state_change_callback(sound_stream_info_h stream_info,
1276 sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
1277 sound_stream_focus_change_reason_e reason, int sound_behavior, const char *extra_info, void *user_data)
1279 sound_stream_info_s *info = (sound_stream_info_s *)stream_info;
1280 LOGI(">> enter, stream_info(%p), change_reason(%d), sound_behavior(0x%x), extra_info(%s)", stream_info, reason, sound_behavior, extra_info);
1283 LOGE("stream info is null");
1287 if (!(info->acquired_focus & SOUND_STREAM_FOCUS_FOR_PLAYBACK) ||
1288 !(info->acquired_focus & SOUND_STREAM_FOCUS_FOR_RECORDING)) {
1289 /* stop virtual stream for rintone-voip or voip */
1290 if (g_voip_vstream_h) {
1291 /* stop virtual stream handle */
1292 _stop_virtual_stream(g_voip_vstream_h);
1293 /* destroy virtual stream handle */
1294 _destroy_virtual_stream(g_voip_vstream_h);
1295 g_voip_vstream_h = NULL;
1296 LOGW("internal voip stream is interrupted by (%d)", reason);
1305 int _set_session_mode(_session_mode_e mode)
1307 int ret = MM_ERROR_NONE;
1308 int w_ret = MM_ERROR_NONE;
1309 int i_ret = SOUND_MANAGER_ERROR_NONE;
1310 bool is_found = false;
1311 MMSoundDeviceList_t device_list;
1312 MMSoundDevice_t tmp_device = NULL;
1313 MMSoundDevice_t proper_device = NULL;
1314 MMSoundDevice_t prev_device = NULL;
1315 mm_sound_device_type_e type;
1318 if (g_cached_session_mode == mode) {
1319 LOGW("session_mode(%d) is same as before", mode);
1324 case _SESSION_MODE_RINGTONE:
1325 if (g_voip_vstream_h) {
1326 /* stop vstream and destroy vstream */
1327 _stop_virtual_stream(g_voip_vstream_h);
1328 _destroy_virtual_stream(g_voip_vstream_h);
1329 g_voip_vstream_h = NULL;
1330 /* destroy stream info */
1331 _destroy_pa_connection_and_unregister_focus(g_voip_stream_info);
1332 free(g_voip_stream_info);
1333 g_voip_stream_info = NULL;
1335 if (!g_voip_stream_info) {
1336 g_voip_stream_info = malloc(sizeof(sound_stream_info_s));
1337 if (!g_voip_stream_info) {
1338 ret = MM_ERROR_OUT_OF_MEMORY;
1341 memset(g_voip_stream_info, 0, sizeof(sound_stream_info_s));
1343 /* create stream info and acquire focus for rintone-voip stream */
1344 g_voip_stream_info->stream_type = "ringtone-voip";
1345 ret = _make_pa_connection_and_register_focus(g_voip_stream_info, true, _voip_focus_state_change_callback, NULL);
1346 if (ret != MM_ERROR_NONE) {
1347 free(g_voip_stream_info);
1348 g_voip_stream_info = NULL;
1352 ret = mm_sound_acquire_focus(g_voip_stream_info->index, FOCUS_FOR_BOTH, "for voip session");
1353 if (ret == MM_ERROR_NONE) {
1354 g_voip_stream_info->acquired_focus |= FOCUS_FOR_BOTH;
1355 _update_focus_status(g_voip_stream_info->index, (unsigned int)g_voip_stream_info->acquired_focus);
1360 /* create virtual stream for ringtone-voip */
1361 i_ret = _create_virtual_stream(g_voip_stream_info, &g_voip_vstream_h);
1362 if (i_ret == SOUND_MANAGER_ERROR_NONE) {
1363 i_ret = _start_virtual_stream(g_voip_vstream_h);
1364 if (i_ret != SOUND_MANAGER_ERROR_NONE)
1367 ret = MM_ERROR_SOUND_INTERNAL;
1371 case _SESSION_MODE_VOICE_WITH_BUILTIN_RECEIVER: /* Built-in RCV and Built-in MIC */
1372 case _SESSION_MODE_VOICE_WITH_BUILTIN_SPEAKER: /* Built-in SPK and Built-in MIC */
1373 case _SESSION_MODE_VOICE_WITH_AUDIO_JACK: /* Earphone spk & mic */
1374 case _SESSION_MODE_VOICE_WITH_BLUETOOTH_SCO: /* Bluetooth spk & mic */
1375 /* check if the device is available now */
1376 ret = mm_sound_get_device_list(MM_SOUND_DEVICE_ALL_FLAG, &device_list);
1377 if (ret != MM_ERROR_NONE) {
1378 LOGE("failed to get current device list");
1381 while (!is_found && ((w_ret = mm_sound_get_next_device(device_list, &tmp_device)) == MM_ERROR_NONE)) {
1382 ret = mm_sound_get_device_type(tmp_device, &type);
1383 if (ret != MM_ERROR_NONE)
1385 ret = mm_sound_get_device_id(tmp_device, &id);
1386 if (ret != MM_ERROR_NONE)
1389 if (g_cached_voip_device_id != -1 && g_cached_voip_device_id == id)
1390 prev_device = tmp_device;
1393 case _SESSION_MODE_VOICE_WITH_BUILTIN_RECEIVER:
1394 if (type == MM_SOUND_DEVICE_TYPE_BUILTIN_RECEIVER) {
1396 proper_device = tmp_device;
1399 case _SESSION_MODE_VOICE_WITH_BUILTIN_SPEAKER:
1400 if (type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER) {
1402 proper_device = tmp_device;
1405 case _SESSION_MODE_VOICE_WITH_AUDIO_JACK:
1406 if (type == MM_SOUND_DEVICE_TYPE_AUDIOJACK) {
1408 proper_device = tmp_device;
1412 case _SESSION_MODE_VOICE_WITH_BLUETOOTH_SCO:
1413 if (type == MM_SOUND_DEVICE_TYPE_BLUETOOTH_SCO) {
1415 proper_device = tmp_device;
1423 LOGE("could not found a proper connected device for this mode(%d)", mode);
1424 ret = MM_ERROR_SOUND_INTERNAL;
1425 goto ERROR_CASE_NO_DESTROY;
1428 /* if ok for the device, go below */
1429 if (g_cached_session_mode == _SESSION_MODE_RINGTONE) {
1430 /* stop vstream and destroy vstream */
1431 _stop_virtual_stream(g_voip_vstream_h);
1432 _destroy_virtual_stream(g_voip_vstream_h);
1433 g_voip_vstream_h = NULL;
1434 /* destroy stream info */
1435 _destroy_pa_connection_and_unregister_focus(g_voip_stream_info);
1436 free(g_voip_stream_info);
1437 g_voip_stream_info = NULL;
1439 /* create stream info and acquire focus for voip stream */
1440 if (g_cached_session_mode == -1 || g_cached_session_mode == _SESSION_MODE_RINGTONE) {
1441 if (!g_voip_stream_info) {
1442 g_voip_stream_info = malloc(sizeof(sound_stream_info_s));
1443 if (!g_voip_stream_info) {
1444 ret = MM_ERROR_OUT_OF_MEMORY;
1447 memset(g_voip_stream_info, 0, sizeof(sound_stream_info_s));
1449 g_voip_stream_info->stream_type = "voip";
1450 ret = _make_pa_connection_and_register_focus(g_voip_stream_info, true, _voip_focus_state_change_callback, NULL);
1451 if (ret != MM_ERROR_NONE) {
1452 free(g_voip_stream_info);
1453 g_voip_stream_info = NULL;
1456 /* set device for routing to the device */
1457 i_ret = _add_device_for_stream_routing(g_voip_stream_info, proper_device);
1458 if (i_ret == SOUND_MANAGER_ERROR_NONE) {
1459 i_ret = _apply_stream_routing(g_voip_stream_info);
1460 if (i_ret != SOUND_MANAGER_ERROR_NONE)
1466 ret = mm_sound_acquire_focus(g_voip_stream_info->index, FOCUS_FOR_BOTH, "for voip session");
1467 if (ret == MM_ERROR_NONE) {
1468 g_voip_stream_info->acquired_focus |= FOCUS_FOR_BOTH;
1469 _update_focus_status(g_voip_stream_info->index, (unsigned int)g_voip_stream_info->acquired_focus);
1473 /* create virtual stream for voip */
1474 i_ret = _create_virtual_stream(g_voip_stream_info, &g_voip_vstream_h);
1475 if (i_ret == SOUND_MANAGER_ERROR_NONE) {
1476 i_ret = _start_virtual_stream(g_voip_vstream_h);
1477 if (i_ret != SOUND_MANAGER_ERROR_NONE)
1483 if (g_cached_voip_device_id != -1 && prev_device) {
1484 /* remove cached device */
1485 i_ret = _remove_device_for_stream_routing(g_voip_stream_info, prev_device);
1486 if (i_ret != SOUND_MANAGER_ERROR_NONE)
1488 /* set device for routing to the device */
1489 i_ret = _add_device_for_stream_routing(g_voip_stream_info, proper_device);
1490 if (i_ret == SOUND_MANAGER_ERROR_NONE) {
1491 i_ret = _apply_stream_routing(g_voip_stream_info);
1492 if (i_ret != SOUND_MANAGER_ERROR_NONE)
1499 mm_sound_free_device_list(device_list);
1502 g_cached_session_mode = mode;
1503 g_cached_voip_device_id = id;
1507 if (g_voip_vstream_h) {
1508 /* destroy virtual stream handle */
1509 _destroy_virtual_stream(g_voip_vstream_h);
1510 g_voip_vstream_h = NULL;
1511 ret = MM_ERROR_SOUND_INTERNAL;
1513 if (g_voip_stream_info) {
1514 /* destroy stream info */
1515 _destroy_pa_connection_and_unregister_focus(g_voip_stream_info);
1516 free(g_voip_stream_info);
1517 g_voip_stream_info = NULL;
1519 ERROR_CASE_NO_DESTROY:
1523 int _make_pa_connection_and_register_focus(sound_stream_info_s *stream_h, bool is_for_session, sound_stream_focus_state_changed_cb callback, void *user_data)
1525 int ret = MM_ERROR_NONE;
1528 bool is_focus_cb_thread = false;
1530 if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread)))
1533 if (is_focus_cb_thread)
1534 return MM_ERROR_SOUND_INVALID_OPERATION;
1536 if (!stream_h->is_focus_unavailable) {
1537 for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++)
1538 if (sound_stream_info_arr[i] == NULL)
1540 if (i == SOUND_STREAM_INFO_ARR_MAX) {
1541 LOGE("client sound stream info array is full");
1546 /* get configuration information of this stream type */
1547 if ((ret = _get_stream_conf_info(stream_h->stream_type, &stream_h->stream_conf_info)))
1550 LOGI("stream_conf_info : stream type[%s], priority[%d], route type[%d]",
1551 stream_h->stream_type, stream_h->stream_conf_info.priority, stream_h->stream_conf_info.route_type);
1553 if (!(stream_h->pa_mainloop = pa_threaded_mainloop_new()))
1556 if (!(stream_h->pa_context = pa_context_new(pa_threaded_mainloop_get_api(stream_h->pa_mainloop), "SOUND_MANAGER_STREAM_INFO")))
1559 pa_context_set_state_callback(stream_h->pa_context, _pa_context_state_cb, stream_h);
1561 if (pa_context_connect(stream_h->pa_context, NULL, 0, NULL) < 0) {
1562 pa_ret = pa_context_errno(stream_h->pa_context);
1566 pa_threaded_mainloop_lock(stream_h->pa_mainloop);
1568 if (pa_threaded_mainloop_start(stream_h->pa_mainloop) < 0)
1569 goto PA_ERROR_WITH_UNLOCK;
1571 /* wait for ready state of the context */
1573 pa_context_state_t state;
1574 state = pa_context_get_state(stream_h->pa_context);
1575 if (state == PA_CONTEXT_READY)
1577 if (!PA_CONTEXT_IS_GOOD(state)) {
1578 pa_ret = pa_context_errno(stream_h->pa_context);
1579 goto PA_ERROR_WITH_UNLOCK;
1581 pa_threaded_mainloop_wait(stream_h->pa_mainloop);
1584 /* get index of this context */
1585 stream_h->index = pa_context_get_index(stream_h->pa_context);
1587 pa_threaded_mainloop_unlock(stream_h->pa_mainloop);
1589 /* register focus */
1590 if (!stream_h->is_focus_unavailable) {
1592 ret = mm_sound_register_focus_for_session(stream_h->index, getpid(), stream_h->stream_type, _focus_state_change_callback, user_data);
1594 ret = mm_sound_register_focus(stream_h->index, stream_h->stream_type, _focus_state_change_callback, user_data);
1595 if (ret == MM_ERROR_NONE) {
1596 stream_h->user_cb = callback;
1597 stream_h->user_data = user_data;
1598 sound_stream_info_arr[i] = stream_h;
1600 LOGE("failed to register focus, ret(0x%x)", ret);
1607 PA_ERROR_WITH_UNLOCK:
1608 pa_threaded_mainloop_unlock(stream_h->pa_mainloop);
1611 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1612 if (stream_h->stream_conf_info.avail_in_devices[i])
1613 free(stream_h->stream_conf_info.avail_in_devices[i]);
1617 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1618 if (stream_h->stream_conf_info.avail_out_devices[i])
1619 free(stream_h->stream_conf_info.avail_out_devices[i]);
1623 for (i = 0; i < AVAIL_FRAMEWORKS_MAX; i++) {
1624 if (stream_h->stream_conf_info.avail_frameworks[i])
1625 free(stream_h->stream_conf_info.avail_frameworks[i]);
1629 if (stream_h->pa_context) {
1630 pa_context_disconnect(stream_h->pa_context);
1631 pa_context_unref(stream_h->pa_context);
1632 stream_h->pa_context = NULL;
1634 if (stream_h->pa_mainloop) {
1635 pa_threaded_mainloop_free(stream_h->pa_mainloop);
1636 stream_h->pa_mainloop = NULL;
1638 ret = MM_ERROR_SOUND_INTERNAL;
1639 LOGE("pa_ret(%d), ret(0x%x)", pa_ret, ret);
1645 int _destroy_pa_connection_and_unregister_focus(sound_stream_info_s *stream_h)
1648 int ret = MM_ERROR_NONE;
1649 bool is_focus_cb_thread = false;
1651 ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread);
1655 if (is_focus_cb_thread)
1656 return MM_ERROR_SOUND_INVALID_OPERATION;
1658 if (stream_h->pa_context) {
1659 pa_context_disconnect(stream_h->pa_context);
1660 pa_context_unref(stream_h->pa_context);
1661 stream_h->pa_context = NULL;
1664 if (stream_h->pa_mainloop) {
1665 pa_threaded_mainloop_free(stream_h->pa_mainloop);
1666 stream_h->pa_mainloop = NULL;
1669 /* unregister focus */
1670 if (!stream_h->is_focus_unavailable) {
1671 ret = mm_sound_unregister_focus(stream_h->index);
1673 LOGE("failed to unregister focus, ret(0x%x)", ret);
1676 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1677 if (stream_h->stream_conf_info.avail_in_devices[i])
1678 free(stream_h->stream_conf_info.avail_in_devices[i]);
1679 if (stream_h->stream_conf_info.avail_out_devices[i])
1680 free(stream_h->stream_conf_info.avail_out_devices[i]);
1682 for (i = 0; i < AVAIL_FRAMEWORKS_MAX; i++) {
1683 if (stream_h->stream_conf_info.avail_frameworks[i])
1684 free(stream_h->stream_conf_info.avail_frameworks[i]);
1687 for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++) {
1688 if (sound_stream_info_arr[i] && sound_stream_info_arr[i]->index == stream_h->index) {
1689 sound_stream_info_arr[i] = NULL;
1697 int _add_device_for_stream_routing(sound_stream_info_s *stream_info, sound_device_h device)
1699 int ret = MM_ERROR_NONE;
1702 bool added_successfully = false;
1704 /* not ready yet. after preparing in libmm-sound, it'll be enabled */
1705 bool use_internal_codec = false;
1707 char *device_type_str = NULL;
1709 mm_sound_device_type_e mm_sound_device_type;
1710 mm_sound_device_io_direction_e device_direction;
1711 sound_device_type_e device_type;
1713 SM_INSTANCE_CHECK_FOR_PRIV(stream_info);
1714 SM_NULL_ARG_CHECK_FOR_PRIV(device);
1716 if (stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL ||
1717 stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1719 /* not ready yet. after preparing in libmm-sound, it'll be enabled */
1720 if (stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1721 if ((ret = mm_sound_get_device_use_internal_codec(device, &use_internal_codec)))
1723 if (use_internal_codec)
1724 return MM_ERROR_POLICY_INTERNAL;
1727 if ((ret = mm_sound_get_device_id(device, &device_id)))
1729 if ((ret = mm_sound_get_device_type(device, &mm_sound_device_type)))
1731 if (ret == MM_ERROR_NONE)
1732 _convert_device_type(mm_sound_device_type, &device_type);
1733 if ((ret = _convert_device_type_enum_to_str(device_type, &device_type_str)))
1735 if ((ret = mm_sound_get_device_io_direction(device, &device_direction)))
1738 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_IN || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
1739 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1740 if (!stream_info->stream_conf_info.avail_in_devices[i])
1743 if (!strncmp(stream_info->stream_conf_info.avail_in_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
1744 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
1745 if (!stream_info->manual_route_info.route_in_devices[j]) {
1746 stream_info->manual_route_info.route_in_devices[j] = (unsigned int)device_id;
1747 added_successfully = true;
1750 if (stream_info->manual_route_info.route_in_devices[j] == (unsigned int)device_id) {
1751 /* it was already set */
1752 return MM_ERROR_POLICY_DUPLICATED;
1758 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_OUT || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
1759 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1760 if (!stream_info->stream_conf_info.avail_out_devices[i])
1763 if (!strncmp(stream_info->stream_conf_info.avail_out_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
1764 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
1765 if (!stream_info->manual_route_info.route_out_devices[j]) {
1766 stream_info->manual_route_info.route_out_devices[j] = (unsigned int)device_id;
1767 added_successfully = true;
1770 if (stream_info->manual_route_info.route_out_devices[j] == (unsigned int)device_id) {
1771 /* it was already set */
1772 return MM_ERROR_POLICY_DUPLICATED;
1780 if (!added_successfully)
1781 ret = MM_ERROR_POLICY_INTERNAL;
1786 int _remove_device_for_stream_routing(sound_stream_info_s *stream_info, sound_device_h device)
1788 int ret = MM_ERROR_NONE;
1791 bool removed_successfully = false;
1792 char *device_type_str = NULL;
1794 mm_sound_device_type_e mm_sound_device_type;
1795 mm_sound_device_io_direction_e device_direction;
1796 sound_device_type_e device_type;
1798 SM_INSTANCE_CHECK_FOR_PRIV(stream_info);
1799 SM_NULL_ARG_CHECK_FOR_PRIV(device);
1801 if (stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL ||
1802 stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1803 if ((ret = mm_sound_get_device_id(device, &device_id)))
1805 if ((ret = mm_sound_get_device_type(device, &mm_sound_device_type)))
1807 if (ret == MM_ERROR_NONE)
1808 _convert_device_type(mm_sound_device_type, &device_type);
1809 if ((ret = _convert_device_type_enum_to_str(device_type, &device_type_str)))
1811 if ((ret = mm_sound_get_device_io_direction(device, &device_direction)))
1814 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_IN || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
1815 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1816 if (!stream_info->stream_conf_info.avail_in_devices[i])
1819 if (!strncmp(stream_info->stream_conf_info.avail_in_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
1820 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
1821 if (stream_info->manual_route_info.route_in_devices[j] == (unsigned int)device_id) {
1822 removed_successfully = true;
1823 stream_info->manual_route_info.route_in_devices[j] = 0;
1830 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_OUT || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
1831 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1832 if (!stream_info->stream_conf_info.avail_out_devices[i])
1835 if (!strncmp(stream_info->stream_conf_info.avail_out_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
1836 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
1837 if (stream_info->manual_route_info.route_out_devices[j] == (unsigned int)device_id) {
1838 removed_successfully = true;
1839 stream_info->manual_route_info.route_out_devices[j] = 0;
1848 if (!removed_successfully)
1849 ret = MM_ERROR_INVALID_ARGUMENT;
1854 int _apply_stream_routing(sound_stream_info_s *stream_info)
1856 int ret = MM_ERROR_NONE;
1858 bool need_to_apply = false;
1860 SM_INSTANCE_CHECK_FOR_PRIV(stream_info);
1862 if (stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL ||
1863 stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1864 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
1865 if (stream_info->manual_route_info.route_in_devices[i]) {
1866 need_to_apply = true;
1869 if (stream_info->manual_route_info.route_out_devices[i]) {
1870 need_to_apply = true;
1875 ret = _set_manual_route_info(stream_info->index, &stream_info->manual_route_info);
1877 return MM_ERROR_SOUND_INVALID_STATE;
1880 ret = MM_ERROR_SOUND_INVALID_STATE;
1885 int _create_virtual_stream(sound_stream_info_s *stream_info, virtual_sound_stream_info_s **virtual_stream)
1887 int ret = MM_ERROR_NONE;
1888 bool result = false;
1889 const char *name = NULL;
1892 SM_INSTANCE_CHECK_FOR_PRIV(virtual_stream);
1893 SM_INSTANCE_CHECK_FOR_PRIV(stream_info);
1895 /* check if this stream_info is available for virtual stream */
1896 name = _convert_api_name(NATIVE_API_SOUND_MANAGER);
1897 for (i = 0; i < AVAIL_FRAMEWORKS_MAX; i++) {
1898 if (stream_info->stream_conf_info.avail_frameworks[i] && !strncmp(stream_info->stream_conf_info.avail_frameworks[i], name, strlen(name))) {
1903 LOGI("stream_type[%s], native api[%s], is_available[%d]", stream_info->stream_type, name, result);
1904 if (result == false) {
1905 ret = MM_ERROR_NOT_SUPPORT_API;
1909 (*virtual_stream) = malloc(sizeof(virtual_sound_stream_info_s));
1910 if (!(*virtual_stream)) {
1911 ret = MM_ERROR_OUT_OF_MEMORY;
1915 memset((*virtual_stream), 0, sizeof(virtual_sound_stream_info_s));
1916 (*virtual_stream)->stream_type = stream_info->stream_type;
1917 (*virtual_stream)->pa_mainloop = stream_info->pa_mainloop;
1918 (*virtual_stream)->pa_context = stream_info->pa_context;
1919 (*virtual_stream)->pa_proplist = pa_proplist_new();
1920 pa_proplist_sets((*virtual_stream)->pa_proplist, PA_PROP_MEDIA_ROLE, (*virtual_stream)->stream_type);
1921 pa_proplist_setf((*virtual_stream)->pa_proplist, PA_PROP_MEDIA_PARENT_ID, "%u", stream_info->index);
1922 (*virtual_stream)->state = _VSTREAM_STATE_READY;
1923 (*virtual_stream)->stream_info = stream_info;
1929 int _destroy_virtual_stream(virtual_sound_stream_info_s *virtual_stream)
1931 int ret = MM_ERROR_NONE;
1933 SM_INSTANCE_CHECK_FOR_PRIV(virtual_stream);
1934 SM_STATE_CHECK_FOR_PRIV(virtual_stream, _VSTREAM_STATE_READY);
1936 virtual_stream->pa_mainloop = NULL;
1937 virtual_stream->pa_context = NULL;
1938 if (virtual_stream->pa_proplist)
1939 pa_proplist_free(virtual_stream->pa_proplist);
1941 free(virtual_stream);
1942 virtual_stream = NULL;
1947 int _start_virtual_stream(virtual_sound_stream_info_s *virtual_stream)
1949 int ret = MM_ERROR_NONE;
1952 int io_direction = 0;
1954 pa_channel_map maps;
1956 SM_INSTANCE_CHECK_FOR_PRIV(virtual_stream);
1957 SM_STATE_CHECK_FOR_PRIV(virtual_stream, _VSTREAM_STATE_READY);
1959 if (virtual_stream->stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL ||
1960 virtual_stream->stream_info->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1961 /* check if the manual route info. is set when it comes to the manual route type */
1962 if (virtual_stream->stream_info->manual_route_info.is_set == false) {
1963 ret = MM_ERROR_SOUND_INVALID_STATE;
1968 /* fill up with default value */
1971 ss.format = PA_SAMPLE_S16LE;
1972 pa_channel_map_init_auto(&maps, ss.channels, PA_CHANNEL_MAP_ALSA);
1974 /* check direction of this stream */
1975 if (virtual_stream->stream_info->stream_conf_info.avail_in_devices[0] != NULL)
1976 io_direction |= SOUND_STREAM_DIRECTION_INPUT;
1977 if (virtual_stream->stream_info->stream_conf_info.avail_out_devices[0] != NULL)
1978 io_direction |= SOUND_STREAM_DIRECTION_OUTPUT;
1980 /* LOCK the pa_threaded_mainloop */
1981 pa_threaded_mainloop_lock(virtual_stream->pa_mainloop);
1983 for (i = 0; i < SOUND_STREAM_DIRECTION_MAX; i++) {
1984 if (io_direction & (i + 1)) {
1985 virtual_stream->pa_stream[i] = pa_stream_new_with_proplist(virtual_stream->pa_context, "VIRTUAL_STREAM", &ss, &maps, virtual_stream->pa_proplist);
1986 if (virtual_stream->pa_stream[i] == NULL) {
1987 LOGE("failed to pa_stream_new_with_proplist()");
1988 pa_ret = pa_context_errno(virtual_stream->pa_context);
1989 ret = MM_ERROR_SOUND_INTERNAL;
1990 goto ERROR_WITH_UNLOCK;
1992 pa_stream_set_state_callback(virtual_stream->pa_stream[i], _pa_stream_state_cb, virtual_stream);
1994 if ((i + 1) == SOUND_STREAM_DIRECTION_OUTPUT) {
1995 pa_ret = pa_stream_connect_playback(virtual_stream->pa_stream[i], NULL, NULL, 0, NULL, NULL);
1997 LOGE("failed to pa_stream_connect_playback()");
1998 pa_ret = pa_context_errno(virtual_stream->pa_context);
1999 ret = MM_ERROR_SOUND_INTERNAL;
2000 goto ERROR_WITH_UNLOCK;
2002 } else if ((i + 1) == SOUND_STREAM_DIRECTION_INPUT) {
2003 pa_ret = pa_stream_connect_record(virtual_stream->pa_stream[i], NULL, NULL, 0);
2005 LOGE("failed to pa_stream_connect_record()");
2006 pa_ret = pa_context_errno(virtual_stream->pa_context);
2007 ret = MM_ERROR_SOUND_INTERNAL;
2008 goto ERROR_WITH_UNLOCK;
2012 /* wait for ready state of the stream */
2014 pa_stream_state_t state;
2015 state = pa_stream_get_state(virtual_stream->pa_stream[i]);
2016 if (state == PA_STREAM_READY)
2018 if (!PA_STREAM_IS_GOOD(state)) {
2019 LOGE("stream(%d) is not good, state : %d", i, state);
2020 pa_ret = pa_context_errno(virtual_stream->pa_context);
2021 ret = MM_ERROR_SOUND_INTERNAL;
2022 goto ERROR_WITH_UNLOCK;
2025 pa_threaded_mainloop_wait(virtual_stream->pa_mainloop);
2029 virtual_stream->state = _VSTREAM_STATE_RUNNING;
2031 /* UNLOCK the pa_threaded_mainloop */
2032 pa_threaded_mainloop_unlock(virtual_stream->pa_mainloop);
2037 /* UNLOCK the pa_threaded_mainloop */
2038 pa_threaded_mainloop_unlock(virtual_stream->pa_mainloop);
2040 for (i = 0; i < SOUND_STREAM_DIRECTION_MAX; i++) {
2041 if (virtual_stream->pa_stream[i]) {
2042 pa_stream_unref(virtual_stream->pa_stream[i]);
2043 virtual_stream->pa_stream[i] = NULL;
2046 LOGE("pa_ret(%d)", pa_ret);
2052 int _stop_virtual_stream(virtual_sound_stream_info_s *virtual_stream)
2054 int ret = MM_ERROR_NONE;
2057 SM_INSTANCE_CHECK_FOR_PRIV(virtual_stream);
2058 SM_STATE_CHECK_FOR_PRIV(virtual_stream, _VSTREAM_STATE_RUNNING);
2060 /* LOCK the pa_threaded_mainloop */
2061 pa_threaded_mainloop_lock(virtual_stream->pa_mainloop);
2063 for (i = 0; i < SOUND_STREAM_DIRECTION_MAX; i++) {
2064 if (virtual_stream->pa_stream[i]) {
2065 pa_stream_disconnect(virtual_stream->pa_stream[i]);
2067 /* wait for terminated state of the stream */
2069 pa_stream_state_t state;
2070 state = pa_stream_get_state(virtual_stream->pa_stream[i]);
2071 if (state == PA_STREAM_TERMINATED)
2073 pa_threaded_mainloop_wait(virtual_stream->pa_mainloop);
2076 pa_stream_unref(virtual_stream->pa_stream[i]);
2077 virtual_stream->pa_stream[i] = NULL;
2081 /* UNLOCK the pa_threaded_mainloop */
2082 pa_threaded_mainloop_unlock(virtual_stream->pa_mainloop);
2084 virtual_stream->state = _VSTREAM_STATE_READY;