summaryrefslogtreecommitdiff
path: root/server/mm_sound_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/mm_sound_server.c')
-rw-r--r--server/mm_sound_server.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/server/mm_sound_server.c b/server/mm_sound_server.c
new file mode 100644
index 0000000..b5bd15c
--- /dev/null
+++ b/server/mm_sound_server.c
@@ -0,0 +1,450 @@
+/*
+ * libmm-sound
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Seungbae Shin <seungbae.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <getopt.h>
+
+#include <vconf.h>
+#include <mm_error.h>
+#include <mm_debug.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <semaphore.h>
+#include <time.h>
+#include <errno.h>
+
+
+#include "../include/mm_sound_common.h"
+#include "../include/mm_sound_utils.h"
+#include "include/mm_sound_thread_pool.h"
+#include "include/mm_sound_mgr_run.h"
+#include "include/mm_sound_mgr_codec.h"
+#include "include/mm_sound_mgr_ipc.h"
+#include "include/mm_sound_mgr_pulse.h"
+#include "include/mm_sound_mgr_asm.h"
+#include "include/mm_sound_mgr_session.h"
+#include "include/mm_sound_mgr_device.h"
+#include "include/mm_sound_mgr_device_headset.h"
+#include "include/mm_sound_mgr_device_dock.h"
+#include "include/mm_sound_mgr_device_hdmi.h"
+#include "include/mm_sound_mgr_device_wfd.h"
+#include <audio-session-manager.h>
+
+#include <glib.h>
+
+#define PLUGIN_ENV "MM_SOUND_PLUGIN_PATH"
+#define PLUGIN_DIR "/usr/lib/soundplugins/"
+#define PLUGIN_MAX 30
+
+#define HIBERNATION_SOUND_CHECK_PATH "/tmp/hibernation/sound_ready"
+#define USE_SYSTEM_SERVER_PROCESS_MONITORING
+
+#define ASM_CHECK_INTERVAL 10000
+
+#define MAX_PLUGIN_DIR_PATH_LEN 256
+
+typedef struct {
+ char plugdir[MAX_PLUGIN_DIR_PATH_LEN];
+ int startserver;
+ int printlist;
+ int testmode;
+ int poweroff;
+ int soundreset;
+} server_arg;
+
+static char *str_errormsg[] = {
+ "Operation is success.",
+ "Handle Init Fail",
+ "Path Init Fail",
+ "Handle Fini Fail",
+ "Path Fini Fail",
+ "Handle Reset Fail",
+ "Path Reset Fail",
+ "Handle Dump Fail",
+ "Path Dump Fail",
+ "Sync Dump Fail",
+};
+
+static int getOption(int argc, char **argv, server_arg *arg);
+static int usgae(int argc, char **argv);
+
+static struct sigaction sigint_action; /* Backup pointer of SIGINT handler */
+static struct sigaction sigabrt_action; /* Backup pointer of SIGABRT signal handler */
+static struct sigaction sigsegv_action; /* Backup pointer of SIGSEGV fault signal handler */
+static struct sigaction sigterm_action; /* Backup pointer of SIGTERM signal handler */
+static struct sigaction sigsys_action; /* Backup pointer of SIGSYS signal handler */
+static void _exit_handler(int sig);
+
+GMainLoop *g_mainloop;
+
+void* pulse_handle;
+
+gpointer event_loop_thread(gpointer data)
+{
+ g_mainloop = g_main_loop_new(NULL, TRUE);
+ if(g_mainloop == NULL) {
+ debug_error("g_main_loop_new() failed\n");
+ }
+ g_main_loop_run(g_mainloop);
+ return NULL;
+}
+
+static void __wait_for_asm_ready ()
+{
+ int retry_count = 0;
+ int asm_ready = 0;
+ while (!asm_ready) {
+ debug_msg("Checking ASM ready....[%d]\n", retry_count++);
+ if (vconf_get_int(ASM_READY_KEY, &asm_ready)) {
+ debug_warning("vconf_get_int for ASM_READY_KEY (%s) failed\n", ASM_READY_KEY);
+ }
+ usleep (ASM_CHECK_INTERVAL);
+ }
+ debug_msg("ASM is now ready...clear the key!!!\n");
+ vconf_set_int(ASM_READY_KEY, 0);
+}
+
+static int _handle_power_off ()
+{
+ int handle = 0;
+ int asm_error = 0;
+
+ if (ASM_register_sound (-1, &handle, ASM_EVENT_EMERGENCY, ASM_STATE_PLAYING, NULL, NULL, ASM_RESOURCE_NONE, &asm_error)) {
+ if (ASM_unregister_sound (handle, ASM_EVENT_EMERGENCY, &asm_error)) {
+ debug_log ("asm register/unregister success!!!\n");
+ return 0;
+ } else {
+ debug_error ("asm unregister failed...0x%x\n", asm_error);
+ }
+ } else {
+ debug_error ("asm register failed...0x%x\n", asm_error);
+ }
+
+ return -1;
+}
+
+static int _handle_sound_reset ()
+{
+ int ret = 0;
+ debug_warning ("not supported\n");
+ return 0;
+}
+
+static sem_t* sem_create_n_wait()
+{
+ sem_t* sem = NULL;
+
+ if ((sem = sem_open ("booting-sound", O_CREAT, 0660, 0))== SEM_FAILED) {
+ debug_error ("error creating sem : %d", errno);
+ return NULL;
+ }
+
+ debug_msg ("returning sem [%p]", sem);
+ return sem;
+}
+
+int main(int argc, char **argv)
+{
+ sem_t* sem = NULL;
+ server_arg serveropt;
+ struct sigaction action;
+#ifdef USE_HIBERNATION
+ int heynotifd = -1;
+#endif
+ int volumes[VOLUME_TYPE_MAX] = {0, };
+#if !defined(USE_SYSTEM_SERVER_PROCESS_MONITORING)
+ int pid;
+#endif
+
+ action.sa_handler = _exit_handler;
+ action.sa_flags = 0;
+ sigemptyset(&action.sa_mask);
+
+ if (getOption(argc, argv, &serveropt))
+ return 1;
+
+ debug_warning("sound_server [%d] init \n", getpid());
+
+ if (serveropt.startserver) {
+ sem = sem_create_n_wait();
+ }
+ /* Daemon process create */
+ if (!serveropt.testmode && serveropt.startserver) {
+#if !defined(USE_SYSTEM_SERVER_PROCESS_MONITORING)
+ daemon(0,0); //chdir to ("/"), and close stdio
+#endif
+ }
+ if (serveropt.poweroff) {
+ if (_handle_power_off() == 0) {
+ debug_log("_handle_power_off success!!\n");
+ } else {
+ debug_error("_handle_power_off failed..\n");
+ }
+ return 0;
+ }
+
+ if (serveropt.soundreset) {
+ if (_handle_sound_reset() == 0) {
+ debug_log("_handle_sound_reset success!!\n");
+ } else {
+ debug_error("_handle_sound_reset failed..\n");
+ }
+ return 0;
+ }
+
+ /* Sound Server Starts!!!*/
+ debug_warning("sound_server [%d] start \n", getpid());
+
+ signal(SIGPIPE, SIG_IGN); //ignore SIGPIPE
+
+#if !defined(USE_SYSTEM_SERVER_PROCESS_MONITORING)
+ while(1)
+ {
+ if ((pid = fork()) < 0)
+ {
+ fprintf(stderr, "Sub Fork Error\n");
+ return 2;
+ }
+ else if(pid == 0)
+ {
+ break;
+ }
+ else if(pid > 0)
+ {
+ wait(&ret);
+ fprintf(stderr, "Killed by signal [%05X]\n", ret);
+ fprintf(stderr, "Daemon is run againg\n");
+ }
+ }
+#endif
+ sigaction(SIGABRT, &action, &sigabrt_action);
+ sigaction(SIGSEGV, &action, &sigsegv_action);
+ sigaction(SIGTERM, &action, &sigterm_action);
+ sigaction(SIGSYS, &action, &sigsys_action);
+
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
+ if(NULL == g_thread_create(event_loop_thread, NULL, FALSE, NULL)) {
+ fprintf(stderr,"event loop thread create failed\n");
+ return 3;
+ }
+
+ if (serveropt.startserver || serveropt.printlist) {
+ MMSoundThreadPoolInit();
+ MMSoundMgrRunInit(serveropt.plugdir);
+ MMSoundMgrCodecInit(serveropt.plugdir);
+ if (!serveropt.testmode)
+ MMSoundMgrIpcInit();
+
+ pulse_handle = MMSoundMgrPulseInit();
+ MMSoundMgrASMInit();
+ /* Wait for ASM Ready */
+ __wait_for_asm_ready();
+ debug_warning("sound_server [%d] asm ready...now, initialize devices!!!\n", getpid());
+
+ _mm_sound_mgr_device_init();
+ MMSoundMgrHeadsetInit();
+ MMSoundMgrDockInit();
+ MMSoundMgrHdmiInit();
+ MMSoundMgrWfdInit();
+ MMSoundMgrSessionInit();
+ }
+
+ debug_warning("sound_server [%d] initialization complete...now, start running!!\n", getpid());
+
+ if (serveropt.startserver) {
+ /* Start Run types */
+ MMSoundMgrRunRunAll();
+
+#ifdef USE_HIBERNATION
+ /* set hibernation check */
+ _mm_sound_check_hibernation (HIBERNATION_SOUND_CHECK_PATH);
+#endif
+ unlink(PA_READY); // remove pa_ready file after sound-server init.
+
+ if (sem_post(sem) == -1) {
+ debug_error ("error sem post : %d", errno);
+ } else {
+ debug_msg ("Ready to play booting sound!!!!");
+ }
+ /* Start Ipc mgr */
+ MMSoundMgrIpcReady();
+ }
+
+ debug_warning("sound_server [%d] terminating \n", getpid());
+
+ if (serveropt.startserver || serveropt.printlist) {
+ MMSoundMgrRunStopAll();
+ if (!serveropt.testmode)
+ MMSoundMgrIpcFini();
+
+ MMSoundMgrCodecFini();
+ MMSoundMgrRunFini();
+ MMSoundThreadPoolFini();
+
+ MMSoundMgrWfdFini();
+ MMSoundMgrHdmiFini();
+ MMSoundMgrDockFini();
+ MMSoundMgrHeadsetFini();
+ MMSoundMgrSessionFini();
+ _mm_sound_mgr_device_fini();
+ MMSoundMgrASMFini();
+ MMSoundMgrPulseFini(pulse_handle);
+#ifdef USE_HIBERNATION
+ if(heynoti_unsubscribe(heynotifd, "HIBERNATION_LEAVE", NULL)) {
+ debug_error("heynoti_unsubscribe failed..\n");
+ }
+ heynoti_close(heynotifd);
+#endif
+ }
+
+ debug_warning("sound_server [%d] exit \n", getpid());
+
+ return 0;
+}
+
+static int getOption(int argc, char **argv, server_arg *arg)
+{
+ int c;
+ char *plugin_env_dir = NULL;
+ static struct option long_options[] = {
+ {"start", 0, 0, 'S'},
+ {"poweroff", 0, 0, 'F'},
+ {"soundreset", 0, 0, 'R'},
+ {"list", 0, 0, 'L'},
+ {"help", 0, 0, 'H'},
+ {"plugdir", 1, 0, 'P'},
+ {"testmode", 0, 0, 'T'},
+ {0, 0, 0, 0}
+ };
+ memset(arg, 0, sizeof(server_arg));
+
+ plugin_env_dir = getenv(PLUGIN_ENV);
+ if (plugin_env_dir) {
+ MMSOUND_STRNCPY(arg->plugdir, plugin_env_dir, MAX_PLUGIN_DIR_PATH_LEN);
+ } else {
+ MMSOUND_STRNCPY(arg->plugdir, PLUGIN_DIR, MAX_PLUGIN_DIR_PATH_LEN);
+ }
+
+ arg->testmode = 0;
+
+ while (1)
+ {
+ int opt_idx = 0;
+
+ c = getopt_long (argc, argv, "SFLHRUP:Tiurd", long_options, &opt_idx);
+ if (c == -1)
+ break;
+ switch (c)
+ {
+ case 'S': /* Start daemon */
+ arg->startserver = 1;
+ break;
+ case 'F': /* Poweroff */
+ arg->poweroff = 1;
+ break;
+ case 'R': /* SoundReset */
+ arg->soundreset = 1;
+ break;
+ case 'L': /* list of plugins */
+ arg->printlist = 1;
+ break;
+ case 'P': /* Custom plugindir */
+ MMSOUND_STRNCPY(arg->plugdir, optarg, MAX_PLUGIN_DIR_PATH_LEN);
+ break;
+ case 'T': /* Test mode */
+ arg->testmode = 1;
+ break;
+ case 'H': /* help msg */
+ default:
+ return usgae(argc, argv);
+ }
+ }
+ if (argc == 1)
+ return usgae(argc, argv);
+ return 0;
+}
+
+//__attribute__ ((destructor))
+static void _exit_handler(int sig)
+{
+ int ret = MM_ERROR_NONE;
+
+ ret = MMSoundMgrRunStopAll();
+ if (ret != MM_ERROR_NONE) {
+ debug_error("Fail to stop run-plugin\n");
+ } else {
+ debug_log("All run-type plugin stopped\n");
+ }
+
+ switch(sig)
+ {
+ case SIGINT:
+ sigaction(SIGINT, &sigint_action, NULL);
+ debug_error("signal(SIGINT) error");
+ break;
+ case SIGABRT:
+ sigaction(SIGABRT, &sigabrt_action, NULL);
+ debug_error("signal(SIGABRT) error");
+ break;
+ case SIGSEGV:
+ sigaction(SIGSEGV, &sigsegv_action, NULL);
+ debug_error("signal(SIGSEGV) error");
+ break;
+ case SIGTERM:
+ sigaction(SIGTERM, &sigterm_action, NULL);
+ debug_error("signal(SIGTERM) error");
+ break;
+ case SIGSYS:
+ sigaction(SIGSYS, &sigsys_action, NULL);
+ debug_error("signal(SIGSYS) error");
+ break;
+ default:
+ break;
+ }
+ raise(sig);
+}
+
+static int usgae(int argc, char **argv)
+{
+ fprintf(stderr, "Usage: %s [Options]\n", argv[0]);
+ fprintf(stderr, "\t%-20s: start sound server.\n", "--start,-S");
+ fprintf(stderr, "\t%-20s: handle poweroff\n", "--poweroff,-F");
+ fprintf(stderr, "\t%-20s: handle soundreset\n", "--soundreset,-R");
+ fprintf(stderr, "\t%-20s: help message.\n", "--help,-H");
+#if 0 /* currently not in use */
+ fprintf(stderr, "\t%-20s: print plugin list.\n", "--list,-L");
+ fprintf(stderr, "\t%-20s: print this message.\n", "--plugdir,-P");
+#endif
+
+ return 1;
+}
+