Fix coverity issue (Unchecked return value)
[platform/core/multimedia/libmm-radio.git] / src / mm_radio_priv_hal.c
1 /*
2  * mm_radio_priv_hal.c
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 /*===========================================================================================
21 |                                                                                                                                                                                       |
22 |  INCLUDE FILES                                                                                                                                                        |
23 |                                                                                                                                                                                       |
24 ========================================================================================== */
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <float.h>
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <unistd.h>
34 #include <errno.h>
35
36 #include <mm_error.h>
37 #include <mm_message.h>
38 #include <mm_sound.h>
39
40 #include "mm_radio_priv_hal.h"
41
42 /*===========================================================================================
43   LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE
44 ========================================================================================== */
45 /*---------------------------------------------------------------------------
46     GLOBAL CONSTANT DEFINITIONS:
47 ---------------------------------------------------------------------------*/
48
49 /*---------------------------------------------------------------------------
50     IMPORTED VARIABLE DECLARATIONS:
51 ---------------------------------------------------------------------------*/
52
53 /*---------------------------------------------------------------------------
54     IMPORTED FUNCTION DECLARATIONS:
55 ---------------------------------------------------------------------------*/
56
57 /*---------------------------------------------------------------------------
58     LOCAL #defines:
59 ---------------------------------------------------------------------------*/
60 #define DEFAULT_DEVICE                          "/dev/radio0"
61 #define TUNER_INDEX                             0
62
63 #define DEFAULT_FREQ                            107700
64
65 #define FREQ_FRAC                               16
66 #define RADIO_FREQ_FORMAT_SET(x_freq)           ((x_freq) * FREQ_FRAC)
67 #define RADIO_FREQ_FORMAT_GET(x_freq)           ((x_freq) / FREQ_FRAC)
68 /* If non-zero, wrap around when at the end of the frequency range, else stop seeking */
69 #define DEFAULT_WRAP_AROUND             1
70
71 #define RADIO_DEFAULT_REGION    MM_RADIO_REGION_GROUP_USA
72 #define READ_MAX_BUFFER_SIZE    1024
73 #define DEFAULT_MAX_MEDIA_VOLUME        15
74 /*---------------------------------------------------------------------------
75     LOCAL CONSTANT DEFINITIONS:
76 ---------------------------------------------------------------------------*/
77
78 /*---------------------------------------------------------------------------
79     LOCAL DATA TYPE DEFINITIONS:
80 ---------------------------------------------------------------------------*/
81
82 /*---------------------------------------------------------------------------
83     GLOBAL VARIABLE DEFINITIONS:
84 ---------------------------------------------------------------------------*/
85 extern int errno;
86
87 /*---------------------------------------------------------------------------
88     LOCAL VARIABLE DEFINITIONS:
89 ---------------------------------------------------------------------------*/
90 /* radio region configuration table */
91 static const MMRadioRegion_t region_table[] = {
92         {                                                       /* Notrh America, South America, South Korea, Taiwan, Australia */
93          MM_RADIO_REGION_GROUP_USA,     /* region type */
94          MM_RADIO_DEEMPHASIS_75_US,     /* de-emphasis */
95          MM_RADIO_FREQ_MIN_87500_KHZ,   /* min freq. */
96          MM_RADIO_FREQ_MAX_108000_KHZ,  /* max freq. */
97          50,
98          },
99         {                                                       /* China, Europe, Africa, Middle East, Hong Kong, India, Indonesia, Russia, Singapore */
100          MM_RADIO_REGION_GROUP_EUROPE,
101          MM_RADIO_DEEMPHASIS_50_US,
102          MM_RADIO_FREQ_MIN_87500_KHZ,
103          MM_RADIO_FREQ_MAX_108000_KHZ,
104          50,
105          },
106         {
107          MM_RADIO_REGION_GROUP_JAPAN,
108          MM_RADIO_DEEMPHASIS_50_US,
109          MM_RADIO_FREQ_MIN_76100_KHZ,
110          MM_RADIO_FREQ_MAX_89900_KHZ,
111          50,
112          },
113 };
114
115 /*---------------------------------------------------------------------------
116     LOCAL FUNCTION PROTOTYPES:
117 ---------------------------------------------------------------------------*/
118 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param);
119 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command);
120 static int __mmradio_get_state(mm_radio_t *radio);
121 static bool __mmradio_set_state(mm_radio_t *radio, int new_state);
122 void _mmradio_seek_cancel(mm_radio_t *radio);
123 static void __mmradio_seek_thread(mm_radio_t *radio);
124 static void __mmradio_scan_thread(mm_radio_t *radio);
125 static bool __is_tunable_frequency(mm_radio_t *radio, int freq);
126
127 #ifdef TIZEN_FEATURE_SOUND_FOCUS
128 static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
129         mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
130         const char *additional_info, void *user_data);
131 static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
132         mm_sound_focus_state_e focus_state, const char *reason_for_change,
133         const char *additional_info, void *user_data);
134 #endif
135
136 static void __mmradio_volume_changed_cb(volume_type_t type, unsigned int volume, void *user_data);
137 static int __mmradio_set_media_volume(mm_radio_t *radio, unsigned int level);
138 static int __resource_release_cb(mm_resource_manager_h rm,
139         mm_resource_manager_res_h res, void *user_data);
140
141 int _mmradio_apply_region(mm_radio_t *radio, MMRadioRegionType region, bool update)
142 {
143         int ret = MM_ERROR_NONE;
144         int count = 0;
145         int index = 0;
146
147         MMRADIO_LOG_FENTER();
148
149         MMRADIO_CHECK_INSTANCE(radio);
150         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_REGION);
151
152         /* if needed, radio region must be updated.
153          * Otherwise, just applying settings to device without it.
154          */
155         if (update) {
156                 count = ARRAY_SIZE(region_table);
157
158                 /* TODO: if auto is supported...get the region info. here */
159
160                 /* update radio region settings */
161                 for (index = 0; index < count; index++) {
162                         /* find the region from pre-defined table */
163                         if (region_table[index].country == region) {
164                                 radio->region_setting.country = region_table[index].country;
165                                 radio->region_setting.deemphasis = region_table[index].deemphasis;
166                                 radio->region_setting.band_min = region_table[index].band_min;
167                                 radio->region_setting.band_max = region_table[index].band_max;
168                                 radio->region_setting.channel_spacing = region_table[index].channel_spacing;
169                         }
170                 }
171         }
172
173         MMRADIO_LOG_INFO("setting region - country: %d, de-emphasis: %d, band range: %d ~ %d KHz",
174                 radio->region_setting.country, radio->region_setting.deemphasis,
175                 radio->region_setting.band_min, radio->region_setting.band_max);
176
177         MMRADIO_LOG_FLEAVE();
178
179         return ret;
180 }
181
182 int _mmradio_create_radio(mm_radio_t *radio)
183 {
184         int ret = MM_ERROR_NONE;
185
186         MMRADIO_LOG_FENTER();
187
188         MMRADIO_CHECK_INSTANCE(radio);
189         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_CREATE);
190
191         /* set default value */
192         radio->freq = DEFAULT_FREQ;
193 #ifdef TIZEN_FEATURE_SOUND_FOCUS
194         memset(&radio->sound_focus, 0, sizeof(mm_radio_sound_focus));
195 #endif
196         memset(&radio->region_setting, 0, sizeof(MMRadioRegion_t));
197         radio->local_volume = 1.0;
198
199         /* create command lock */
200         ret = pthread_mutex_init(&radio->cmd_lock, NULL);
201         if (ret) {
202                 MMRADIO_LOG_ERROR("failed to create mutex");
203                 return MM_ERROR_RADIO_INTERNAL;
204         }
205
206         ret = pthread_mutex_init(&radio->volume_lock, NULL);
207         if (ret) {
208                 MMRADIO_LOG_ERROR("failed to create volume mutex");
209                 return MM_ERROR_RADIO_INTERNAL;
210         }
211
212         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
213
214         /* initialize resource manager */
215         ret = mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
216                         __resource_release_cb, radio, &radio->resource_manager);
217         if (ret) {
218                 MMRADIO_LOG_ERROR("failed to create resource manager");
219                 return MM_ERROR_RADIO_INTERNAL;
220         }
221
222 #ifdef TIZEN_FEATURE_SOUND_FOCUS
223         ret = mmradio_sound_focus_register(&radio->sound_focus,
224                 (mm_sound_focus_changed_cb)__mmradio_sound_focus_cb,
225                 (mm_sound_focus_changed_watch_cb)__mmradio_sound_focus_watch_cb,
226                 (void *)radio);
227
228         if (ret) {
229                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
230                 MMRADIO_LOG_ERROR("failed to register sound focus");
231                 return MM_ERROR_RADIO_INTERNAL;
232         }
233 #endif
234
235         ret = radio_hal_interface_init(&(radio->hal_inf));
236         if (ret) {
237                 MMRADIO_LOG_ERROR("failed to init mmradio hal interface");
238                 return ret;
239         }
240
241         MMRADIO_LOG_FLEAVE();
242
243         return MM_ERROR_NONE;
244 }
245
246 int _mmradio_realize(mm_radio_t *radio)
247 {
248         int ret = MM_ERROR_NONE;
249         bool update = false;
250         int max = 0;
251         unsigned volume = 0;
252         MMRadioRegionType region = MM_RADIO_REGION_GROUP_NONE;
253
254         MMRADIO_LOG_FENTER();
255
256         MMRADIO_CHECK_INSTANCE(radio);
257         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_REALIZE);
258
259         ret = pthread_mutex_init(&radio->seek_cancel_mutex, NULL);
260         if (ret < 0) {
261                 MMRADIO_LOG_ERROR("failed to create seek cancel mutex %d", ret);
262                 return MM_ERROR_RADIO_INTERNAL;
263         }
264
265         if (radio->region_setting.country == MM_RADIO_REGION_GROUP_NONE) {
266                 /* not initialized      yet. set it with default region */
267                 region = RADIO_DEFAULT_REGION;
268                 update = true;
269         } else {
270                 /* already initialized by application */
271                 region = radio->region_setting.country;
272         }
273
274         ret = _mmradio_apply_region(radio, region, update);
275
276 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
277         ret = sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_RADIO, NULL, radio, &radio->stream_info);
278         if (ret != MM_ERROR_NONE) {
279                 MMRADIO_LOG_ERROR("failed to create stream information");
280                 MMRADIO_LOG_FLEAVE();
281                 return ret;
282         }
283         ret = sound_manager_create_virtual_stream(radio->stream_info, &radio->vstream);
284         if (ret != MM_ERROR_NONE) {
285                 MMRADIO_LOG_ERROR("sound_manager_create_virtual_stream error");
286                 MMRADIO_LOG_FLEAVE();
287                 return ret;
288         }
289 #endif
290
291         ret = sound_manager_get_max_volume(SOUND_TYPE_MEDIA, &max);
292         if (ret != MM_ERROR_NONE) {
293                 MMRADIO_LOG_WARNING("failed to get max volume");
294                 radio->max_media_volume = DEFAULT_MAX_MEDIA_VOLUME;
295         } else {
296                 radio->max_media_volume = max;
297         }
298
299         ret = mm_sound_volume_get_value(VOLUME_TYPE_MEDIA, &volume);
300
301         if (ret != MM_ERROR_NONE)
302                 MMRADIO_LOG_WARNING("failed to get media volume");
303
304         MMRADIO_VOLUME_LOCK(radio);
305         radio->media_volume = volume;
306         MMRADIO_VOLUME_UNLOCK(radio);
307
308         ret = mm_sound_add_volume_changed_callback(__mmradio_volume_changed_cb, (void *)radio, &radio->volume_subs_id);
309         if (ret != MM_ERROR_NONE)
310                 MMRADIO_LOG_WARNING("failed to register volume changed callback");
311
312         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
313
314         MMRADIO_LOG_FLEAVE();
315
316         return MM_ERROR_NONE;
317 }
318
319 int _mmradio_unrealize(mm_radio_t *radio)
320 {
321         int ret = MM_ERROR_NONE;
322
323         MMRADIO_LOG_FENTER();
324
325         MMRADIO_CHECK_INSTANCE(radio);
326         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNREALIZE);
327
328         ret = mm_sound_remove_volume_changed_callback(radio->volume_subs_id);
329         if (ret != MM_ERROR_NONE)
330                 MMRADIO_LOG_WARNING("mm_sound_remove_volume_changed_callback error");
331
332         /*Finish if there are scans*/
333         _mmradio_stop_scan(radio);
334
335         /*Stop radio if started*/
336         _mmradio_stop(radio);
337
338         /* close radio device here !!!! */
339         radio_hal_close(radio->hal_inf);
340         radio_hal_unprepare(radio->hal_inf);
341 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
342         sound_manager_destroy_virtual_stream(radio->vstream);
343         sound_manager_destroy_stream_information(radio->stream_info);
344 #endif
345
346         pthread_mutex_destroy(&radio->seek_cancel_mutex);
347
348         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
349
350         MMRADIO_LOG_FLEAVE();
351
352         return ret;
353 }
354
355 int _mmradio_destroy(mm_radio_t *radio)
356 {
357         int ret = MM_ERROR_NONE;
358         MMRADIO_LOG_FENTER();
359
360         MMRADIO_CHECK_INSTANCE(radio);
361         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_DESTROY);
362
363         _mmradio_unrealize(radio);
364
365         ret = radio_hal_interface_deinit(radio->hal_inf);
366         if (ret) {
367                 MMRADIO_LOG_ERROR("failed to deinitialize radio hal interface");
368                 return ret;
369         }
370
371         /* destroy command lock */
372         ret = pthread_mutex_destroy(&radio->cmd_lock);
373         if (ret)
374                 MMRADIO_LOG_ERROR("failed to destory muxtex");
375
376         ret = pthread_mutex_destroy(&radio->volume_lock);
377         if (ret)
378                 MMRADIO_LOG_ERROR("failed to destory volume mutex");
379
380 #ifdef TIZEN_FEATURE_SOUND_FOCUS
381         ret = mmradio_sound_focus_deregister(&radio->sound_focus);
382         if (ret) {
383                 MMRADIO_LOG_ERROR("failed to deregister sound focus");
384                 return MM_ERROR_RADIO_INTERNAL;
385         }
386 #endif
387
388         ret = mm_resource_manager_destroy(radio->resource_manager);
389         if (ret) {
390                 MMRADIO_LOG_ERROR("failed to destroy resource manager");
391                 return MM_ERROR_RADIO_INTERNAL;
392         }
393
394         MMRADIO_LOG_FLEAVE();
395
396         return MM_ERROR_NONE;
397 }
398
399 /* unit should be KHz */
400 int _mmradio_set_frequency(mm_radio_t *radio, int freq)
401 {
402         int ret = MM_ERROR_NONE;
403
404         MMRADIO_LOG_FENTER();
405
406         MMRADIO_CHECK_INSTANCE(radio);
407         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_FREQ);
408
409         MMRADIO_LOG_INFO("Setting %d frequency", freq);
410
411         radio->freq = freq;
412
413         ret = radio_hal_set_frequency(radio->hal_inf, freq);
414         if (ret != MM_ERROR_NONE) {
415                 MMRADIO_LOG_ERROR("failed to set radio hal frequency");
416                 MMRADIO_LOG_FLEAVE();
417                 return ret;
418         }
419
420         MMRADIO_LOG_FLEAVE();
421
422         return ret;
423
424 }
425
426 int _mmradio_get_frequency(mm_radio_t *radio, int *pFreq)
427 {
428         int ret = MM_ERROR_NONE;
429         uint32_t freq = 0;
430         MMRADIO_LOG_FENTER();
431
432         MMRADIO_CHECK_INSTANCE(radio);
433         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_FREQ);
434
435         MMRADIO_RETURN_VAL_IF_FAIL(pFreq, MM_ERROR_INVALID_ARGUMENT);
436
437         ret = radio_hal_get_frequency(radio->hal_inf, &freq);
438         if (ret != MM_ERROR_NONE) {
439                 MMRADIO_LOG_ERROR("failed to get radio hal frequency");
440                 *pFreq = 0;
441                 return ret;
442         }
443
444         /* update freq in handle */
445         MMRADIO_LOG_INFO("Updating %d frequency", freq);
446         radio->freq = freq;
447
448         *pFreq = (int)radio->freq;
449
450         MMRADIO_LOG_FLEAVE();
451
452         return ret;
453 }
454
455 int _mmradio_mute(mm_radio_t *radio)
456 {
457         int ret = MM_ERROR_NONE;
458         MMRADIO_LOG_FENTER();
459
460         MMRADIO_CHECK_INSTANCE(radio);
461         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_MUTE);
462
463         ret = radio_hal_mute(radio->hal_inf);
464         if (ret == MM_ERROR_NOT_SUPPORT_API) {
465                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
466         } else if (ret != MM_ERROR_NONE) {
467                 MMRADIO_LOG_ERROR("failed to set radio hal mute");
468                 MMRADIO_LOG_FLEAVE();
469                 return ret;
470         }
471
472         radio->is_muted = TRUE;
473         MMRADIO_LOG_INFO("Radio mute state [%d]", radio->is_muted);
474         MMRADIO_LOG_FLEAVE();
475
476         return ret;
477 }
478
479 int _mmradio_unmute(mm_radio_t *radio)
480 {
481         int ret = MM_ERROR_NONE;
482         MMRADIO_LOG_FENTER();
483
484         MMRADIO_CHECK_INSTANCE(radio);
485         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNMUTE);
486
487         ret = radio_hal_unmute(radio->hal_inf);
488         if (ret == MM_ERROR_NOT_SUPPORT_API) {
489                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
490         } else if (ret != MM_ERROR_NONE) {
491                 MMRADIO_LOG_ERROR("failed to set radio hal unmute");
492                 MMRADIO_LOG_FLEAVE();
493                 return ret;
494         }
495
496         radio->is_muted = FALSE;
497         MMRADIO_LOG_INFO("Radio mute state [%d]", radio->is_muted);
498         MMRADIO_LOG_FLEAVE();
499
500         return ret;
501 }
502
503 int _mmradio_set_message_callback(mm_radio_t *radio, MMMessageCallback callback, void *user_param)
504 {
505         MMRADIO_LOG_FENTER();
506
507         MMRADIO_CHECK_INSTANCE(radio);
508
509         radio->msg_cb = callback;
510         radio->msg_cb_param = user_param;
511
512         MMRADIO_LOG_DEBUG("msg_cb : 0x%x msg_cb_param : 0x%x", callback, user_param);
513
514         MMRADIO_LOG_FLEAVE();
515
516         return MM_ERROR_NONE;
517 }
518
519 int _mmradio_get_state(mm_radio_t *radio, int *pState)
520 {
521         int state = 0;
522
523         MMRADIO_LOG_FENTER();
524
525         MMRADIO_CHECK_INSTANCE(radio);
526         MMRADIO_RETURN_VAL_IF_FAIL(pState, MM_ERROR_INVALID_ARGUMENT);
527
528         state = __mmradio_get_state(radio);
529
530         *pState = state;
531
532         MMRADIO_LOG_FLEAVE();
533
534         return MM_ERROR_NONE;
535 }
536
537 int _mmradio_start(mm_radio_t *radio)
538 {
539         int ret = MM_ERROR_NONE;
540         unsigned int volume = 0;
541
542         MMRADIO_LOG_FENTER();
543
544         MMRADIO_CHECK_INSTANCE(radio);
545         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START);
546
547         MMRADIO_LOG_INFO("now tune to frequency : %d", radio->freq);
548
549 #ifdef TIZEN_FEATURE_SOUND_FOCUS
550         if (radio->sound_focus.handle > 0) {
551                 ret = mmradio_acquire_sound_focus(&radio->sound_focus);
552                 if (ret != MM_ERROR_NONE) {
553                         MMRADIO_LOG_ERROR("failed to acquire sound focus");
554                         return ret;
555                 }
556         }
557
558         /* check previous acquired focus */
559         if (radio->sound_focus.watch_id > 0) {
560                 char *stream_type = NULL;
561                 char *ext_info = NULL;
562                 int option = 0;
563
564                 ret = mm_sound_get_stream_type_of_acquired_focus(FOCUS_FOR_BOTH, &stream_type, &option, &ext_info);
565                 if (ret == MM_ERROR_NONE) {
566                         MMRADIO_LOG_DEBUG("Focus is acquired by stream_type[%s], option[%d], ext_info[%s]",
567                                 stream_type, option, ext_info);
568                         if (!strcmp(stream_type, "alarm") || !strcmp(stream_type, "ringtone-voip") ||
569                                 !strcmp(stream_type, "ringtone-call") || !strcmp(stream_type, "voip") ||
570                                 !strcmp(stream_type, "call-voice") || !strcmp(stream_type, "call-video")) {
571                                 MMRADIO_LOG_DEBUG("Blcoked by session policy, focus_acquired_by[%s]", stream_type);
572                                 free(ext_info);
573                                 free(stream_type);
574                                 return MM_ERROR_POLICY_BLOCKED;
575                         }
576                         free(ext_info);
577                         free(stream_type);
578                 }
579         }
580 #endif
581
582         if (!radio->is_ready) {
583                 ret = mm_resource_manager_mark_for_acquire(radio->resource_manager,
584                         MM_RESOURCE_MANAGER_RES_TYPE_RADIO,
585                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &radio->radio_resource);
586                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
587                         MMRADIO_LOG_ERROR("resource manager mark for acquire fail");
588                         return MM_ERROR_RADIO_INTERNAL;
589                 }
590
591                 radio->interrupted_by_resource_conflict = FALSE;
592                 ret = mm_resource_manager_commit(radio->resource_manager);
593                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
594                         MMRADIO_LOG_ERROR("failed to commit resource manager");
595                         mm_resource_manager_mark_for_release(radio->resource_manager,
596                                 radio->radio_resource);
597                         radio->radio_resource = NULL;
598                         return ret;
599                 }
600
601                 ret = radio_hal_prepare(radio->hal_inf);
602                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
603                         MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
604                 } else if (ret != MM_ERROR_NONE) {
605                         MMRADIO_LOG_ERROR("failed to prepare radio hal");
606                         goto error2;
607                 }
608
609                 ret = radio_hal_open(radio->hal_inf);
610                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
611                         MMRADIO_LOG_WARNING("radio_hal_open is not supported");
612                 } else if (ret != MM_ERROR_NONE) {
613                         MMRADIO_LOG_ERROR("failed to open radio hal");
614                         goto error1;
615                 }
616                 radio->is_ready = TRUE;
617         } else {
618                 MMRADIO_LOG_DEBUG("radio prepared and opened");
619         }
620
621         ret = mm_sound_volume_get_value(VOLUME_TYPE_MEDIA, &volume);
622         if (ret != MM_ERROR_NONE)
623                 MMRADIO_LOG_WARNING("failed to get media volume");
624
625         ret = __mmradio_set_media_volume(radio, volume);
626         if (ret != MM_ERROR_NONE) {
627                 MMRADIO_LOG_ERROR("failed to set media volume");
628                 goto error1;
629         }
630
631         ret = radio_hal_start(radio->hal_inf);
632         if (ret == MM_ERROR_NOT_SUPPORT_API) {
633                 MMRADIO_LOG_WARNING("radio_hal_start is not supported");
634         } else if (ret) {
635                 MMRADIO_LOG_ERROR("failed to start radio hal");
636                 goto error1;
637         }
638
639         /* set stored frequency */
640         ret = radio_hal_set_frequency(radio->hal_inf, radio->freq);
641         if (ret) {
642                 MMRADIO_LOG_ERROR("failed to set radio hal frequency");
643                 goto error1;
644         }
645
646 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
647         ret = sound_manager_start_virtual_stream(radio->vstream);
648         if (ret) {
649                 MMRADIO_LOG_ERROR("failed to start sound manager virtual stream");
650                 goto error1;
651         }
652 #endif
653
654         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
655
656         MMRADIO_LOG_FLEAVE();
657
658         return MM_ERROR_NONE;
659
660 error1:
661         radio_hal_close(radio->hal_inf);
662 error2:
663         radio_hal_unprepare(radio->hal_inf);
664         radio->is_ready = FALSE;
665         return ret;
666 }
667
668 int _mmradio_stop(mm_radio_t *radio)
669 {
670         int ret = MM_ERROR_NONE;
671
672         MMRADIO_LOG_FENTER();
673
674         MMRADIO_CHECK_INSTANCE(radio);
675         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP);
676
677         radio->seek_unmute = FALSE;
678         /*cancel if any seek*/
679         _mmradio_seek_cancel(radio);
680 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
681         ret = sound_manager_stop_virtual_stream(radio->vstream);
682         if (ret != MM_ERROR_NONE) {
683                 MMRADIO_LOG_ERROR("failed to stop virtual_stream");
684                 return ret;
685         }
686 #endif
687
688         ret = radio_hal_stop(radio->hal_inf);
689         if (ret == MM_ERROR_NOT_SUPPORT_API) {
690                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
691         } else if (ret) {
692                 MMRADIO_LOG_ERROR("failed to stop radio hal");
693                 return ret;
694         }
695
696         /* close radio device here !!!! */
697         ret = radio_hal_close(radio->hal_inf);
698         if (ret == MM_ERROR_NOT_SUPPORT_API) {
699                 MMRADIO_LOG_WARNING("radio_hal_close is not supported");
700         } else if (ret != MM_ERROR_NONE) {
701                 MMRADIO_LOG_ERROR("failed to close radio hal");
702                 return ret;
703         }
704
705         ret = radio_hal_unprepare(radio->hal_inf);
706         if (ret == MM_ERROR_NOT_SUPPORT_API) {
707                 MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
708         } else if (ret != MM_ERROR_NONE) {
709                 MMRADIO_LOG_ERROR("failed to unprepare radio hal");
710                 return ret;
711         }
712
713         radio->is_ready = FALSE;
714
715         if (!radio->interrupted_by_resource_conflict && /* is being released */
716                         radio->radio_resource != NULL) {
717                 ret = mm_resource_manager_mark_for_release(radio->resource_manager,
718                                 radio->radio_resource);
719                 radio->radio_resource = NULL;
720                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
721                         MMRADIO_LOG_ERROR("failed to mark resource for release, ret(0x%x)", ret);
722                         return ret;
723                 }
724
725                 ret = mm_resource_manager_commit(radio->resource_manager);
726                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
727                         MMRADIO_LOG_ERROR("resource manager commit fail");
728         }
729
730 #ifdef TIZEN_FEATURE_SOUND_FOCUS
731         if (radio->sound_focus.handle > 0) {
732                 ret = mmradio_release_sound_focus(&radio->sound_focus);
733                 if (ret) {
734                         MMRADIO_LOG_ERROR("failed to release sound focus");
735                         return ret;
736                 }
737         }
738 #endif
739         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
740
741         MMRADIO_LOG_FLEAVE();
742
743         return MM_ERROR_NONE;
744 }
745
746 int _mmradio_seek(mm_radio_t *radio, MMRadioSeekDirectionType direction)
747 {
748         int ret = MM_ERROR_NONE;
749
750         MMRADIO_LOG_FENTER();
751
752         MMRADIO_CHECK_INSTANCE(radio);
753         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SEEK);
754
755         if (radio->is_seeking) {
756                 MMRADIO_LOG_ERROR("[RADIO_ERROR_INVALID_OPERATION]radio is seeking, can't serve another request try again");
757                 return MM_ERROR_RADIO_INTERNAL;
758         }
759
760         radio->seek_unmute = FALSE;
761         radio->is_seeking = TRUE;
762         radio->seek_cancel = FALSE;
763
764         if (!radio->is_muted) {
765                 ret = radio_hal_mute(radio->hal_inf);
766                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
767                         MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
768                 } else if (ret) {
769                         MMRADIO_LOG_ERROR("failed to set radio hal mute");
770                         return ret;
771                 }
772                 radio->seek_unmute = TRUE;
773         }
774
775         MMRADIO_LOG_INFO("trying to seek. direction[0:UP/1:DOWN) %d", direction);
776         radio->seek_direction = direction;
777
778         ret = pthread_create(&radio->seek_thread, NULL, (void *)__mmradio_seek_thread, (void *)radio);
779
780         if (ret) {
781                 MMRADIO_LOG_DEBUG("failed to create thread");
782                 radio->is_seeking = FALSE;
783                 radio->seek_cancel = TRUE;
784                 if (radio->seek_unmute) {
785                         ret = radio_hal_mute(radio->hal_inf);
786                         if (ret == MM_ERROR_NOT_SUPPORT_API) {
787                                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
788                         } else if (ret) {
789                                 MMRADIO_LOG_ERROR("failed to set radio hal mute");
790                                 radio->seek_unmute = FALSE;
791                                 return ret;
792                         }
793                 }
794                 return MM_ERROR_RADIO_INTERNAL;
795         }
796
797         MMRADIO_LOG_FLEAVE();
798
799         return MM_ERROR_NONE;
800 }
801
802 void _mmradio_seek_cancel(mm_radio_t *radio)
803 {
804         int ret = MM_ERROR_NONE;
805         char str_error[READ_MAX_BUFFER_SIZE];
806         MMRADIO_LOG_FENTER();
807
808         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
809
810         /*cancel any outstanding seek request*/
811         radio->seek_cancel = TRUE;
812         if (radio->seek_thread) {
813                 ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
814                 MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
815                 if (ret == EBUSY) { /* it was already locked by other */
816                         MMRADIO_LOG_WARNING("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
817                 } else if (ret == 0) {
818                         MMRADIO_LOG_INFO("trylock is successful. unlock now");
819                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
820                 } else {
821                         MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
822                 }
823                 MMRADIO_LOG_DEBUG("pthread_join seek_thread");
824                 pthread_join(radio->seek_thread, NULL);
825                 MMRADIO_LOG_DEBUG("done");
826                 radio->is_seeking = FALSE;
827                 radio->seek_thread = 0;
828         }
829         MMRADIO_LOG_FLEAVE();
830 }
831
832
833 int _mmradio_start_scan(mm_radio_t *radio)
834 {
835         int ret = MM_ERROR_NONE;
836
837         MMRADIO_LOG_FENTER();
838
839         MMRADIO_CHECK_INSTANCE(radio);
840         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START_SCAN);
841
842         int scan_tr_id = 0;
843
844         radio->stop_scan = false;
845
846         if (!radio->is_ready) {
847                 ret = mm_resource_manager_mark_for_acquire(radio->resource_manager,
848                         MM_RESOURCE_MANAGER_RES_TYPE_RADIO,
849                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &radio->radio_resource);
850                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
851                         MMRADIO_LOG_ERROR("resource manager mark for acquire fail");
852                         return MM_ERROR_RADIO_INTERNAL;
853                 }
854
855                 radio->interrupted_by_resource_conflict = FALSE;
856                 ret = mm_resource_manager_commit(radio->resource_manager);
857                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
858                         MMRADIO_LOG_ERROR("failed to commit resource manager");
859                         mm_resource_manager_mark_for_release(radio->resource_manager,
860                                 radio->radio_resource);
861                         radio->radio_resource = NULL;
862                         return ret;
863                 }
864
865                 ret = radio_hal_prepare(radio->hal_inf);
866                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
867                         MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
868                 } else if (ret != MM_ERROR_NONE) {
869                         MMRADIO_LOG_ERROR("failed to prepare radio hal");
870                         return ret;
871                 }
872
873                 ret = radio_hal_open(radio->hal_inf);
874                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
875                         MMRADIO_LOG_WARNING("radio_hal_open is not supported");
876                 } else if (ret != MM_ERROR_NONE) {
877                         MMRADIO_LOG_ERROR("failed to open radio hal");
878                         MMRADIO_LOG_FLEAVE();
879                         return ret;
880                 }
881                 radio->is_ready = TRUE;
882         } else {
883                 MMRADIO_LOG_DEBUG("radio prepared and opened");
884         }
885
886         scan_tr_id = pthread_create(&radio->scan_thread, NULL, (void *)__mmradio_scan_thread, (void *)radio);
887
888         if (scan_tr_id != 0) {
889                 MMRADIO_LOG_ERROR("failed to create thread : scan");
890                 return MM_ERROR_RADIO_NOT_INITIALIZED;
891         }
892
893         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
894
895         MMRADIO_LOG_FLEAVE();
896
897         return MM_ERROR_NONE;
898 }
899
900 int _mmradio_stop_scan(mm_radio_t *radio)
901 {
902         int ret = 0;
903         char str_error[READ_MAX_BUFFER_SIZE];
904         MMRADIO_LOG_FENTER();
905
906         MMRADIO_CHECK_INSTANCE(radio);
907         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP_SCAN);
908
909         radio->stop_scan = true;
910
911         if (radio->scan_thread > 0) {
912                 /* make sure all the search is stopped else we'll wait till search finish which is not ideal*/
913                 ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
914                 MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
915                 if (ret == EBUSY) { /* it was already locked by other */
916                         MMRADIO_LOG_WARNING("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
917                 } else if (ret == 0) {
918                         MMRADIO_LOG_INFO("trylock is successful. unlock now");
919                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
920                 } else {
921                         MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
922                 }
923                 MMRADIO_LOG_DEBUG("pthread_join scan_thread");
924                 pthread_join(radio->scan_thread, NULL);
925                 radio->scan_thread = 0;
926         }
927
928         MMRADIO_LOG_FLEAVE();
929
930         return MM_ERROR_NONE;
931 }
932
933 int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value)
934 {
935         int ret = MM_ERROR_NONE;
936         int32_t strength = 0;
937         MMRADIO_LOG_FENTER();
938         MMRADIO_CHECK_INSTANCE(radio);
939
940         MMRADIO_RETURN_VAL_IF_FAIL(value, MM_ERROR_INVALID_ARGUMENT);
941
942         /* just return stored frequency if radio device is not ready */
943         ret = radio_hal_get_signal_strength(radio->hal_inf, &strength);
944         if (ret == MM_ERROR_NOT_SUPPORT_API) {
945                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
946         } else if (ret != MM_ERROR_NONE) {
947                 MMRADIO_LOG_ERROR("failed to get radio hal signal strength");
948                 *value = 0;
949                 MMRADIO_LOG_FLEAVE();
950                 return ret;
951         }
952         *value = (int)strength;
953         MMRADIO_LOG_FLEAVE();
954         return MM_ERROR_NONE;
955 }
956
957 void __mmradio_scan_thread(mm_radio_t *radio)
958 {
959         int ret = MM_ERROR_NONE;
960         int prev_freq = 0;
961
962         MMRADIO_LOG_FENTER();
963         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
964
965         ret = radio_hal_mute(radio->hal_inf);
966
967         if (ret == MM_ERROR_NOT_SUPPORT_API) {
968                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
969         } else if (ret != MM_ERROR_NONE) {
970                 MMRADIO_LOG_ERROR("faied to set radio hal mute");
971                 goto FINISHED;
972         }
973         ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min);
974
975         if (ret != MM_ERROR_NONE)
976                 goto FINISHED;
977
978         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL);
979         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
980
981         while (!radio->stop_scan) {
982                 uint32_t freq = 0;
983                 MMMessageParamType param = { 0, };
984
985                 MMRADIO_LOG_DEBUG("scanning....");
986
987                 pthread_mutex_lock(&radio->seek_cancel_mutex);
988
989                 if (radio->stop_scan) {
990                         MMRADIO_LOG_INFO("scan was canceled");
991                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
992                         goto FINISHED;
993                 }
994
995                 ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP);
996
997                 pthread_mutex_unlock(&radio->seek_cancel_mutex);
998
999                 if (ret != MM_ERROR_NONE) {
1000                         MMRADIO_LOG_ERROR("radio scanning error");
1001                         break;
1002                 }
1003
1004                 /* now we can get new frequency from radio device */
1005                 if (radio->stop_scan)
1006                         break;
1007
1008                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
1009                 if (ret != MM_ERROR_NONE) {
1010                         MMRADIO_LOG_ERROR("failed to get current frequency");
1011                 } else {
1012                         if (freq <= prev_freq) {
1013                                 MMRADIO_LOG_ERROR("frequency is less than previous [%d] -> [%d] we wrapped around, we are finished scanning", prev_freq, freq);
1014                                 break;
1015                         }
1016
1017                         prev_freq = param.radio_scan.frequency = (int)freq;
1018                         MMRADIO_LOG_INFO("scanning : new frequency : [%d]", param.radio_scan.frequency);
1019
1020                         /* drop if max freq is scanned */
1021                         if (param.radio_scan.frequency >= radio->region_setting.band_max) {
1022                                 MMRADIO_LOG_WARNING("%d freq is dropping...and stopping scan", param.radio_scan.frequency);
1023                                 break;
1024                         }
1025
1026                         if (radio->stop_scan) {
1027                                 /* doesn't need to post */
1028                                 break;
1029                         }
1030
1031                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, &param);
1032                 }
1033         }
1034 FINISHED:
1035         if (radio->old_state == MM_RADIO_STATE_READY) {
1036                 MMRADIO_LOG_DEBUG("old state is ready");
1037         } else if (radio->old_state == MM_RADIO_STATE_PLAYING) {
1038                 MMRADIO_LOG_DEBUG("old state is playing");
1039                 ret = radio_hal_unmute(radio->hal_inf);
1040                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
1041                         MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
1042                 } else if (ret != MM_ERROR_NONE) {
1043                         MMRADIO_LOG_ERROR("failed to set radio hal unmute");
1044                         goto FINISHED_ERR;
1045                 }
1046                 ret = radio_hal_set_frequency(radio->hal_inf, prev_freq);
1047                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
1048                         MMRADIO_LOG_WARNING("radio_hal_set_frequency is not supported");
1049                 } else if (ret != MM_ERROR_NONE) {
1050                         MMRADIO_LOG_ERROR("failed to set radio hal frequency");
1051                         goto FINISHED_ERR;
1052                 }
1053         }
1054
1055 FINISHED_ERR:
1056
1057         if (radio->old_state == MM_RADIO_STATE_PLAYING) {
1058                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
1059         } else {
1060                 /* close radio device here !!!! */
1061                 ret = radio_hal_close(radio->hal_inf);
1062                 if (ret == MM_ERROR_NOT_SUPPORT_API)
1063                         MMRADIO_LOG_WARNING("radio_hal_close is not supported");
1064                 else if (ret != MM_ERROR_NONE)
1065                         MMRADIO_LOG_ERROR("failed to close radio hal");
1066
1067                 ret = radio_hal_unprepare(radio->hal_inf);
1068                 if (ret == MM_ERROR_NOT_SUPPORT_API)
1069                         MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
1070                 else if (ret != MM_ERROR_NONE)
1071                         MMRADIO_LOG_ERROR("failed to unprepare radio hal");
1072
1073                 radio->is_ready = FALSE;
1074
1075                 if (!radio->interrupted_by_resource_conflict && /* is being released */
1076                                 radio->radio_resource != NULL) {
1077                         ret = mm_resource_manager_mark_for_release(radio->resource_manager,
1078                                         radio->radio_resource);
1079                         radio->radio_resource = NULL;
1080                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
1081                                 MMRADIO_LOG_ERROR("failed to mark resource for release, ret(0x%x)", ret);
1082                 }
1083
1084                 ret = mm_resource_manager_commit(radio->resource_manager);
1085                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
1086                         MMRADIO_LOG_ERROR("resource manager commit fail");
1087
1088                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
1089         }
1090
1091         if (!radio->stop_scan)
1092                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL);
1093         else
1094                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL);
1095
1096         MMRADIO_LOG_FLEAVE();
1097
1098         radio->scan_thread = 0;
1099         pthread_exit(NULL);
1100 }
1101
1102 bool __is_tunable_frequency(mm_radio_t *radio, int freq)
1103 {
1104         MMRADIO_LOG_FENTER();
1105
1106         MMRADIO_CHECK_INSTANCE(radio);
1107
1108         if (freq >= radio->region_setting.band_max
1109                 || freq <= radio->region_setting.band_min)
1110                 return false;
1111
1112         MMRADIO_LOG_FLEAVE();
1113
1114         return true;
1115 }
1116
1117 void __mmradio_seek_thread(mm_radio_t *radio)
1118 {
1119         int ret = MM_ERROR_NONE;
1120         uint32_t freq = 0;
1121         MMMessageParamType param = {0, };
1122
1123         MMRADIO_LOG_FENTER();
1124         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1125
1126         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL);
1127
1128         MMRADIO_LOG_DEBUG("seeking....");
1129
1130         if (!radio->seek_cancel) {
1131
1132                 MMRADIO_LOG_DEBUG("try to seek ");
1133                 pthread_mutex_lock(&radio->seek_cancel_mutex);
1134                 MMRADIO_LOG_DEBUG("seek start");
1135
1136                 if (radio->seek_cancel) {
1137                         MMRADIO_LOG_INFO("seek was canceled so we return failure to application");
1138                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
1139                         goto SEEK_FAILED;
1140                 }
1141
1142                 ret = radio_hal_seek(radio->hal_inf, radio->seek_direction);
1143                 pthread_mutex_unlock(&radio->seek_cancel_mutex);
1144                 if (ret) {
1145                         MMRADIO_LOG_ERROR("failed to seek radio hal");
1146                         goto SEEK_FAILED;
1147                 }
1148
1149                 /* now we can get new frequency from radio device */
1150                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
1151                 if (ret) {
1152                         MMRADIO_LOG_ERROR("failed to get current frequency");
1153                         goto SEEK_FAILED;
1154                 }
1155
1156                 MMRADIO_LOG_DEBUG("found frequency");
1157
1158                 /* if same freq is found, ignore it and search next one. */
1159                 if (freq == radio->prev_seek_freq) {
1160                         MMRADIO_LOG_WARNING("It's same with previous found one. So, trying next one.");
1161                         goto SEEK_FAILED;
1162                 }
1163
1164                 /* check if it's limit freq or not */
1165                 if (__is_tunable_frequency(radio, freq)) {
1166                         /* now tune to new frequency */
1167                         ret = radio_hal_set_frequency(radio->hal_inf, freq);
1168                         if (ret) {
1169                                 MMRADIO_LOG_ERROR("failed to tune to new frequency");
1170                                 goto SEEK_FAILED;
1171                         }
1172                         radio->freq = (int)freq;
1173                         MMRADIO_LOG_WARNING("setting frequency : [%d]", radio->freq);
1174                 }
1175
1176                 if (radio->seek_unmute) {
1177                         /* now turn on radio
1178                          * In the case of limit freq, tuner should be unmuted.
1179                          * Otherwise, sound can't output even though application set new frequency.
1180                          */
1181                         ret = radio_hal_unmute(radio->hal_inf);
1182                         if (ret) {
1183                                 MMRADIO_LOG_ERROR("failed to set unmute radio hal");
1184                                 goto SEEK_FAILED;
1185                         }
1186                         radio->seek_unmute = FALSE;
1187                 }
1188
1189                 param.radio_scan.frequency = radio->prev_seek_freq = (int)freq;
1190                 MMRADIO_LOG_INFO("seeking : new frequency : [%d]", param.radio_scan.frequency);
1191                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1192         }
1193
1194         radio->seek_thread = 0;
1195         radio->is_seeking = FALSE;
1196
1197         MMRADIO_LOG_FLEAVE();
1198
1199         pthread_exit(NULL);
1200
1201 SEEK_FAILED:
1202         if (radio->seek_unmute) {
1203                 /* now turn on radio
1204                 * In the case of limit freq, tuner should be unmuted.
1205                 * Otherwise, sound can't output even though application set new frequency.
1206                 */
1207                 ret = radio_hal_unmute(radio->hal_inf);
1208                 if (ret)
1209                         MMRADIO_LOG_ERROR("failed to set unmute radio hal");
1210                 radio->seek_unmute = FALSE;
1211         }
1212         /* freq -1 means it's failed to seek */
1213         param.radio_scan.frequency = -1;
1214         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1215         radio->is_seeking = FALSE;
1216         radio->seek_thread = 0;
1217         pthread_exit(NULL);
1218 }
1219
1220 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param)
1221 {
1222         MMRADIO_CHECK_INSTANCE(radio);
1223
1224         MMRADIO_LOG_FENTER();
1225
1226         if (!radio->msg_cb) {
1227                 MMRADIO_LOG_WARNING("failed to post a message because msg cb didn't register");
1228                 return false;
1229         }
1230
1231         MMRADIO_LOG_DEBUG("address of msg_cb : %p", radio->msg_cb);
1232
1233         radio->msg_cb(msgtype, param, radio->msg_cb_param);
1234
1235         MMRADIO_LOG_FLEAVE();
1236
1237         return true;
1238 }
1239
1240 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command)
1241 {
1242         MMRadioStateType radio_state = MM_RADIO_STATE_NUM;
1243
1244         MMRADIO_LOG_FENTER();
1245
1246         MMRADIO_CHECK_INSTANCE(radio);
1247
1248         radio_state = __mmradio_get_state(radio);
1249
1250         MMRADIO_LOG_INFO("incomming command : %d  current state : %d", command, radio_state);
1251
1252         switch (command) {
1253         case MMRADIO_COMMAND_CREATE:
1254                 {
1255                         if (radio_state != 0)
1256                                 goto NO_OP;
1257                 }
1258                 break;
1259
1260         case MMRADIO_COMMAND_REALIZE:
1261                 {
1262                         if (radio_state == MM_RADIO_STATE_READY ||
1263                                 radio_state == MM_RADIO_STATE_PLAYING ||
1264                                 radio_state == MM_RADIO_STATE_SCANNING)
1265                                 goto NO_OP;
1266
1267                         if (radio_state == 0)
1268                                 goto INVALID_STATE;
1269                 }
1270                 break;
1271
1272         case MMRADIO_COMMAND_UNREALIZE:
1273                 {
1274                         if (radio_state == MM_RADIO_STATE_NULL)
1275                                 goto NO_OP;
1276
1277                         /* we can call unrealize at any higher state */
1278                 }
1279                 break;
1280
1281         case MMRADIO_COMMAND_START:
1282                 {
1283                         if (radio_state == MM_RADIO_STATE_PLAYING)
1284                                 goto NO_OP;
1285
1286                         if (radio_state != MM_RADIO_STATE_READY)
1287                                 goto INVALID_STATE;
1288                 }
1289                 break;
1290
1291         case MMRADIO_COMMAND_STOP:
1292                 {
1293                         if (radio_state == MM_RADIO_STATE_READY)
1294                                 goto NO_OP;
1295
1296                         if (radio_state != MM_RADIO_STATE_PLAYING)
1297                                 goto INVALID_STATE;
1298                 }
1299                 break;
1300
1301         case MMRADIO_COMMAND_START_SCAN:
1302                 {
1303                         if (radio_state == MM_RADIO_STATE_SCANNING)
1304                                 goto NO_OP;
1305
1306                         if (radio_state == MM_RADIO_STATE_NULL)
1307                                 goto INVALID_STATE;
1308                 }
1309                 break;
1310
1311         case MMRADIO_COMMAND_STOP_SCAN:
1312                 {
1313                         if (radio_state == MM_RADIO_STATE_READY)
1314                                 goto NO_OP;
1315
1316                         if (radio_state != MM_RADIO_STATE_SCANNING)
1317                                 goto INVALID_STATE;
1318                 }
1319                 break;
1320
1321         case MMRADIO_COMMAND_DESTROY:
1322         case MMRADIO_COMMAND_MUTE:
1323         case MMRADIO_COMMAND_UNMUTE:
1324         case MMRADIO_COMMAND_SET_FREQ:
1325         case MMRADIO_COMMAND_GET_FREQ:
1326         case MMRADIO_COMMAND_SET_REGION:
1327         case MMRADIO_COMMAND_SET_VOLUME:
1328         case MMRADIO_COMMAND_GET_VOLUME:
1329                 {
1330                         /* we can do it at any state */
1331                 }
1332                 break;
1333
1334         case MMRADIO_COMMAND_SEEK:
1335                 {
1336                         if (radio_state != MM_RADIO_STATE_PLAYING)
1337                                 goto INVALID_STATE;
1338                 }
1339                 break;
1340
1341         case MMRADIO_COMMAND_GET_REGION:
1342                 {
1343                         if (radio_state == MM_RADIO_STATE_NULL)
1344                                 goto INVALID_STATE;
1345                 }
1346                 break;
1347
1348         default:
1349                 MMRADIO_LOG_DEBUG("not handled in FSM. don't care it");
1350                 break;
1351         }
1352
1353         MMRADIO_LOG_DEBUG("status OK");
1354
1355         radio->cmd = command;
1356
1357         MMRADIO_LOG_FLEAVE();
1358
1359         return MM_ERROR_NONE;
1360
1361 INVALID_STATE:
1362         MMRADIO_LOG_WARNING("invalid state. current : %d  command : %d", radio_state, command);
1363         MMRADIO_LOG_FLEAVE();
1364         return MM_ERROR_RADIO_INVALID_STATE;
1365
1366 NO_OP:
1367         MMRADIO_LOG_WARNING("mm-radio is in the desired state(%d). doing noting", radio_state);
1368         MMRADIO_LOG_FLEAVE();
1369         return MM_ERROR_RADIO_NO_OP;
1370
1371 }
1372
1373 static bool __mmradio_set_state(mm_radio_t *radio, int new_state)
1374 {
1375         MMMessageParamType msg = { 0, };
1376         int msg_type = MM_MESSAGE_UNKNOWN;
1377
1378         MMRADIO_LOG_FENTER();
1379
1380         if (!radio) {
1381                 MMRADIO_LOG_WARNING("calling set_state with invalid radio handle");
1382                 return false;
1383         }
1384
1385         if (radio->current_state == new_state && radio->pending_state == 0) {
1386                 MMRADIO_LOG_WARNING("we are in same state");
1387                 return true;
1388         }
1389
1390         /* set state */
1391         radio->old_state = radio->current_state;
1392         radio->current_state = new_state;
1393
1394         /* fill message param */
1395         msg.union_type = MM_MSG_UNION_STATE;
1396         msg.state.previous = radio->old_state;
1397         msg.state.current = radio->current_state;
1398
1399 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1400         /* post message to application */
1401         if (radio->sound_focus.by_focus_cb) {
1402                 msg_type = MM_MESSAGE_STATE_INTERRUPTED;
1403                 msg.state.code = radio->sound_focus.event_src;
1404                 MMRADIO_POST_MSG(radio, msg_type, &msg);
1405         } else if (radio->interrupted_by_resource_conflict) {
1406                 msg_type = MM_MESSAGE_STATE_INTERRUPTED;
1407                 msg.state.code = MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT;
1408                 MMRADIO_POST_MSG(radio, msg_type, &msg);
1409         } else {
1410                 msg_type = MM_MESSAGE_STATE_CHANGED;
1411                 MMRADIO_POST_MSG(radio, msg_type, &msg);
1412         }
1413 #else
1414         if (radio->interrupted_by_resource_conflict) {
1415                  msg_type = MM_MESSAGE_STATE_INTERRUPTED;
1416                  msg.state.code = MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT;
1417                  MMRADIO_POST_MSG(radio, msg_type, &msg);
1418          } else {
1419                  msg_type = MM_MESSAGE_STATE_CHANGED;
1420                  MMRADIO_POST_MSG(radio, msg_type, &msg);
1421          }
1422
1423 #endif
1424
1425         MMRADIO_LOG_FLEAVE();
1426
1427         return true;
1428 }
1429
1430 static int __mmradio_get_state(mm_radio_t *radio)
1431 {
1432         MMRADIO_CHECK_INSTANCE(radio);
1433
1434         MMRADIO_LOG_INFO("radio state : current : [%d]   old : [%d]   pending : [%d]",
1435                 radio->current_state, radio->old_state, radio->pending_state);
1436
1437         return radio->current_state;
1438 }
1439
1440 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1441 static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
1442         mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
1443         const char *additional_info, void *user_data)
1444 {
1445         mm_radio_t *radio = (mm_radio_t *)user_data;
1446         enum MMMessageInterruptedCode event_source;
1447         int result = MM_ERROR_NONE;
1448         int postMsg = false;
1449
1450         MMRADIO_LOG_FENTER();
1451         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1452         MMRADIO_LOG_INFO("focus_state [%d]", focus_state);
1453
1454         mmradio_get_sound_focus_reason(focus_state, reason_for_change, FALSE, &event_source, &postMsg);
1455         radio->sound_focus.event_src = event_source;
1456
1457         switch (focus_state) {
1458         case FOCUS_IS_RELEASED:{
1459                         radio->sound_focus.cur_focus_type &= ~focus_type;
1460                         radio->sound_focus.by_focus_cb = true;
1461
1462                         MMRADIO_CMD_LOCK(radio);
1463                         result = _mmradio_stop(radio);
1464                         if (result)
1465                                 MMRADIO_LOG_ERROR("failed to stop radio");
1466                         MMRADIO_CMD_UNLOCK(radio);
1467
1468                         radio->sound_focus.by_focus_cb = false;
1469
1470                         MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d", radio->sound_focus.cur_focus_type);
1471                 }
1472                 break;
1473
1474         case FOCUS_IS_ACQUIRED:{
1475                         MMMessageParamType msg = { 0, };
1476                         msg.union_type = MM_MSG_UNION_CODE;
1477                         msg.code = event_source;
1478
1479                         radio->sound_focus.cur_focus_type |= focus_type;
1480
1481                         if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1482                                 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1483
1484                         MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d", radio->sound_focus.cur_focus_type);
1485                 }
1486                 break;
1487
1488         default:
1489                 MMRADIO_LOG_DEBUG("Unknown focus_state");
1490                 break;
1491         }
1492
1493         MMRADIO_LOG_FLEAVE();
1494 }
1495
1496 static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
1497         mm_sound_focus_state_e focus_state, const char *reason_for_change,
1498         const char *additional_info, void *user_data)
1499 {
1500         mm_radio_t *radio = (mm_radio_t *)user_data;
1501         enum MMMessageInterruptedCode event_source;
1502         int result = MM_ERROR_NONE;
1503         int postMsg = false;
1504
1505         MMRADIO_LOG_FENTER();
1506         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1507         MMRADIO_LOG_INFO("focus_state [%d]", focus_state);
1508
1509         mmradio_get_sound_focus_reason(focus_state, reason_for_change, TRUE, &event_source, &postMsg);
1510         radio->sound_focus.event_src = event_source;
1511
1512         switch (focus_state) {
1513         case FOCUS_IS_ACQUIRED: {
1514                         radio->sound_focus.cur_focus_type &= ~focus_type;
1515                         radio->sound_focus.by_focus_cb = true;
1516
1517                         MMRADIO_CMD_LOCK(radio);
1518                         result = _mmradio_stop(radio);
1519                         if (result)
1520                                 MMRADIO_LOG_ERROR("failed to stop radio");
1521                         MMRADIO_CMD_UNLOCK(radio);
1522
1523                         radio->sound_focus.by_focus_cb = false;
1524
1525                         MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1526                 }
1527                 break;
1528
1529         case FOCUS_IS_RELEASED: {
1530                         MMMessageParamType msg = { 0, };
1531                         msg.union_type = MM_MSG_UNION_CODE;
1532                         msg.code = event_source;
1533
1534                         radio->sound_focus.cur_focus_type |= focus_type;
1535
1536                         if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1537                                 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1538
1539                         MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d", radio->sound_focus.cur_focus_type);
1540                 }
1541                 break;
1542
1543         default:
1544                 MMRADIO_LOG_DEBUG("Unknown focus_state");
1545                 break;
1546         }
1547
1548         MMRADIO_LOG_FLEAVE();
1549 }
1550 #endif
1551
1552 static void __mmradio_volume_changed_cb(volume_type_t type, unsigned int volume, void *user_data)
1553 {
1554         mm_radio_t *radio = (mm_radio_t *)user_data;
1555         int ret = MM_ERROR_NONE;
1556         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1557         if (type == VOLUME_TYPE_MEDIA) {
1558                 MMRADIO_LOG_INFO("Change FM Radio volume to %d", volume);
1559                 ret = __mmradio_set_media_volume(radio, volume);
1560                 if (ret != MM_ERROR_NONE)
1561                         MMRADIO_LOG_ERROR("failed to set media volume");
1562                 return;
1563         }
1564 }
1565
1566 int _mmradio_get_region_type(mm_radio_t *radio, MMRadioRegionType *type)
1567 {
1568         MMRADIO_LOG_FENTER();
1569         MMRADIO_CHECK_INSTANCE(radio);
1570         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1571
1572         MMRADIO_RETURN_VAL_IF_FAIL(type, MM_ERROR_INVALID_ARGUMENT);
1573
1574         *type = radio->region_setting.country;
1575
1576         MMRADIO_LOG_FLEAVE();
1577         return MM_ERROR_NONE;
1578 }
1579
1580 int _mmradio_get_region_frequency_range(mm_radio_t *radio, unsigned int *min_freq, unsigned int *max_freq)
1581 {
1582         MMRADIO_LOG_FENTER();
1583         MMRADIO_CHECK_INSTANCE(radio);
1584         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1585
1586         MMRADIO_RETURN_VAL_IF_FAIL(min_freq && max_freq, MM_ERROR_INVALID_ARGUMENT);
1587
1588         *min_freq = radio->region_setting.band_min;
1589         *max_freq = radio->region_setting.band_max;
1590
1591         MMRADIO_LOG_FLEAVE();
1592         return MM_ERROR_NONE;
1593 }
1594
1595 int _mmradio_get_channel_spacing(mm_radio_t *radio, unsigned int *ch_spacing)
1596 {
1597         MMRADIO_LOG_FENTER();
1598         MMRADIO_CHECK_INSTANCE(radio);
1599         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1600
1601         MMRADIO_RETURN_VAL_IF_FAIL(ch_spacing, MM_ERROR_INVALID_ARGUMENT);
1602
1603         *ch_spacing = radio->region_setting.channel_spacing;
1604
1605         MMRADIO_LOG_FLEAVE();
1606         return MM_ERROR_NONE;
1607 }
1608
1609 int _mmradio_set_volume(mm_radio_t *radio, float volume)
1610 {
1611         int ret = MM_ERROR_NONE;
1612
1613         MMRADIO_LOG_FENTER();
1614
1615         MMRADIO_CHECK_INSTANCE(radio);
1616         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME);
1617
1618         MMRADIO_LOG_INFO("Setting %f volume", volume);
1619
1620         MMRADIO_VOLUME_LOCK(radio);
1621         radio->local_volume = volume;
1622         MMRADIO_VOLUME_UNLOCK(radio);
1623
1624         ret = radio_hal_set_volume(radio->hal_inf, volume);
1625         if (ret != MM_ERROR_NONE)
1626                 MMRADIO_LOG_ERROR("failed to set radio hal volume");
1627
1628         MMRADIO_LOG_FLEAVE();
1629
1630         return ret;
1631 }
1632
1633 int _mmradio_get_volume(mm_radio_t *radio, float *pVolume)
1634 {
1635         int ret = MM_ERROR_NONE;
1636         float volume = 0.0;
1637         MMRADIO_LOG_FENTER();
1638
1639         MMRADIO_CHECK_INSTANCE(radio);
1640         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_VOLUME);
1641
1642         MMRADIO_RETURN_VAL_IF_FAIL(pVolume, MM_ERROR_INVALID_ARGUMENT);
1643
1644         ret = radio_hal_get_volume(radio->hal_inf, &volume);
1645         if (ret != MM_ERROR_NONE) {
1646                 MMRADIO_LOG_ERROR("failed to get radio hal volume");
1647                 *pVolume = 0;
1648                 return ret;
1649         }
1650
1651         MMRADIO_VOLUME_LOCK(radio);
1652         radio->local_volume = volume;
1653         *pVolume = (float)radio->local_volume;
1654         MMRADIO_VOLUME_UNLOCK(radio);
1655
1656         MMRADIO_LOG_FLEAVE();
1657
1658         return ret;
1659 }
1660
1661 static int __mmradio_set_media_volume(mm_radio_t *radio, unsigned int level)
1662 {
1663         int ret = MM_ERROR_NONE;
1664
1665         MMRADIO_LOG_FENTER();
1666
1667         MMRADIO_CHECK_INSTANCE(radio);
1668         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME);
1669
1670         MMRADIO_LOG_INFO("Setting %d volume", level);
1671
1672         MMRADIO_VOLUME_LOCK(radio);
1673         radio->media_volume = level;
1674         MMRADIO_VOLUME_UNLOCK(radio);
1675
1676         ret = radio_hal_set_media_volume(radio->hal_inf, level);
1677         if (ret != MM_ERROR_NONE)
1678                 MMRADIO_LOG_ERROR("failed to set radio hal media volume");
1679
1680         MMRADIO_LOG_FLEAVE();
1681
1682         return ret;
1683 }
1684
1685 static int __resource_release_cb(mm_resource_manager_h rm,
1686         mm_resource_manager_res_h res, void *user_data)
1687 {
1688         mm_radio_t *radio = NULL;
1689
1690         MMRADIO_LOG_FENTER();
1691
1692         if (!user_data) {
1693                 MMRADIO_LOG_ERROR("user_data is null");
1694                 return FALSE;
1695         }
1696
1697         radio = (mm_radio_t *)user_data;
1698         radio->radio_resource = NULL;
1699
1700         MMRADIO_LOG_DEBUG("radio resource conflict so, resource will be freed by _mmradio_stop");
1701
1702         radio->interrupted_by_resource_conflict = TRUE;
1703
1704         MMRADIO_CMD_LOCK(radio);
1705         if (_mmradio_stop(radio) != MM_ERROR_NONE)
1706                 MMRADIO_LOG_ERROR("failed to stop radio");
1707         MMRADIO_CMD_UNLOCK(radio);
1708
1709         MMRADIO_LOG_FLEAVE();
1710
1711         return FALSE;
1712 }