4 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Sangchul Lee <sc11.lee@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.
32 #include <sys/socket.h>
35 #include "../include/mm_sound_focus_socket.h"
36 #include "include/mm_sound_mgr_focus.h"
37 #include "include/mm_sound_mgr_focus_ipc.h"
39 static pthread_t g_focus_ready_thread_id = 0;
41 typedef int (*focus_function_handler) (int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
42 static int handle_register_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
43 static int handle_unregister_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
44 static int handle_add_watch_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
45 static int handle_remove_watch_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
46 static int handle_acquire_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
47 static int handle_release_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
48 static int handle_set_focus_reacquisition(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
49 static int handle_deliver_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
50 static int handle_get_acquired_focus_info(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result);
53 FOCUS_FUNCTION_REGISTER,
54 FOCUS_FUNCTION_UNREGISTER,
55 FOCUS_FUNCTION_ADD_WATCH,
56 FOCUS_FUNCTION_REMOVE_WATCH,
57 FOCUS_FUNCTION_ACQUIRE,
58 FOCUS_FUNCTION_RELEASE,
59 FOCUS_FUNCTION_SET_REACQUISITION,
60 FOCUS_FUNCTION_DELIVER,
61 FOCUS_FUNCTION_GET_ACQUIRED_INFO,
65 #define DEFAULT_FOCUS_THREAD_READY_TIMEOUT 5
66 #define MAX_FOCUS_THREAD_READY_WAIT_RETRY 6
68 typedef struct mm_sound_focus_thread_data {
72 gboolean listen_ready;
73 } focus_thread_data_t;
75 typedef struct mm_sound_focus_function_intf {
77 focus_function_handler handler;
78 } mm_sound_focus_function_intf_t;
80 static mm_sound_focus_function_intf_t functions[FOCUS_FUNCTION_MAX] = {
81 [FOCUS_FUNCTION_REGISTER] = {
82 .name = FOCUS_FUNC_NAME_REGISTER,
83 .handler = handle_register_focus
85 [FOCUS_FUNCTION_UNREGISTER] = {
86 .name = FOCUS_FUNC_NAME_UNREGISTER,
87 .handler = handle_unregister_focus
89 [FOCUS_FUNCTION_ADD_WATCH] = {
90 .name = FOCUS_FUNC_NAME_ADD_WATCH,
91 .handler = handle_add_watch_focus
93 [FOCUS_FUNCTION_REMOVE_WATCH] = {
94 .name = FOCUS_FUNC_NAME_REMOVE_WATCH,
95 .handler = handle_remove_watch_focus
97 [FOCUS_FUNCTION_ACQUIRE] = {
98 .name = FOCUS_FUNC_NAME_ACQUIRE,
99 .handler = handle_acquire_focus
101 [FOCUS_FUNCTION_RELEASE] = {
102 .name = FOCUS_FUNC_NAME_RELEASE,
103 .handler = handle_release_focus
105 [FOCUS_FUNCTION_SET_REACQUISITION] = {
106 .name = FOCUS_FUNC_NAME_SET_REACQUISITION,
107 .handler = handle_set_focus_reacquisition
109 [FOCUS_FUNCTION_DELIVER] = {
110 .name = FOCUS_FUNC_NAME_DELIVER,
111 .handler = handle_deliver_focus
113 [FOCUS_FUNCTION_GET_ACQUIRED_INFO] = {
114 .name = FOCUS_FUNC_NAME_GET_ACQUIRED_INFO,
115 .handler = handle_get_acquired_focus_info
119 static int handle_register_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
121 int ret = MM_ERROR_NONE;
125 ret = __mm_sound_mgr_focus_ipc_register_focus(param->pid, fd, param->stream_type);
126 result->handle_id = fd;
133 static int handle_unregister_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
135 int ret = MM_ERROR_NONE;
139 if (fd != param->handle_id) {
140 debug_error("fd[%d] does not match with handle_id[%d] from param", fd, param->handle_id);
141 return MM_ERROR_SOUND_INTERNAL;
143 ret = __mm_sound_mgr_focus_ipc_unregister_focus(param->pid, param->handle_id);
150 static int handle_add_watch_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
152 int ret = MM_ERROR_NONE;
156 ret = __mm_sound_mgr_focus_ipc_add_watch_node(param->pid, fd, param->focus_type);
157 result->handle_id = fd;
164 static int handle_remove_watch_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
166 int ret = MM_ERROR_NONE;
170 if (fd != param->handle_id) {
171 debug_error("fd[%d] does not match with handle_id[%d] from param", fd, param->handle_id);
172 return MM_ERROR_SOUND_INTERNAL;
174 ret = __mm_sound_mgr_focus_ipc_remove_watch_node(param->pid, param->handle_id);
181 static int handle_acquire_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
183 int ret = MM_ERROR_NONE;
187 if (fd != param->handle_id) {
188 debug_error("fd[%d] does not match with handle_id[%d] from param", fd, param->handle_id);
189 return MM_ERROR_SOUND_INTERNAL;
191 ret = __mm_sound_mgr_focus_ipc_acquire_focus(param->pid, param->handle_id, param->focus_type,
192 param->option, param->ext_info, true);
199 static int handle_release_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
201 int ret = MM_ERROR_NONE;
205 if (fd != param->handle_id) {
206 debug_error("fd[%d] does not match with handle_id[%d] from param", fd, param->handle_id);
207 return MM_ERROR_SOUND_INTERNAL;
209 ret = __mm_sound_mgr_focus_ipc_release_focus(param->pid, param->handle_id, param->focus_type,
210 param->option, param->ext_info, true);
217 static int handle_set_focus_reacquisition(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
219 int ret = MM_ERROR_NONE;
223 if (fd != param->handle_id) {
224 debug_error("fd[%d] does not match with handle_id[%d] from param", fd, param->handle_id);
225 return MM_ERROR_SOUND_INTERNAL;
227 ret = __mm_sound_mgr_focus_ipc_set_focus_reacquisition(param->pid, param->handle_id, param->reacquisition);
234 static int handle_deliver_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
236 int ret = MM_ERROR_NONE;
240 ret = __mm_sound_mgr_focus_ipc_deliver_focus(param->pid, param->handle_id, param->handle_id_dst, param->focus_type);
247 static int handle_get_acquired_focus_info(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
249 int ret = MM_ERROR_NONE;
250 char *res_stream_type = NULL;
251 char *res_ext_info = NULL;
256 debug_error("invalid arguments, result[%p]", result);
257 return MM_ERROR_INVALID_ARGUMENT;
260 ret = __mm_sound_mgr_focus_ipc_get_acquired_focus_stream_type(param->focus_type, &res_stream_type, &result->option, &res_ext_info);
261 if (ret == MM_ERROR_NONE) {
262 MMSOUND_STRNCPY(result->stream_type, res_stream_type, MM_SOUND_NAME_NUM);
263 MMSOUND_STRNCPY(result->ext_info, res_ext_info, MM_SOUND_NAME_NUM);
271 static int focus_functions_handler(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
274 int ret = MM_ERROR_NONE;
277 return MM_ERROR_INVALID_ARGUMENT;
279 debug_msg("fd[%d], param[%p], function_name[%s]", fd, param, param->func_name);
281 for (i = 0; i < FOCUS_FUNCTION_MAX; i++) {
282 if (!strncmp(param->func_name, functions[i].name, MAX_ERROR_LEN))
283 ret = functions[i].handler(fd, param, result);
289 static bool need_to_exit(const char *func_name)
291 if (!strncmp(func_name, FOCUS_FUNC_NAME_UNREGISTER, MM_SOUND_NAME_NUM) ||
292 !strncmp(func_name, FOCUS_FUNC_NAME_REMOVE_WATCH, MM_SOUND_NAME_NUM) ||
293 !strncmp(func_name, FOCUS_FUNC_NAME_GET_ACQUIRED_INFO, MM_SOUND_NAME_NUM))
300 static focus_thread_data_t *__focus_thread_data_create(const int *sockfd)
302 focus_thread_data_t *thread_data = NULL;
303 thread_data = g_new0(focus_thread_data_t, 1);
305 thread_data->sockfd = sockfd;
306 g_mutex_init(&thread_data->wait_mutex);
307 g_cond_init(&thread_data->wait_cond);
308 thread_data->listen_ready = FALSE;
313 static void __focus_thread_ready_signal(focus_thread_data_t *thread_data)
315 g_assert(thread_data);
317 g_mutex_lock(&thread_data->wait_mutex);
319 debug_msg("signaling focus thread ready!");
320 thread_data->listen_ready = TRUE;
321 g_cond_signal(&thread_data->wait_cond);
323 g_mutex_unlock(&thread_data->wait_mutex);
326 static gboolean __focus_thread_ready_wait(focus_thread_data_t *thread_data, int timeout_sec)
329 g_autoptr(GMutexLocker) locker = NULL;
331 g_assert(thread_data);
333 locker = g_mutex_locker_new(&thread_data->wait_mutex);
335 end_time = g_get_monotonic_time() + timeout_sec * G_TIME_SPAN_SECOND;
337 while (!thread_data->listen_ready) {
338 if (!g_cond_wait_until(&thread_data->wait_cond,
339 &thread_data->wait_mutex,
341 debug_error("timeout!!!");
344 debug_msg("wait done! ready:%d", thread_data->listen_ready);
347 return thread_data->listen_ready;
350 static void __focus_thread_data_destroy(focus_thread_data_t *thread_data)
352 g_assert(thread_data);
354 g_mutex_clear(&thread_data->wait_mutex);
355 g_cond_clear(&thread_data->wait_cond);
360 static void *work_thread_func(void *data)
362 int accepted_fd = -1;
363 char str_error[MAX_ERROR_LEN] = {'\0',};
364 _mm_sound_focus_socket_param_t read_data;
365 _mm_sound_focus_socket_result_t result;
371 debug_error("invalid data");
375 accepted_fd = (int)(uintptr_t)(data);
378 memset(&read_data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
379 if ((rval = read(accepted_fd, &read_data, sizeof(_mm_sound_focus_socket_param_t))) < 0) {
380 strerror_r(errno, str_error, sizeof(str_error));
381 debug_error("failed to read(), err: %s", str_error);
383 } else if (rval == sizeof(_mm_sound_focus_socket_param_t)) {
384 int ret = MM_ERROR_NONE;
386 debug_log("data read successfully, command[%s], pid[%d]",
387 read_data.func_name, read_data.pid);
389 memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
390 if ((ret = focus_functions_handler(accepted_fd, &read_data, &result)))
391 debug_error("failed to focus_function_handler(), err[0x%x]", ret);
395 if (write(accepted_fd, &result, sizeof(_mm_sound_focus_socket_result_t)) < 0) {
396 strerror_r(errno, str_error, sizeof(str_error));
397 debug_error("failed to write(), err: %s", str_error);
400 if (need_to_exit(read_data.func_name))
403 debug_error("failed to read(), read size mismatched, rval(%d), expect size(%zu)",
404 rval, sizeof(_mm_sound_focus_socket_param_t));
409 /* clean-up FD and focus node */
410 mm_sound_mgr_focus_emergent_exit_by_id(accepted_fd);
412 debug_msg("now close fd[%d]", accepted_fd);
420 static void *ready_thread_func(void *data)
422 int accepted_fd = -1;
423 char str_error[MAX_ERROR_LEN] = {'\0',};
425 pthread_t focus_work_thread_id;
428 focus_thread_data_t *thread_data = (focus_thread_data_t *)data;
431 debug_error("invalid data");
437 ret = pthread_attr_init(&attr);
439 debug_error("failed to init pthread attr, errno=%d", ret);
443 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
445 debug_error("failed to set detach state, errno=%d", ret);
449 if (listen(*thread_data->sockfd, 5)) {
450 strerror_r(errno, str_error, sizeof(str_error));
451 debug_error("failed to listen(), err: %s", str_error);
454 debug_msg("listen for fd [%d] success", *thread_data->sockfd);
456 __focus_thread_ready_signal(thread_data);
458 while (*thread_data->sockfd != -1) {
459 accepted_fd = accept(*thread_data->sockfd, NULL, NULL);
460 if (accepted_fd == -1) {
461 strerror_r(errno, str_error, sizeof(str_error));
462 debug_error("failed to accept(), err: %s", str_error);
466 debug_log("accepted fd [%d]", accepted_fd);
468 if (pthread_create(&focus_work_thread_id, &attr, (void *)work_thread_func, (void *)(uintptr_t)accepted_fd)) {
469 debug_error("failed to create work thread, accepted_fd(%d)", accepted_fd);
474 __focus_thread_data_destroy(thread_data);
477 pthread_attr_destroy(&attr);
484 int MMSoundMgrFocusSocketInit(int *sockfd)
487 struct sockaddr_un addr_un;
488 char str_error[128] = {'\0',};
491 debug_error("input param fd is null");
492 return MM_ERROR_INVALID_ARGUMENT;
495 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
497 strerror_r(errno, str_error, sizeof(str_error));
498 debug_error("failed to socket(), err: %s", str_error);
502 debug_msg("focus server socket fd [%d]", socket_fd);
504 memset(&addr_un, 0, sizeof(addr_un));
505 addr_un.sun_family = AF_UNIX;
506 strncpy(addr_un.sun_path, FOCUS_SERVER_SOCK, sizeof(addr_un.sun_path));
508 if (bind(socket_fd, (struct sockaddr *)&addr_un, sizeof(addr_un))) {
510 strerror_r(errsv, str_error, sizeof(str_error));
511 debug_error("failed to bind(), err: %s", str_error);
512 if (errsv == EADDRINUSE) {
513 unlink(FOCUS_SERVER_SOCK);
514 debug_msg("unlink socket and bind again...");
515 if (bind(socket_fd, (struct sockaddr *)&addr_un, sizeof(addr_un))) {
516 strerror_r(errno, str_error, sizeof(str_error));
517 debug_error("failed to bind() again, err: %s", str_error);
525 debug_msg("focus server socket binding success");
531 return MM_ERROR_NONE;
537 return MM_ERROR_SOUND_INTERNAL;
540 void MMSoundMgrFocusSocketFini(int *sockfd)
544 if (g_focus_ready_thread_id) {
545 unlink(FOCUS_SERVER_SOCK);
548 shutdown(*sockfd, SHUT_RDWR);
553 debug_msg("try pthread join for thread id:%lu", g_focus_ready_thread_id);
554 pthread_join(g_focus_ready_thread_id, NULL);
555 debug_msg("pthread joined well");
556 g_focus_ready_thread_id = 0;
562 int MMSoundMgrFocusSocketReadyToWork(const int *sockfd)
564 focus_thread_data_t *thread_data = NULL;
565 int retry_remaining = MAX_FOCUS_THREAD_READY_WAIT_RETRY;
568 debug_error("input param sockfd [%d] is not valid", *sockfd);
569 return MM_ERROR_INVALID_ARGUMENT;
572 debug_msg("sockfd [%d]", *sockfd);
574 thread_data = __focus_thread_data_create(sockfd);
576 if (pthread_create(&g_focus_ready_thread_id, NULL, (void *)ready_thread_func, thread_data)) {
577 debug_error("failed to create ready thread");
582 if (__focus_thread_ready_wait(thread_data, DEFAULT_FOCUS_THREAD_READY_TIMEOUT)) {
583 debug_msg("[%d] wait success!!", retry_remaining);
584 return MM_ERROR_NONE;
587 debug_error("[%d] focus thread is not ready for %u sec!!!",
588 retry_remaining, DEFAULT_FOCUS_THREAD_READY_TIMEOUT);
589 } while (--retry_remaining > 0);
592 __focus_thread_data_destroy(thread_data);
593 return MM_ERROR_SOUND_INTERNAL;