beaaa6799705ad864a87e89d97086b62c62e87a3
[platform/core/multimedia/libmm-sound.git] / focus_server / mm_sound_mgr_focus_socket.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@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 <stdio.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <string.h>
26
27 #include <mm_error.h>
28 #include <mm_debug.h>
29
30 #include <gio/gio.h>
31
32 #include <sys/socket.h>
33 #include <sys/un.h>
34
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"
38
39 static pthread_t g_focus_ready_thread_id = 0;
40
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);
51
52 enum {
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,
62         FOCUS_FUNCTION_MAX,
63 };
64
65 #define DEFAULT_FOCUS_THREAD_READY_TIMEOUT 5
66 #define MAX_FOCUS_THREAD_READY_WAIT_RETRY 6
67
68 typedef struct mm_sound_focus_thread_data {
69         const int *sockfd;
70         GMutex wait_mutex;
71         GCond wait_cond;
72         gboolean listen_ready;
73 } focus_thread_data_t;
74
75 typedef struct mm_sound_focus_function_intf {
76         const char *name;
77         focus_function_handler handler;
78 } mm_sound_focus_function_intf_t;
79
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
84         },
85         [FOCUS_FUNCTION_UNREGISTER] = {
86                 .name = FOCUS_FUNC_NAME_UNREGISTER,
87                 .handler = handle_unregister_focus
88         },
89         [FOCUS_FUNCTION_ADD_WATCH] = {
90                 .name = FOCUS_FUNC_NAME_ADD_WATCH,
91                 .handler = handle_add_watch_focus
92         },
93         [FOCUS_FUNCTION_REMOVE_WATCH] = {
94                 .name = FOCUS_FUNC_NAME_REMOVE_WATCH,
95                 .handler = handle_remove_watch_focus
96         },
97         [FOCUS_FUNCTION_ACQUIRE] = {
98                 .name = FOCUS_FUNC_NAME_ACQUIRE,
99                 .handler = handle_acquire_focus
100         },
101         [FOCUS_FUNCTION_RELEASE] = {
102                 .name = FOCUS_FUNC_NAME_RELEASE,
103                 .handler = handle_release_focus
104         },
105         [FOCUS_FUNCTION_SET_REACQUISITION] = {
106                 .name = FOCUS_FUNC_NAME_SET_REACQUISITION,
107                 .handler = handle_set_focus_reacquisition
108         },
109         [FOCUS_FUNCTION_DELIVER] = {
110                 .name = FOCUS_FUNC_NAME_DELIVER,
111                 .handler = handle_deliver_focus
112         },
113         [FOCUS_FUNCTION_GET_ACQUIRED_INFO] = {
114                 .name = FOCUS_FUNC_NAME_GET_ACQUIRED_INFO,
115                 .handler = handle_get_acquired_focus_info
116         }
117 };
118
119 static int handle_register_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
120 {
121         int ret = MM_ERROR_NONE;
122
123         debug_fenter();
124
125         ret = __mm_sound_mgr_focus_ipc_register_focus(param->pid, fd, param->stream_type);
126         result->handle_id = fd;
127
128         debug_fleave();
129
130         return ret;
131 }
132
133 static int handle_unregister_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
134 {
135         int ret = MM_ERROR_NONE;
136
137         debug_fenter();
138
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;
142         }
143         ret = __mm_sound_mgr_focus_ipc_unregister_focus(param->pid, param->handle_id);
144
145         debug_fleave();
146
147         return ret;
148 }
149
150 static int handle_add_watch_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
151 {
152         int ret = MM_ERROR_NONE;
153
154         debug_fenter();
155
156         ret = __mm_sound_mgr_focus_ipc_add_watch_node(param->pid, fd, param->focus_type);
157         result->handle_id = fd;
158
159         debug_fleave();
160
161         return ret;
162 }
163
164 static int handle_remove_watch_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
165 {
166         int ret = MM_ERROR_NONE;
167
168         debug_fenter();
169
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;
173         }
174         ret = __mm_sound_mgr_focus_ipc_remove_watch_node(param->pid, param->handle_id);
175
176         debug_fleave();
177
178         return ret;
179 }
180
181 static int handle_acquire_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
182 {
183         int ret = MM_ERROR_NONE;
184
185         debug_fenter();
186
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;
190         }
191         ret = __mm_sound_mgr_focus_ipc_acquire_focus(param->pid, param->handle_id, param->focus_type,
192                                                                                                 param->option, param->ext_info, true);
193
194         debug_fleave();
195
196         return ret;
197 }
198
199 static int handle_release_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
200 {
201         int ret = MM_ERROR_NONE;
202
203         debug_fenter();
204
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;
208         }
209         ret = __mm_sound_mgr_focus_ipc_release_focus(param->pid, param->handle_id, param->focus_type,
210                                                                                                 param->option, param->ext_info, true);
211
212         debug_fleave();
213
214         return ret;
215 }
216
217 static int handle_set_focus_reacquisition(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
218 {
219         int ret = MM_ERROR_NONE;
220
221         debug_fenter();
222
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;
226         }
227         ret = __mm_sound_mgr_focus_ipc_set_focus_reacquisition(param->pid, param->handle_id, param->reacquisition);
228
229         debug_fleave();
230
231         return ret;
232 }
233
234 static int handle_deliver_focus(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
235 {
236         int ret = MM_ERROR_NONE;
237
238         debug_fenter();
239
240         ret = __mm_sound_mgr_focus_ipc_deliver_focus(param->pid, param->handle_id, param->handle_id_dst, param->focus_type);
241
242         debug_fleave();
243
244         return ret;
245 }
246
247 static int handle_get_acquired_focus_info(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
248 {
249         int ret = MM_ERROR_NONE;
250         char *res_stream_type = NULL;
251         char *res_ext_info = NULL;
252
253         debug_fenter();
254
255         if (!result) {
256                 debug_error("invalid arguments, result[%p]", result);
257                 return MM_ERROR_INVALID_ARGUMENT;
258         }
259
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);
264         }
265
266         debug_fleave();
267
268         return ret;
269 }
270
271 static int focus_functions_handler(int fd, _mm_sound_focus_socket_param_t *param, _mm_sound_focus_socket_result_t *result)
272 {
273         int i = 0;
274         int ret = MM_ERROR_NONE;
275
276         if (param == NULL)
277                 return MM_ERROR_INVALID_ARGUMENT;
278
279         debug_msg("fd[%d], param[%p], function_name[%s]", fd, param, param->func_name);
280
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);
284         }
285
286         return ret;
287 }
288
289 static bool need_to_exit(const char *func_name)
290 {
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))
294                 return true;
295
296         return false;
297 }
298
299
300 static focus_thread_data_t *__focus_thread_data_create(const int *sockfd)
301 {
302         focus_thread_data_t *thread_data = NULL;
303         thread_data = g_new0(focus_thread_data_t, 1);
304
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;
309
310         return thread_data;
311 }
312
313 static void __focus_thread_ready_signal(focus_thread_data_t *thread_data)
314 {
315         g_assert(thread_data);
316
317         g_mutex_lock(&thread_data->wait_mutex);
318
319         debug_msg("signaling focus thread ready!");
320         thread_data->listen_ready = TRUE;
321         g_cond_signal(&thread_data->wait_cond);
322
323         g_mutex_unlock(&thread_data->wait_mutex);
324 }
325
326 static gboolean __focus_thread_ready_wait(focus_thread_data_t *thread_data, int timeout_sec)
327 {
328         gint64 end_time;
329         g_autoptr(GMutexLocker) locker = NULL;
330
331         g_assert(thread_data);
332
333         locker = g_mutex_locker_new(&thread_data->wait_mutex);
334
335         end_time = g_get_monotonic_time() + timeout_sec * G_TIME_SPAN_SECOND;
336
337         while (!thread_data->listen_ready) {
338                 if (!g_cond_wait_until(&thread_data->wait_cond,
339                                                         &thread_data->wait_mutex,
340                                                         end_time)) {
341                         debug_error("timeout!!!");
342                         break;
343                 }
344                 debug_msg("wait done! ready:%d", thread_data->listen_ready);
345         }
346
347         return thread_data->listen_ready;
348 }
349
350 static void __focus_thread_data_destroy(focus_thread_data_t *thread_data)
351 {
352         g_assert(thread_data);
353
354         g_mutex_clear(&thread_data->wait_mutex);
355         g_cond_clear(&thread_data->wait_cond);
356
357         g_free(thread_data);
358 }
359
360 static void *work_thread_func(void *data)
361 {
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;
366         int rval = 0;
367
368         debug_fenter();
369
370         if (!data) {
371                 debug_error("invalid data");
372                 pthread_exit(NULL);
373         }
374
375         accepted_fd = (int)(uintptr_t)(data);
376
377         while (1) {
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);
382
383                 } else if (rval == sizeof(_mm_sound_focus_socket_param_t)) {
384                         int ret = MM_ERROR_NONE;
385
386                         debug_log("data read successfully, command[%s], pid[%d]",
387                                         read_data.func_name, read_data.pid);
388
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);
392                         result.ret = ret;
393
394                         /* send result */
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);
398                         }
399
400                         if (need_to_exit(read_data.func_name))
401                                 break;
402                 } else {
403                         debug_error("failed to read(), read size mismatched, rval(%d), expect size(%zu)",
404                                                 rval, sizeof(_mm_sound_focus_socket_param_t));
405                         break;
406                 }
407         }
408
409         /* clean-up FD and focus node */
410         mm_sound_mgr_focus_emergent_exit_by_id(accepted_fd);
411
412         debug_msg("now close fd[%d]", accepted_fd);
413         close(accepted_fd);
414
415         debug_fleave();
416
417         pthread_exit(NULL);
418 }
419
420 static void *ready_thread_func(void *data)
421 {
422         int accepted_fd = -1;
423         char str_error[MAX_ERROR_LEN] = {'\0',};
424         int ret = 0;
425         pthread_t focus_work_thread_id;
426         pthread_attr_t attr;
427
428         focus_thread_data_t *thread_data = (focus_thread_data_t *)data;
429
430         if (!thread_data) {
431                 debug_error("invalid data");
432                 pthread_exit(NULL);
433         }
434
435         debug_fenter();
436
437         ret = pthread_attr_init(&attr);
438         if (ret != 0) {
439                 debug_error("failed to init pthread attr, errno=%d", ret);
440                 goto LEAVE;
441         }
442
443         ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
444         if (ret != 0) {
445                 debug_error("failed to set detach state, errno=%d", ret);
446                 goto LEAVE;
447         }
448
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);
452                 goto LEAVE;
453         }
454         debug_msg("listen for fd [%d] success", *thread_data->sockfd);
455
456         __focus_thread_ready_signal(thread_data);
457
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);
463                         break;
464                 }
465
466                 debug_log("accepted fd [%d]", accepted_fd);
467
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);
470                         break;
471                 }
472         }
473
474         __focus_thread_data_destroy(thread_data);
475
476 LEAVE:
477         pthread_attr_destroy(&attr);
478
479         debug_fleave();
480
481         pthread_exit(NULL);
482 }
483
484 int MMSoundMgrFocusSocketInit(int *sockfd)
485 {
486         int socket_fd;
487         struct sockaddr_un addr_un;
488         char str_error[128] = {'\0',};
489
490         if (!sockfd) {
491                 debug_error("input param fd is null");
492                 return MM_ERROR_INVALID_ARGUMENT;
493         }
494
495         socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
496         if (socket_fd < 0) {
497                 strerror_r(errno, str_error, sizeof(str_error));
498                 debug_error("failed to socket(), err: %s", str_error);
499                 goto LEAVE;
500         }
501
502         debug_msg("focus server socket fd [%d]", socket_fd);
503
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));
507
508         if (bind(socket_fd, (struct sockaddr *)&addr_un, sizeof(addr_un))) {
509                 int errsv = errno;
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);
518                                 goto LEAVE;
519                         }
520                 } else {
521                         goto LEAVE;
522                 }
523         }
524
525         debug_msg("focus server socket binding success");
526
527         *sockfd = socket_fd;
528
529         debug_leave();
530
531         return MM_ERROR_NONE;
532
533 LEAVE:
534         if (socket_fd >= 0)
535                 close(socket_fd);
536
537         return MM_ERROR_SOUND_INTERNAL;
538 }
539
540 void MMSoundMgrFocusSocketFini(int *sockfd)
541 {
542         debug_enter();
543
544         if (g_focus_ready_thread_id) {
545                 unlink(FOCUS_SERVER_SOCK);
546
547                 if (*sockfd != -1) {
548                         shutdown(*sockfd, SHUT_RDWR);
549                         close(*sockfd);
550                         *sockfd = -1;
551                 }
552
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;
557         }
558
559         debug_leave();
560 }
561
562 int MMSoundMgrFocusSocketReadyToWork(const int *sockfd)
563 {
564         focus_thread_data_t *thread_data = NULL;
565         int retry_remaining = MAX_FOCUS_THREAD_READY_WAIT_RETRY;
566
567         if (*sockfd < 0) {
568                 debug_error("input param sockfd [%d] is not valid", *sockfd);
569                 return MM_ERROR_INVALID_ARGUMENT;
570         }
571
572         debug_msg("sockfd [%d]", *sockfd);
573
574         thread_data = __focus_thread_data_create(sockfd);
575
576         if (pthread_create(&g_focus_ready_thread_id, NULL, (void *)ready_thread_func, thread_data)) {
577                 debug_error("failed to create ready thread");
578                 goto ERROR_INTERNAL;
579         }
580
581         do {
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;
585                 }
586
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);
590
591 ERROR_INTERNAL:
592         __focus_thread_data_destroy(thread_data);
593         return MM_ERROR_SOUND_INTERNAL;
594 }