Move out dbus unrelated logic code from client_dbus.c
[platform/core/multimedia/libmm-sound.git] / mm_sound_pcm.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <memory.h>
24 #include <unistd.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <vconf.h>
30
31 #include <sys/stat.h>
32 #include <errno.h>
33
34 #include <mm_types.h>
35 #include <mm_error.h>
36 #include <mm_message.h>
37 #include <mm_debug.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"
43
44 #include <audio-session-manager.h>
45 #include <mm_session.h>
46 #include <mm_session_private.h>
47
48
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*/
52
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)
56
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)
61
62 typedef enum {
63         MMSOUND_SESSION_TYPE_PLAYBACK,
64         MMSOUND_SESSION_TYPE_CAPTURE,
65 }MMSound_session_type_e;
66
67 enum {
68         MMSOUND_SESSION_REGISTERED_INTERNALLY,
69         MMSOUND_SESSION_REGISTERED_BY_OUTSIDE_MEDIA,
70 };
71
72 typedef struct {
73         int                     handle;
74         int                     asm_handle;
75         ASM_sound_events_t      asm_event;
76         int                     asm_options;
77         int                     session_registered_type;
78
79         bool                    is_started;
80         bool                    is_playback;
81         bool                    skip_session;
82         ASM_resource_t resource;
83         pthread_mutex_t pcm_mutex_internal;
84         MMMessageCallback       msg_cb;
85         void *msg_cb_param;
86
87         unsigned int rate;
88         MMSoundPcmChannel_t channel;
89         MMSoundPcmFormat_t format;
90         unsigned int byte_per_sec;
91
92         int volume_config;
93
94 } mm_sound_pcm_t;
95
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);
101
102 static char* _get_channel_str(MMSoundPcmChannel_t channel)
103 {
104         if (channel == MMSOUND_PCM_MONO)
105                 return "Mono";
106         else if (channel == MMSOUND_PCM_STEREO)
107                 return "Stereo";
108         else
109                 return "Unknown";
110 }
111
112 static char* _get_format_str(MMSoundPcmFormat_t format)
113 {
114         if (format == MMSOUND_PCM_S16_LE)
115                 return "S16LE";
116         else if (format == MMSOUND_PCM_U8)
117                 return "U8";
118         else
119                 return "Unknown";
120 }
121
122 static int _get_asm_information(MMSound_session_type_e session_type, ASM_sound_events_t *type, int *options, int *session_registered_type)
123 {
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;
128
129         if(type == NULL)
130                 return MM_ERROR_SOUND_INVALID_POINTER;
131
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;
139                 }
140                 ret = _mm_session_util_write_type(-1, cur_session);
141                 if (ret) {
142                         debug_error("_mm_session_util_write_type() failed\n");
143                         return MM_ERROR_SOUND_INTERNAL;
144                 }
145                 *session_registered_type = MMSOUND_SESSION_REGISTERED_INTERNALLY;
146         } else {
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);
156                                 if (ret) {
157                                         debug_error("_mm_session_util_write_type() failed\n");
158                                         return MM_ERROR_SOUND_INTERNAL;
159                                 }
160                                 *session_registered_type = MMSOUND_SESSION_REGISTERED_BY_OUTSIDE_MEDIA;
161                         }
162                 }
163         }
164
165         /* convert MM_SESSION_TYPE to ASM_EVENT_TYPE */
166         switch (cur_session)
167         {
168         case MM_SESSION_TYPE_MEDIA:
169         case MM_SESSION_TYPE_MEDIA_RECORD:
170                 asm_event = ASM_EVENT_MEDIA_MMSOUND;
171                 break;
172         case MM_SESSION_TYPE_NOTIFY:
173                 asm_event = ASM_EVENT_NOTIFY;
174                 break;
175         case MM_SESSION_TYPE_ALARM:
176                 asm_event = ASM_EVENT_ALARM;
177                 break;
178         case MM_SESSION_TYPE_CALL:
179                 asm_event = ASM_EVENT_CALL;
180                 break;
181         case MM_SESSION_TYPE_VIDEOCALL:
182                 asm_event = ASM_EVENT_VIDEOCALL;
183                 break;
184         case MM_SESSION_TYPE_VOIP:
185                 asm_event = ASM_EVENT_VOIP;
186                 break;
187         case MM_SESSION_TYPE_EMERGENCY:
188                 asm_event = ASM_EVENT_EMERGENCY;
189                 break;
190         case MM_SESSION_TYPE_VOICE_RECOGNITION:
191                 asm_event = ASM_EVENT_VOICE_RECOGNITION;
192                 break;
193         case MM_SESSION_TYPE_RECORD_AUDIO:
194                 asm_event = ASM_EVENT_MMCAMCORDER_AUDIO;
195                 break;
196         case MM_SESSION_TYPE_RECORD_VIDEO:
197                 asm_event = ASM_EVENT_MMCAMCORDER_VIDEO;
198                 break;
199         default:
200                 debug_error("Unexpected %d\n", cur_session);
201                 return MM_ERROR_SOUND_INTERNAL;
202         }
203
204         *type = asm_event;
205         *options = session_options;
206         return MM_ERROR_NONE;
207 }
208
209 static bool _check_skip_session_type_for_capture(mm_sound_pcm_t *pcmHandle, mm_sound_source_type_e type)
210 {
211         bool ret = false;
212         int session_result = MM_ERROR_NONE;
213         switch (type)
214         {
215         case SUPPORT_SOURCE_TYPE_DEFAULT:
216         case SUPPORT_SOURCE_TYPE_VOICECONTROL:
217                 ret = false;
218                 break;
219         case SUPPORT_SOURCE_TYPE_MIRRORING:
220                 ret = true;
221                 break;
222         default:
223                 debug_error("Unexpected %d\n", type);
224                 return false;
225         }
226         if (ret) {
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);
234                         }
235                 }
236         }
237         return ret;
238 }
239
240 static void _sound_pcm_send_message (mm_sound_pcm_t *pcmHandle, int message, int code)
241 {
242         int ret = 0;
243         if (pcmHandle->msg_cb) {
244                 MMMessageParamType msg;
245                 msg.union_type = MM_MSG_UNION_CODE;
246                 msg.code = code;
247
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);
252         } else {
253                 debug_log ("No pcm msg callback\n");
254         }
255 }
256
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)
258 {
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;
262
263         /* Check input param */
264         if(pcmHandle == NULL) {
265                 debug_error("sound_pcm_asm_callback cb_data is null\n");
266                 return cb_res;
267         }
268
269         debug_log ("command = %d, handle = %p, is_started = %d\n",command, pcmHandle, pcmHandle->is_started);
270         switch(command)
271         {
272         case ASM_COMMAND_PAUSE:
273         case ASM_COMMAND_STOP:
274                 /* Do 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;
279                 break;
280
281         case ASM_COMMAND_RESUME:
282                 cb_res = ASM_CB_RES_IGNORE;
283                 message = MM_MESSAGE_READY_TO_RESUME;
284                 break;
285
286         case ASM_COMMAND_PLAY:
287         case ASM_COMMAND_NONE:
288                 debug_error ("Not an expected case!!!!\n");
289                 break;
290         }
291
292         /* execute user callback if callback available */
293         _sound_pcm_send_message (pcmHandle, message, event_src);
294
295         return cb_res;
296 }
297
298 static int _pcm_sound_ignore_session (MMSoundPcmHandle_t handle, MMSound_session_type_e type)
299 {
300         int result = MM_ERROR_NONE;
301         int session_result = MM_ERROR_NONE;
302         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
303         int errorcode = 0;
304
305         debug_fenter();
306
307         /* Check input param */
308         if(pcmHandle == NULL) {
309                 debug_error ("Handle is null, return Invalid Argument\n");
310                 result = MM_ERROR_INVALID_ARGUMENT;
311                 goto EXIT;
312         }
313
314         if (pcmHandle->is_started) {
315                 debug_error ("Operation is not permitted while started\n");
316                 result = MM_ERROR_SOUND_INVALID_STATE;
317                 goto EXIT;
318         }
319
320         PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
321
322         /* Unregister ASM */
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;
327                 }
328                 pcmHandle->skip_session = true;
329                 pcmHandle->asm_handle = 0;
330         }
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);
339                         }
340                 }
341         }
342
343         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
344
345 EXIT:
346         debug_fleave();
347         return result;
348 }
349
350 EXPORT_API
351 int mm_sound_pcm_capture_open(MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format)
352 {
353         mm_sound_pcm_t *pcmHandle = NULL;
354         int size = 0;
355         int result = MM_ERROR_NONE;
356         int errorcode = 0;
357         int ret_mutex = 0;
358         int ret = MM_ERROR_NONE;
359
360         int volume_config = 0;
361         pa_sample_spec ss;
362         char stream_type[MM_SOUND_STREAM_TYPE_LEN] = {0, };
363
364         mm_sound_handle_route_info route_info;
365         route_info.policy = HANDLE_ROUTE_POLICY_DEFAULT;
366
367         debug_warning ("enter : rate=[%d], channel=[%x], format=[%x]\n", rate, channel, format);
368
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;
372         } else {
373                 ss.rate = rate;
374         }
375
376         switch(channel)
377         {
378         case MMSOUND_PCM_MONO:
379                 ss.channels = 1;
380                 break;
381         case MMSOUND_PCM_STEREO:
382                 ss.channels = 2;
383                 break;
384
385         default:
386                 debug_error("Unsupported channel type\n");
387                 return MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL;
388         }
389
390         switch(format)
391         {
392         case MMSOUND_PCM_U8:
393                 ss.format = PA_SAMPLE_U8;
394                 break;
395         case MMSOUND_PCM_S16_LE:
396                 ss.format = PA_SAMPLE_S16LE;
397                 break;
398         default:
399                 debug_error("Unsupported format type\n");
400                 return MM_ERROR_SOUND_DEVICE_INVALID_FORMAT;
401         }
402
403         pcmHandle = calloc(sizeof(mm_sound_pcm_t), 1);
404         if(pcmHandle == NULL)
405                 return MM_ERROR_OUT_OF_MEMORY;
406
407         ret_mutex = pthread_mutex_init(&pcmHandle->pcm_mutex_internal, NULL);
408         if(ret_mutex != 0)
409         {
410                 free(pcmHandle);
411                 return MM_ERROR_OUT_OF_MEMORY;
412         }
413
414         /* Register ASM */
415         /* get session information */
416         ret = _get_asm_information(MMSOUND_SESSION_TYPE_CAPTURE, &pcmHandle->asm_event, &pcmHandle->asm_options, &pcmHandle->session_registered_type);
417         if(ret) {
418                 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
419                 free(pcmHandle);
420                 return ret;
421         }
422         PCM_CAPTURE_H_COUNT_INC();
423
424         /* register asm */
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))
434                 {
435                         debug_error("ASM_register_sound() failed 0x%x\n", errorcode);
436                         PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
437                         free(pcmHandle);
438                         PCM_CAPTURE_H_COUNT_DEC();
439                         return MM_ERROR_POLICY_BLOCKED;
440                 }
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);
443                 }
444         } else {
445                 pcmHandle->skip_session = true;
446         }
447
448         /* Open */
449         if(pcmHandle->asm_event == ASM_EVENT_VOIP)
450                 volume_config = VOLUME_TYPE_VOIP;
451         else
452                 volume_config = VOLUME_TYPE_SYSTEM; //dose not effect at capture mode
453
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);
460                 free(pcmHandle);
461                 PCM_CAPTURE_H_COUNT_DEC();
462                 return result;
463         }
464
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);
470
471         /* Set handle to return */
472         *handle = (MMSoundPcmHandle_t)pcmHandle;
473
474         debug_warning ("success : handle=[%p], size=[%d]\n", pcmHandle, size);
475
476         return size;
477 }
478
479 EXPORT_API
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)
481 {
482         mm_sound_pcm_t *pcmHandle = NULL;
483         int size = 0;
484         int result = MM_ERROR_NONE;
485         int errorcode = 0;
486         int ret_mutex = 0;
487
488         int volume_config = 0;
489         pa_sample_spec ss;
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, };
493
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);
496
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;
500         } else {
501                 ss.rate = rate;
502         }
503
504         switch(channel)
505         {
506         case MMSOUND_PCM_MONO:
507                 ss.channels = 1;
508                 break;
509         case MMSOUND_PCM_STEREO:
510                 ss.channels = 2;
511                 break;
512
513         default:
514                 debug_error("Unsupported channel type\n");
515                 return MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL;
516         }
517
518         switch(format)
519         {
520         case MMSOUND_PCM_U8:
521                 ss.format = PA_SAMPLE_U8;
522                 break;
523         case MMSOUND_PCM_S16_LE:
524                 ss.format = PA_SAMPLE_S16LE;
525                 break;
526         default:
527                 debug_error("Unsupported format type\n");
528                 return MM_ERROR_SOUND_DEVICE_INVALID_FORMAT;
529         }
530
531         pcmHandle = calloc(sizeof(mm_sound_pcm_t), 1);
532         if(pcmHandle == NULL)
533                 return MM_ERROR_OUT_OF_MEMORY;
534
535         ret_mutex = pthread_mutex_init(&pcmHandle->pcm_mutex_internal, NULL);
536         if(ret_mutex != 0)
537         {
538                 free(pcmHandle);
539                 return MM_ERROR_OUT_OF_MEMORY;
540         }
541
542         /* Register ASM */
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);
546                 free(pcmHandle);
547                 return MM_ERROR_POLICY_INTERNAL;
548         }
549         PCM_CAPTURE_H_COUNT_INC();
550
551         switch (source_type) {
552         case SUPPORT_SOURCE_TYPE_VOIP:
553                 route_info.policy = HANDLE_ROUTE_POLICY_IN_VOIP;
554                 break;
555         case SUPPORT_SOURCE_TYPE_MIRRORING:
556                 route_info.policy = HANDLE_ROUTE_POLICY_IN_MIRRORING;
557                 break;
558         case SUPPORT_SOURCE_TYPE_DEFAULT:
559         case SUPPORT_SOURCE_TYPE_VIDEOCALL:
560         case SUPPORT_SOURCE_TYPE_VOICERECORDING:
561                 break;
562         case SUPPORT_SOURCE_TYPE_VOICECONTROL:
563                 pcmHandle->asm_event = ASM_EVENT_EXCLUSIVE_RESOURCE;
564                 pcmHandle->resource = ASM_RESOURCE_VOICECONTROL;
565                 break;
566         default:
567                 break;
568         }
569
570         /* register asm */
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);
583                         free(pcmHandle);
584                         PCM_CAPTURE_H_COUNT_DEC();
585                         return MM_ERROR_POLICY_BLOCKED;
586                 }
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);
589                 }
590         } else {
591                 pcmHandle->skip_session = true;
592         }
593
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;
597         else
598                 volume_config = VOLUME_TYPE_SYSTEM; //dose not effect at capture mode
599
600         mm_sound_convert_volume_type_to_stream_type(volume_config, stream_type);
601         if (result) {
602                 debug_error("mm_sound_convert_volume_type_to_stream_type failed (0x%x)", result);
603                 return result;
604         }
605
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);
611                 free(pcmHandle);
612                 PCM_CAPTURE_H_COUNT_DEC();
613                 return result;
614         }
615
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);
621
622         /* Set handle to return */
623         *handle = (MMSoundPcmHandle_t)pcmHandle;
624
625         debug_warning ("success : handle=[%p], size=[%d]\n", handle, size);
626
627         return size;
628 }
629
630 EXPORT_API
631 int mm_sound_pcm_capture_ignore_session(MMSoundPcmHandle_t *handle)
632 {
633         return _pcm_sound_ignore_session(handle, MMSOUND_SESSION_TYPE_CAPTURE);
634 }
635
636 static int _pcm_sound_start (MMSoundPcmHandle_t handle)
637 {
638         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
639         int errorcode = 0;
640         int ret = 0;
641
642         debug_fenter();
643
644         /* Check input param */
645         if(pcmHandle == NULL) {
646                 debug_error ("Handle is null, return Invalid Argument\n");
647                 ret = MM_ERROR_INVALID_ARGUMENT;
648                 goto NULL_HANDLE;
649         }
650
651         PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
652
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;
658                         goto EXIT;
659                 }
660         }
661
662         /* Update State */
663         pcmHandle->is_started = true;
664
665         /* Un-Cork */
666         mm_sound_pa_cork(pcmHandle->handle, 0);
667
668 EXIT:
669         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
670
671 NULL_HANDLE:
672         debug_fleave();
673         return ret;
674 }
675
676 EXPORT_API
677 int mm_sound_pcm_capture_start(MMSoundPcmHandle_t handle)
678 {
679         int ret = MM_ERROR_NONE;
680
681         debug_warning ("enter : handle=[%p]\n", handle);
682
683         ret = _pcm_sound_start (handle);
684         if (ret != MM_ERROR_NONE)  {
685                 debug_error ("_pcm_sound_start() failed (%x)\n", ret);
686                 goto EXIT;
687         }
688
689 EXIT:
690         debug_warning ("leave : handle=[%p], ret=[0x%X]", handle, ret);
691
692         return ret;
693 }
694
695 static int _pcm_sound_stop_internal (MMSoundPcmHandle_t handle)
696 {
697         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
698
699         /* Check input param */
700         if(pcmHandle == NULL)
701                 return MM_ERROR_INVALID_ARGUMENT;
702
703         /* Check State */
704         if (pcmHandle->is_started == false) {
705                 debug_warning ("Can't stop because not started\n");
706                 return MM_ERROR_SOUND_INVALID_STATE;
707         }
708
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");
713                 }
714         }
715
716         /* Update State */
717         pcmHandle->is_started = false;
718
719         /* Cork */
720         return mm_sound_pa_cork(pcmHandle->handle, 1);
721 }
722
723 static int _pcm_sound_stop(MMSoundPcmHandle_t handle)
724 {
725         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
726         int errorcode = 0;
727         int ret = MM_ERROR_NONE;
728
729         debug_fenter();
730
731         /* Check input param */
732         if(pcmHandle == NULL) {
733                 debug_error ("Handle is null, return Invalid Argument\n");
734                 ret = MM_ERROR_INVALID_ARGUMENT;
735                 goto NULL_HANDLE;
736         }
737
738         PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
739
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;
748                                 goto EXIT;
749                         }
750                 }
751         }
752
753 EXIT:
754         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
755 NULL_HANDLE:
756         debug_fleave();
757         return ret;
758 }
759
760 EXPORT_API
761 int mm_sound_pcm_capture_stop(MMSoundPcmHandle_t handle)
762 {
763         int ret = 0;
764
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);
768
769         return ret;
770 }
771
772 EXPORT_API
773 int mm_sound_pcm_capture_flush(MMSoundPcmHandle_t handle)
774 {
775         int ret = 0;
776         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
777
778         /* Check input param */
779         if(pcmHandle == NULL)
780                 return MM_ERROR_INVALID_ARGUMENT;
781
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);
785
786         return ret;
787 }
788
789 EXPORT_API
790 int mm_sound_pcm_capture_read(MMSoundPcmHandle_t handle, void *buffer, const unsigned int length )
791 {
792         int ret = 0;
793         static int read_byte = 0;
794         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
795
796         /* Check input param */
797         if(pcmHandle == NULL) {
798                 debug_error ("Handle is null, return Invalid Argument\n");
799                 ret =  MM_ERROR_INVALID_ARGUMENT;
800                 goto NULL_HANDLE;
801         }
802         PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
803
804         if(buffer == NULL) {
805                 debug_error("Invalid buffer pointer\n");
806                 ret = MM_ERROR_SOUND_INVALID_POINTER;
807                 goto EXIT;
808         }
809         if(length == 0 ) {
810                 debug_error ("length is 0, return 0\n");
811                 ret = 0;
812                 goto EXIT;
813         }
814
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;
820                 goto EXIT;
821         }
822
823         /* Read */
824         ret = mm_sound_pa_read(pcmHandle->handle, buffer, length);
825
826 EXIT:
827         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
828 NULL_HANDLE:
829         read_byte += length;
830
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);
833                 read_byte = 0;
834         }
835         return ret;
836 }
837
838 EXPORT_API
839 int mm_sound_pcm_capture_close(MMSoundPcmHandle_t handle)
840 {
841         int result = MM_ERROR_NONE;
842         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
843         int errorcode = 0;
844
845         debug_warning ("enter : handle=[%p]\n", handle);
846
847         /* Check input param */
848         if(pcmHandle == NULL) {
849                 debug_error ("Handle is null, return Invalid Argument\n");
850                 result = MM_ERROR_INVALID_ARGUMENT;
851                 goto NULL_HDL;
852         }
853         PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
854         /* Close */
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;
858                 goto EXIT;
859         }
860
861         /* Unregister ASM */
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;
873                                         goto EXIT;
874                                 }
875                         }
876                 }
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);
882                         if (result) {
883                                 debug_error("_mm_session_util_write_information() [type %d, options %x] failed[%x]", MM_SESSION_TYPE_MEDIA, pcmHandle->asm_options, result);
884                         }
885                 }
886         }
887
888 EXIT:
889         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
890 NULL_HDL:
891         debug_warning ("leave : handle=[%p], ret=[0x%X]\n", handle, result);
892         /* Free handle */
893         if (pcmHandle) {
894                 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
895                 free(pcmHandle);
896                 pcmHandle = NULL;
897         }
898         PCM_CAPTURE_H_COUNT_DEC();
899
900         return result;
901 }
902
903 EXPORT_API
904 int mm_sound_pcm_set_message_callback (MMSoundPcmHandle_t handle, MMMessageCallback callback, void *user_param)
905 {
906         mm_sound_pcm_t *pcmHandle =  (mm_sound_pcm_t*)handle;
907
908         if(pcmHandle == NULL || callback == NULL)
909                 return MM_ERROR_INVALID_ARGUMENT;
910
911         pcmHandle->msg_cb = callback;
912         pcmHandle->msg_cb_param = user_param;
913
914         debug_log ("set pcm message callback (%p,%p)\n", callback, user_param);
915
916         return MM_ERROR_NONE;
917 }
918
919 EXPORT_API
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)
921 {
922         mm_sound_pcm_t *pcmHandle = NULL;
923         int size = 0;
924         int result = MM_ERROR_NONE;
925         int errorcode = 0;
926         int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config);
927         int ret_mutex = 0;
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, };
931
932         pa_sample_spec ss;
933
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);
936
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;
941         }
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;
945         } else {
946                 ss.rate = rate;
947         }
948
949         switch(channel)
950         {
951         case MMSOUND_PCM_MONO:
952                 ss.channels = 1;
953                 break;
954         case MMSOUND_PCM_STEREO:
955                 ss.channels = 2;
956                 break;
957         default:
958                 debug_error("Unsupported channel type\n");
959                 return MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL;
960         }
961
962         switch(format)
963         {
964         case MMSOUND_PCM_U8:
965                 ss.format = PA_SAMPLE_U8;
966                 break;
967         case MMSOUND_PCM_S16_LE:
968                 ss.format = PA_SAMPLE_S16LE;
969                 break;
970         default:
971                 debug_error("Unsupported format type\n");
972                 return MM_ERROR_SOUND_DEVICE_INVALID_FORMAT;
973         }
974
975         pcmHandle = calloc(sizeof(mm_sound_pcm_t),1);
976         if(pcmHandle == NULL)
977                 return MM_ERROR_OUT_OF_MEMORY;
978
979         ret_mutex = pthread_mutex_init(&pcmHandle->pcm_mutex_internal, NULL);
980         if(ret_mutex != 0) {
981                 debug_error ("error mutex init....%d");
982                 result = MM_ERROR_OUT_OF_MEMORY;
983                 goto ERROR;
984         }
985
986         /* Register ASM */
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;
996                         goto ERROR;
997                 }
998
999                 // should be fixed. call forwarding engine(voip) use call volume type.
1000                 if(volume_type == VOLUME_TYPE_CALL) {
1001                         pcmHandle->skip_session = true;
1002                 }
1003
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) {
1011
1012                         /* register asm */
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;
1017                                 goto ERROR;
1018                         }
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);
1021                         }
1022                 } else {
1023                         pcmHandle->skip_session = true;
1024                 }
1025         } else {
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;
1031                         goto ERROR;
1032                 }
1033         }
1034
1035
1036         /* Open */
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;
1042                 goto ERROR;
1043         }
1044
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);
1048         if(result) {
1049                 debug_error("Cork Error 0x%x\n", result);
1050                 result = MM_ERROR_SOUND_INTERNAL;
1051                 goto ERROR;
1052         }
1053
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;
1060
1061         /* Set handle to return */
1062         *handle = (MMSoundPcmHandle_t)pcmHandle;
1063
1064         debug_warning ("success : handle=[%p], size=[%d]\n", pcmHandle, size);
1065         return size;
1066
1067 ERROR:
1068         if (pcmHandle) {
1069                 if(ret_mutex == 0) {
1070                         PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
1071                 }
1072                 free(pcmHandle);
1073         }
1074         return result;
1075 }
1076
1077 EXPORT_API
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)
1079 {
1080         return mm_sound_pcm_play_open_ex (handle, rate, channel, format, volume_config, ASM_EVENT_MONITOR);
1081 }
1082
1083 EXPORT_API
1084 int mm_sound_pcm_play_open(MMSoundPcmHandle_t *handle, const unsigned int rate, MMSoundPcmChannel_t channel, MMSoundPcmFormat_t format, int volume_config)
1085 {
1086         return mm_sound_pcm_play_open_ex (handle, rate, channel, format, volume_config, ASM_EVENT_NONE);
1087 }
1088
1089 EXPORT_API
1090 int mm_sound_pcm_play_start(MMSoundPcmHandle_t handle)
1091 {
1092         int ret = 0;
1093
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);
1097
1098         return ret;
1099 }
1100
1101 EXPORT_API
1102 int mm_sound_pcm_play_stop(MMSoundPcmHandle_t handle)
1103 {
1104         int ret = 0;
1105
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);
1109
1110         return ret;
1111 }
1112
1113 EXPORT_API
1114 int mm_sound_pcm_play_drain(MMSoundPcmHandle_t handle)
1115 {
1116         int ret = 0;
1117         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1118
1119         /* Check input param */
1120         if(pcmHandle == NULL)
1121                 return MM_ERROR_INVALID_ARGUMENT;
1122
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);
1126
1127         return ret;
1128 }
1129
1130 EXPORT_API
1131 int mm_sound_pcm_play_flush(MMSoundPcmHandle_t handle)
1132 {
1133         int ret = 0;
1134         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1135
1136         /* Check input param */
1137         if(pcmHandle == NULL)
1138                 return MM_ERROR_INVALID_ARGUMENT;
1139
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);
1143
1144         return ret;
1145 }
1146
1147 EXPORT_API
1148 int mm_sound_pcm_play_write(MMSoundPcmHandle_t handle, void* ptr, unsigned int length_byte)
1149 {
1150         int ret = 0;
1151         static int written_byte = 0;
1152         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1153
1154         /* Check input param */
1155         if(pcmHandle == NULL) {
1156                 debug_error ("Handle is null, return Invalid Argument\n");
1157                 ret = MM_ERROR_INVALID_ARGUMENT;
1158                 goto NULL_HANDLE;
1159         }
1160
1161         PCM_LOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1162
1163         if(ptr == NULL) {
1164                 debug_error("Invalid buffer pointer\n");
1165                 ret = MM_ERROR_SOUND_INVALID_POINTER;
1166                 goto EXIT;
1167         }
1168         if(length_byte == 0 ) {
1169                 debug_error ("length is 0, return 0\n");
1170                 ret = 0;
1171                 goto EXIT;
1172         }
1173
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;
1179                 goto EXIT;
1180         }
1181
1182         /* Write */
1183         ret = mm_sound_pa_write(pcmHandle->handle, ptr, length_byte);
1184
1185
1186 EXIT:
1187         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1188 NULL_HANDLE:
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);
1192                 written_byte = 0;
1193         }
1194
1195         return ret;
1196 }
1197
1198 EXPORT_API
1199 int mm_sound_pcm_play_close(MMSoundPcmHandle_t handle)
1200 {
1201         int result = MM_ERROR_NONE;
1202         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1203         int errorcode = 0;
1204
1205         debug_warning ("enter : handle=[%p]\n", handle);
1206
1207         /* Check input param */
1208         if(pcmHandle == NULL) {
1209                 debug_error ("Handle is null, return Invalid Argument\n");
1210                 result = MM_ERROR_INVALID_ARGUMENT;
1211                 goto NULL_HANDLE;
1212         }
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;
1220                         goto EXIT;
1221                 }
1222         }
1223         pcmHandle->is_started = false;
1224         /* Close */
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;
1228                 goto EXIT;
1229         }
1230
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);
1241                         }
1242                 }
1243         }
1244
1245 EXIT:
1246         PCM_UNLOCK_INTERNAL(&pcmHandle->pcm_mutex_internal);
1247 NULL_HANDLE:
1248         debug_warning ("leave : handle=[%p], result[0x%X]\n", handle, result);
1249         if (pcmHandle) {
1250                 /* Free handle */
1251                 PCM_LOCK_DESTROY_INTERNAL(&pcmHandle->pcm_mutex_internal);
1252                 free(pcmHandle);
1253                 pcmHandle= NULL;
1254         }
1255
1256         return result;
1257 }
1258
1259 EXPORT_API
1260 int mm_sound_pcm_play_ignore_session(MMSoundPcmHandle_t *handle)
1261 {
1262         return _pcm_sound_ignore_session(handle, MMSOUND_SESSION_TYPE_PLAYBACK);
1263 }
1264
1265 EXPORT_API
1266 int mm_sound_pcm_get_latency(MMSoundPcmHandle_t handle, int *latency)
1267 {
1268         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1269         int mlatency = 0;
1270
1271         /* Check input param */
1272         if (latency == NULL)
1273                 return MM_ERROR_INVALID_ARGUMENT;
1274
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;
1279         }
1280
1281         *latency = mlatency;
1282
1283         return MM_ERROR_NONE;
1284 }
1285
1286 EXPORT_API
1287 int mm_sound_pcm_is_started(MMSoundPcmHandle_t handle, bool *is_started)
1288 {
1289         mm_sound_pcm_t *pcmHandle = (mm_sound_pcm_t*)handle;
1290
1291         /* Check input param */
1292         if (is_started == NULL)
1293                 return MM_ERROR_INVALID_ARGUMENT;
1294
1295         *is_started = pcmHandle->is_started;
1296
1297         return MM_ERROR_NONE;
1298 }