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