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