4 * Copyright (c) 2000 - 2011 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.
33 #include <semaphore.h>
38 #include "include/mm_sound.h"
39 #include "include/mm_sound_msg.h"
40 #include "include/mm_sound_client.h"
42 #include <mm_session.h>
43 #include <mm_session_private.h>
45 #define __DIRECT_CALLBACK__
46 //#define __GIDLE_CALLBACK__
49 #if defined(__GSOURCE_CALLBACK__)
53 #define MEMTYPE_SUPPORT_MAX (1024 * 1024) /* 1MB */
54 #define MEMTYPE_TRANS_PER_MAX (128 * 1024) /* 128K */
57 int g_msg_scsnd; /* global msg queue id sound client snd */
58 int g_msg_scrcv; /* global msg queue id sound client rcv */
59 int g_msg_sccb; /* global msg queue id sound client callback */
62 struct __callback_param
64 mm_sound_stop_callback_func callback;
69 static int g_exit_thread = 0;
71 int g_mutex_initted = -1;
72 pthread_mutex_t g_thread_mutex;
74 static void* callbackfunc(void *param);
76 /* manage IPC (msg contorl) */
77 static int __MMIpcCBSndMsg(mm_ipc_msg_t *msg);
78 static int __MMIpcRecvMsg(int msgtype, mm_ipc_msg_t *msg);
79 static int __MMIpcSndMsg(mm_ipc_msg_t *msg);
80 static int __MMIpcCBRecvMsg(int msgtype, mm_ipc_msg_t *msg);
81 static int __MMSoundGetMsg(void);
83 int MMSoundClientInit(void)
85 int ret = MM_ERROR_NONE;
92 int MMSoundClientCallbackFini(void)
94 mm_ipc_msg_t msgsnd={0,};
95 int ret = MM_ERROR_NONE;
99 /* When the the callback thread is not created, do not wait destory thread */
100 /* g_thread_id is initialized : -1 */
101 /* g_thread_id is set to 0, when the callback thread is created */
102 if (g_thread_id != -1)
104 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_INF_DESTROY_CB;
105 msgsnd.sound_msg.msgid = getpid();
106 ret = __MMIpcCBSndMsg(&msgsnd);
107 if (ret != MM_ERROR_NONE)
109 debug_critical("[Client] Fail to send message\n");
111 /* wait for leave callback thread */
112 while (g_exit_thread == 0)
117 if (g_mutex_initted != -1)
119 pthread_mutex_destroy(&g_thread_mutex);
120 g_mutex_initted = -1;
123 return MM_ERROR_NONE;
126 #if defined(__GSOURCE_CALLBACK__)
127 gboolean sndcb_fd_check(GSource * source)
130 fd_list = source->poll_fds;
135 temp = (GPollFD*)fd_list->data;
136 if (temp->revents & (POLLIN|POLLPRI))
138 fd_list = fd_list->next;
141 return FALSE; /* there is no change in any fd state */
144 gboolean sndcb_fd_prepare(GSource *source, gint *timeout)
149 gboolean sndcb_fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
155 gboolean RunCallback(gpointer *data)
157 mm_ipc_msg_t* msg = NULL;
159 debug_msg("[Client] execute mm_sound stop callback function\n");
161 msg = (mm_ipc_msg_t*)data;
162 ((mm_sound_stop_callback_func)msg->sound_msg.callback)(msg->sound_msg.cbdata);
167 static void* callbackfunc(void *param)
169 int ret = MM_ERROR_SOUND_INTERNAL;
170 mm_ipc_msg_t *msgrcv = NULL;
177 debug_msg("[Client] callback thread for [%d] is created\n", instance);
179 msgrcv = (mm_ipc_msg_t*)malloc(sizeof(mm_ipc_msg_t));
182 debug_critical("[Client] Failed to memory allocation\n");
188 #if defined(__GSOURCE_CALLBACK__)
190 gchar* eventFile = NULL;
191 GSource* cmd_fd_gsrc = NULL;
192 GSourceFuncs *src_funcs = NULL; // handler function
193 guint gsource_handle;
194 GPollFD *g_fd_cmd = NULL; // file descriptor
197 debug_warning("[Client] Waiting message\n");
198 ret = __MMIpcCBRecvMsg(instance, msgrcv);
199 if (ret != MM_ERROR_NONE)
201 debug_error("[Client] Fail to receive msg in callback\n");
205 debug_msg("[Client] Receive msgtype : [%d]\n", msgrcv->sound_msg.msgtype);
207 switch (msgrcv->sound_msg.msgtype)
209 case MM_SOUND_MSG_INF_STOP_CB:
210 debug_msg("[Client] callback : %p\n", msgrcv->sound_msg.callback);
211 debug_msg("[Client] data : %p\n", msgrcv->sound_msg.cbdata);
213 if (msgrcv->sound_msg.callback)
215 #if defined(__DIRECT_CALLBACK__)
216 ((mm_sound_stop_callback_func)msgrcv->sound_msg.callback)(msgrcv->sound_msg.cbdata);
217 #elif defined(__GIDLE_CALLBACK__)
219 eventid = g_idle_add((GSourceFunc)RunCallback, (gpointer)msgrcv);
220 debug_msg("[Client] Event Source ID : %d\n", eventid);
222 #elif defined(__GSOURCE_CALLBACK__)
223 char eventBuf[3]="OK";
224 ////////////////////////
225 // 0. Make event source
226 eventFile = g_strdup_printf("/tmp/%d_0x%08x_0x%08x", instance, (unsigned int)msgrcv->sound_msg.callback, (unsigned int)msgrcv->sound_msg.cbdata);
227 eventFd = open(eventFile, O_RDWR|O_CREAT);
230 debug_critical("Event File creation failed\n");
234 // 1. make GSource Object
235 src_funcs = (GSourceFuncs *)g_malloc(sizeof(GSourceFuncs));
237 debug_error("MMSoundCallback : g_malloc failed on g_src_funcs");
240 src_funcs->prepare = sndcb_fd_prepare;
241 src_funcs->check = sndcb_fd_check;
242 src_funcs->dispatch = sndcb_fd_dispatch;
243 src_funcs->finalize = NULL;
244 cmd_fd_gsrc = g_source_new(src_funcs,sizeof(GSource));
246 debug_error("MMSoundCallback : g_malloc failed on m_readfd");
250 // 2. add file description which used in g_loop()
251 g_fd_cmd = (GPollFD*)g_malloc(sizeof(GPollFD));
252 g_fd_cmd->fd = eventFd;
253 g_fd_cmd->events = POLLIN|POLLPRI;
255 // 3. combine g_source object and file descriptor
256 g_source_add_poll(cmd_fd_gsrc,g_fd_cmd);
257 gsource_handle = g_source_attach(cmd_fd_gsrc, NULL);
259 debug_error("MMSoundCallback : Error: Failed to attach the source to context");
264 g_source_set_callback(cmd_fd_gsrc,RunCallback,(gpointer)g_fd_cmd,NULL);
265 debug_msg("MMSoundCallback : g_source_set_callback() done\n")
268 write(eventFd, eventBuf, sizeof(eventBuf));
273 g_source_remove_poll(cmd_fd_gsrc, g_fd_cmd);
274 g_source_remove(gsource_handle);
281 ////////////////////////
285 case MM_SOUND_MSG_INF_DESTROY_CB:
289 case MM_SOUND_MSG_INF_ACTIVE_DEVICE_CB:
290 debug_msg("[Client] device_in : %p\n", msgrcv->sound_msg.device_in);
291 debug_msg("[Client] device_out : %p\n", msgrcv->sound_msg.device_out);
292 debug_msg("[Client] callback : %p\n", msgrcv->sound_msg.callback);
293 debug_msg("[Client] data : %p\n", msgrcv->sound_msg.cbdata);
295 if (msgrcv->sound_msg.callback)
297 ((mm_sound_active_device_changed_cb)msgrcv->sound_msg.callback)(msgrcv->sound_msg.device_in, msgrcv->sound_msg.device_out, msgrcv->sound_msg.cbdata);
300 case MM_SOUND_MSG_INF_AVAILABLE_ROUTE_CB:
301 debug_msg("[Client] callback : %p\n", msgrcv->sound_msg.callback);
302 debug_msg("[Client] data : %p\n", msgrcv->sound_msg.cbdata);
304 if (msgrcv->sound_msg.callback)
307 mm_sound_route route;
309 for (route_index = 0; route_index < sizeof(msgrcv->sound_msg.route_list) / sizeof(int); route_index++) {
310 route = msgrcv->sound_msg.route_list[route_index];
313 if (msgrcv->sound_msg.is_available) {
314 debug_msg("[Client] available route : %d\n", route);
316 debug_msg("[Client] unavailable route : %d\n", route);
318 ((mm_sound_available_route_changed_cb)msgrcv->sound_msg.callback)(route, msgrcv->sound_msg.is_available, msgrcv->sound_msg.cbdata);
324 debug_msg("Receive wrong msg in callback func\n");
332 debug_msg("[Client] callback [%d] is leaved\n", instance);
337 static int __mm_sound_client_get_msg_queue(void)
339 int ret = MM_ERROR_NONE;
341 if (g_mutex_initted == -1)
343 pthread_mutex_init(&g_thread_mutex, NULL);
344 debug_msg("[Client] mutex initialized. \n");
347 /* Get msg queue id */
348 ret = __MMSoundGetMsg();
349 if(ret != MM_ERROR_NONE)
351 debug_critical("[Client] Fail to get message queue id\n");
358 int MMSoundClientPlayTone(int number, int volume_config, double volume, int time, int *handle)
360 mm_ipc_msg_t msgrcv = {0,};
361 mm_ipc_msg_t msgsnd = {0,};
363 int ret = MM_ERROR_NONE;
364 int instance = -1; /* instance is unique to communicate with server : client message queue filter type */
368 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
371 /* read mm-session type */
372 int sessionType = MM_SESSION_TYPE_SHARE;
373 if(MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType))
375 debug_warning("[Client] Read MMSession Type failed. use default \"share\" type\n");
376 sessionType = MM_SESSION_TYPE_SHARE;
378 if(MM_ERROR_NONE != mm_session_init(sessionType))
380 debug_critical("[Client] MMSessionInit() failed\n");
381 return MM_ERROR_POLICY_INTERNAL;
386 debug_msg("[Client] pid for client ::: [%d]\n", instance);
388 pthread_mutex_lock(&g_thread_mutex);
391 debug_msg("[Client] Input number : %d\n", number);
392 /* Send req memory */
393 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_DTMF;
394 msgsnd.sound_msg.msgid = instance;
395 msgsnd.sound_msg.session_type = sessionType;//asm_session_type;
396 msgsnd.sound_msg.volume = volume;//This does not effect anymore
397 msgsnd.sound_msg.volume_config = volume_config;
398 msgsnd.sound_msg.tone = number;
399 msgsnd.sound_msg.handle = -1;
400 msgsnd.sound_msg.repeat = time;
402 ret = __MMIpcSndMsg(&msgsnd);
403 if (ret != MM_ERROR_NONE)
405 debug_error("[Client] Fail to send msg\n");
410 ret = __MMIpcRecvMsg(instance, &msgrcv);
411 if (ret != MM_ERROR_NONE)
413 debug_error("[Client] Fail to recieve msg\n");
417 switch (msgrcv.sound_msg.msgtype)
419 case MM_SOUND_MSG_RES_DTMF:
420 *handle = msgrcv.sound_msg.handle;
422 debug_error("[Client] The handle is not get\n");
424 debug_msg("[Client] Success to play sound sound handle : [%d]\n", *handle);
426 case MM_SOUND_MSG_RES_ERROR:
427 debug_error("[Client] Error occurred \n");
428 ret = msgrcv.sound_msg.code;
432 debug_critical("[Client] Unexpected state with communication \n");
433 ret = msgrcv.sound_msg.code;
438 pthread_mutex_unlock(&g_thread_mutex);
445 int MMSoundClientPlaySound(MMSoundPlayParam *param, int tone, int keytone, int *handle)
447 mm_ipc_msg_t msgrcv = {0,};
448 mm_ipc_msg_t msgsnd = {0,};
449 unsigned char* sharedmem = NULL;
451 int ret = MM_ERROR_NONE;
452 int instance = -1; /* instance is unique to communicate with server : client message queue filter type */
455 void *mmap_buf = NULL;
456 static int keybase = 0;
460 memset(shm_name, 0, sizeof(shm_name));
462 ret = __mm_sound_client_get_msg_queue();
463 if (ret != MM_ERROR_NONE)
466 /* read mm-session type */
467 int sessionType = MM_SESSION_TYPE_SHARE;
468 if(MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType))
470 debug_warning("[Client] Read MMSession Type failed. use default \"share\" type\n");
471 sessionType = MM_SESSION_TYPE_SHARE;
473 if(MM_ERROR_NONE != mm_session_init(sessionType))
475 debug_critical("[Client] MMSessionInit() failed\n");
476 return MM_ERROR_POLICY_INTERNAL;
482 debug_msg("[Client] pid for client ::: [%d]\n", instance);
485 /* callback thread is created just once & when the callback is exist */
488 if (g_thread_id == -1)
490 g_thread_id = pthread_create(&g_thread, NULL, callbackfunc, NULL);
491 if (g_thread_id == -1)
493 debug_critical("[Client] Fail to create thread %s\n", strerror(errno));
494 return MM_ERROR_SOUND_INTERNAL;
499 pthread_mutex_lock(&g_thread_mutex);
502 if ((param->mem_ptr && param->mem_size))
504 debug_msg("The memptr : [%p]\n", param->mem_ptr);
505 debug_msg("The memptr : [%d]\n", param->mem_size);
506 /* Limitted memory size */
507 if (param->mem_ptr && param->mem_size > MEMTYPE_SUPPORT_MAX)
509 debug_msg("[Client] Memory size is too big. We support size of media to 1MB\n");
513 debug_msg("[Client] memory size : %d\n", param->mem_size);
514 snprintf(shm_name, sizeof(shm_name)-1, "%d_%d", instance, keybase);
515 debug_msg("[Client] The shm_path : [%s]\n", shm_name);
518 shm_fd = shm_open(shm_name, O_RDWR |O_CREAT, 0666);
521 perror("[Client] Fail create shm_open\n");
522 debug_error("[Client] Fail to create shm_open\n");
526 if(ftruncate(shm_fd, param->mem_size) == -1)
528 debug_error("[Client] Fail to ftruncate\n");
532 mmap_buf = mmap (0, MEMTYPE_SUPPORT_MAX, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
533 if (mmap_buf == MAP_FAILED)
535 debug_error("[Client] MMAP failed \n");
539 sharedmem = mmap_buf;
541 if(ret != MM_ERROR_NONE)
543 debug_error("[Client] Not allocated shared memory");
546 debug_msg("[Client] Sheared mem ptr : %p\n", sharedmem);
547 debug_msg("[Client] Sheared key : [%d]\n", 1);
548 /* Send req memory */
549 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_MEMORY;
550 msgsnd.sound_msg.msgid = instance;
551 msgsnd.sound_msg.callback = (void*)(param->callback);
552 msgsnd.sound_msg.cbdata = (void*)(param->data);
553 msgsnd.sound_msg.memptr = (int)sharedmem;
554 msgsnd.sound_msg.sharedkey = 1; /* In case of shared memory file name */
555 msgsnd.sound_msg.session_type = sessionType;//asm_session_type;
556 msgsnd.sound_msg.priority = param->priority;
559 strncpy(msgsnd.sound_msg.filename, shm_name, 512);
560 debug_msg("[Client] shm_name : %s\n", msgsnd.sound_msg.filename);
562 msgsnd.sound_msg.memsize = param->mem_size;
563 msgsnd.sound_msg.volume = param->volume;
564 msgsnd.sound_msg.tone = tone;
565 msgsnd.sound_msg.handle = -1;
566 msgsnd.sound_msg.repeat = param->loop;
567 msgsnd.sound_msg.volume_config = param->volume_config;
568 msgsnd.sound_msg.keytone = keytone;
569 msgsnd.sound_msg.handle_route = param->handle_route;
571 /* Send req memory */
572 debug_msg("[Client] Shared mem ptr %p, %p, size %d\n", sharedmem, param->mem_ptr, param->mem_size);
573 memcpy(sharedmem, param->mem_ptr, param->mem_size);
576 if (close(shm_fd) == -1)
578 debug_error("[Client] Fail to close file\n");
579 ret = MM_ERROR_SOUND_INTERNAL;
583 ret = __MMIpcSndMsg(&msgsnd);
584 if (ret != MM_ERROR_NONE)
586 debug_error("[Client] Fail to send msg\n");
592 /* File type set for send msg */
593 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_FILE;
594 msgsnd.sound_msg.msgid = instance;
595 msgsnd.sound_msg.callback = (void*)(param->callback);
596 msgsnd.sound_msg.cbdata = (void*)(param->data);
597 msgsnd.sound_msg.volume = param->volume;
598 msgsnd.sound_msg.tone = tone;
599 msgsnd.sound_msg.handle = -1;
600 msgsnd.sound_msg.repeat = param->loop;
601 msgsnd.sound_msg.volume_config = param->volume_config;
602 msgsnd.sound_msg.session_type = sessionType;//asm_session_type;
603 msgsnd.sound_msg.priority = param->priority;
604 msgsnd.sound_msg.handle_route = param->handle_route;
606 if((strlen(param->filename)) < FILE_PATH)
608 strncpy(msgsnd.sound_msg.filename, param->filename, sizeof(msgsnd.sound_msg.filename)-1);
612 debug_error("File name is over count\n");
613 ret = MM_ERROR_SOUND_INVALID_PATH;
616 msgsnd.sound_msg.keytone = keytone;
618 debug_msg("[Client] callback : %p\n", msgsnd.sound_msg.callback);
619 debug_msg("[Client] cbdata : %p\n", msgsnd.sound_msg.cbdata);
621 ret = __MMIpcSndMsg(&msgsnd);
622 if (ret != MM_ERROR_NONE)
624 debug_error("[Client] Fail to send msg\n");
631 ret = __MMIpcRecvMsg(instance, &msgrcv);
632 if (ret != MM_ERROR_NONE)
634 debug_error("[Client] Fail to recieve msg\n");
638 switch (msgrcv.sound_msg.msgtype)
640 case MM_SOUND_MSG_RES_FILE:
641 *handle = msgrcv.sound_msg.handle;
642 debug_msg("[Client] Success to play sound sound handle : [%d]\n", *handle);
644 case MM_SOUND_MSG_RES_MEMORY:
645 *handle = msgrcv.sound_msg.handle;
647 debug_error("[Client] The handle is not get\n");
649 shm_unlink(shm_name);
650 if (ret != MM_ERROR_NONE)
652 debug_critical("[Client] Fail to remove shared memory, must be checked\n");
655 debug_msg("[Client] Success to play sound sound handle : [%d]\n", *handle);
657 case MM_SOUND_MSG_RES_ERROR:
658 debug_error("[Client] Error occurred \n");
659 ret = msgrcv.sound_msg.code;
663 debug_critical("[Client] Unexpected state with communication \n");
664 ret = msgrcv.sound_msg.code;
669 pthread_mutex_unlock(&g_thread_mutex);
675 int MMSoundClientStopSound(int handle)
677 mm_ipc_msg_t msgrcv = {0,};
678 mm_ipc_msg_t msgsnd = {0,};
679 int ret = MM_ERROR_NONE;
683 debug_msg("[Client] The stop audio handle ::: [%d]\n", handle);
689 ret = MM_ERROR_INVALID_ARGUMENT;
693 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
696 pthread_mutex_lock(&g_thread_mutex);
699 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_STOP;
700 msgsnd.sound_msg.msgid = instance;
701 msgsnd.sound_msg.handle = handle; /* handle means audio handle slot id */
703 ret = __MMIpcSndMsg(&msgsnd);
704 if (ret != MM_ERROR_NONE)
706 debug_error("Fail to send msg\n");
711 ret = __MMIpcRecvMsg(instance, &msgrcv);
712 if (ret != MM_ERROR_NONE)
714 debug_error("[Client] Fail to recieve msg\n");
717 switch (msgrcv.sound_msg.msgtype)
719 case MM_SOUND_MSG_RES_STOP:
720 debug_msg("[Client] Success to stop sound\n");
722 case MM_SOUND_MSG_RES_ERROR:
723 debug_error("[Client] Error occurred \n");
724 ret = msgrcv.sound_msg.code;
728 debug_critical("[Client] Unexpected state with communication \n");
729 ret = msgrcv.sound_msg.code;
735 pthread_mutex_unlock(&g_thread_mutex);
742 int _mm_sound_client_is_route_available(mm_sound_route route, bool *is_available)
744 mm_ipc_msg_t msgrcv = {0,};
745 mm_ipc_msg_t msgsnd = {0,};
746 int ret = MM_ERROR_NONE;
751 *is_available = FALSE;
753 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
756 pthread_mutex_lock(&g_thread_mutex);
759 /* Send REQ_IS_ROUTE_AVAILABLE */
760 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_IS_ROUTE_AVAILABLE;
761 msgsnd.sound_msg.msgid = instance;
762 msgsnd.sound_msg.route = route;
764 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
768 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
771 switch (msgrcv.sound_msg.msgtype)
773 case MM_SOUND_MSG_RES_IS_ROUTE_AVAILABLE:
774 *is_available = msgrcv.sound_msg.is_available;
775 debug_msg("[Client] Success to check given route is available %d\n", *is_available);
777 case MM_SOUND_MSG_RES_ERROR:
778 debug_error("[Client] Error occurred \n");
779 ret = msgrcv.sound_msg.code;
783 debug_critical("[Client] Unexpected state with communication \n");
784 ret = msgrcv.sound_msg.code;
790 pthread_mutex_unlock(&g_thread_mutex);
796 static int _handle_foreach_callback(mm_ipc_msg_t *msg)
799 mm_sound_route route;
803 if (msg->sound_msg.callback == NULL) {
804 debug_error ("[Client] Foreach callback is [%p], cbdata = %p => exit",
805 msg->sound_msg.callback, msg->sound_msg.cbdata);
806 return MM_ERROR_SOUND_INTERNAL;
809 for (route_index = 0; route_index < MM_SOUND_ROUTE_NUM; route_index++) {
810 route = msg->sound_msg.route_list[route_index];
813 debug_msg("[Client] available route : %d\n", route);
814 if (((mm_sound_available_route_cb)msg->sound_msg.callback)(route, msg->sound_msg.cbdata) == false) {
815 debug_msg ("[Client] user doesn't want anymore. quit loop!!\n");
822 return MM_ERROR_NONE;
825 int _mm_sound_client_foreach_available_route_cb(mm_sound_available_route_cb available_route_cb, void *user_data)
827 mm_ipc_msg_t msgrcv = {0,};
828 mm_ipc_msg_t msgsnd = {0,};
829 int ret = MM_ERROR_NONE;
834 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
837 pthread_mutex_lock(&g_thread_mutex);
840 /* Send REQ_FOREACH_AVAILABLE_ROUTE_CB */
841 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_FOREACH_AVAILABLE_ROUTE_CB;
842 msgsnd.sound_msg.msgid = instance;
843 msgsnd.sound_msg.callback = (void *)available_route_cb;
844 msgsnd.sound_msg.cbdata = (void *)user_data;
846 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
850 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
853 switch (msgrcv.sound_msg.msgtype)
855 case MM_SOUND_MSG_RES_FOREACH_AVAILABLE_ROUTE_CB:
856 debug_msg("[Client] Success to set foreach available route callback\n");
857 msgrcv.sound_msg.callback = (void *)available_route_cb;
858 msgrcv.sound_msg.cbdata = (void *)user_data;
859 ret = _handle_foreach_callback (&msgrcv);
861 case MM_SOUND_MSG_RES_ERROR:
862 debug_error("[Client] Error occurred \n");
863 ret = msgrcv.sound_msg.code;
867 debug_critical("[Client] Unexpected state with communication \n");
868 ret = msgrcv.sound_msg.code;
874 pthread_mutex_unlock(&g_thread_mutex);
880 int _mm_sound_client_set_active_route(mm_sound_route route)
882 mm_ipc_msg_t msgrcv = {0,};
883 mm_ipc_msg_t msgsnd = {0,};
884 int ret = MM_ERROR_NONE;
889 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
892 pthread_mutex_lock(&g_thread_mutex);
895 /* Send REQ_SET_ACTIVE_ROUTE */
896 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_SET_ACTIVE_ROUTE;
897 msgsnd.sound_msg.msgid = instance;
898 msgsnd.sound_msg.route = route;
900 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
904 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
907 switch (msgrcv.sound_msg.msgtype)
909 case MM_SOUND_MSG_RES_SET_ACTIVE_ROUTE:
910 debug_msg("[Client] Success to add active device callback\n");
912 case MM_SOUND_MSG_RES_ERROR:
913 debug_error("[Client] Error occurred \n");
914 ret = msgrcv.sound_msg.code;
918 debug_critical("[Client] Unexpected state with communication \n");
919 ret = msgrcv.sound_msg.code;
925 pthread_mutex_unlock(&g_thread_mutex);
931 int _mm_sound_client_get_active_device(mm_sound_device_in *device_in, mm_sound_device_out *device_out)
933 mm_ipc_msg_t msgrcv = {0,};
934 mm_ipc_msg_t msgsnd = {0,};
935 int ret = MM_ERROR_NONE;
940 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
943 pthread_mutex_lock(&g_thread_mutex);
946 /* Send REQ_GET_ACTIVE_DEVICE */
947 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_GET_ACTIVE_DEVICE;
948 msgsnd.sound_msg.msgid = instance;
950 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
954 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
957 switch (msgrcv.sound_msg.msgtype)
959 case MM_SOUND_MSG_RES_GET_ACTIVE_DEVICE:
960 *device_in = msgrcv.sound_msg.device_in;
961 *device_out = msgrcv.sound_msg.device_out;
962 debug_msg("[Client] Success to get active device %d %d\n", *device_in, *device_out);
964 case MM_SOUND_MSG_RES_ERROR:
965 debug_error("[Client] Error occurred \n");
966 ret = msgrcv.sound_msg.code;
970 debug_critical("[Client] Unexpected state with communication \n");
971 ret = msgrcv.sound_msg.code;
977 pthread_mutex_unlock(&g_thread_mutex);
983 int _mm_sound_client_add_active_device_changed_callback(mm_sound_active_device_changed_cb func, void* user_data)
985 mm_ipc_msg_t msgrcv = {0,};
986 mm_ipc_msg_t msgsnd = {0,};
987 int ret = MM_ERROR_NONE;
992 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
995 pthread_mutex_lock(&g_thread_mutex);
998 /* Send REQ_ADD_ACTIVE_DEVICE_CB */
999 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_ADD_ACTIVE_DEVICE_CB;
1000 msgsnd.sound_msg.msgid = instance;
1001 msgsnd.sound_msg.callback = func;
1002 msgsnd.sound_msg.cbdata = user_data;
1004 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
1008 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
1011 switch (msgrcv.sound_msg.msgtype)
1013 case MM_SOUND_MSG_RES_ADD_ACTIVE_DEVICE_CB:
1014 debug_msg("[Client] Success to add active device callback\n");
1015 if (g_thread_id == -1)
1017 g_thread_id = pthread_create(&g_thread, NULL, callbackfunc, NULL);
1018 if (g_thread_id == -1)
1020 debug_critical("[Client] Fail to create thread %s\n", strerror(errno));
1021 ret = MM_ERROR_SOUND_INTERNAL;
1026 case MM_SOUND_MSG_RES_ERROR:
1027 debug_error("[Client] Error occurred \n");
1028 ret = msgrcv.sound_msg.code;
1032 debug_critical("[Client] Unexpected state with communication \n");
1033 ret = msgrcv.sound_msg.code;
1039 pthread_mutex_unlock(&g_thread_mutex);
1045 int _mm_sound_client_remove_active_device_changed_callback(void)
1047 mm_ipc_msg_t msgrcv = {0,};
1048 mm_ipc_msg_t msgsnd = {0,};
1049 int ret = MM_ERROR_NONE;
1054 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
1057 pthread_mutex_lock(&g_thread_mutex);
1059 instance = getpid();
1060 /* Send REQ_REMOVE_ACTIVE_DEVICE_CB */
1061 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_REMOVE_ACTIVE_DEVICE_CB;
1062 msgsnd.sound_msg.msgid = instance;
1064 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
1068 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
1071 switch (msgrcv.sound_msg.msgtype)
1073 case MM_SOUND_MSG_RES_REMOVE_ACTIVE_DEVICE_CB:
1074 debug_msg("[Client] Success to remove active device callback\n");
1076 case MM_SOUND_MSG_RES_ERROR:
1077 debug_error("[Client] Error occurred \n");
1078 ret = msgrcv.sound_msg.code;
1082 debug_critical("[Client] Unexpected state with communication \n");
1083 ret = msgrcv.sound_msg.code;
1089 pthread_mutex_unlock(&g_thread_mutex);
1095 int _mm_sound_client_add_available_route_changed_callback(mm_sound_available_route_changed_cb func, void* user_data)
1097 mm_ipc_msg_t msgrcv = {0,};
1098 mm_ipc_msg_t msgsnd = {0,};
1099 int ret = MM_ERROR_NONE;
1104 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
1107 pthread_mutex_lock(&g_thread_mutex);
1109 instance = getpid();
1110 /* Send REQ_ADD_AVAILABLE_ROUTE_CB */
1111 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_ADD_AVAILABLE_ROUTE_CB;
1112 msgsnd.sound_msg.msgid = instance;
1113 msgsnd.sound_msg.callback = func;
1114 msgsnd.sound_msg.cbdata = user_data;
1116 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
1120 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
1123 switch (msgrcv.sound_msg.msgtype)
1125 case MM_SOUND_MSG_RES_ADD_AVAILABLE_ROUTE_CB:
1126 debug_msg("[Client] Success to add available route callback\n");
1127 if (g_thread_id == -1)
1129 g_thread_id = pthread_create(&g_thread, NULL, callbackfunc, NULL);
1130 if (g_thread_id == -1)
1132 debug_critical("[Client] Fail to create thread %s\n", strerror(errno));
1133 ret = MM_ERROR_SOUND_INTERNAL;
1138 case MM_SOUND_MSG_RES_ERROR:
1139 debug_error("[Client] Error occurred \n");
1140 ret = msgrcv.sound_msg.code;
1144 debug_critical("[Client] Unexpected state with communication \n");
1145 ret = msgrcv.sound_msg.code;
1151 pthread_mutex_unlock(&g_thread_mutex);
1157 int _mm_sound_client_remove_available_route_changed_callback(void)
1159 mm_ipc_msg_t msgrcv = {0,};
1160 mm_ipc_msg_t msgsnd = {0,};
1161 int ret = MM_ERROR_NONE;
1166 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
1169 pthread_mutex_lock(&g_thread_mutex);
1171 instance = getpid();
1172 /* Send REQ_REMOVE_AVAILABLE_ROUTE_CB */
1173 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_REMOVE_AVAILABLE_ROUTE_CB;
1174 msgsnd.sound_msg.msgid = instance;
1176 if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE)
1180 if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE)
1183 switch (msgrcv.sound_msg.msgtype)
1185 case MM_SOUND_MSG_RES_REMOVE_AVAILABLE_ROUTE_CB:
1186 debug_msg("[Client] Success to remove available route callback\n");
1188 case MM_SOUND_MSG_RES_ERROR:
1189 debug_error("[Client] Error occurred \n");
1190 ret = msgrcv.sound_msg.code;
1194 debug_critical("[Client] Unexpected state with communication \n");
1195 ret = msgrcv.sound_msg.code;
1201 pthread_mutex_unlock(&g_thread_mutex);
1207 static int __MMIpcCBSndMsg(mm_ipc_msg_t *msg)
1210 msg->msg_type = msg->sound_msg.msgid;
1211 if (msgsnd(g_msg_sccb, msg,DSIZE, 0)== -1)
1215 debug_warning("[Client] Not acces.\n");
1217 else if(errno == EAGAIN)
1219 debug_warning("[Client] Blocked process [msgflag & IPC_NOWAIT != 0]\n");
1221 else if(errno == EIDRM)
1223 debug_warning("[Client] Removed msgid from system\n");
1225 else if(errno == EINTR)
1227 debug_warning("[Client] Iterrrupted by singnal\n");
1229 else if(errno == EINVAL)
1231 debug_warning("[Client] Invalid msgid or msgtype < 1 or out of data size \n");
1233 debug_critical("[Client] Fail to callback send message msgid : [%d] \n", g_msg_sccb);
1234 return MM_ERROR_COMMON_UNKNOWN;
1236 return MM_ERROR_NONE;
1239 static int __MMIpcCBRecvMsg(int msgtype, mm_ipc_msg_t *msg)
1242 if(msgrcv(g_msg_sccb, msg, DSIZE, msgtype, 0) == -1)
1246 debug_warning("[Client] Not acces.\n");
1248 else if(errno == EACCES)
1250 debug_warning("[Client] Access denied\n");
1252 else if(errno == ENOMSG)
1254 debug_warning("[Client] Blocked process [msgflag & IPC_NOWAIT != 0]\n");
1256 else if(errno == EIDRM)
1258 debug_warning("[Client] Removed msgid from system\n");
1260 else if(errno == EINTR)
1262 debug_warning("[Client] Iterrrupted by singnal\n");
1264 else if(errno == EINVAL)
1266 debug_warning("[Client] Invalid msgid \n");
1269 debug_error("[Client] Fail to callback receive msgid : [%d] \n", g_msg_sccb);
1270 return MM_ERROR_COMMON_UNKNOWN;
1272 return MM_ERROR_NONE;
1275 static int __MMIpcRecvMsg(int msgtype, mm_ipc_msg_t *msg)
1277 int retry_count = 0;
1280 while (msgrcv(g_msg_scrcv, msg, DSIZE, msgtype, IPC_NOWAIT) == -1) {
1281 if (errno == ENOMSG) {
1282 if (retry_count < 20000) { /* usec is 10^-6 sec so, 5ms * 20000 = 10sec. */
1287 return MM_ERROR_SOUND_INTERNAL;
1289 } else if (errno == E2BIG) {
1290 debug_warning("[Client] Not acces.\n");
1291 } else if (errno == EACCES) {
1292 debug_warning("[Client] Access denied\n");
1293 } else if (errno == ENOMSG) {
1294 debug_warning("[Client] Blocked process [msgflag & IPC_NOWAIT != 0]\n");
1295 } else if (errno == EIDRM) {
1296 debug_warning("[Client] Removed msgid from system\n");
1297 } else if (errno == EINTR) {
1298 debug_warning("[Client] Iterrrupted by singnal\n");
1300 } else if (errno == EINVAL) {
1301 debug_warning("[Client] Invalid msgid \n");
1304 debug_error("[Client] Fail to recive msgid : [%d] \n", g_msg_scrcv);
1305 return MM_ERROR_COMMON_UNKNOWN;
1307 debug_log("[Client] Retry %d times when receive msg\n", retry_count);
1308 return MM_ERROR_NONE;
1311 static int __MMIpcSndMsg(mm_ipc_msg_t *msg)
1314 msg->msg_type = msg->sound_msg.msgid;
1315 if (msgsnd(g_msg_scsnd, msg,DSIZE, 0) == -1)
1317 if (errno == EACCES) {
1318 debug_warning("[Client] Not access.\n");
1319 } else if (errno == EAGAIN) {
1320 debug_warning("[Client] Blocked process msgflag & IPC_NOWAIT != 0]\n");
1321 } else if (errno == EIDRM) {
1322 debug_warning("[Client] Removed msgid from system\n");
1323 } else if (errno == EINTR) {
1324 debug_warning("[Client] Iterrrupted by singnal\n");
1325 } else if (errno == EINVAL) {
1326 debug_warning("Invalid msgid or msgtype < 1 or out of data size \n");
1327 } else if (errno == EFAULT) {
1328 debug_warning("[Client] The address pointed to by msgp isn't accessible \n");
1329 } else if (errno == ENOMEM) {
1330 debug_warning("[Client] The system does not have enough memory to make a copy of the message pointed to by msgp\n");
1333 debug_critical("[Client] Fail to send message msgid : [%d] \n", g_msg_scsnd);
1334 return MM_ERROR_SOUND_INTERNAL;
1336 return MM_ERROR_NONE;
1339 static int __MMSoundGetMsg(void)
1341 /* Init message queue, generate msgid for communication to server */
1342 /* The key value to get msgid is defined "mm_sound_msg.h". Shared with server */
1346 /* get msg queue rcv, snd, cb */
1347 g_msg_scsnd = msgget(ftok(KEY_BASE_PATH, RCV_MSG), 0666);
1348 g_msg_scrcv = msgget(ftok(KEY_BASE_PATH, SND_MSG), 0666);
1349 g_msg_sccb = msgget(ftok(KEY_BASE_PATH, CB_MSG), 0666);
1351 if ((g_msg_scsnd == -1 || g_msg_scrcv == -1 || g_msg_sccb == -1) != MM_ERROR_NONE) {
1352 if (errno == EACCES) {
1353 debug_warning("Require ROOT permission.\n");
1354 } else if (errno == ENOMEM) {
1355 debug_warning("System memory is empty.\n");
1356 } else if(errno == ENOSPC) {
1357 debug_warning("Resource is empty.\n");
1359 debug_error("Fail to GET msgid\n");
1360 return MM_ERROR_SOUND_INTERNAL;
1363 debug_msg("Get msg queue id from server : [%d]\n", g_msg_scsnd);
1364 debug_msg("Get msg queue id from server : [%d]\n", g_msg_scrcv);
1365 debug_msg("Get msg queue id from server : [%d]\n", g_msg_sccb);
1368 return MM_ERROR_NONE;
1373 int MMSoundClientIsBtA2dpOn (bool *connected, char** bt_name)
1375 mm_ipc_msg_t msgrcv = {0,};
1376 mm_ipc_msg_t msgsnd = {0,};
1377 int ret = MM_ERROR_NONE;
1382 instance = getpid();
1384 if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE)
1387 pthread_mutex_lock(&g_thread_mutex);
1390 msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_IS_BT_A2DP_ON;
1391 msgsnd.sound_msg.msgid = instance;
1393 ret = __MMIpcSndMsg(&msgsnd);
1394 if (ret != MM_ERROR_NONE)
1396 debug_error("Fail to send msg\n");
1401 ret = __MMIpcRecvMsg(instance, &msgrcv);
1402 if (ret != MM_ERROR_NONE)
1404 debug_error("Fail to recieve msg\n");
1407 switch (msgrcv.sound_msg.msgtype)
1409 case MM_SOUND_MSG_RES_IS_BT_A2DP_ON:
1410 debug_msg("Success to get IS_BT_A2DP_ON [%d][%s]\n", msgrcv.sound_msg.code, msgrcv.sound_msg.filename);
1411 *connected = (bool)msgrcv.sound_msg.code;
1413 *bt_name = strdup (msgrcv.sound_msg.filename);
1417 case MM_SOUND_MSG_RES_ERROR:
1418 debug_error("Error occurred \n");
1419 ret = msgrcv.sound_msg.code;
1423 debug_critical("Unexpected state with communication \n");
1424 ret = msgrcv.sound_msg.code;
1430 pthread_mutex_unlock(&g_thread_mutex);
1436 #endif // PULSE_CLIENT