stream is on device
[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 mm_sound_device_list_t *g_device_list;
34
35 static int _check_for_valid_mask (int flags)
36 {
37         int ret = MM_ERROR_NONE;
38         bool at_least_cond = false;
39
40         if (flags > 0 && flags <= MM_SOUND_DEVICE_ALL_FLAG) {
41                 if (flags & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG)
42                         at_least_cond = true;
43                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG))
44                         at_least_cond = true;
45                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG))
46                         at_least_cond = true;
47                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG))
48                         at_least_cond = true;
49                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG))
50                         at_least_cond = true;
51                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG))
52                         at_least_cond = true;
53                 if (!at_least_cond && (flags & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG))
54                         at_least_cond = true;
55         } else {
56                 ret = MM_ERROR_INVALID_ARGUMENT;
57         }
58         if (!at_least_cond) {
59                 ret = MM_ERROR_INVALID_ARGUMENT;
60         }
61         if (ret) {
62                 debug_error("flags[0x%x] is not valid\n", flags);
63         }
64         return ret;
65 }
66
67 static int __convert_device_type_to_enum (char *device_type, mm_sound_device_type_e *device_type_enum)
68 {
69         int ret = MM_ERROR_NONE;
70
71         if (!device_type || !device_type_enum) {
72                 return MM_ERROR_INVALID_ARGUMENT;
73         }
74
75         if (!strncmp(device_type, "builtin-speaker", VOLUME_TYPE_LEN)) {
76                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
77         } else if (!strncmp(device_type, "builtin-receiver", VOLUME_TYPE_LEN)) {
78                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_RECEIVER;
79         } else if (!strncmp(device_type, "builtin-mic", VOLUME_TYPE_LEN)) {
80                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_MIC;
81         } else if (!strncmp(device_type, "audio-jack", VOLUME_TYPE_LEN)) {
82                 *device_type_enum = MM_SOUND_DEVICE_TYPE_AUDIOJACK;
83         } else if (!strncmp(device_type, "bt-a2dp", VOLUME_TYPE_LEN)) {
84                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP;
85         } else if (!strncmp(device_type, "bt-sco", VOLUME_TYPE_LEN)) {
86                 *device_type_enum = MM_SOUND_DEVICE_TYPE_BLUETOOTH_SCO;
87         } else if (!strncmp(device_type, "hdmi", VOLUME_TYPE_LEN)) {
88                 *device_type_enum = MM_SOUND_DEVICE_TYPE_HDMI;
89         } else if (!strncmp(device_type, "forwarding", VOLUME_TYPE_LEN)) {
90                 *device_type_enum = MM_SOUND_DEVICE_TYPE_MIRRORING;
91         } else if (!strncmp(device_type, "usb-audio", VOLUME_TYPE_LEN)) {
92                 *device_type_enum = MM_SOUND_DEVICE_TYPE_USB_AUDIO;
93         } else {
94                 ret = MM_ERROR_INVALID_ARGUMENT;
95                 debug_error("not supported device_type(%s), err(0x%08x)", device_type, ret);
96         }
97
98         return ret;
99 }
100
101 static int __free_device_list(mm_sound_device_list_t *device_list_t)
102 {
103         if (!device_list_t)
104                 return MM_ERROR_INVALID_ARGUMENT;
105
106         debug_log("free device list %p", device_list_t);
107         g_list_free_full(device_list_t->list, g_free);
108         g_free(device_list_t);
109
110         return MM_ERROR_NONE;
111 }
112
113 EXPORT_API
114 int mm_sound_add_device_connected_callback(int flags, mm_sound_device_connected_cb func, void *user_data, unsigned int *id)
115 {
116         int ret = MM_ERROR_NONE;
117
118         if (func == NULL || id == NULL) {
119                 debug_error("argument is not valid\n");
120                 return MM_ERROR_INVALID_ARGUMENT;
121         }
122         ret = _check_for_valid_mask(flags);
123         if (ret == MM_ERROR_NONE) {
124                 ret = mm_sound_client_add_device_connected_callback(flags, func, user_data, id);
125                 if (ret < 0) {
126                         debug_error("Could not add device connected callback, ret = %x\n", ret);
127                 }
128         }
129
130         return ret;
131 }
132
133 EXPORT_API
134 int mm_sound_remove_device_connected_callback(unsigned int id)
135 {
136         int ret = MM_ERROR_NONE;
137
138         ret = mm_sound_client_remove_device_connected_callback(id);
139         if (ret < 0) {
140                 debug_error("Could not remove device connected callback, ret = %x\n", ret);
141         }
142
143         return ret;
144 }
145
146 EXPORT_API
147 int mm_sound_add_device_information_changed_callback(int flags, mm_sound_device_info_changed_cb func, void *user_data, unsigned int *id)
148 {
149         int ret = MM_ERROR_NONE;
150
151         if (func == NULL || id == NULL) {
152                 debug_error("argument is not valid\n");
153                 return MM_ERROR_INVALID_ARGUMENT;
154         }
155         ret = _check_for_valid_mask(flags);
156         if (ret == MM_ERROR_NONE) {
157                 ret = mm_sound_client_add_device_info_changed_callback(flags, func, user_data, id);
158                 if (ret < 0) {
159                         debug_error("Could not add device information changed callback, ret = %x\n", ret);
160                 }
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\n", ret);
174         }
175
176         return ret;
177 }
178
179 EXPORT_API
180 int mm_sound_add_device_state_changed_callback(int flags, mm_sound_device_state_changed_cb func, void *user_data, unsigned int *id)
181 {
182         int ret = MM_ERROR_NONE;
183
184         if (func == NULL || id == NULL) {
185                 debug_error("argument is not valid\n");
186                 return MM_ERROR_INVALID_ARGUMENT;
187         }
188         ret = _check_for_valid_mask(flags);
189         if (ret == MM_ERROR_NONE) {
190                 ret = mm_sound_client_add_device_state_changed_callback(flags, func, user_data, id);
191                 if (ret < 0) {
192                         debug_error("Could not add device state changed callback, ret = %x\n", ret);
193                 }
194         }
195
196         return ret;
197 }
198
199 EXPORT_API
200 int mm_sound_remove_device_state_changed_callback(unsigned int id)
201 {
202         int ret = MM_ERROR_NONE;
203
204         ret = mm_sound_client_remove_device_state_changed_callback(id);
205         if (ret < 0) {
206                 debug_error("Could not remove device state changed callback, ret = %x\n", ret);
207         }
208
209         return ret;
210 }
211
212
213 EXPORT_API
214 int mm_sound_get_current_device_list(mm_sound_device_flags_e flags, MMSoundDeviceList_t *device_list)
215 {
216         int ret = MM_ERROR_NONE;
217
218         if (!device_list) {
219                 return MM_ERROR_INVALID_ARGUMENT;
220         }
221         ret = _check_for_valid_mask(flags);
222         if (ret != MM_ERROR_NONE) {
223                 debug_error("mask[0x%x] is invalid, ret=0x%x", flags, ret);
224                 return ret;
225         }
226
227         /* free previously allocated list */
228         if (g_device_list != NULL)
229                 __free_device_list(g_device_list);
230
231         if (!(g_device_list = g_malloc0(sizeof(mm_sound_device_list_t)))) {
232                 debug_error("[Client] Allocate device list failed");
233                 return MM_ERROR_SOUND_INTERNAL;
234         }
235
236         g_device_list->is_new_device_list = true;
237
238         ret = mm_sound_client_get_current_connected_device_list(flags, g_device_list);
239         if (ret < 0) {
240                 debug_error("Could not get current connected device list, ret = %x\n", ret);
241                 g_free(g_device_list);
242                 g_device_list = NULL;
243         } else {
244                 *device_list = g_device_list;
245         }
246
247         return ret;
248 }
249
250 EXPORT_API
251 int mm_sound_get_device_list(int flags, MMSoundDeviceList_t *device_list)
252 {
253         int ret = MM_ERROR_NONE;
254         mm_sound_device_list_t *_device_list;
255
256         if (!device_list) {
257                 return MM_ERROR_INVALID_ARGUMENT;
258         }
259         ret = _check_for_valid_mask(flags);
260         if (ret != MM_ERROR_NONE) {
261                 debug_error("mask[0x%x] is invalid, ret=0x%x", flags, ret);
262                 return ret;
263         }
264
265         if (!(_device_list = g_malloc0(sizeof(mm_sound_device_list_t)))) {
266                 debug_error("[Client] Allocate device list failed");
267                 return MM_ERROR_SOUND_INTERNAL;
268         }
269
270         _device_list->is_new_device_list = true;
271
272         ret = mm_sound_client_get_current_connected_device_list(flags, _device_list);
273         if (ret < 0) {
274                 debug_error("Could not get current connected device list, ret = %x\n", ret);
275                 g_free(_device_list);
276         } else {
277                 *device_list = _device_list;
278         }
279
280         return ret;
281 }
282
283 EXPORT_API
284 int mm_sound_free_device_list(MMSoundDeviceList_t device_list)
285 {
286         return __free_device_list((mm_sound_device_list_t*) device_list);
287 }
288
289 EXPORT_API
290 int mm_sound_get_next_device (MMSoundDeviceList_t device_list, MMSoundDevice_t *device)
291 {
292         int ret = MM_ERROR_NONE;
293         mm_sound_device_list_t *device_list_t = NULL;
294         GList *node = NULL;
295         if (!device_list || !device) {
296                 return MM_ERROR_INVALID_ARGUMENT;
297         }
298         device_list_t = (mm_sound_device_list_t*) device_list;
299         if (device_list_t->is_new_device_list) {
300                 node = g_list_first(device_list_t->list);
301         } else {
302                 node = g_list_next(device_list_t->list);
303         }
304         if (!node) {
305                 ret = MM_ERROR_SOUND_NO_DATA;
306         } else {
307                 if (device_list_t->is_new_device_list) {
308                         device_list_t->is_new_device_list = false;
309                 } else {
310                         device_list_t->list = node;
311                 }
312                 *device = (mm_sound_device_t*)node->data;
313                 debug_log("next device[0x%x]\n", *device);
314         }
315         return ret;
316 }
317
318 EXPORT_API
319 int mm_sound_get_prev_device (MMSoundDeviceList_t device_list, MMSoundDevice_t *device)
320 {
321         int ret = MM_ERROR_NONE;
322         mm_sound_device_list_t *device_list_t = NULL;
323         GList *node = NULL;
324         if (!device_list || !device) {
325                 return MM_ERROR_INVALID_ARGUMENT;
326         }
327         device_list_t = (mm_sound_device_list_t*) device_list;
328         node = g_list_previous(device_list_t->list);
329         if (!node) {
330                 ret = MM_ERROR_SOUND_NO_DATA;
331                 debug_error("Could not get previous device, ret = %x\n", ret);
332         } else {
333                 device_list_t->list = node;
334                 *device = (mm_sound_device_t*)node->data;
335                 debug_log("previous device[0x%x]\n", *device);
336         }
337         return ret;
338 }
339
340 EXPORT_API
341 int mm_sound_get_device_type(MMSoundDevice_t device_h, mm_sound_device_type_e *type)
342 {
343         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
344         if(!device || !type) {
345                 debug_error("invalid argument\n");
346                 return MM_ERROR_INVALID_ARGUMENT;
347         }
348         __convert_device_type_to_enum(device->type, type);
349         debug_log("device_handle:0x%x, type:%d\n", device, *type);
350
351         return MM_ERROR_NONE;
352 }
353
354 EXPORT_API
355 int mm_sound_get_device_io_direction(MMSoundDevice_t device_h, mm_sound_device_io_direction_e *io_direction)
356 {
357         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
358         if(!device) {
359                 debug_error("invalid handle\n");
360                 return MM_ERROR_INVALID_ARGUMENT;
361         }
362         *io_direction = device->io_direction;
363         debug_log("device_handle:0x%x, io_direction:%d (1:IN,2:OUT,3:INOUT)\n", device, *io_direction);
364
365         return MM_ERROR_NONE;
366 }
367
368 EXPORT_API
369 int mm_sound_get_device_id(MMSoundDevice_t device_h, int *id)
370 {
371         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
372         if(!device) {
373                 debug_error("invalid handle\n");
374                 return MM_ERROR_INVALID_ARGUMENT;
375         }
376         *id = device->id;
377         debug_log("device_handle:0x%x, id:%d\n", device, *id);
378
379         return MM_ERROR_NONE;
380 }
381
382 EXPORT_API
383 int mm_sound_get_device_state(MMSoundDevice_t device_h, mm_sound_device_state_e *state)
384 {
385         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
386         if(!device) {
387                 debug_error("invalid handle\n");
388                 return MM_ERROR_INVALID_ARGUMENT;
389         }
390         *state = device->state;
391         debug_log("device_handle:0x%x, state:%d (0:INACTIVATED,1:ACTIVATED)\n", device, *state);
392
393         return MM_ERROR_NONE;
394 }
395
396 EXPORT_API
397 int mm_sound_get_device_name(MMSoundDevice_t device_h, char **name)
398 {
399         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
400         if(!device) {
401                 debug_error("invalid handle\n");
402                 return MM_ERROR_INVALID_ARGUMENT;
403         }
404         *name = device->name;
405         debug_log("device_handle:0x%x, name:%s\n", device, *name);
406
407         return MM_ERROR_NONE;
408 }
409
410 EXPORT_API
411 int mm_sound_is_stream_on_device(int stream_id, MMSoundDevice_t device_h, bool *is_on)
412 {
413         int ret = MM_ERROR_NONE;
414         int i;
415         mm_sound_device_t *device = (mm_sound_device_t*)device_h;
416         bool _is_on = false;
417
418         if(!device || !is_on) {
419                 debug_error("invalid argument\n");
420                 return MM_ERROR_INVALID_ARGUMENT;
421         }
422
423         if (device->stream_num >= 0) {
424                 debug_log("device_handle has stream id");
425                 for (i = 0; i < device->stream_num; i++) {
426                         if (device->stream_id[i] == stream_id) {
427                                 _is_on = true;
428                                 break;
429                         }
430                 }
431         } else {
432                 debug_log("device_handle dosn't have stream id");
433                 /* No information about stream in client-side, should ask to server-side */
434                 if ((ret = mm_sound_client_is_stream_on_device(stream_id, device->id, &_is_on)) < 0) {
435                         debug_error("Failed to query is stream on");
436                         return MM_ERROR_SOUND_INTERNAL;
437                 }
438         }
439
440         debug_log("device(%d) %s stream(%d)\n", device->id, _is_on ? "has" : "doesn't have", stream_id);
441         *is_on = _is_on;
442
443         return ret;
444 }
445
446