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