fix tmp code define
[platform/core/api/sound-manager.git] / src / sound_manager.c
1 /*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "sound_manager.h"
18 #include "sound_manager_private.h"
19
20 #define TMP_CODE
21
22 _session_interrupt_info_s g_session_interrupt_cb_table = {0, NULL, NULL};
23 _volume_changed_info_s g_volume_changed_cb_table = {NULL, NULL};
24 _focus_watch_info_s g_focus_watch_cb_table = {-1, NULL, NULL};
25 _device_connected_info_s g_device_connected_cb_table = {NULL, NULL};
26 _device_changed_info_s g_device_info_changed_cb_table = {NULL, NULL};
27
28 sound_session_type_e g_cached_session = -1;
29 _session_mode_e g_cached_session_mode = -1;
30
31 /* These variables will be removed when session features are deprecated. */
32 extern int g_stream_info_count;
33 extern pthread_mutex_t g_stream_info_count_mutex;
34
35 #ifdef TMP_CODE
36 /*temporary variable for set/get voip session mode. When 2.4  feature for routing is fully implemented, it will be removed.*/
37 sound_session_voip_mode_e tmp_mode = -1;
38 #endif
39
40 int sound_manager_get_max_volume (sound_type_e type, int *max)
41 {
42         const char *volume_type = NULL;
43         unsigned int max_level = 0;
44         int ret = MM_ERROR_NONE;
45
46         if (max == NULL)
47                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
48
49         if (type >= SOUND_TYPE_NUM || type < 0)
50                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
51         ret = __convert_sound_type (type, &volume_type);
52         if (ret == MM_ERROR_NONE) {
53                 ret = __get_volume_max_level("out", volume_type, &max_level);
54                 if (ret == MM_ERROR_NONE)
55                         *max = (int)max_level -1;       // actual volume step can be max step - 1
56         }
57
58         return __convert_sound_manager_error_code(__func__, ret);
59 }
60
61 int sound_manager_set_volume (sound_type_e type, int volume)
62 {
63         int ret = MM_ERROR_NONE;
64
65         if (type >= SOUND_TYPE_NUM || type < 0)
66                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
67         if (volume < 0)
68                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
69
70         ret = mm_sound_volume_set_value(type, volume);
71         LOGI("returns : type=%d, volume=%d, ret=%p", type, volume, ret);
72
73         return __convert_sound_manager_error_code(__func__, ret);
74 }
75
76 int sound_manager_get_volume (sound_type_e type, int *volume)
77 {
78         int ret = MM_ERROR_NONE;
79         unsigned int uvolume;
80
81         if (type >= SOUND_TYPE_NUM || type < 0)
82                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
83         if (volume == NULL)
84                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
85
86         ret = mm_sound_volume_get_value(type, &uvolume);
87         if (ret == MM_ERROR_NONE)
88                 *volume = uvolume;
89
90         LOGI("returns : type=%d, volume=%d, ret=%p", type, *volume, ret);
91
92         return __convert_sound_manager_error_code(__func__, ret);
93 }
94
95 int sound_manager_set_current_sound_type (sound_type_e type)
96 {
97         int ret = MM_ERROR_NONE;
98
99         if (type >= SOUND_TYPE_NUM || type < 0)
100                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
101
102         ret = mm_sound_volume_primary_type_set(type);
103
104         return __convert_sound_manager_error_code(__func__, ret);
105 }
106
107 int sound_manager_get_current_sound_type (sound_type_e *type)
108 {
109         int ret = MM_ERROR_NONE;
110
111         if (type == NULL)
112                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
113         ret = mm_sound_volume_get_current_playing_type((volume_type_t *)type);
114
115         LOGI("returns : type=%d, ret=%p", *type, ret);
116
117         return __convert_sound_manager_error_code(__func__, ret);
118 }
119
120 int sound_manager_unset_current_sound_type (void)
121 {
122         int ret = MM_ERROR_NONE;
123
124         ret = mm_sound_volume_primary_type_clear();
125
126         return __convert_sound_manager_error_code(__func__, ret);
127 }
128
129 int sound_manager_set_volume_changed_cb (sound_manager_volume_changed_cb callback, void* user_data)
130 {
131         int ret = MM_ERROR_NONE;
132
133         ret = mm_sound_add_volume_changed_callback((mm_sound_volume_changed_cb)callback, user_data);
134         if (ret == MM_ERROR_NONE) {
135                 g_volume_changed_cb_table.user_cb = (sound_manager_volume_changed_cb)callback;
136                 g_volume_changed_cb_table.user_data = user_data;
137         }
138
139         return __convert_sound_manager_error_code(__func__, ret);
140 }
141
142 int sound_manager_unset_volume_changed_cb (void)
143 {
144         int ret = MM_ERROR_NONE;
145
146         if (g_volume_changed_cb_table.user_cb) {
147                 ret = mm_sound_remove_volume_changed_callback();
148                 if (ret == MM_ERROR_NONE) {
149                         g_volume_changed_cb_table.user_cb = NULL;
150                         g_volume_changed_cb_table.user_data = NULL;
151                 }
152         } else {
153                 ret = MM_ERROR_SOUND_INTERNAL;
154         }
155
156         return __convert_sound_manager_error_code(__func__, ret);
157 }
158
159 int sound_manager_create_stream_information (sound_stream_type_e stream_type, sound_stream_focus_state_changed_cb callback, void *user_data, sound_stream_info_h *stream_info)
160 {
161         int ret = MM_ERROR_NONE;
162
163         LOGI(">> enter");
164
165         SM_NULL_ARG_CHECK(stream_info);
166         SM_NULL_ARG_CHECK(callback);
167
168         if (g_session_interrupt_cb_table.is_registered)
169                 return __convert_sound_manager_error_code(__func__, MM_ERROR_SOUND_INTERNAL);
170
171         sound_stream_info_s *stream_h = malloc(sizeof(sound_stream_info_s));
172         if (!stream_h) {
173                 ret = MM_ERROR_OUT_OF_MEMORY;
174         } else {
175                 memset(stream_h, 0, sizeof(sound_stream_info_s));
176                 ret = __convert_stream_type(stream_type, stream_h->stream_type);
177                 if (ret == MM_ERROR_NONE) {
178                         ret = _make_pa_connection_and_register_focus(stream_h, callback, user_data);
179                         if (ret == MM_ERROR_NONE) {
180                                 *stream_info = (sound_stream_info_h)stream_h;
181                                 LOGI("<< leave : stream_h(%p), index(%u), user_cb(%p), cnt(%d), ret(%p)", stream_h, stream_h->index, stream_h->user_cb, g_stream_info_count, ret);
182                         }
183                 }
184                 if (ret) {
185                         free(stream_h);
186                 }
187         }
188
189         return __convert_sound_manager_error_code(__func__, ret);
190 }
191
192 int sound_manager_destroy_stream_information (sound_stream_info_h stream_info)
193 {
194         int ret = MM_ERROR_NONE;
195         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
196
197         LOGI(">> enter");
198
199         SM_INSTANCE_CHECK(stream_h);
200
201         ret = _destroy_pa_connection_and_unregister_focus(stream_h);
202
203         LOGI("<< leave : cnt(%d), ret(%p)", g_stream_info_count, ret);
204
205         return __convert_sound_manager_error_code(__func__, ret);
206 }
207
208 int sound_manager_add_device_for_stream_routing (sound_stream_info_h stream_info, sound_device_h device)
209 {
210         int ret = MM_ERROR_NONE;
211         int i = 0;
212         int j = 0;
213         bool added_successfully = false;
214         char *device_type_str = NULL;
215         int device_id = 0;
216         mm_sound_device_type_e device_type;
217         mm_sound_device_io_direction_e device_direction;
218         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
219
220         LOGI(">> enter");
221
222         SM_INSTANCE_CHECK(stream_h);
223         SM_NULL_ARG_CHECK(device);
224
225         if (stream_h->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL) {
226                 ret = mm_sound_get_device_id(device, &device_id);
227                 if (ret) {
228                         return __convert_sound_manager_error_code(__func__, ret);
229                 }
230                 ret = mm_sound_get_device_type(device, &device_type);
231                 if (ret) {
232                         return __convert_sound_manager_error_code(__func__, ret);
233                 }
234                 ret = __convert_device_type(device_type, &device_type_str);
235                 if (ret) {
236                         return __convert_sound_manager_error_code(__func__, ret);
237                 }
238                 ret = mm_sound_get_device_io_direction(device, &device_direction);
239                 if (ret) {
240                         return __convert_sound_manager_error_code(__func__, ret);
241                 }
242                 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_IN || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
243                         for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
244                                 if (stream_h->stream_conf_info.avail_in_devices[i]) {
245                                         if (!strncmp(stream_h->stream_conf_info.avail_in_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
246                                                 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
247                                                         if (!stream_h->manual_route_info.route_in_devices[j]) {
248                                                                 stream_h->manual_route_info.route_in_devices[j] = (unsigned int)device_id;
249                                                                 added_successfully = true;
250                                                                 break;
251                                                         }
252                                                         if (stream_h->manual_route_info.route_in_devices[j] == (unsigned int)device_id) {
253                                                                 /* it was already set */
254                                                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_DUPLICATED);
255                                                         }
256                                                 }
257                                         }
258                                 } else {
259                                         break;
260                                 }
261                         }
262                 }
263                 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_OUT || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
264                         for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
265                                 if (stream_h->stream_conf_info.avail_out_devices[i]) {
266                                         if (!strncmp(stream_h->stream_conf_info.avail_out_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
267                                                 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
268                                                         if (!stream_h->manual_route_info.route_out_devices[j]) {
269                                                                 stream_h->manual_route_info.route_out_devices[j] = (unsigned int)device_id;
270                                                                 added_successfully = true;
271                                                                 break;
272                                                         }
273                                                         if (stream_h->manual_route_info.route_out_devices[j] == (unsigned int)device_id) {
274                                                                 /* it was already set */
275                                                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_DUPLICATED);
276                                                         }
277                                                 }
278                                         }
279                                 } else {
280                                         break;
281                                 }
282                         }
283                 }
284         }
285
286         if (!added_successfully) {
287                 ret = MM_ERROR_POLICY_INTERNAL;
288         }
289
290         LOGI("<< leave : ret(%p)", ret);
291
292         return __convert_sound_manager_error_code(__func__, ret);
293 }
294
295 int sound_manager_remove_device_for_stream_routing (sound_stream_info_h stream_info, sound_device_h device)
296 {
297         int ret = MM_ERROR_NONE;
298         int i = 0;
299         int j = 0;
300         bool removed_successfully = false;
301         char *device_type_str = NULL;
302         int device_id = 0;
303         mm_sound_device_type_e device_type;
304         mm_sound_device_io_direction_e device_direction;
305         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
306
307         LOGI(">> enter");
308
309         SM_INSTANCE_CHECK(stream_h);
310         SM_NULL_ARG_CHECK(device);
311
312         if (stream_h->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL) {
313                 ret = mm_sound_get_device_id(device, &device_id);
314                 if (ret) {
315                         return __convert_sound_manager_error_code(__func__, ret);
316                 }
317                 ret = mm_sound_get_device_type(device, &device_type);
318                 if (ret) {
319                         return __convert_sound_manager_error_code(__func__, ret);
320                 }
321                 ret = __convert_device_type(device_type, &device_type_str);
322                 ret = mm_sound_get_device_io_direction(device, &device_direction);
323                 if (ret) {
324                         return __convert_sound_manager_error_code(__func__, ret);
325                 }
326                 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_IN || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
327                         for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
328                                 if (stream_h->stream_conf_info.avail_in_devices[i]) {
329                                         if (!strncmp(stream_h->stream_conf_info.avail_in_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
330                                                 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
331                                                         if (stream_h->manual_route_info.route_in_devices[j] == (unsigned int)device_id) {
332                                                                 removed_successfully = true;
333                                                                 stream_h->manual_route_info.route_in_devices[j] = 0;
334                                                                 break;
335                                                         }
336                                                 }
337                                         }
338                                 } else {
339                                         break;
340                                 }
341                         }
342                 }
343                 if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_OUT || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) {
344                         for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
345                                 if (stream_h->stream_conf_info.avail_out_devices[i]) {
346                                         if (!strncmp(stream_h->stream_conf_info.avail_out_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) {
347                                                 for (j = 0; j < AVAIL_DEVICES_MAX; j++) {
348                                                         if (stream_h->manual_route_info.route_out_devices[j] == (unsigned int)device_id) {
349                                                                 removed_successfully = true;
350                                                                 stream_h->manual_route_info.route_out_devices[j] = 0;
351                                                                 break;
352                                                         }
353                                                 }
354                                         }
355                                 } else {
356                                         break;
357                                 }
358                         }
359                 }
360         }
361
362         if (!removed_successfully) {
363                 ret = MM_ERROR_INVALID_ARGUMENT;
364         }
365
366         LOGI("<< leave : ret(%p)", ret);
367
368         return __convert_sound_manager_error_code(__func__, ret);
369 }
370
371 int sound_manager_apply_stream_routing (sound_stream_info_h stream_info)
372 {
373         int ret = MM_ERROR_NONE;
374         int i = 0;
375         bool need_to_apply = false;
376         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
377
378         LOGI(">> enter");
379
380         SM_INSTANCE_CHECK(stream_h);
381
382         if (stream_h->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL) {
383                 for (i = 0; i < AVAIL_DEVICES_MAX; i++) {
384                         if (stream_h->manual_route_info.route_in_devices[i]) {
385                                 need_to_apply = true;
386                                 break;
387                         }
388                         if (stream_h->manual_route_info.route_out_devices[i]) {
389                                 need_to_apply = true;
390                                 break;
391                         }
392                 }
393                 if (need_to_apply) {
394                         ret = __set_manual_route_info(stream_h->index, &stream_h->manual_route_info);
395                 } else {
396                         __convert_sound_manager_error_code(__func__, MM_ERROR_SOUND_INVALID_STATE);
397                 }
398         } else {
399                 ret = MM_ERROR_SOUND_INVALID_STATE;
400         }
401
402         LOGI("<< leave : ret(%p)", ret);
403
404         return __convert_sound_manager_error_code(__func__, ret);
405 }
406
407 int sound_manager_acquire_focus (sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, const char *additional_info)
408 {
409         int ret = MM_ERROR_NONE;
410         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
411
412         LOGI(">> enter");
413
414         SM_INSTANCE_CHECK(stream_h);
415
416         ret = mm_sound_acquire_focus(stream_h->index, (mm_sound_focus_type_e)focus_mask, additional_info);
417         if (ret == MM_ERROR_NONE) {
418                 stream_h->acquired_focus |= focus_mask;
419         }
420
421         LOGI("<< leave : ret(%p)", ret);
422
423         return __convert_sound_manager_error_code(__func__, ret);
424 }
425
426 int sound_manager_release_focus (sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, const char *additional_info)
427 {
428         int ret = MM_ERROR_NONE;
429         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
430
431         LOGI(">> enter");
432
433         SM_INSTANCE_CHECK(stream_h);
434
435         ret = mm_sound_release_focus(stream_h->index, (mm_sound_focus_type_e)focus_mask, additional_info);
436         if (ret == MM_ERROR_NONE) {
437                 stream_h->acquired_focus &= ~focus_mask;
438         }
439
440         LOGI("<< leave : ret(%p)", ret);
441
442         return __convert_sound_manager_error_code(__func__, ret);
443 }
444
445 int sound_manager_get_focus_state (sound_stream_info_h stream_info, sound_stream_focus_state_e *state_for_playback, sound_stream_focus_state_e *state_for_recording)
446 {
447         int ret = MM_ERROR_NONE;
448         sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info;
449
450         LOGI(">> enter");
451
452         SM_INSTANCE_CHECK(stream_h);
453         if (!state_for_playback && !state_for_recording)
454                 ret = MM_ERROR_INVALID_ARGUMENT;
455
456         if (state_for_playback)
457                 *state_for_playback = (stream_h->acquired_focus & SOUND_STREAM_FOCUS_FOR_PLAYBACK)?SOUND_STREAM_FOCUS_STATE_ACQUIRED:SOUND_STREAM_FOCUS_STATE_RELEASED;
458         if (state_for_recording)
459                 *state_for_recording = (stream_h->acquired_focus & SOUND_STREAM_FOCUS_FOR_RECORDING)?SOUND_STREAM_FOCUS_STATE_ACQUIRED:SOUND_STREAM_FOCUS_STATE_RELEASED;
460
461         LOGI("<< leave : acquired_focus(%p)", stream_h->acquired_focus);
462
463         return __convert_sound_manager_error_code(__func__, ret);
464 }
465
466 int sound_manager_set_focus_state_watch_cb (sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_watch_cb callback, void *user_data)
467 {
468         int ret = MM_ERROR_NONE;
469         int id = -1;
470
471         LOGI(">> enter");
472
473         SM_NULL_ARG_CHECK(callback);
474         SM_ENTER_CRITICAL_SECTION_WITH_RETURN( &g_stream_info_count_mutex, SOUND_MANAGER_ERROR_INTERNAL);
475
476         if (!g_focus_watch_cb_table.user_cb) {
477                 SM_REF_FOR_STREAM_INFO(g_stream_info_count, ret);
478                 ret = mm_sound_set_focus_watch_callback((mm_sound_focus_type_e)focus_mask, _focus_watch_callback, user_data, &id);
479                 if (ret == MM_ERROR_NONE) {
480                         g_focus_watch_cb_table.index = id;
481                         g_focus_watch_cb_table.user_cb = callback;
482                         g_focus_watch_cb_table.user_data = user_data;
483                 }
484         } else {
485                 ret = MM_ERROR_SOUND_INTERNAL;
486         }
487
488         SM_LEAVE_CRITICAL_SECTION(&g_stream_info_count_mutex);
489
490         LOGI("<< leave : cnt(%d), ret(%p)", g_stream_info_count, ret);
491
492         return __convert_sound_manager_error_code(__func__, ret);
493 }
494
495 int sound_manager_unset_focus_state_watch_cb (void)
496 {
497         int ret = MM_ERROR_NONE;
498
499         LOGI(">> enter");
500
501         SM_ENTER_CRITICAL_SECTION_WITH_RETURN( &g_stream_info_count_mutex, SOUND_MANAGER_ERROR_INTERNAL);
502
503         if (g_focus_watch_cb_table.user_cb) {
504                 ret = mm_sound_unset_focus_watch_callback(g_focus_watch_cb_table.index);
505                 if (ret == MM_ERROR_NONE) {
506                         g_focus_watch_cb_table.index = -1;
507                         g_focus_watch_cb_table.user_cb = NULL;
508                         g_focus_watch_cb_table.user_data = NULL;
509                         SM_UNREF_FOR_STREAM_INFO(g_stream_info_count, ret);
510                 } else {
511                         ret = MM_ERROR_SOUND_INTERNAL;
512                 }
513         } else {
514                 ret = MM_ERROR_SOUND_INTERNAL;
515         }
516
517         SM_LEAVE_CRITICAL_SECTION(&g_stream_info_count_mutex);
518
519         LOGI("<< leave : cnt(%d), ret(%p)", g_stream_info_count, ret);
520
521         return __convert_sound_manager_error_code(__func__, ret);
522 }
523
524 int sound_manager_set_session_type (sound_session_type_e type)
525 {
526         int ret = MM_ERROR_NONE;
527         int cur_session = -1;
528         int new_session = MM_SESSION_TYPE_MEDIA;
529
530         LOGI(">> enter : type=%d", type);
531
532         if (type < SOUND_SESSION_TYPE_MEDIA || type >  SOUND_SESSION_TYPE_VOIP)
533                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
534
535         /* it is not supported both session and stream feature at the same time */
536         if (g_stream_info_count)
537                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
538
539         switch (type) {
540         case SOUND_SESSION_TYPE_MEDIA:
541                 new_session = MM_SESSION_TYPE_MEDIA;
542                 break;
543         case SOUND_SESSION_TYPE_ALARM:
544                 new_session = MM_SESSION_TYPE_ALARM;
545                 break;
546         case SOUND_SESSION_TYPE_NOTIFICATION:
547                 new_session = MM_SESSION_TYPE_NOTIFY;
548                 break;
549         case SOUND_SESSION_TYPE_EMERGENCY:
550                 new_session = MM_SESSION_TYPE_EMERGENCY;
551                 break;
552         case SOUND_SESSION_TYPE_VOIP:
553                 new_session = MM_SESSION_TYPE_VOIP;
554                 break;
555         }
556
557         /* valid session check */
558         ret = mm_session_get_current_type(&cur_session);
559         if (ret == MM_ERROR_NONE) {
560                 if (cur_session == MM_SESSION_TYPE_MEDIA_RECORD) {
561                         if (type > SOUND_SESSION_TYPE_MEDIA) {
562                                 LOGE("<< leave : Could not set this type(%d) during camera/recorder/audio-io(in)/radio", type);
563                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
564                         }
565                 }
566                 if (cur_session == MM_SESSION_TYPE_VIDEOCALL ||
567                         cur_session >= MM_SESSION_TYPE_VOICE_RECOGNITION) {
568                         return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
569                 }
570         }
571
572         if (g_session_interrupt_cb_table.is_registered) {
573                 if (new_session == cur_session ||
574                         ((new_session == SOUND_SESSION_TYPE_MEDIA) && (cur_session == MM_SESSION_TYPE_MEDIA_RECORD))) {
575                         LOGI("<< leave : already set type=%d, ret=%p", type, ret);
576                         return SOUND_MANAGER_ERROR_NONE;
577                 } else {
578                         ret = mm_session_finish();
579                         if (ret != MM_ERROR_NONE) {
580                                 return __convert_sound_manager_error_code(__func__, ret);
581                         }
582                         g_session_interrupt_cb_table.is_registered = 0;
583                         g_cached_session_mode = -1;
584                 }
585         }
586         ret = mm_session_init_ex(new_session , _session_interrupt_cb, NULL);
587         if (ret == MM_ERROR_NONE) {
588                 g_session_interrupt_cb_table.is_registered = 1;
589         }
590         if (new_session == MM_SESSION_TYPE_VOIP || new_session == MM_SESSION_TYPE_CALL) {
591                 /* set default sub-session for voip */
592                 ret = mm_session_set_subsession (MM_SUBSESSION_TYPE_RINGTONE, MM_SUBSESSION_OPTION_NONE);
593                 if (ret != MM_ERROR_NONE) {
594                         return __convert_sound_manager_error_code(__func__, ret);
595                 }
596                 g_cached_session_mode = _SESSION_MODE_RINGTONE;
597         }
598         LOGI("<< leave : type=%d, ret=%p", type, ret);
599
600         return __convert_sound_manager_error_code(__func__, ret);
601 }
602
603 int sound_manager_get_session_type (sound_session_type_e *type)
604 {
605         int ret = MM_ERROR_NONE;
606         int cur_session;
607
608         if (type == NULL)
609                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
610         ret = mm_session_get_current_type(&cur_session);
611         if (ret != 0)
612                 cur_session = SOUND_SESSION_TYPE_DEFAULT;
613         if ((cur_session > MM_SESSION_TYPE_EMERGENCY) &&
614                         (cur_session != MM_SESSION_TYPE_VOIP)) {
615                 if (g_cached_session != -1)
616                         cur_session = g_cached_session;
617                 else //will be never reach here. just prevent code
618                         cur_session = SOUND_SESSION_TYPE_DEFAULT;
619         }
620
621         switch (cur_session) {
622         case MM_SESSION_TYPE_MEDIA:
623         case MM_SESSION_TYPE_MEDIA_RECORD:
624                 *type = SOUND_SESSION_TYPE_MEDIA;
625                 break;
626         case MM_SESSION_TYPE_ALARM:
627                 *type = SOUND_SESSION_TYPE_ALARM;
628                 break;
629         case MM_SESSION_TYPE_NOTIFY:
630                 *type = SOUND_SESSION_TYPE_NOTIFICATION;
631                 break;
632         case MM_SESSION_TYPE_EMERGENCY:
633                 *type = SOUND_SESSION_TYPE_EMERGENCY;
634                 break;
635         case MM_SESSION_TYPE_VOIP:
636                 *type = SOUND_SESSION_TYPE_VOIP;
637                 break;
638         default:
639                 *type = cur_session;
640                 break;
641         }
642
643         LOGI("returns : type=%d, ret=%p", *type, ret);
644
645         return 0;
646 }
647
648 int sound_manager_set_media_session_option (sound_session_option_for_starting_e s_option, sound_session_option_for_during_play_e d_option)
649 {
650         int ret = MM_ERROR_NONE;
651         int session = 0;
652         int session_option = 0;
653         int updated = 0;
654
655         LOGI(">> enter : option for starting=%d, for during play=%d", s_option, d_option);
656
657         if (s_option < 0 || s_option >  SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START)
658                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
659         if (d_option < 0 || d_option >  SOUND_SESSION_OPTION_UNINTERRUPTIBLE_DURING_PLAY)
660                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
661
662         ret = mm_session_get_current_information(&session, &session_option);
663         if (ret != 0 || !g_session_interrupt_cb_table.is_registered) {
664                 LOGW("need to set session type first");
665                 return __convert_sound_manager_error_code(__func__, ret);
666         } else if (ret == MM_ERROR_NONE && session > MM_SESSION_TYPE_MEDIA) {
667                 if (session == MM_SESSION_TYPE_MEDIA_RECORD) {
668                         if (!g_session_interrupt_cb_table.is_registered) {
669                                 LOGE("Already set by camera/recorder/audio-io(in)/radio API, but need to set session to Media first");
670                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
671                         }
672                 } else {
673                         return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
674                 }
675         }
676
677         switch (s_option) {
678         case SOUND_SESSION_OPTION_MIX_WITH_OTHERS_WHEN_START:
679                 if (session_option & MM_SESSION_OPTION_PAUSE_OTHERS) {
680                         ret = mm_session_update_option(MM_SESSION_UPDATE_TYPE_REMOVE, MM_SESSION_OPTION_PAUSE_OTHERS);
681                         if (ret) {
682                                 return __convert_sound_manager_error_code(__func__, ret);
683                         }
684                         updated = 1;
685                 }
686                 break;
687         case SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START:
688                 if (!(session_option & MM_SESSION_OPTION_PAUSE_OTHERS)) {
689                         ret = mm_session_update_option(MM_SESSION_UPDATE_TYPE_ADD, MM_SESSION_OPTION_PAUSE_OTHERS);
690                         if (ret) {
691                                 return __convert_sound_manager_error_code(__func__, ret);
692                         }
693                         updated = 1;
694                 }
695                 break;
696         }
697
698         switch (d_option) {
699         case SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY:
700                 if (session_option & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
701                         ret = mm_session_update_option(MM_SESSION_UPDATE_TYPE_REMOVE, MM_SESSION_OPTION_UNINTERRUPTIBLE);
702                         if (ret) {
703                                 return __convert_sound_manager_error_code(__func__, ret);
704                         }
705                         updated = 1;
706                 }
707                 break;
708         case SOUND_SESSION_OPTION_UNINTERRUPTIBLE_DURING_PLAY:
709                 if (!(session_option & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
710                         ret = mm_session_update_option(MM_SESSION_UPDATE_TYPE_ADD, MM_SESSION_OPTION_UNINTERRUPTIBLE);
711                         if (ret) {
712                                 return __convert_sound_manager_error_code(__func__, ret);
713                         }
714                         updated = 1;
715                 }
716                 break;
717         }
718
719         if (updated) {
720                 LOGI("<< leave : updated");
721         } else {
722                 LOGI("<< leave : already set same option(%x), skip it", session_option);
723         }
724
725         return __convert_sound_manager_error_code(__func__, ret);
726 }
727
728 int sound_manager_get_media_session_option (sound_session_option_for_starting_e *s_option, sound_session_option_for_during_play_e *d_option)
729 {
730         int ret = MM_ERROR_NONE;
731         int session = 0;
732         int session_options = 0;
733
734         LOGI(">> enter");
735
736         if (s_option == NULL || d_option == NULL)
737                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
738
739         ret = mm_session_get_current_information(&session, &session_options);
740         if (ret != 0) {
741                 return __convert_sound_manager_error_code(__func__, ret);
742         } else if (session > SOUND_SESSION_TYPE_MEDIA) {
743                 if (session == MM_SESSION_TYPE_MEDIA_RECORD) {
744                         if (!g_session_interrupt_cb_table.is_registered) {
745                                 LOGE("Already set by camera/recorder/audio-io(in)/radio API, but need to set session to Media first");
746                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
747                         }
748                 } else {
749                         return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
750                 }
751         }
752         /* get option */
753         if (session_options & MM_SESSION_OPTION_PAUSE_OTHERS) {
754                 *s_option = SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START;
755         } else {
756                 *s_option = SOUND_SESSION_OPTION_MIX_WITH_OTHERS_WHEN_START;
757         }
758         if (session_options & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
759                 *d_option = SOUND_SESSION_OPTION_UNINTERRUPTIBLE_DURING_PLAY;
760         } else {
761                 *d_option = SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY;
762         }
763
764         LOGI("<< leave : option for starting=%d, for during play=%d", *s_option, *d_option);
765
766         return SOUND_MANAGER_ERROR_NONE;
767 }
768
769 int sound_manager_set_media_session_resumption_option (sound_session_option_for_resumption_e option)
770 {
771         int ret = MM_ERROR_NONE;
772         int session = 0;
773         int session_option = 0;
774         int updated = 0;
775
776         LOGI(">> enter : option for resumption=%d (0:by system, 1:by system or media paused)", option);
777
778         if (option < SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM || option > SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM_OR_MEDIA_PAUSED)
779                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
780
781         ret = mm_session_get_current_information(&session, &session_option);
782         if (ret != 0 || !g_session_interrupt_cb_table.is_registered) {
783                 LOGW("need to set session type first");
784                 return __convert_sound_manager_error_code(__func__, ret);
785         } else if (ret == MM_ERROR_NONE && session > MM_SESSION_TYPE_MEDIA) {
786                 if (session == MM_SESSION_TYPE_MEDIA_RECORD) {
787                         if (!g_session_interrupt_cb_table.is_registered) {
788                                 LOGE("Already set by camera/recorder/audio-io(in)/radio API, but need to set session to Media first");
789                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
790                         }
791                 } else {
792                         return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
793                 }
794         }
795
796         switch (option) {
797         case SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM:
798                 if (session_option & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED) {
799                         ret = mm_session_update_option(MM_SESSION_UPDATE_TYPE_REMOVE, MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED);
800                         if (ret) {
801                                 return __convert_sound_manager_error_code(__func__, ret);
802                         }
803                         updated = 1;
804                 }
805                 break;
806         case SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM_OR_MEDIA_PAUSED:
807                 if (!(session_option & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED)) {
808                         ret = mm_session_update_option(MM_SESSION_UPDATE_TYPE_ADD, MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED);
809                         if (ret) {
810                                 return __convert_sound_manager_error_code(__func__, ret);
811                         }
812                         updated = 1;
813                 }
814                 break;
815         }
816
817         if (updated) {
818                 LOGI("<< leave : updated");
819         } else {
820                 LOGI("<< leave : already set same option(%x), skip it", session_option);
821         }
822
823         return __convert_sound_manager_error_code(__func__, ret);
824 }
825
826 int sound_manager_get_media_session_resumption_option (sound_session_option_for_resumption_e *option)
827 {
828         int ret = MM_ERROR_NONE;
829         int session = 0;
830         int session_options = 0;
831
832         LOGI(">> enter");
833
834         if (option == NULL)
835                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
836         ret = mm_session_get_current_information(&session, &session_options);
837         if (ret != 0) {
838                 return __convert_sound_manager_error_code(__func__, ret);
839         } else if (session > SOUND_SESSION_TYPE_MEDIA) {
840                 if (session == MM_SESSION_TYPE_MEDIA_RECORD) {
841                         if (!g_session_interrupt_cb_table.is_registered) {
842                                 LOGE("Already set by camera/recorder/audio-io(in)/radio API, but need to set session to Media first");
843                                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
844                         }
845                 } else {
846                         return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
847                 }
848         }
849         /* get option */
850         if (session_options & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED) {
851                 *option = SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM_OR_MEDIA_PAUSED;
852         } else {
853                 *option = SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM;
854         }
855
856         LOGI("<< leave : option for resumption=%d (0:by system, 1:by system or media paused)", *option);
857
858         return SOUND_MANAGER_ERROR_NONE;
859 }
860
861 int sound_manager_set_voip_session_mode (sound_session_voip_mode_e mode)
862 {
863         int ret = MM_ERROR_NONE;
864         int session = 0;
865         int session_options = 0;
866
867         LOGI(">> enter : mode=%d", mode);
868
869         ret = mm_session_get_current_information(&session, &session_options);
870         if (ret != MM_ERROR_NONE) {
871                 return __convert_sound_manager_error_code(__func__, ret);
872         } else if (session != MM_SESSION_TYPE_VOIP) {
873                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
874         }
875         if (mode < SOUND_SESSION_VOIP_MODE_RINGTONE || mode > SOUND_SESSION_VOIP_MODE_VOICE_WITH_BLUETOOTH) {
876                 ret = MM_ERROR_INVALID_ARGUMENT;
877                 return __convert_sound_manager_error_code(__func__, ret);
878         }
879         ret = __set_session_mode ((_session_mode_e)mode);
880
881 #ifdef TMP_CODE
882         /* temporary code. When 2.4 feature for routing is fully implemented, it will be removed. */
883         tmp_mode = mode;
884 #endif
885
886         LOGI("<< leave : session=%p, mode=%d, ret=%p", session, mode, ret);
887
888         return __convert_sound_manager_error_code(__func__, ret);
889 }
890
891 int sound_manager_get_voip_session_mode (sound_session_voip_mode_e *mode)
892 {
893         int ret = MM_ERROR_NONE;
894         int session = 0;
895         int session_options = 0;
896 #ifndef TMP_CODE
897         _session_mode_e _mode = 0;
898 #endif
899
900         if (mode == NULL) {
901                 LOGI("mode is null");
902                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
903         }
904
905         ret = mm_session_get_current_information(&session, &session_options);
906         if (ret != MM_ERROR_NONE) {
907                 LOGI("session = %d, option = %d", session, session_options);
908                 return __convert_sound_manager_error_code(__func__, ret);
909         } else if (session != MM_SESSION_TYPE_VOIP) {
910                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
911         }
912
913 #ifdef TMP_CODE
914         /* temporary code. When 2.4 feature for routing is fully implemented, it will be removed. */
915         *mode = tmp_mode;
916 #else
917         ret = __get_session_mode(&_mode);
918         if (ret == MM_ERROR_NONE)
919                 *mode = (sound_session_voip_mode_e)_mode;
920 #endif
921
922         LOGI("returns : session=%p, mode=%d, ret=%p", session, *mode, ret);
923
924         return __convert_sound_manager_error_code(__func__, ret);
925 }
926
927 int sound_manager_set_session_interrupted_cb (sound_session_interrupted_cb callback, void *user_data)
928 {
929         int ret = MM_ERROR_NONE;
930         if (callback == NULL)
931                 return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT);
932
933         /* it is not supported both session and stream feature at the same time */
934         if (g_stream_info_count)
935                 return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_INTERNAL);
936
937         if (g_session_interrupt_cb_table.is_registered == 0) {
938                 ret = mm_session_init_ex(SOUND_SESSION_TYPE_DEFAULT /*default*/ , _session_interrupt_cb, NULL);
939                 if (ret != 0)
940                         return __convert_sound_manager_error_code(__func__, ret);
941                 g_session_interrupt_cb_table.is_registered = 1;
942         }
943
944         g_session_interrupt_cb_table.user_cb = (sound_session_interrupted_cb)callback;
945         g_session_interrupt_cb_table.user_data = user_data;
946         return SOUND_MANAGER_ERROR_NONE;
947 }
948
949 int sound_manager_unset_session_interrupted_cb (void)
950 {
951         int ret = MM_ERROR_NONE;
952         if (g_session_interrupt_cb_table.user_cb) {
953                 g_session_interrupt_cb_table.user_cb = NULL;
954                 g_session_interrupt_cb_table.user_data = NULL;
955         } else {
956                 ret = MM_ERROR_SOUND_INTERNAL;
957         }
958         return __convert_sound_manager_error_code(__func__, ret);
959 }
960
961 int sound_manager_get_current_device_list (sound_device_mask_e device_mask, sound_device_list_h *device_list)
962 {
963         int ret = MM_ERROR_NONE;
964         ret = mm_sound_get_current_device_list((mm_sound_device_flags_e)device_mask, device_list);
965
966         return __convert_sound_manager_error_code(__func__, ret);
967 }
968
969 int sound_manager_get_next_device (sound_device_list_h device_list, sound_device_h *device)
970 {
971         int ret = MM_ERROR_NONE;
972         ret = mm_sound_get_next_device(device_list, device);
973
974         return __convert_sound_manager_error_code(__func__, ret);
975 }
976
977 int sound_manager_get_prev_device (sound_device_list_h device_list, sound_device_h *device)
978 {
979         int ret = MM_ERROR_NONE;
980         ret = mm_sound_get_prev_device(device_list, device);
981
982         return __convert_sound_manager_error_code(__func__, ret);
983 }
984
985 int sound_manager_get_device_type (sound_device_h device, sound_device_type_e *type)
986 {
987         int ret = MM_ERROR_NONE;
988         ret = mm_sound_get_device_type(device, (mm_sound_device_type_e*)type);
989
990         return __convert_sound_manager_error_code(__func__, ret);
991 }
992
993 int sound_manager_get_device_io_direction (sound_device_h device, sound_device_io_direction_e *io_direction)
994 {
995         int ret = MM_ERROR_NONE;
996         mm_sound_device_io_direction_e mm_sound_io_direction;
997         ret = mm_sound_get_device_io_direction(device, &mm_sound_io_direction);
998         if (ret == MM_ERROR_NONE) {
999                 ret = __convert_device_io_direction(mm_sound_io_direction, io_direction);
1000         }
1001
1002         return __convert_sound_manager_error_code(__func__, ret);
1003 }
1004
1005 int sound_manager_get_device_id (sound_device_h device, int *id)
1006 {
1007         int ret = MM_ERROR_NONE;
1008         ret = mm_sound_get_device_id(device, id);
1009
1010         return __convert_sound_manager_error_code(__func__, ret);
1011 }
1012
1013 int sound_manager_get_device_name (sound_device_h device, char **name)
1014 {
1015         int ret = MM_ERROR_NONE;
1016         ret = mm_sound_get_device_name(device, name);
1017
1018         return __convert_sound_manager_error_code(__func__, ret);
1019 }
1020
1021 int sound_manager_get_device_state (sound_device_h device, sound_device_state_e *state)
1022 {
1023         int ret = MM_ERROR_NONE;
1024         ret = mm_sound_get_device_state(device, (mm_sound_device_state_e*)state);
1025
1026         return __convert_sound_manager_error_code(__func__, ret);
1027 }
1028
1029 int sound_manager_set_device_connected_cb (sound_device_mask_e device_mask, sound_device_connected_cb callback, void *user_data)
1030 {
1031         int ret = MM_ERROR_NONE;
1032         ret = mm_sound_add_device_connected_callback((mm_sound_device_flags_e)device_mask, (mm_sound_device_connected_cb)callback, user_data);
1033         if (ret == MM_ERROR_NONE) {
1034                 g_device_connected_cb_table.user_cb = (sound_device_connected_cb)callback;
1035                 g_device_connected_cb_table.user_data = user_data;
1036         }
1037
1038         return __convert_sound_manager_error_code(__func__, ret);
1039 }
1040
1041 int sound_manager_unset_device_connected_cb (void)
1042 {
1043         int ret = MM_ERROR_NONE;
1044         if (g_device_connected_cb_table.user_cb) {
1045                 ret = mm_sound_remove_device_connected_callback();
1046                 if (ret == MM_ERROR_NONE) {
1047                         g_device_connected_cb_table.user_cb = NULL;
1048                         g_device_connected_cb_table.user_data = NULL;
1049                 }
1050         } else {
1051                 ret = MM_ERROR_SOUND_INTERNAL;
1052         }
1053
1054         return __convert_sound_manager_error_code(__func__, ret);
1055 }
1056
1057 int sound_manager_set_device_information_changed_cb (sound_device_mask_e device_mask, sound_device_information_changed_cb callback, void *user_data)
1058 {
1059         int ret = MM_ERROR_NONE;
1060         ret = mm_sound_add_device_information_changed_callback((mm_sound_device_flags_e)device_mask, (mm_sound_device_info_changed_cb)callback, user_data);
1061         if (ret == MM_ERROR_NONE) {
1062                 g_device_info_changed_cb_table.user_cb = (sound_device_information_changed_cb)callback;
1063                 g_device_info_changed_cb_table.user_data = user_data;
1064         }
1065
1066         return __convert_sound_manager_error_code(__func__, ret);
1067 }
1068
1069 int sound_manager_unset_device_information_changed_cb (void)
1070 {
1071         int ret = MM_ERROR_NONE;
1072         if (g_device_info_changed_cb_table.user_cb) {
1073                 ret = mm_sound_remove_device_information_changed_callback();
1074                 if (ret == MM_ERROR_NONE) {
1075                         g_device_info_changed_cb_table.user_cb = NULL;
1076                         g_device_info_changed_cb_table.user_data = NULL;
1077                 }
1078         } else {
1079                 ret = MM_ERROR_SOUND_INTERNAL;
1080         }
1081
1082         return __convert_sound_manager_error_code(__func__, ret);
1083 }
1084
1085 __attribute__ ((destructor))
1086 void __sound_manager_finalize (void)
1087 {
1088         int ret = MM_ERROR_NONE;
1089
1090         if (g_session_interrupt_cb_table.is_registered) {
1091                 LOGI("<ENTER>");
1092                 ret = mm_session_finish();
1093                 if (ret != MM_ERROR_NONE) {
1094                         LOGE("[%s] failed to mm_session_finish(), ret(%p)", __func__, ret);
1095                 }
1096                 g_session_interrupt_cb_table.is_registered = 0;
1097                 LOGI("<LEAVE>");
1098         }
1099 }
1100
1101 __attribute__ ((constructor))
1102 void __sound_manager_initialize (void)
1103 {
1104
1105 }