keysound: support keysound priority
[platform/core/multimedia/libmm-sound.git] / mm_sound_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 <stdlib.h>
23 #include <unistd.h>
24 #include <mm_debug.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include "include/mm_sound.h"
28 #include "include/mm_sound_common.h"
29 #include "include/mm_sound_focus_socket.h"
30
31 #define MAX_CONNECT_RETRY 100
32 #define RETRY_CONNECT_INTERVAL_US 300000
33
34 #define _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid) \
35 do { \
36         MMSOUND_STRNCPY(x_param.func_name, x_func_name, MM_SOUND_NAME_NUM); \
37         x_param.pid = x_pid; \
38 } while (0) \
39
40 #define _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id) \
41 do { \
42         _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid); \
43         x_param.handle_id = x_id; \
44 } while (0) \
45
46 #define FILL_SOCKET_PARAM_REGISTER(x_param, x_func_name, x_pid, x_stream_type) \
47 do { \
48         _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid); \
49         MMSOUND_STRNCPY(x_param.stream_type, x_stream_type, MM_SOUND_NAME_NUM); \
50 } while (0) \
51
52 #define FILL_SOCKET_PARAM_UNREGISTER(x_param, x_func_name, x_pid, x_id) \
53 do { \
54         _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
55 } while (0) \
56
57 #define FILL_SOCKET_PARAM_ADD_WATCH(x_param, x_func_name, x_pid, x_focus_type) \
58 do { \
59         _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid); \
60         x_param.focus_type = x_focus_type; \
61 } while (0) \
62
63 #define FILL_SOCKET_PARAM_REMOVE_WATCH(x_param, x_func_name, x_pid, x_id) \
64 do { \
65         _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
66 } while (0) \
67
68 #define FILL_SOCKET_PARAM_SET_REACQUISITION(x_param, x_func_name, x_pid, x_id, x_reacquisition) \
69 do { \
70         _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
71         x_param.reacquisition = x_reacquisition; \
72 } while (0) \
73
74 #define FILL_SOCKET_PARAM_DELIVER(x_param, x_func_name, x_pid, x_src_id, x_dst_id, x_focus_type) \
75 do { \
76         _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_src_id); \
77         x_param.handle_id_dst = x_dst_id; \
78         x_param.focus_type = x_focus_type; \
79 } while (0) \
80
81 #define FILL_SOCKET_PARAM_GET_ACQUIRED(x_param, x_func_name, x_focus_type) \
82 do { \
83         MMSOUND_STRNCPY(x_param.func_name, x_func_name, MM_SOUND_NAME_NUM); \
84         x_param.focus_type = x_focus_type; \
85 } while (0) \
86
87 #define FILL_SOCKET_PARAM(x_param, x_func_name, x_pid, x_id, x_focus_type, x_option, x_ext_info, x_is_in_thread) \
88 do { \
89         _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
90         x_param.focus_type = x_focus_type; \
91         x_param.option = x_option; \
92         MMSOUND_STRNCPY(x_param.ext_info, x_ext_info, MM_SOUND_NAME_NUM); \
93         x_param.is_in_thread = x_is_in_thread; \
94 } while (0) \
95
96 static int _get_client_socket_fd(int *fd)
97 {
98         int socket_fd;
99         char str_error[128] = {'\0',};
100
101         if (fd == NULL) {
102                 debug_error("input param fd is null");
103                 return MM_ERROR_INVALID_ARGUMENT;
104         }
105
106         socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
107         if (socket_fd < 0) {
108                 strerror_r(errno, str_error, sizeof(str_error));
109                 debug_error("failed to socket(), err: %s", str_error);
110                 return MM_ERROR_SOUND_INTERNAL;
111         }
112
113         debug_log("focus client socket fd[%d]", socket_fd);
114
115         *fd = socket_fd;
116
117         return MM_ERROR_NONE;
118 }
119
120 static int _connect_socket_fd(int fd)
121 {
122         int retry_remaining = MAX_CONNECT_RETRY;
123         int ret = 0;
124         struct sockaddr_un addr_un;
125         char str_error[128] = {'\0',};
126
127         if (fd < 0) {
128                 debug_error("invalid fd[%d]", fd);
129                 return MM_ERROR_INVALID_ARGUMENT;
130         }
131
132         memset(&addr_un, 0, sizeof(addr_un));
133         addr_un.sun_family = AF_UNIX;
134         strncpy(addr_un.sun_path, FOCUS_SERVER_SOCK, sizeof(addr_un.sun_path));
135
136         do {
137                 ret = connect(fd, (struct sockaddr *)&addr_un, sizeof(addr_un));
138                 if (ret == 0) {
139                         debug_log("connected successfully, fd[%d]", fd);
140                         return MM_ERROR_NONE;
141                 }
142
143                 strerror_r(errno, str_error, sizeof(str_error));
144                 debug_error("[%2d] failed to connect() to %s, err: %s",
145                         retry_remaining, addr_un.sun_path, str_error);
146
147                 usleep(RETRY_CONNECT_INTERVAL_US);
148         } while (--retry_remaining > 0);
149
150         debug_error("Timed-out(%u us) for connection",
151                         MAX_CONNECT_RETRY * RETRY_CONNECT_INTERVAL_US);
152
153         return MM_ERROR_SOUND_INTERNAL;
154 }
155
156 static int _send_data_to_server(int fd, _mm_sound_focus_socket_param_t *data, _mm_sound_focus_socket_result_t *result)
157 {
158         char str_error[MAX_ERROR_LEN] = {'\0',};
159         int rval = 0;
160
161         if (fd < 0 || data == NULL) {
162                 debug_error("invalid parameter, fd[%d], data[%p]", fd, data);
163                 return MM_ERROR_INVALID_ARGUMENT;
164         }
165
166         if (write(fd, data, sizeof(_mm_sound_focus_socket_param_t)) < 0) {
167                 strerror_r(errno, str_error, sizeof(str_error));
168                 debug_error("failed to write(), err: %s", str_error);
169                 return MM_ERROR_SOUND_INTERNAL;
170         }
171
172         /* return message from server */
173         if ((rval = read(fd, result, sizeof(_mm_sound_focus_socket_result_t))) < 0) {
174                 strerror_r(errno, str_error, sizeof(str_error));
175                 debug_error("failed to read(), err: %s", str_error);
176                 return MM_ERROR_SOUND_INTERNAL;
177         }
178
179         debug_log("func_name[%s], rval[%d], ret[0x%x]", data->func_name, rval, result->ret);
180
181         return result->ret;
182 }
183
184 EXPORT_API
185 int mm_sound_focus_socket_register(int pid, const char *stream_type, int *client_fd, int *server_fd)
186 {
187         int ret = MM_ERROR_NONE;
188         _mm_sound_focus_socket_param_t data;
189         _mm_sound_focus_socket_result_t result;
190
191         debug_fenter();
192
193         if (!stream_type || !client_fd || !server_fd)
194                 return MM_ERROR_INVALID_ARGUMENT;
195
196         if ((ret = _get_client_socket_fd(client_fd))) {
197                 debug_error("failed to _get_client_socket_fd()");
198                 return MM_ERROR_SOUND_INTERNAL;
199         }
200         if ((ret = _connect_socket_fd(*client_fd))) {
201                 debug_error("failed to _connect_socket_fd()");
202                 close(*client_fd);
203                 return MM_ERROR_SOUND_INTERNAL;
204         }
205
206         /* get accepted fd from server */
207         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
208         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
209         FILL_SOCKET_PARAM_REGISTER(data, FOCUS_FUNC_NAME_REGISTER, pid, stream_type);
210         if ((ret = _send_data_to_server(*client_fd, &data, &result))) {
211                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
212                 close(*client_fd);
213                 return ret;
214         }
215
216         debug_msg("CONNECTED : client fd[%d], server fd[%d]", *client_fd, result.handle_id);
217         *server_fd = result.handle_id;
218
219         debug_fleave();
220
221         return ret;
222 }
223
224 EXPORT_API
225 int mm_sound_focus_socket_unregister(int pid, int client_fd, int server_fd)
226 {
227         int ret = MM_ERROR_NONE;
228         _mm_sound_focus_socket_param_t data;
229         _mm_sound_focus_socket_result_t result;
230
231         debug_fenter();
232
233         debug_msg("DISCONNECTING : client fd[%d], server fd[%d]", client_fd, server_fd);
234
235         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
236         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
237         FILL_SOCKET_PARAM_UNREGISTER(data, FOCUS_FUNC_NAME_UNREGISTER, pid, server_fd);
238         if ((ret = _send_data_to_server(client_fd, &data, &result)))
239                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
240
241         close(client_fd);
242
243         debug_fleave();
244
245         return ret;
246 }
247
248 EXPORT_API
249 int mm_sound_focus_socket_add_watch_cb(int pid, mm_sound_focus_type_e focus_type, int *client_fd, int *server_fd)
250 {
251         int ret = MM_ERROR_NONE;
252         _mm_sound_focus_socket_param_t data;
253         _mm_sound_focus_socket_result_t result;
254
255         debug_fenter();
256
257         if (!client_fd || !server_fd)
258                 return MM_ERROR_INVALID_ARGUMENT;
259
260         if ((ret = _get_client_socket_fd(client_fd))) {
261                 debug_error("failed to _get_client_socket_fd()");
262                 return MM_ERROR_SOUND_INTERNAL;
263         }
264         if ((ret = _connect_socket_fd(*client_fd))) {
265                 debug_error("failed to _connect_socket_fd()");
266                 close(*client_fd);
267                 return MM_ERROR_SOUND_INTERNAL;
268         }
269
270         /* get accepted fd from server */
271         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
272         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
273         FILL_SOCKET_PARAM_ADD_WATCH(data, FOCUS_FUNC_NAME_ADD_WATCH, pid, focus_type);
274         if ((ret = _send_data_to_server(*client_fd, &data, &result))) {
275                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
276                 close(*client_fd);
277                 return ret;
278         }
279
280         debug_msg("ADDED WATCH CB : client fd[%d], server fd[%d]", *client_fd, result.handle_id);
281         *server_fd = result.handle_id;
282
283         debug_fleave();
284
285         return ret;
286 }
287
288 EXPORT_API
289 int mm_sound_focus_socket_remove_watch_cb(int pid, int client_fd, int server_fd)
290 {
291         int ret = MM_ERROR_NONE;
292         _mm_sound_focus_socket_param_t data;
293         _mm_sound_focus_socket_result_t result;
294
295         debug_fenter();
296
297         debug_msg("REMOVING WATCH CB : client fd[%d], server fd[%d]", client_fd, server_fd);
298
299         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
300         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
301         FILL_SOCKET_PARAM_REMOVE_WATCH(data, FOCUS_FUNC_NAME_REMOVE_WATCH, pid, server_fd);
302         if ((ret = _send_data_to_server(client_fd, &data, &result)))
303                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
304
305         close(client_fd);
306
307         debug_fleave();
308
309         return ret;
310 }
311
312 EXPORT_API
313 int mm_sound_focus_socket_acquire(int pid, int client_fd, int server_fd, mm_sound_focus_type_e focus_type, int option, const char *ext_info, bool is_in_thread)
314 {
315         int ret = MM_ERROR_NONE;
316         _mm_sound_focus_socket_param_t data;
317         _mm_sound_focus_socket_result_t result;
318
319         debug_fenter();
320
321         if (pid <= 0 || client_fd < 0 || server_fd < 0 || option < 0) {
322                 debug_error("invalid parameter, pid[%d], fd[%d/%d], option[%d]",
323                                         pid, client_fd, server_fd, option);
324                 return MM_ERROR_INVALID_ARGUMENT;
325         }
326         if (focus_type < FOCUS_FOR_PLAYBACK || focus_type > FOCUS_FOR_BOTH) {
327                 debug_error("focus type[%d] is not valid", focus_type);
328                 return MM_ERROR_INVALID_ARGUMENT;
329         }
330
331         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
332         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
333         FILL_SOCKET_PARAM(data, FOCUS_FUNC_NAME_ACQUIRE, pid, server_fd, focus_type,
334                                         option, ext_info, is_in_thread);
335
336         if ((ret = _send_data_to_server(client_fd, &data, &result)))
337                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
338
339         debug_fleave();
340
341         return ret;
342 }
343
344 EXPORT_API
345 int mm_sound_focus_socket_release(int pid, int client_fd, int server_fd, mm_sound_focus_type_e focus_type, int option, const char *ext_info, bool is_in_thread)
346 {
347         int ret = MM_ERROR_NONE;
348         _mm_sound_focus_socket_param_t data;
349         _mm_sound_focus_socket_result_t result;
350
351         debug_fenter();
352
353         if (pid <= 0 || client_fd < 0 || server_fd < 0 || option < 0) {
354                 debug_error("invalid parameter, pid[%d], fd[%d/%d], option[%d]",
355                                         pid, client_fd, server_fd, option);
356                 return MM_ERROR_INVALID_ARGUMENT;
357         }
358         if (focus_type < FOCUS_FOR_PLAYBACK || focus_type > FOCUS_FOR_BOTH) {
359                 debug_error("focus type is not valid");
360                 return MM_ERROR_INVALID_ARGUMENT;
361         }
362
363         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
364         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
365         FILL_SOCKET_PARAM(data, FOCUS_FUNC_NAME_RELEASE, pid, server_fd, focus_type,
366                                         option, ext_info, is_in_thread);
367
368         if ((ret = _send_data_to_server(client_fd, &data, &result)))
369                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
370
371         debug_fleave();
372
373         return ret;
374 }
375
376
377 EXPORT_API
378 int mm_sound_focus_socket_set_reacquisition(int pid, int client_fd, int server_fd, bool reacquisition)
379 {
380         int ret = MM_ERROR_NONE;
381         _mm_sound_focus_socket_param_t data;
382         _mm_sound_focus_socket_result_t result;
383
384         debug_fenter();
385
386         if (pid <= 0 || client_fd < 0 || server_fd < 0) {
387                 debug_error("invalid parameter, pid[%d], fd[%d/%d]", pid, client_fd, server_fd);
388                 return MM_ERROR_INVALID_ARGUMENT;
389         }
390
391         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
392         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
393         FILL_SOCKET_PARAM_SET_REACQUISITION(data, FOCUS_FUNC_NAME_SET_REACQUISITION, pid, server_fd, reacquisition);
394
395         if ((ret = _send_data_to_server(client_fd, &data, &result)))
396                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
397
398         debug_fleave();
399
400         return ret;
401 }
402
403 EXPORT_API
404 int mm_sound_focus_socket_deliver(int pid, int src_client_fd, int src_server_fd, int dst_client_fd, int dst_server_fd, mm_sound_focus_type_e focus_type)
405 {
406         int ret = MM_ERROR_NONE;
407         _mm_sound_focus_socket_param_t data;
408         _mm_sound_focus_socket_result_t result;
409
410         debug_fenter();
411
412         if (pid <= 0 || src_client_fd < 0 || src_server_fd < 0 || dst_client_fd < 0 || dst_server_fd < 0) {
413                 debug_error("invalid parameter, pid[%d], src_fd[%d/%d], dst_fd[%d/%d]",
414                                         pid, src_client_fd, src_server_fd, dst_client_fd, dst_server_fd);
415                 return MM_ERROR_INVALID_ARGUMENT;
416         }
417
418         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
419         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
420         FILL_SOCKET_PARAM_DELIVER(data, FOCUS_FUNC_NAME_DELIVER, pid, src_server_fd, dst_server_fd, focus_type);
421
422         if ((ret = _send_data_to_server(dst_client_fd, &data, &result)))
423                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
424
425         debug_fleave();
426
427         return ret;
428 }
429
430 EXPORT_API
431 int mm_sound_focus_socket_get_acquired_focus_stream_type(mm_sound_focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
432 {
433         int ret = MM_ERROR_NONE;
434         int fd = 0;
435         _mm_sound_focus_socket_param_t data;
436         _mm_sound_focus_socket_result_t result;
437
438         debug_fenter();
439
440         if (!stream_type) {
441                 debug_error("invalid parameter, stream_type[%p]", stream_type);
442                 return MM_ERROR_INVALID_ARGUMENT;
443         }
444         if ((ret = _get_client_socket_fd(&fd))) {
445                 debug_error("failed to _get_client_socket_fd()");
446                 return MM_ERROR_SOUND_INTERNAL;
447         }
448         if ((ret = _connect_socket_fd(fd))) {
449                 debug_error("failed to _connect_socket_fd()");
450                 close(fd);
451                 return MM_ERROR_SOUND_INTERNAL;
452         }
453
454         memset(&data, 0x00, sizeof(_mm_sound_focus_socket_param_t));
455         memset(&result, 0x00, sizeof(_mm_sound_focus_socket_result_t));
456         FILL_SOCKET_PARAM_GET_ACQUIRED(data, FOCUS_FUNC_NAME_GET_ACQUIRED_INFO, focus_type);
457
458         if ((ret = _send_data_to_server(fd, &data, &result))) {
459                 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
460                 close(fd);
461                 return ret;
462         }
463
464         debug_msg("stream_type[%s], option[%d], ext_info[%s]", result.stream_type, result.option, result.ext_info);
465
466         *stream_type = strdup(result.stream_type);
467         *ext_info = strdup(result.ext_info);
468         *option = result.option;
469
470         close(fd);
471
472         debug_fleave();
473
474         return ret;
475 }