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.
25 #include <sys/socket.h>
27 #include "include/mm_sound.h"
28 #include "include/mm_sound_common.h"
29 #include "include/mm_sound_focus_socket.h"
31 #define MAX_CONNECT_RETRY 100
32 #define RETRY_CONNECT_INTERVAL_US 300000
34 #define _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid) \
36 MMSOUND_STRNCPY(x_param.func_name, x_func_name, MM_SOUND_NAME_NUM); \
37 x_param.pid = x_pid; \
40 #define _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id) \
42 _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid); \
43 x_param.handle_id = x_id; \
46 #define FILL_SOCKET_PARAM_REGISTER(x_param, x_func_name, x_pid, x_stream_type) \
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); \
52 #define FILL_SOCKET_PARAM_UNREGISTER(x_param, x_func_name, x_pid, x_id) \
54 _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
57 #define FILL_SOCKET_PARAM_ADD_WATCH(x_param, x_func_name, x_pid, x_focus_type) \
59 _FILL_SOCKET_PARAM(x_param, x_func_name, x_pid); \
60 x_param.focus_type = x_focus_type; \
63 #define FILL_SOCKET_PARAM_REMOVE_WATCH(x_param, x_func_name, x_pid, x_id) \
65 _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
68 #define FILL_SOCKET_PARAM_SET_REACQUISITION(x_param, x_func_name, x_pid, x_id, x_reacquisition) \
70 _FILL_SOCKET_PARAM_WITH_HANDLE(x_param, x_func_name, x_pid, x_id); \
71 x_param.reacquisition = x_reacquisition; \
74 #define FILL_SOCKET_PARAM_DELIVER(x_param, x_func_name, x_pid, x_src_id, x_dst_id, x_focus_type) \
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; \
81 #define FILL_SOCKET_PARAM_GET_ACQUIRED(x_param, x_func_name, x_focus_type) \
83 MMSOUND_STRNCPY(x_param.func_name, x_func_name, MM_SOUND_NAME_NUM); \
84 x_param.focus_type = x_focus_type; \
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) \
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; \
96 static int _get_client_socket_fd(int *fd)
99 char str_error[128] = {'\0',};
102 debug_error("input param fd is null");
103 return MM_ERROR_INVALID_ARGUMENT;
106 socket_fd = socket(AF_UNIX, SOCK_STREAM, 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;
113 debug_log("focus client socket fd[%d]", socket_fd);
117 return MM_ERROR_NONE;
120 static int _connect_socket_fd(int fd)
122 int retry_remaining = MAX_CONNECT_RETRY;
124 struct sockaddr_un addr_un;
125 char str_error[128] = {'\0',};
128 debug_error("invalid fd[%d]", fd);
129 return MM_ERROR_INVALID_ARGUMENT;
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));
137 ret = connect(fd, (struct sockaddr *)&addr_un, sizeof(addr_un));
139 debug_log("connected successfully, fd[%d]", fd);
140 return MM_ERROR_NONE;
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);
147 usleep(RETRY_CONNECT_INTERVAL_US);
148 } while (--retry_remaining > 0);
150 debug_error("Timed-out(%u us) for connection",
151 MAX_CONNECT_RETRY * RETRY_CONNECT_INTERVAL_US);
153 return MM_ERROR_SOUND_INTERNAL;
156 static int _send_data_to_server(int fd, _mm_sound_focus_socket_param_t *data, _mm_sound_focus_socket_result_t *result)
158 char str_error[MAX_ERROR_LEN] = {'\0',};
161 if (fd < 0 || data == NULL) {
162 debug_error("invalid parameter, fd[%d], data[%p]", fd, data);
163 return MM_ERROR_INVALID_ARGUMENT;
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;
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;
179 debug_log("func_name[%s], rval[%d], ret[0x%x]", data->func_name, rval, result->ret);
185 int mm_sound_focus_socket_register(int pid, const char *stream_type, int *client_fd, int *server_fd)
187 int ret = MM_ERROR_NONE;
188 _mm_sound_focus_socket_param_t data;
189 _mm_sound_focus_socket_result_t result;
193 if (!stream_type || !client_fd || !server_fd)
194 return MM_ERROR_INVALID_ARGUMENT;
196 if ((ret = _get_client_socket_fd(client_fd))) {
197 debug_error("failed to _get_client_socket_fd()");
198 return MM_ERROR_SOUND_INTERNAL;
200 if ((ret = _connect_socket_fd(*client_fd))) {
201 debug_error("failed to _connect_socket_fd()");
203 return MM_ERROR_SOUND_INTERNAL;
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);
216 debug_msg("CONNECTED : client fd[%d], server fd[%d]", *client_fd, result.handle_id);
217 *server_fd = result.handle_id;
225 int mm_sound_focus_socket_unregister(int pid, int client_fd, int server_fd)
227 int ret = MM_ERROR_NONE;
228 _mm_sound_focus_socket_param_t data;
229 _mm_sound_focus_socket_result_t result;
233 debug_msg("DISCONNECTING : client fd[%d], server fd[%d]", client_fd, server_fd);
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);
249 int mm_sound_focus_socket_add_watch_cb(int pid, mm_sound_focus_type_e focus_type, int *client_fd, int *server_fd)
251 int ret = MM_ERROR_NONE;
252 _mm_sound_focus_socket_param_t data;
253 _mm_sound_focus_socket_result_t result;
257 if (!client_fd || !server_fd)
258 return MM_ERROR_INVALID_ARGUMENT;
260 if ((ret = _get_client_socket_fd(client_fd))) {
261 debug_error("failed to _get_client_socket_fd()");
262 return MM_ERROR_SOUND_INTERNAL;
264 if ((ret = _connect_socket_fd(*client_fd))) {
265 debug_error("failed to _connect_socket_fd()");
267 return MM_ERROR_SOUND_INTERNAL;
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);
280 debug_msg("ADDED WATCH CB : client fd[%d], server fd[%d]", *client_fd, result.handle_id);
281 *server_fd = result.handle_id;
289 int mm_sound_focus_socket_remove_watch_cb(int pid, int client_fd, int server_fd)
291 int ret = MM_ERROR_NONE;
292 _mm_sound_focus_socket_param_t data;
293 _mm_sound_focus_socket_result_t result;
297 debug_msg("REMOVING WATCH CB : client fd[%d], server fd[%d]", client_fd, server_fd);
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);
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)
315 int ret = MM_ERROR_NONE;
316 _mm_sound_focus_socket_param_t data;
317 _mm_sound_focus_socket_result_t result;
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;
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;
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);
336 if ((ret = _send_data_to_server(client_fd, &data, &result)))
337 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
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)
347 int ret = MM_ERROR_NONE;
348 _mm_sound_focus_socket_param_t data;
349 _mm_sound_focus_socket_result_t result;
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;
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;
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);
368 if ((ret = _send_data_to_server(client_fd, &data, &result)))
369 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
378 int mm_sound_focus_socket_set_reacquisition(int pid, int client_fd, int server_fd, bool reacquisition)
380 int ret = MM_ERROR_NONE;
381 _mm_sound_focus_socket_param_t data;
382 _mm_sound_focus_socket_result_t result;
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;
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);
395 if ((ret = _send_data_to_server(client_fd, &data, &result)))
396 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
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)
406 int ret = MM_ERROR_NONE;
407 _mm_sound_focus_socket_param_t data;
408 _mm_sound_focus_socket_result_t result;
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;
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);
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);
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)
433 int ret = MM_ERROR_NONE;
435 _mm_sound_focus_socket_param_t data;
436 _mm_sound_focus_socket_result_t result;
441 debug_error("invalid parameter, stream_type[%p]", stream_type);
442 return MM_ERROR_INVALID_ARGUMENT;
444 if ((ret = _get_client_socket_fd(&fd))) {
445 debug_error("failed to _get_client_socket_fd()");
446 return MM_ERROR_SOUND_INTERNAL;
448 if ((ret = _connect_socket_fd(fd))) {
449 debug_error("failed to _connect_socket_fd()");
451 return MM_ERROR_SOUND_INTERNAL;
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);
458 if ((ret = _send_data_to_server(fd, &data, &result))) {
459 debug_error("failed to _send_data_to_server(), ret[0x%x]", ret);
464 debug_msg("stream_type[%s], option[%d], ext_info[%s]", result.stream_type, result.option, result.ext_info);
466 *stream_type = strdup(result.stream_type);
467 *ext_info = strdup(result.ext_info);
468 *option = result.option;