Fix aarch64 casting build warnings
[platform/core/multimedia/libmm-sound.git] / mm_sound_device.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2014 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
25 #include <mm_debug.h>
26
27 #include "include/mm_sound.h"
28 #include "include/mm_sound_device.h"
29 #include "include/mm_sound_client.h"
30
31 #define VOLUME_TYPE_LEN 64
32
33 static mm_sound_device_list_t g_device_list;
34 static pthread_mutex_t g_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
35
36 static int _check_for_valid_mask(int flags)
37 {
38         int ret = MM_ERROR_NONE;
39         bool at_least_cond = false;
40
41         if (flags > 0 && flags <= MM_SOUND_DEVICE_ALL_FLAG) {
42                 if (flags & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG)
43                         at_least_cond = true;
44                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG))
45                         at_least_cond = true;
46                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG))
47                         at_least_cond = true;
48                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG))
49                         at_least_cond = true;
50                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG))
51                         at_least_cond = true;
52                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG))
53                         at_least_cond = true;
54                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG))
55                         at_least_cond = true;
56         } else {
57                 ret = MM_ERROR_INVALID_ARGUMENT;
58         }
59
60         if (!at_least_cond)
61                 ret = MM_ERROR_INVALID_ARGUMENT;
62
63         if (ret)
64                 debug_error("flags[0x%x] is not valid", flags);
65
66         return ret;
67 }
68
69 static int __convert_device_type_to_enum(char *device_type, mm_sound_device_type_e *device_type_enum)
70 {
71         int ret = MM_ERROR_NONE;
72
73         if (!device_type || !device_type_enum)
74                 return MM_ERROR_INVALID_ARGUMENT;
75
76         if (!strncmp(device_type, "builtin-speaker", VOLUME_TYPE_LEN)) {
77                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
78         } else if (!strncmp(device_type, "builtin-receiver", VOLUME_TYPE_LEN)) {
79                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_RECEIVER;
80         } else if (!strncmp(device_type, "builtin-mic", VOLUME_TYPE_LEN)) {
81                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_MIC;
82         } else if (!strncmp(device_type, "audio-jack", VOLUME_TYPE_LEN)) {
83                 *device_type_enum = MM_SOUND_DEVICE_TYPE_AUDIOJACK;
84         } else if (!strncmp(device_type, "bt-a2dp", VOLUME_TYPE_LEN)) {
85                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP;
86         } else if (!strncmp(device_type, "bt-sco", VOLUME_TYPE_LEN)) {
87                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BLUETOOTH_SCO;
88         } else if (!strncmp(device_type, "hdmi", VOLUME_TYPE_LEN)) {
89                 *device_type_enum = MM_SOUND_DEVICE_TYPE_HDMI;
90         } else if (!strncmp(device_type, "forwarding", VOLUME_TYPE_LEN)) {
91                 *device_type_enum = MM_SOUND_DEVICE_TYPE_MIRRORING;
92         } else if (!strncmp(device_type, "usb-audio", VOLUME_TYPE_LEN)) {
93                 *device_type_enum = MM_SOUND_DEVICE_TYPE_USB_AUDIO;
94         } else if (!strncmp(device_type, "network", VOLUME_TYPE_LEN)) {
95                 *device_type_enum = MM_SOUND_DEVICE_TYPE_NETWORK;
96         } else {
97                 ret = MM_ERROR_INVALID_ARGUMENT;
98                 debug_error("not supported device_type(%s), err(0x%08x)", device_type, ret);
99         }
100
101         return ret;
102 }
103
104 static int __free_device_list(mm_sound_device_list_t *device_list_t)
105 {
106         if (!device_list_t)
107                 return MM_ERROR_INVALID_ARGUMENT;
108
109         debug_log("free device list %p", device_list_t);
110         g_list_free_full(g_list_first(device_list_t->list), g_free);
111         g_free(device_list_t);
112
113         return MM_ERROR_NONE;
114 }
115
116 EXPORT_API
117 int mm_sound_add_device_connected_callback(int flags, mm_sound_device_connected_cb func, void *user_data, unsigned int *id)
118 {
119         int ret = MM_ERROR_NONE;
120
121         if (func == NULL || id == NULL) {
122                 debug_error("argument is not valid");
123                 return MM_ERROR_INVALID_ARGUMENT;
124         }
125         ret = _check_for_valid_mask(flags);
126         if (ret == MM_ERROR_NONE) {
127                 ret = mm_sound_client_add_device_connected_callback(flags, func, user_data, id);
128                 if (ret < 0)
129                         debug_error("Could not add device connected callback, ret = %x", ret);
130         }
131
132         return ret;
133 }
134
135 EXPORT_API
136 int mm_sound_remove_device_connected_callback(unsigned int id)
137 {
138         int ret = MM_ERROR_NONE;
139
140         ret = mm_sound_client_remove_device_connected_callback(id);
141         if (ret < 0)
142                 debug_error("Could not remove device connected callback, ret = %x", ret);
143
144         return ret;
145 }
146
147 EXPORT_API
148 int mm_sound_add_device_information_changed_callback(int flags, mm_sound_device_info_changed_cb func, void *user_data, unsigned int *id)
149 {
150         int ret = MM_ERROR_NONE;
151
152         if (func == NULL || id == NULL) {
153                 debug_error("argument is not valid");
154                 return MM_ERROR_INVALID_ARGUMENT;
155         }
156         ret = _check_for_valid_mask(flags);
157         if (ret == MM_ERROR_NONE) {
158                 ret = mm_sound_client_add_device_info_changed_callback(flags, func, user_data, id);
159                 if (ret < 0)
160                         debug_error("Could not add device information changed callback, ret = %x", ret);
161         }
162
163         return ret;
164 }
165
166 EXPORT_API
167 int mm_sound_remove_device_information_changed_callback(unsigned int id)
168 {
169         int ret = MM_ERROR_NONE;
170
171         ret = mm_sound_client_remove_device_info_changed_callback(id);
172         if (ret < 0)
173                 debug_error("Could not remove device information changed callback, ret = %x", ret);
174
175         return ret;
176 }
177
178 EXPORT_API
179 int mm_sound_add_device_state_changed_callback(int flags, mm_sound_device_state_changed_cb func, void *user_data, unsigned int *id)
180 {
181         int ret = MM_ERROR_NONE;
182
183         if (func == NULL || id == NULL) {
184                 debug_error("argument is not valid");
185                 return MM_ERROR_INVALID_ARGUMENT;
186         }
187         ret = _check_for_valid_mask(flags);
188         if (ret == MM_ERROR_NONE) {
189                 ret = mm_sound_client_add_device_state_changed_callback(flags, func, user_data, id);
190                 if (ret < 0)
191                         debug_error("Could not add device state changed callback, ret = %x", ret);
192         }
193
194         return ret;
195 }
196
197 EXPORT_API
198 int mm_sound_remove_device_state_changed_callback(unsigned int id)
199 {
200         int ret = MM_ERROR_NONE;
201
202         ret = mm_sound_client_remove_device_state_changed_callback(id);
203         if (ret < 0)
204                 debug_error("Could not remove device state changed callback, ret = %x", ret);
205
206         return ret;
207 }
208
209 EXPORT_API
210 int mm_sound_add_device_running_changed_callback(int flags, mm_sound_device_running_changed_cb func, void *user_data, unsigned int *id)
211 {
212         int ret = MM_ERROR_NONE;
213
214         if (func == NULL || id == NULL) {
215                 debug_error("argument is not valid");
216                 return MM_ERROR_INVALID_ARGUMENT;
217         }
218         ret = _check_for_valid_mask(flags);
219         if (ret == MM_ERROR_NONE) {
220                 ret = mm_sound_client_add_device_running_changed_callback(flags, func, user_data, id);
221                 if (ret < 0) {
222                         debug_error("Could not add device running changed callback, ret = %x", ret);
223                 }
224         }
225
226         return ret;
227 }
228
229 EXPORT_API
230 int mm_sound_remove_device_running_changed_callback(unsigned int id)
231 {
232         int ret = MM_ERROR_NONE;
233
234         ret = mm_sound_client_remove_device_running_changed_callback(id);
235         if (ret < 0) {
236                 debug_error("Could not remove device running changed callback, ret = %x", ret);
237         }
238
239         return ret;
240 }
241
242 EXPORT_API
243 int mm_sound_get_current_device_list(mm_sound_device_flags_e flags, MMSoundDeviceList_t *device_list)
244 {
245         int ret = MM_ERROR_NONE;
246
247         if (!device_list)
248                 return MM_ERROR_INVALID_ARGUMENT;
249
250         ret = _check_for_valid_mask(flags);
251         if (ret != MM_ERROR_NONE) {
252                 debug_error("mask[0x%x] is invalid, ret=0x%x", flags, ret);
253                 return ret;
254         }
255
256         pthread_mutex_lock(&g_thread_mutex);
257
258         if (g_device_list.list != NULL) {
259                 g_list_free_full(g_device_list.list, g_free);
260                 g_device_list.list = NULL;
261         }
262
263         g_device_list.is_new_device_list = true;
264
265         ret = mm_sound_client_get_current_connected_device_list(flags, &g_device_list);
266         if (ret < 0) {
267                 debug_error("Could not get current connected device list, ret = %x", ret);
268                 g_device_list.list = NULL;
269         } else {
270                 *device_list = &g_device_list;
271         }
272
273         pthread_mutex_unlock(&g_thread_mutex);
274
275         return ret;
276 }
277
278 EXPORT_API
279 int mm_sound_get_device_list(int flags, MMSoundDeviceList_t *device_list)
280 {
281         int ret = MM_ERROR_NONE;
282         mm_sound_device_list_t *_device_list;
283
284         if (!device_list)
285                 return MM_ERROR_INVALID_ARGUMENT;
286
287         ret = _check_for_valid_mask(flags);
288         if (ret != MM_ERROR_NONE) {
289                 debug_error("mask[0x%x] is invalid, ret=0x%x", flags, ret);
290                 return ret;
291         }
292
293         if (!(_device_list = g_malloc0(sizeof(mm_sound_device_list_t)))) {
294                 debug_error("Allocate device list failed");
295                 return MM_ERROR_SOUND_INTERNAL;
296         }
297
298         _device_list->is_new_device_list = true;
299
300         ret = mm_sound_client_get_current_connected_device_list(flags, _device_list);
301         if (ret < 0) {
302                 debug_error("Could not get current connected device list, ret = %x", ret);
303                 g_free(_device_list);
304         } else {
305                 *device_list = _device_list;
306         }
307
308         return ret;
309 }
310
311 EXPORT_API
312 int mm_sound_free_device_list(MMSoundDeviceList_t device_list)
313 {
314         return __free_device_list((mm_sound_device_list_t*) device_list);
315 }
316
317 EXPORT_API
318 int mm_sound_free_device(MMSoundDevice_t device_h)
319 {
320         if (device_h == NULL)
321                 return MM_ERROR_INVALID_ARGUMENT;
322
323         g_free(device_h);
324
325         return MM_ERROR_NONE;
326 }
327
328 EXPORT_API
329 int mm_sound_get_device_by_id(int device_id, MMSoundDevice_t *device_h)
330 {
331         int ret = MM_ERROR_NONE;
332         mm_sound_device_t *device = NULL;
333
334         if (device_id < 1 || device_h == NULL)
335                 return MM_ERROR_INVALID_ARGUMENT;
336
337         ret = mm_sound_client_get_device_by_id(device_id, &device);
338         if (ret < 0)
339                 debug_error("Could not get device by id, ret = %x", ret);
340         else
341                 *device_h = device;
342
343         return ret;
344 }
345
346 EXPORT_API
347 int mm_sound_get_next_device(MMSoundDeviceList_t device_list, MMSoundDevice_t *device)
348 {
349         int ret = MM_ERROR_NONE;
350         mm_sound_device_list_t *device_list_t = NULL;
351         GList *node = NULL;
352
353         if (!device_list || !device)
354                 return MM_ERROR_INVALID_ARGUMENT;
355
356         device_list_t = (mm_sound_device_list_t*) device_list;
357         if (device_list_t->is_new_device_list)
358                 node = g_list_first(device_list_t->list);
359         else
360                 node = g_list_next(device_list_t->list);
361
362         if (!node) {
363                 ret = MM_ERROR_SOUND_NO_DATA;
364         } else {
365                 if (device_list_t->is_new_device_list)
366                         device_list_t->is_new_device_list = false;
367                 else
368                         device_list_t->list = node;
369
370                 *device = (mm_sound_device_t*)node->data;
371                 debug_log("next device[%p]", *device);
372         }
373         return ret;
374 }
375
376 EXPORT_API
377 int mm_sound_get_prev_device(MMSoundDeviceList_t device_list, MMSoundDevice_t *device)
378 {
379         int ret = MM_ERROR_NONE;
380         mm_sound_device_list_t *device_list_t = NULL;
381         GList *node = NULL;
382
383         if (!device_list || !device)
384                 return MM_ERROR_INVALID_ARGUMENT;
385
386         device_list_t = (mm_sound_device_list_t*) device_list;
387         node = g_list_previous(device_list_t->list);
388         if (!node) {
389                 ret = MM_ERROR_SOUND_NO_DATA;
390                 debug_error("Could not get previous device, ret = %x", ret);
391         } else {
392                 device_list_t->list = node;
393                 *device = (mm_sound_device_t*)node->data;
394                 debug_log("previous device[%p]", *device);
395         }
396         return ret;
397 }
398
399 EXPORT_API
400 int mm_sound_get_device_type(MMSoundDevice_t device_h, mm_sound_device_type_e *type)
401 {
402         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
403         if (!device || !type) {
404                 debug_error("invalid argument");
405                 return MM_ERROR_INVALID_ARGUMENT;
406         }
407         __convert_device_type_to_enum(device->type, type);
408         debug_log("device_handle:%p, type:%d", device, *type);
409
410         return MM_ERROR_NONE;
411 }
412
413 EXPORT_API
414 int mm_sound_get_device_io_direction(MMSoundDevice_t device_h, mm_sound_device_io_direction_e *io_direction)
415 {
416         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
417         if (!device) {
418                 debug_error("invalid handle");
419                 return MM_ERROR_INVALID_ARGUMENT;
420         }
421         *io_direction = device->io_direction;
422         debug_log("device_handle:%p, io_direction:%d (1:IN,2:OUT,3:INOUT)", device, *io_direction);
423
424         return MM_ERROR_NONE;
425 }
426
427 EXPORT_API
428 int mm_sound_get_device_id(MMSoundDevice_t device_h, int *id)
429 {
430         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
431         if (!device) {
432                 debug_error("invalid handle");
433                 return MM_ERROR_INVALID_ARGUMENT;
434         }
435         *id = device->id;
436         debug_log("device_handle:%p, id:%d", device, *id);
437
438         return MM_ERROR_NONE;
439 }
440
441 EXPORT_API
442 int mm_sound_get_device_state(MMSoundDevice_t device_h, mm_sound_device_state_e *state)
443 {
444         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
445         if (!device) {
446                 debug_error("invalid handle");
447                 return MM_ERROR_INVALID_ARGUMENT;
448         }
449         *state = device->state;
450         debug_log("device_handle:%p, state:%d (0:INACTIVATED,1:ACTIVATED)", device, *state);
451
452         return MM_ERROR_NONE;
453 }
454
455 EXPORT_API
456 int mm_sound_get_device_name(MMSoundDevice_t device_h, char **name)
457 {
458         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
459         if (!device) {
460                 debug_error("invalid handle");
461                 return MM_ERROR_INVALID_ARGUMENT;
462         }
463         *name = device->name;
464         debug_log("device_handle:%p, name:%s", device, *name);
465
466         return MM_ERROR_NONE;
467 }
468
469 EXPORT_API
470 int mm_sound_get_device_vendor_id(MMSoundDevice_t device_h, int *vendor_id)
471 {
472         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
473         if (!device) {
474                 debug_error("invalid handle");
475                 return MM_ERROR_INVALID_ARGUMENT;
476         }
477         *vendor_id = device->vendor_id;
478         debug_log("device_handle:%p, vendor id:%04x", device, *vendor_id);
479
480         return MM_ERROR_NONE;
481 }
482
483 EXPORT_API
484 int mm_sound_get_device_product_id(MMSoundDevice_t device_h, int *product_id)
485 {
486         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
487         if (!device) {
488                 debug_error("invalid handle");
489                 return MM_ERROR_INVALID_ARGUMENT;
490         }
491         *product_id = device->product_id;
492         debug_log("device_handle:%p, product id:%04x", device, *product_id);
493
494         return MM_ERROR_NONE;
495 }
496
497 EXPORT_API
498 int mm_sound_is_stream_on_device(int stream_id, MMSoundDevice_t device_h, bool *is_on)
499 {
500         int ret = MM_ERROR_NONE;
501         int i;
502         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
503         bool _is_on = false;
504
505         if (!device || !is_on) {
506                 debug_error("invalid argument");
507                 return MM_ERROR_INVALID_ARGUMENT;
508         }
509
510         if (device->stream_num >= 0) {
511                 debug_log("device_handle has stream id");
512                 for (i = 0; i < device->stream_num; i++) {
513                         if (device->stream_id[i] == stream_id) {
514                                 _is_on = true;
515                                 break;
516                         }
517                 }
518         } else {
519                 debug_log("device_handle dosn't have stream id");
520                 /* No information about stream in client-side, should ask to server-side */
521                 if ((ret = mm_sound_client_is_stream_on_device(stream_id, device->id, &_is_on)) < 0) {
522                         debug_error("Failed to query is stream on");
523                         return MM_ERROR_SOUND_INTERNAL;
524                 }
525         }
526
527         debug_log("device(%d) %s stream(%d)", device->id, _is_on ? "has" : "doesn't have", stream_id);
528         *is_on = _is_on;
529
530         return ret;
531 }
532
533 EXPORT_API
534 int mm_sound_is_stream_on_device_by_id(int stream_id, int device_id, bool *is_on)
535 {
536         int ret = MM_ERROR_NONE;
537         bool _is_on = false;
538
539         if (!is_on) {
540                 debug_error("invalid argument");
541                 return MM_ERROR_INVALID_ARGUMENT;
542         }
543
544         if ((ret = mm_sound_client_is_stream_on_device(stream_id, device_id, &_is_on)) < 0) {
545                 debug_error("Failed to query is stream on");
546                 return MM_ERROR_SOUND_INTERNAL;
547         }
548
549         debug_log("device(%d) %s stream(%d)", device_id, _is_on ? "has" : "doesn't have", stream_id);
550         *is_on = _is_on;
551
552         return ret;
553 }
554
555 EXPORT_API
556 int mm_sound_is_device_running(MMSoundDevice_t device_h, bool *is_running)
557 {
558         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
559         if (!device || !is_running) {
560                 debug_error("invalid argument");
561                 return MM_ERROR_INVALID_ARGUMENT;
562         }
563         *is_running = device->is_running;
564         debug_log("device_handle:0x%p, running:%d", device, *is_running);
565
566         return MM_ERROR_NONE;
567 }