4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
27 #include <sys/types.h>
36 #include <mm_message.h>
38 #include "include/mm_sound_private.h"
39 #include "include/mm_sound.h"
40 #include "include/mm_sound_utils.h"
41 #include "include/mm_sound_common.h"
42 #include "include/mm_sound_pa_client.h"
44 #include <audio-session-manager.h>
45 #include <mm_session.h>
46 #include <mm_session_private.h>
49 #define _MIN_SYSTEM_SAMPLERATE 8000
50 #define _MAX_SYSTEM_SAMPLERATE 48000
51 #define RW_LOG_PERIOD 5 /* period(second) for print log in capture read or play write*/
53 #define PCM_LOCK_INTERNAL(LOCK) do { pthread_mutex_lock(LOCK); } while (0)
54 #define PCM_UNLOCK_INTERNAL(LOCK) do { pthread_mutex_unlock(LOCK); } while (0)
55 #define PCM_LOCK_DESTROY_INTERNAL(LOCK) do { pthread_mutex_destroy(LOCK); } while (0)
57 int g_capture_h_count = 0;
58 #define PCM_CAPTURE_H_COUNT_INC() do { g_capture_h_count++; } while (0)
59 #define PCM_CAPTURE_H_COUNT_DEC() do { g_capture_h_count--; if(g_capture_h_count < 0) debug_error ("g_capture_h_count[%d] is not valid, check application side for proper handle usage\n", g_capture_h_count); } while (0)
60 #define PCM_CAPTURE_H_COUNT_GET(x_val) do { x_val = g_capture_h_count; } while (0)
63 MMSOUND_SESSION_TYPE_PLAYBACK,
64 MMSOUND_SESSION_TYPE_CAPTURE,
65 }MMSound_session_type_e;
68 MMSOUND_SESSION_REGISTERED_INTERNALLY,
69 MMSOUND_SESSION_REGISTERED_BY_OUTSIDE_MEDIA,
75 ASM_sound_events_t asm_event;
77 int session_registered_type;
82 ASM_resource_t resource;
83 pthread_mutex_t pcm_mutex_internal;
84 MMMessageCallback msg_cb;
88 MMSoundPcmChannel_t channel;
89 MMSoundPcmFormat_t format;
90 unsigned int byte_per_sec;
96 static int _pcm_sound_start (MMSoundPcmHandle_t handle);
97 static int _pcm_sound_stop_internal (MMSoundPcmHandle_t handle);
98 static int _pcm_sound_stop(MMSoundPcmHandle_t handle);
99 static void _sound_pcm_send_message (mm_sound_pcm_t *pcmHandle, int message, int code);
100 static int _pcm_sound_ignore_session (MMSoundPcmHandle_t handle, MMSound_session_type_e type);
102 static char* _get_channel_str(MMSoundPcmChannel_t channel)
104 if (channel == MMSOUND_PCM_MONO)
106 else if (channel == MMSOUND_PCM_STEREO)
112 static char* _get_format_str(MMSoundPcmFormat_t format)
114 if (format == MMSOUND_PCM_S16_LE)
116 else if (format == MMSOUND_PCM_U8)
122 static int _get_asm_information(MMSound_session_type_e session_type, ASM_sound_events_t *type, int *options, int *session_registered_type)
124 int cur_session = MM_SESSION_TYPE_MEDIA;
125 int session_options = 0;
126 int ret = MM_ERROR_NONE;
127 ASM_sound_events_t asm_event;
130 return MM_ERROR_SOUND_INVALID_POINTER;
132 /* read session information */
133 if(_mm_session_util_read_information(-1, &cur_session, &session_options) < 0) {
134 debug_log("Read Session Information failed. Set default \"Media\" type\n");
135 if (session_type == MMSOUND_SESSION_TYPE_PLAYBACK) {
136 cur_session = MM_SESSION_TYPE_MEDIA;
137 } else if (session_type == MMSOUND_SESSION_TYPE_CAPTURE) {
138 cur_session = MM_SESSION_TYPE_MEDIA_RECORD;
140 ret = _mm_session_util_write_type(-1, cur_session);
142 debug_error("_mm_session_util_write_type() failed\n");
143 return MM_ERROR_SOUND_INTERNAL;
145 *session_registered_type = MMSOUND_SESSION_REGISTERED_INTERNALLY;
147 /* session was already registered */
148 if (session_type == MMSOUND_SESSION_TYPE_CAPTURE) {
149 if (cur_session > MM_SESSION_TYPE_MEDIA && cur_session < MM_SESSION_TYPE_CALL) {
150 debug_error("current session type(%d) does not support capture\n", session_type);
151 return MM_ERROR_POLICY_BLOCKED;
152 } else if (cur_session == MM_SESSION_TYPE_MEDIA) {
153 debug_log("session was already registered to MEDIA, update it to MEDIA_RECORD");
154 /* update session information */
155 ret = _mm_session_util_write_information(-1, MM_SESSION_TYPE_MEDIA_RECORD, session_options);
157 debug_error("_mm_session_util_write_type() failed\n");
158 return MM_ERROR_SOUND_INTERNAL;
160 *session_registered_type = MMSOUND_SESSION_REGISTERED_BY_OUTSIDE_MEDIA;
165 /* convert MM_SESSION_TYPE to ASM_EVENT_TYPE */
168 case MM_SESSION_TYPE_MEDIA:
169 case MM_SESSION_TYPE_MEDIA_RECORD:
170 asm_event = ASM_EVENT_MEDIA_MMSOUND;
172 case MM_SESSION_TYPE_NOTIFY:
173 asm_event = ASM_EVENT_NOTIFY;
175 case MM_SESSION_TYPE_ALARM:
176 asm_event = ASM_EVENT_ALARM;
178 case MM_SESSION_TYPE_CALL:
179 asm_event = ASM_EVENT_CALL;
181 case MM_SESSION_TYPE_VIDEOCALL:
182 asm_event = ASM_EVENT_VIDEOCALL;
184 case MM_SESSION_TYPE_VOIP:
185 asm_event = ASM_EVENT_VOIP;
187 case MM_SESSION_TYPE_EMERGENCY:
188 asm_event = ASM_EVENT_EMERGENCY;
190 case MM_SESSION_TYPE_VOICE_RECOGNITION:
191 asm_event = ASM_EVENT_VOICE_RECOGNITION;
193 case MM_SESSION_TYPE_RECORD_AUDIO:
194 asm_event = ASM_EVENT_MMCAMCORDER_AUDIO;
196 case MM_SESSION_TYPE_RECORD_VIDEO:
197 asm_event = ASM_EVENT_MMCAMCORDER_VIDEO;
200 debug_error("Unexpected %d\n", cur_session);
201 return MM_ERROR_SOUND_INTERNAL;
205 *options = session_options;
206 return MM_ERROR_NONE;
209 static bool _check_skip_session_type_for_capture(mm_sound_pcm_t *pcmHandle, mm_sound_source_type_e type)
212 int session_result = MM_ERROR_NONE;
215 case SUPPORT_SOURCE_TYPE_DEFAULT:
216 case SUPPORT_SOURCE_TYPE_VOICECONTROL:
219 case SUPPORT_SOURCE_TYPE_MIRRORING:
223 debug_error("Unexpected %d\n", type);
227 int capture_h_count = 0;
228 PCM_CAPTURE_H_COUNT_GET(capture_h_count);
229 if (capture_h_count == 1) { /* if it is last one */
230 /* Recover session information */
231 session_result = _mm_session_util_write_information(-1, MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options);
232 if (session_result) {
233 debug_error("_mm_session_util_write_information() [type %d, options %x] failed[%x]", MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options, session_result);
240 static void _sound_pcm_send_message (mm_sound_pcm_t *pcmHandle, int message, int code)
243 if (pcmHandle->msg_cb) {
244 MMMessageParamType msg;
245 msg.union_type = MM_MSG_UNION_CODE;
248 debug_log ("calling msg callback(%p) with message(%d), code(%d), msg callback param(%p)\n",
249 pcmHandle->msg_cb, message, msg.code, pcmHandle->msg_cb_param);
250 ret = pcmHandle->msg_cb(message, &msg, pcmHandle->msg_cb_param);
251 debug_log ("msg callback returned (%d)\n", ret);
253 debug_log ("No pcm msg callback\n");
257 static ASM_cb_result_t sound_pcm_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void *cb_data)
259 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t *)cb_data;
260 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
261 int message = MM_MESSAGE_SOUND_PCM_INTERRUPTED;
263 /* Check input param */
264 if(pcmHandle == NULL) {
265 debug_error("sound_pcm_asm_callback cb_data is null\n");
269 debug_log ("command = %d, handle = %p, is_started = %d\n",command, pcmHandle, pcmHandle->is_started);
272 case ASM_COMMAND_PAUSE:
273 case ASM_COMMAND_STOP:
275 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
276 _pcm_sound_stop_internal (pcmHandle);
277 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
278 cb_res = ASM_CB_RES_PAUSE;
281 case ASM_COMMAND_RESUME:
282 cb_res = ASM_CB_RES_IGNORE;
283 message = MM_MESSAGE_READY_TO_RESUME;
286 case ASM_COMMAND_PLAY:
287 case ASM_COMMAND_NONE:
288 debug_error ("Not an expected case!!!!\n");
292 /* execute user callback if callback available */
293 _sound_pcm_send_message (pcmHandle, message, event_src);
298 static int _pcm_sound_ignore_session (MMSoundPcmHandle_t handle, MMSound_session_type_e type)
300 int result = MM_ERROR_NONE;
301 int session_result = MM_ERROR_NONE;
302 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
307 /* Check input param */
308 if(pcmHandle == NULL) {
309 debug_error ("Handle is null, return Invalid Argument\n");
310 result = MM_ERROR_INVALID_ARGUMENT;
314 if (pcmHandle->is_started) {
315 debug_error ("Operation is not permitted while started\n");
316 result = MM_ERROR_SOUND_INVALID_STATE;
320 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
323 if (pcmHandle->skip_session == false && pcmHandle->asm_handle) {
324 if(!ASM_unregister_sound(pcmHandle->asm_handle, pcmHandle->asm_event, &errorcode)) {
325 debug_error("ASM_unregister failed with 0x%x\n", errorcode);
326 result = MM_ERROR_SOUND_INTERNAL;
328 pcmHandle->skip_session = true;
329 pcmHandle->asm_handle = 0;
331 if (type == MMSOUND_SESSION_TYPE_CAPTURE){
332 int capture_h_count = 0;
333 PCM_CAPTURE_H_COUNT_GET(capture_h_count);
334 if (capture_h_count == 1) { /* if it is last one */
335 /* Recover session information */
336 session_result = _mm_session_util_write_information(-1, MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options);
337 if (session_result) {
338 debug_error("_mm_session_util_write_information() [type %d, options %x] failed[%x]", MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options, session_result);
343 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
351 int mm_sound_pcm_capture_open(MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format)
353 mm_sound_pcm_t *pcmHandle = NULL;
355 int result = MM_ERROR_NONE;
358 int ret = MM_ERROR_NONE;
360 int volume_config = 0;
362 char stream_type[MM_SOUND_STREAM_TYPE_LEN] = {0, };
364 mm_sound_handle_route_info route_info;
365 route_info.policy = HANDLE_ROUTE_POLICY_DEFAULT;
367 debug_warning ("enter : rate=[%d], channel=[%x], format=[%x]\n", rate, channel, format);
369 if (rate < _MIN_SYSTEM_SAMPLERATE || rate > _MAX_SYSTEM_SAMPLERATE) {
370 debug_error("unsupported sample rate %u", rate);
371 return MM_ERROR_SOUND_DEVICE_INVALID_SAMPLERATE;
378 case MMSOUND_PCM_MONO:
381 case MMSOUND_PCM_STEREO:
386 debug_error("Unsupported channel type\n");
387 return MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL;
393 ss.format = PA_SAMPLE_U8;
395 case MMSOUND_PCM_S16_LE:
396 ss.format = PA_SAMPLE_S16LE;
399 debug_error("Unsupported format type\n");
400 return MM_ERROR_SOUND_DEVICE_INVALID_FORMAT;
403 pcmHandle = calloc(sizeof(mm_sound_pcm_t), 1);
404 if(pcmHandle == NULL)
405 return MM_ERROR_OUT_OF_MEMORY;
407 ret_mutex = pthread_mutex_init(&pcmHandle->pcm_mutex_internal, NULL);
411 return MM_ERROR_OUT_OF_MEMORY;
415 /* get session information */
416 ret = _get_asm_information(MMSOUND_SESSION_TYPE_CAPTURE, &pcmHandle->asm_event, &pcmHandle->asm_options, &pcmHandle->session_registered_type);
418 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
422 PCM_CAPTURE_H_COUNT_INC();
425 if(pcmHandle->asm_event != ASM_EVENT_CALL &&
426 pcmHandle->asm_event != ASM_EVENT_VIDEOCALL &&
427 pcmHandle->asm_event != ASM_EVENT_VOIP &&
428 pcmHandle->asm_event != ASM_EVENT_VOICE_RECOGNITION &&
429 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_AUDIO &&
430 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_VIDEO &&
431 pcmHandle->skip_session == false) {
432 if(!ASM_register_sound(-1, &pcmHandle->asm_handle, pcmHandle->asm_event,
433 /* ASM_STATE_PLAYING */ ASM_STATE_NONE, sound_pcm_asm_callback, (void*)pcmHandle, pcmHandle->resource, &errorcode))
435 debug_error("ASM_register_sound() failed 0x%x\n", errorcode);
436 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
438 PCM_CAPTURE_H_COUNT_DEC();
439 return MM_ERROR_POLICY_BLOCKED;
441 if(!ASM_set_session_option(pcmHandle->asm_handle, pcmHandle->asm_options, &errorcode)) {
442 debug_error("ASM_set_session_option() failed 0x%x\n", errorcode);
445 pcmHandle->skip_session = true;
449 if(pcmHandle->asm_event == ASM_EVENT_VOIP)
450 volume_config = VOLUME_TYPE_VOIP;
452 volume_config = VOLUME_TYPE_SYSTEM; //dose not effect at capture mode
454 mm_sound_convert_volume_type_to_stream_type(volume_config, stream_type);
455 pcmHandle->handle = mm_sound_pa_open(HANDLE_MODE_INPUT, &route_info, 0, volume_config, &ss, NULL, &size, stream_type, -1);
456 if(pcmHandle->handle<0) {
457 result = pcmHandle->handle;
458 debug_error("Device Open Error 0x%x\n", result);
459 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
461 PCM_CAPTURE_H_COUNT_DEC();
465 pcmHandle->is_playback = false;
466 pcmHandle->rate = rate;
467 pcmHandle->channel = channel;
468 pcmHandle->format = format;
469 pcmHandle->byte_per_sec = rate*(format==MMSOUND_PCM_U8?1:2)*(channel==MMSOUND_PCM_MONO?1:2);
471 /* Set handle to return */
472 *handle = (MMSoundPcmHandle_t)pcmHandle;
474 debug_warning ("success : handle=[%p], size=[%d]\n", pcmHandle, size);
480 int mm_sound_pcm_capture_open_ex(MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format, mm_sound_source_type_e source_type)
482 mm_sound_pcm_t *pcmHandle = NULL;
484 int result = MM_ERROR_NONE;
488 int volume_config = 0;
490 mm_sound_handle_route_info route_info;
491 route_info.policy = HANDLE_ROUTE_POLICY_DEFAULT;
492 char stream_type[MM_SOUND_STREAM_TYPE_LEN] = {0, };
494 debug_warning ("enter : rate=[%d Hz], channel=[%x][%s], format=[%x][%s], source_type=[%x]\n",
495 rate, channel, _get_channel_str(channel), format, _get_format_str(format), source_type);
497 if (rate < _MIN_SYSTEM_SAMPLERATE || rate > _MAX_SYSTEM_SAMPLERATE) {
498 debug_error("unsupported sample rate %u", rate);
499 return MM_ERROR_SOUND_DEVICE_INVALID_SAMPLERATE;
506 case MMSOUND_PCM_MONO:
509 case MMSOUND_PCM_STEREO:
514 debug_error("Unsupported channel type\n");
515 return MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL;
521 ss.format = PA_SAMPLE_U8;
523 case MMSOUND_PCM_S16_LE:
524 ss.format = PA_SAMPLE_S16LE;
527 debug_error("Unsupported format type\n");
528 return MM_ERROR_SOUND_DEVICE_INVALID_FORMAT;
531 pcmHandle = calloc(sizeof(mm_sound_pcm_t), 1);
532 if(pcmHandle == NULL)
533 return MM_ERROR_OUT_OF_MEMORY;
535 ret_mutex = pthread_mutex_init(&pcmHandle->pcm_mutex_internal, NULL);
539 return MM_ERROR_OUT_OF_MEMORY;
543 /* get session information */
544 if(MM_ERROR_NONE != _get_asm_information(MMSOUND_SESSION_TYPE_CAPTURE, &pcmHandle->asm_event, &pcmHandle->asm_options, &pcmHandle->session_registered_type)) {
545 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
547 return MM_ERROR_POLICY_INTERNAL;
549 PCM_CAPTURE_H_COUNT_INC();
551 switch (source_type) {
552 case SUPPORT_SOURCE_TYPE_VOIP:
553 route_info.policy = HANDLE_ROUTE_POLICY_IN_VOIP;
555 case SUPPORT_SOURCE_TYPE_MIRRORING:
556 route_info.policy = HANDLE_ROUTE_POLICY_IN_MIRRORING;
558 case SUPPORT_SOURCE_TYPE_DEFAULT:
559 case SUPPORT_SOURCE_TYPE_VIDEOCALL:
560 case SUPPORT_SOURCE_TYPE_VOICERECORDING:
562 case SUPPORT_SOURCE_TYPE_VOICECONTROL:
563 pcmHandle->asm_event = ASM_EVENT_EXCLUSIVE_RESOURCE;
564 pcmHandle->resource = ASM_RESOURCE_VOICECONTROL;
571 if(pcmHandle->asm_event != ASM_EVENT_CALL &&
572 pcmHandle->asm_event != ASM_EVENT_VIDEOCALL &&
573 pcmHandle->asm_event != ASM_EVENT_VOIP &&
574 pcmHandle->asm_event != ASM_EVENT_VOICE_RECOGNITION &&
575 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_AUDIO &&
576 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_VIDEO &&
577 pcmHandle->skip_session == false &&
578 _check_skip_session_type_for_capture(pcmHandle, source_type) == false) {
579 if(!ASM_register_sound(-1, &pcmHandle->asm_handle, pcmHandle->asm_event,
580 /* ASM_STATE_PLAYING */ ASM_STATE_NONE, sound_pcm_asm_callback, (void*)pcmHandle, pcmHandle->resource, &errorcode)) {
581 debug_error("ASM_register_sound() failed 0x%x\n", errorcode);
582 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
584 PCM_CAPTURE_H_COUNT_DEC();
585 return MM_ERROR_POLICY_BLOCKED;
587 if(!ASM_set_session_option(pcmHandle->asm_handle, pcmHandle->asm_options, &errorcode)) {
588 debug_error("ASM_set_session_option() failed 0x%x\n", errorcode);
591 pcmHandle->skip_session = true;
594 /* For Video Call or VoIP select volume type VOLUME_TYPE_VOIP for sink/source */
595 if( (pcmHandle->asm_event == ASM_EVENT_VIDEOCALL) || (pcmHandle->asm_event == ASM_EVENT_VOIP) )
596 volume_config = VOLUME_TYPE_VOIP;
598 volume_config = VOLUME_TYPE_SYSTEM; //dose not effect at capture mode
600 mm_sound_convert_volume_type_to_stream_type(volume_config, stream_type);
602 debug_error("mm_sound_convert_volume_type_to_stream_type failed (0x%x)", result);
606 pcmHandle->handle = mm_sound_pa_open(HANDLE_MODE_INPUT, &route_info, 0, volume_config, &ss, NULL, &size, stream_type, -1);
607 if(pcmHandle->handle<0) {
608 result = pcmHandle->handle;
609 debug_error("Device Open Error 0x%x\n", result);
610 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
612 PCM_CAPTURE_H_COUNT_DEC();
616 pcmHandle->is_playback = false;
617 pcmHandle->rate = rate;
618 pcmHandle->channel = channel;
619 pcmHandle->format = format;
620 pcmHandle->byte_per_sec = rate*(format==MMSOUND_PCM_U8?1:2)*(channel==MMSOUND_PCM_MONO?1:2);
622 /* Set handle to return */
623 *handle = (MMSoundPcmHandle_t)pcmHandle;
625 debug_warning ("success : handle=[%p], size=[%d]\n", handle, size);
631 int mm_sound_pcm_capture_ignore_session(MMSoundPcmHandle_t *handle)
633 return _pcm_sound_ignore_session(handle, MMSOUND_SESSION_TYPE_CAPTURE);
636 static int _pcm_sound_start (MMSoundPcmHandle_t handle)
638 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
644 /* Check input param */
645 if(pcmHandle == NULL) {
646 debug_error ("Handle is null, return Invalid Argument\n");
647 ret = MM_ERROR_INVALID_ARGUMENT;
651 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
653 if (pcmHandle->skip_session == false) {
654 /* ASM set state to PLAYING */
655 if (!ASM_set_sound_state(pcmHandle->asm_handle, pcmHandle->asm_event, ASM_STATE_PLAYING, pcmHandle->resource, &errorcode)) {
656 debug_error("ASM_set_sound_state(PLAYING) failed 0x%x\n", errorcode);
657 ret = MM_ERROR_POLICY_BLOCKED;
663 pcmHandle->is_started = true;
666 mm_sound_pa_cork(pcmHandle->handle, 0);
669 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
677 int mm_sound_pcm_capture_start(MMSoundPcmHandle_t handle)
679 int ret = MM_ERROR_NONE;
681 debug_warning ("enter : handle=[%p]\n", handle);
683 ret = _pcm_sound_start (handle);
684 if (ret != MM_ERROR_NONE) {
685 debug_error ("_pcm_sound_start() failed (%x)\n", ret);
690 debug_warning ("leave : handle=[%p], ret=[0x%X]", handle, ret);
695 static int _pcm_sound_stop_internal (MMSoundPcmHandle_t handle)
697 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
699 /* Check input param */
700 if(pcmHandle == NULL)
701 return MM_ERROR_INVALID_ARGUMENT;
704 if (pcmHandle->is_started == false) {
705 debug_warning ("Can't stop because not started\n");
706 return MM_ERROR_SOUND_INVALID_STATE;
709 /* Drain if playback mode */
710 if (pcmHandle->is_playback) {
711 if(MM_ERROR_NONE != mm_sound_pa_drain(pcmHandle->handle)) {
712 debug_error("drain failed\n");
717 pcmHandle->is_started = false;
720 return mm_sound_pa_cork(pcmHandle->handle, 1);
723 static int _pcm_sound_stop(MMSoundPcmHandle_t handle)
725 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
727 int ret = MM_ERROR_NONE;
731 /* Check input param */
732 if(pcmHandle == NULL) {
733 debug_error ("Handle is null, return Invalid Argument\n");
734 ret = MM_ERROR_INVALID_ARGUMENT;
738 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
740 /* Do stop procedure */
741 ret = _pcm_sound_stop_internal(handle);
742 if (ret == MM_ERROR_NONE) {
743 /* Set ASM State to STOP */
744 if (pcmHandle->skip_session == false) {
745 if (!ASM_set_sound_state(pcmHandle->asm_handle, pcmHandle->asm_event, ASM_STATE_STOP, pcmHandle->resource, &errorcode)) {
746 debug_error("ASM_set_sound_state(STOP) failed 0x%x\n", errorcode);
747 ret = MM_ERROR_POLICY_BLOCKED;
754 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
761 int mm_sound_pcm_capture_stop(MMSoundPcmHandle_t handle)
765 debug_warning ("enter : handle=[%p]\n", handle);
766 ret = _pcm_sound_stop(handle);
767 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, ret);
773 int mm_sound_pcm_capture_flush(MMSoundPcmHandle_t handle)
776 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
778 /* Check input param */
779 if(pcmHandle == NULL)
780 return MM_ERROR_INVALID_ARGUMENT;
782 debug_warning ("enter : handle=[%p]\n", handle);
783 ret = mm_sound_pa_flush(pcmHandle->handle);
784 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, ret);
790 int mm_sound_pcm_capture_read(MMSoundPcmHandle_t handle, void *buffer, const unsigned int length )
793 static int read_byte = 0;
794 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
796 /* Check input param */
797 if(pcmHandle == NULL) {
798 debug_error ("Handle is null, return Invalid Argument\n");
799 ret = MM_ERROR_INVALID_ARGUMENT;
802 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
805 debug_error("Invalid buffer pointer\n");
806 ret = MM_ERROR_SOUND_INVALID_POINTER;
810 debug_error ("length is 0, return 0\n");
815 /* Check State : return fail if not started */
816 if (!pcmHandle->is_started) {
817 /* not started, return fail */
818 debug_error ("Not started yet, return Invalid State \n");
819 ret = MM_ERROR_SOUND_INVALID_STATE;
824 ret = mm_sound_pa_read(pcmHandle->handle, buffer, length);
827 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
831 if(ret > 0 && read_byte>pcmHandle->byte_per_sec*RW_LOG_PERIOD){
832 debug_log ("(%d)/read-once, (%d)/%dsec bytes read \n", length, read_byte, RW_LOG_PERIOD);
839 int mm_sound_pcm_capture_close(MMSoundPcmHandle_t handle)
841 int result = MM_ERROR_NONE;
842 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
845 debug_warning ("enter : handle=[%p]\n", handle);
847 /* Check input param */
848 if(pcmHandle == NULL) {
849 debug_error ("Handle is null, return Invalid Argument\n");
850 result = MM_ERROR_INVALID_ARGUMENT;
853 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
855 if(MM_ERROR_NONE != mm_sound_pa_close(pcmHandle->handle)) {
856 debug_error("handle close failed 0x%X", result);
857 result = MM_ERROR_SOUND_INTERNAL;
862 if (pcmHandle->skip_session == false) {
863 if(pcmHandle->asm_event != ASM_EVENT_CALL &&
864 pcmHandle->asm_event != ASM_EVENT_VIDEOCALL &&
865 pcmHandle->asm_event != ASM_EVENT_VOIP &&
866 pcmHandle->asm_event != ASM_EVENT_VOICE_RECOGNITION &&
867 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_AUDIO &&
868 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_VIDEO) {
869 if (pcmHandle->asm_handle) {
870 if(!ASM_unregister_sound(pcmHandle->asm_handle, pcmHandle->asm_event, &errorcode)) {
871 debug_error("ASM_unregister failed with 0x%x\n", errorcode);
872 result = MM_ERROR_SOUND_INTERNAL;
877 int capture_h_count = 0;
878 PCM_CAPTURE_H_COUNT_GET(capture_h_count);
879 if (capture_h_count == 1) { /* if it is last one */
880 /* Recover session information */
881 result = _mm_session_util_write_information(-1, MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options);
883 debug_error("_mm_session_util_write_information() [type %d, options %x] failed[%x]", MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options, result);
889 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
891 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, result);
894 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
898 PCM_CAPTURE_H_COUNT_DEC();
904 int mm_sound_pcm_set_message_callback (MMSoundPcmHandle_t handle, MMMessageCallback callback, void *user_param)
906 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
908 if(pcmHandle == NULL || callback == NULL)
909 return MM_ERROR_INVALID_ARGUMENT;
911 pcmHandle->msg_cb = callback;
912 pcmHandle->msg_cb_param = user_param;
914 debug_log ("set pcm message callback (%p,%p)\n", callback, user_param);
916 return MM_ERROR_NONE;
920 int mm_sound_pcm_play_open_ex (MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format, int volume_config, ASM_sound_events_t asm_event)
922 mm_sound_pcm_t *pcmHandle = NULL;
924 int result = MM_ERROR_NONE;
926 int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config);
928 mm_sound_handle_route_info route_info;
929 route_info.policy = HANDLE_ROUTE_POLICY_OUT_AUTO;
930 char stream_type[MM_SOUND_STREAM_TYPE_LEN] = {0, };
934 debug_warning ("enter : rate=[%d], channel=[%x][%s], format=[%x][%s], volconf=[%d], event=[%d]\n",
935 rate, channel, _get_channel_str(channel), format, _get_format_str(format), volume_config, asm_event);
937 /* Check input param */
938 if (volume_type < 0 || volume_type >= VOLUME_TYPE_MAX) {
939 debug_error("Volume type is invalid %d\n", volume_type);
940 return MM_ERROR_INVALID_ARGUMENT;
942 if (rate < _MIN_SYSTEM_SAMPLERATE || rate > _MAX_SYSTEM_SAMPLERATE) {
943 debug_error("unsupported sample rate %u", rate);
944 return MM_ERROR_SOUND_DEVICE_INVALID_SAMPLERATE;
951 case MMSOUND_PCM_MONO:
954 case MMSOUND_PCM_STEREO:
958 debug_error("Unsupported channel type\n");
959 return MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL;
965 ss.format = PA_SAMPLE_U8;
967 case MMSOUND_PCM_S16_LE:
968 ss.format = PA_SAMPLE_S16LE;
971 debug_error("Unsupported format type\n");
972 return MM_ERROR_SOUND_DEVICE_INVALID_FORMAT;
975 pcmHandle = calloc(sizeof(mm_sound_pcm_t),1);
976 if(pcmHandle == NULL)
977 return MM_ERROR_OUT_OF_MEMORY;
979 ret_mutex = pthread_mutex_init(&pcmHandle->pcm_mutex_internal, NULL);
981 debug_error ("error mutex init....%d");
982 result = MM_ERROR_OUT_OF_MEMORY;
987 debug_log ("session start : input asm_event = %d-------------\n", asm_event);
988 if (asm_event == ASM_EVENT_MONITOR) {
989 debug_log ("Skip SESSION for event (%d)\n", asm_event);
990 pcmHandle->skip_session = true;
991 } else if (asm_event == ASM_EVENT_NONE) {
992 /* get session information */
993 if(MM_ERROR_NONE != _get_asm_information(MMSOUND_SESSION_TYPE_PLAYBACK, &pcmHandle->asm_event, &pcmHandle->asm_options, &pcmHandle->session_registered_type)) {
994 debug_error ("_get_asm_information failed....\n");
995 result = MM_ERROR_POLICY_INTERNAL;
999 // should be fixed. call forwarding engine(voip) use call volume type.
1000 if(volume_type == VOLUME_TYPE_CALL) {
1001 pcmHandle->skip_session = true;
1004 if(pcmHandle->asm_event != ASM_EVENT_CALL &&
1005 pcmHandle->asm_event != ASM_EVENT_VIDEOCALL &&
1006 pcmHandle->asm_event != ASM_EVENT_VOIP &&
1007 pcmHandle->asm_event != ASM_EVENT_VOICE_RECOGNITION &&
1008 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_AUDIO &&
1009 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_VIDEO &&
1010 pcmHandle->skip_session == false) {
1013 if(!ASM_register_sound(-1, &pcmHandle->asm_handle, pcmHandle->asm_event,
1014 ASM_STATE_NONE, sound_pcm_asm_callback, (void*)pcmHandle, pcmHandle->resource, &errorcode)) {
1015 debug_error("ASM_register_sound() failed 0x%x\n", errorcode);
1016 result = MM_ERROR_POLICY_BLOCKED;
1019 if(!ASM_set_session_option(pcmHandle->asm_handle, pcmHandle->asm_options, &errorcode)) {
1020 debug_error("ASM_set_session_option() failed 0x%x\n", errorcode);
1023 pcmHandle->skip_session = true;
1026 /* register asm using asm_event input */
1027 if(!ASM_register_sound(-1, &pcmHandle->asm_handle, asm_event,
1028 ASM_STATE_NONE, NULL, (void*)pcmHandle, pcmHandle->resource, &errorcode)) {
1029 debug_error("ASM_register_sound() failed 0x%x\n", errorcode);
1030 result = MM_ERROR_POLICY_BLOCKED;
1037 mm_sound_convert_volume_type_to_stream_type(volume_type, stream_type);
1038 pcmHandle->handle = mm_sound_pa_open(HANDLE_MODE_OUTPUT, &route_info, 0, volume_config, &ss, NULL, &size, stream_type, -1);
1039 if(!pcmHandle->handle) {
1040 debug_error("Device Open Error 0x%x\n");
1041 result = MM_ERROR_SOUND_DEVICE_NOT_OPENED;
1045 /* Set corked state, uncork will be done at prepare()
1046 FIXME: we should consider audio_open() return with corked state */
1047 result = mm_sound_pa_cork(pcmHandle->handle, 1);
1049 debug_error("Cork Error 0x%x\n", result);
1050 result = MM_ERROR_SOUND_INTERNAL;
1054 pcmHandle->is_playback = true;
1055 pcmHandle->rate = rate;
1056 pcmHandle->channel = channel;
1057 pcmHandle->format = format;
1058 pcmHandle->byte_per_sec = rate*(format==MMSOUND_PCM_U8?1:2)*(channel==MMSOUND_PCM_MONO?1:2);
1059 pcmHandle->volume_config = volume_config;
1061 /* Set handle to return */
1062 *handle = (MMSoundPcmHandle_t)pcmHandle;
1064 debug_warning ("success : handle=[%p], size=[%d]\n", pcmHandle, size);
1069 if(ret_mutex == 0) {
1070 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
1078 int mm_sound_pcm_play_open_no_session(MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format, int volume_config)
1080 return mm_sound_pcm_play_open_ex (handle, rate, channel, format, volume_config, ASM_EVENT_MONITOR);
1084 int mm_sound_pcm_play_open(MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format, int volume_config)
1086 return mm_sound_pcm_play_open_ex (handle, rate, channel, format, volume_config, ASM_EVENT_NONE);
1090 int mm_sound_pcm_play_start(MMSoundPcmHandle_t handle)
1094 debug_warning ("enter : handle=[%p]\n", handle);
1095 ret = _pcm_sound_start (handle);
1096 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, ret);
1102 int mm_sound_pcm_play_stop(MMSoundPcmHandle_t handle)
1106 debug_warning ("enter : handle=[%p]\n", handle);
1107 ret = _pcm_sound_stop(handle);
1108 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, ret);
1114 int mm_sound_pcm_play_drain(MMSoundPcmHandle_t handle)
1117 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1119 /* Check input param */
1120 if(pcmHandle == NULL)
1121 return MM_ERROR_INVALID_ARGUMENT;
1123 debug_warning ("enter : handle=[%p]\n", handle);
1124 ret = mm_sound_pa_drain(pcmHandle->handle);
1125 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, ret);
1131 int mm_sound_pcm_play_flush(MMSoundPcmHandle_t handle)
1134 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1136 /* Check input param */
1137 if(pcmHandle == NULL)
1138 return MM_ERROR_INVALID_ARGUMENT;
1140 debug_warning ("enter : handle=[%p]\n", handle);
1141 ret = mm_sound_pa_flush(pcmHandle->handle);
1142 debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, ret);
1148 int mm_sound_pcm_play_write(MMSoundPcmHandle_t handle, void* ptr, unsigned int length_byte)
1151 static int written_byte = 0;
1152 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1154 /* Check input param */
1155 if(pcmHandle == NULL) {
1156 debug_error ("Handle is null, return Invalid Argument\n");
1157 ret = MM_ERROR_INVALID_ARGUMENT;
1161 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1164 debug_error("Invalid buffer pointer\n");
1165 ret = MM_ERROR_SOUND_INVALID_POINTER;
1168 if(length_byte == 0 ) {
1169 debug_error ("length is 0, return 0\n");
1174 /* Check State : return fail if not started */
1175 if (!pcmHandle->is_started) {
1176 /* not started, return fail */
1177 debug_error ("Not started yet, return Invalid State \n");
1178 ret = MM_ERROR_SOUND_INVALID_STATE;
1183 ret = mm_sound_pa_write(pcmHandle->handle, ptr, length_byte);
1187 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1189 written_byte += length_byte;
1190 if(ret > 0 && written_byte>pcmHandle->byte_per_sec*RW_LOG_PERIOD){
1191 debug_log ("(%d)/write-once, (%d)/%dsec bytes written\n", length_byte, written_byte, RW_LOG_PERIOD);
1199 int mm_sound_pcm_play_close(MMSoundPcmHandle_t handle)
1201 int result = MM_ERROR_NONE;
1202 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1205 debug_warning ("enter : handle=[%p]\n", handle);
1207 /* Check input param */
1208 if(pcmHandle == NULL) {
1209 debug_error ("Handle is null, return Invalid Argument\n");
1210 result = MM_ERROR_INVALID_ARGUMENT;
1213 PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1214 /* Drain if needed */
1215 if (pcmHandle->is_started) {
1216 /* stop() is not called before close(), drain is needed */
1217 if(MM_ERROR_NONE != mm_sound_pa_drain(pcmHandle->handle)) {
1218 debug_error("drain failed\n");
1219 result = MM_ERROR_SOUND_INTERNAL;
1223 pcmHandle->is_started = false;
1225 if(MM_ERROR_NONE != mm_sound_pa_close(pcmHandle->handle)) {
1226 debug_error("handle close failed. handle(%d)", pcmHandle->handle);
1227 result = MM_ERROR_SOUND_INTERNAL;
1231 if (pcmHandle->skip_session == false) {
1232 /* Unregister ASM */
1233 if(pcmHandle->asm_event != ASM_EVENT_CALL &&
1234 pcmHandle->asm_event != ASM_EVENT_VIDEOCALL &&
1235 pcmHandle->asm_event != ASM_EVENT_VOIP &&
1236 pcmHandle->asm_event != ASM_EVENT_VOICE_RECOGNITION &&
1237 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_AUDIO &&
1238 pcmHandle->asm_event != ASM_EVENT_MMCAMCORDER_VIDEO) {
1239 if(!ASM_unregister_sound(pcmHandle->asm_handle, pcmHandle->asm_event, &errorcode)) {
1240 debug_error("ASM_unregister failed with 0x%x\n", errorcode);
1246 PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1248 debug_warning ("leave : handle=[%p], result[0x%X]\n", handle, result);
1251 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
1260 int mm_sound_pcm_play_ignore_session(MMSoundPcmHandle_t *handle)
1262 return _pcm_sound_ignore_session(handle, MMSOUND_SESSION_TYPE_PLAYBACK);
1266 int mm_sound_pcm_get_latency(MMSoundPcmHandle_t handle, int *latency)
1268 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1271 /* Check input param */
1272 if (latency == NULL)
1273 return MM_ERROR_INVALID_ARGUMENT;
1275 if (MM_ERROR_NONE != mm_sound_pa_get_latency(pcmHandle->handle, &mlatency)) {
1276 debug_error("Get Latency Error");
1277 /* FIXME : is this correct return value? */
1278 return MM_ERROR_SOUND_DEVICE_NOT_OPENED;
1281 *latency = mlatency;
1283 return MM_ERROR_NONE;
1287 int mm_sound_pcm_is_started(MMSoundPcmHandle_t handle, bool *is_started)
1289 mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1291 /* Check input param */
1292 if (is_started == NULL)
1293 return MM_ERROR_INVALID_ARGUMENT;
1295 *is_started = pcmHandle->is_started;
1297 return MM_ERROR_NONE;