Fixed deadlock and doesn't change state after scan_stop.
[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_total_volume(mm_radio_t *radio);
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         MMRADIO_VOLUME_LOCK(radio);
552         radio->media_volume = volume;
553         MMRADIO_VOLUME_UNLOCK(radio);
554
555         ret = __mmradio_set_total_volume(radio);
556         if (ret == MM_ERROR_NOT_SUPPORT_API) {
557                 MMRADIO_LOG_WARNING("radio_hal_set_volume is not supported");
558         } else if (ret) {
559                 MMRADIO_LOG_ERROR("failed to radio_hal_set_volume\n");
560                 goto error1;
561         }
562
563         ret = radio_hal_start(radio->hal_inf);
564         if (ret == MM_ERROR_NOT_SUPPORT_API) {
565                 MMRADIO_LOG_WARNING("radio_hal_start is not supported");
566         } else if (ret) {
567                 MMRADIO_LOG_ERROR("failed to radio_hal_start\n");
568                 goto error1;
569         }
570
571         /* set stored frequency */
572         ret = radio_hal_set_frequency(radio->hal_inf, radio->freq);
573         if (ret) {
574                 MMRADIO_LOG_ERROR("failed to radio_hal_set_frequency\n");
575                 goto error1;
576         }
577
578 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
579         ret = sound_manager_start_virtual_stream(radio->vstream);
580         if (ret) {
581                 MMRADIO_LOG_ERROR("failed to sound_manager_start_virtual_stream\n");
582                 goto error;
583         }
584 #endif
585
586         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
587
588         MMRADIO_LOG_FLEAVE();
589
590         return MM_ERROR_NONE;
591
592 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
593 error:
594         sound_manager_stop_virtual_stream(radio->vstream);
595 #endif
596 error1:
597         radio_hal_close(radio->hal_inf);
598 error2:
599         radio_hal_unprepare(radio->hal_inf);
600         radio->is_ready = FALSE;
601         return ret;
602 }
603
604 int _mmradio_stop(mm_radio_t *radio)
605 {
606         int ret = MM_ERROR_NONE;
607
608         MMRADIO_LOG_FENTER();
609
610         MMRADIO_CHECK_INSTANCE(radio);
611         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP);
612
613         radio->seek_unmute = FALSE;
614         /*cancel if any seek*/
615         _mmradio_seek_cancel(radio);
616 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
617         ret = sound_manager_stop_virtual_stream(radio->vstream);
618         if (ret != MM_ERROR_NONE) {
619                 MMRADIO_LOG_ERROR("failed to stop virtual_stream");
620                 return ret;
621         }
622 #endif
623
624         ret = radio_hal_stop(radio->hal_inf);
625         if (ret == MM_ERROR_NOT_SUPPORT_API) {
626                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
627         } else if (ret) {
628                 MMRADIO_LOG_ERROR("failed to radio_hal_stop\n");
629                 return ret;
630         }
631
632         /* close radio device here !!!! */
633         ret = radio_hal_close(radio->hal_inf);
634         if (ret == MM_ERROR_NOT_SUPPORT_API) {
635                 MMRADIO_LOG_WARNING("radio_hal_close is not supported");
636         } else if (ret != MM_ERROR_NONE) {
637                 MMRADIO_LOG_ERROR("radio_hal_close_device error");
638                 return ret;
639         }
640
641         ret = radio_hal_unprepare(radio->hal_inf);
642         if (ret == MM_ERROR_NOT_SUPPORT_API) {
643                 MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
644         } else if (ret != MM_ERROR_NONE) {
645                 MMRADIO_LOG_ERROR("radio_hal_close_device error");
646                 return ret;
647         }
648
649         radio->is_ready = FALSE;
650
651 #ifdef TIZEN_FEATURE_SOUND_FOCUS
652         if (radio->sound_focus.handle > 0) {
653                 ret = mmradio_release_sound_focus(&radio->sound_focus);
654                 if (ret) {
655                         MMRADIO_LOG_ERROR("mmradio_release_audio_focus is failed\n");
656                         return ret;
657                 }
658         }
659 #endif
660         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
661
662         MMRADIO_LOG_FLEAVE();
663
664         return MM_ERROR_NONE;
665 }
666
667 int _mmradio_seek(mm_radio_t *radio, MMRadioSeekDirectionType direction)
668 {
669         int ret = MM_ERROR_NONE;
670
671         MMRADIO_LOG_FENTER();
672
673         MMRADIO_CHECK_INSTANCE(radio);
674         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SEEK);
675
676         if (radio->is_seeking) {
677                 MMRADIO_LOG_ERROR("[RADIO_ERROR_INVALID_OPERATION]radio is seeking, can't serve another request try again");
678                 return MM_ERROR_RADIO_INTERNAL;
679         }
680
681         radio->seek_unmute = FALSE;
682         radio->is_seeking = TRUE;
683         radio->seek_cancel = FALSE;
684
685         if (!radio->is_muted) {
686                 ret = radio_hal_mute(radio->hal_inf);
687                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
688                         MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
689                 } else if (ret) {
690                         MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
691                         return ret;
692                 }
693                 radio->seek_unmute = TRUE;
694         }
695
696         MMRADIO_LOG_DEBUG("trying to seek. direction[0:UP/1:DOWN) %d\n", direction);
697         radio->seek_direction = direction;
698
699         ret = pthread_create(&radio->seek_thread, NULL, (void *)__mmradio_seek_thread, (void *)radio);
700
701         if (ret) {
702                 MMRADIO_LOG_DEBUG("failed create thread\n");
703                 radio->is_seeking = FALSE;
704                 radio->seek_cancel = TRUE;
705                 if (radio->seek_unmute) {
706                         ret = radio_hal_mute(radio->hal_inf);
707                         if (ret == MM_ERROR_NOT_SUPPORT_API) {
708                                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
709                         } else if (ret) {
710                                 MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
711                                 radio->seek_unmute = FALSE;
712                                 return ret;
713                         }
714                 }
715                 return MM_ERROR_RADIO_INTERNAL;
716         }
717
718         MMRADIO_LOG_FLEAVE();
719
720         return MM_ERROR_NONE;
721 }
722
723 void _mmradio_seek_cancel(mm_radio_t *radio)
724 {
725         int ret = MM_ERROR_NONE;
726         char str_error[READ_MAX_BUFFER_SIZE];
727         MMRADIO_LOG_FENTER();
728
729         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
730
731         /*cancel any outstanding seek request*/
732         radio->seek_cancel = TRUE;
733         if (radio->seek_thread) {
734                 ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
735                 MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
736                 if (ret == EBUSY) { /* it was already locked by other */
737                         MMRADIO_LOG_DEBUG("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
738                 } else if (ret == 0) {
739                         MMRADIO_LOG_DEBUG("trylock is successful. unlock now");
740                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
741                 } else {
742                         MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
743                 }
744                 MMRADIO_LOG_DEBUG("pthread_join seek_thread");
745                 pthread_join(radio->seek_thread, NULL);
746                 MMRADIO_LOG_DEBUG("done");
747                 radio->is_seeking = FALSE;
748                 radio->seek_thread = 0;
749         }
750         MMRADIO_LOG_FLEAVE();
751 }
752
753
754 int _mmradio_start_scan(mm_radio_t *radio)
755 {
756         int ret = MM_ERROR_NONE;
757
758         MMRADIO_LOG_FENTER();
759
760         MMRADIO_CHECK_INSTANCE(radio);
761         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START_SCAN);
762
763         int scan_tr_id = 0;
764
765         radio->stop_scan = false;
766
767         if (!radio->is_ready) {
768                 ret = radio_hal_prepare(radio->hal_inf);
769                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
770                         MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
771                 } else if (ret != MM_ERROR_NONE) {
772                         MMRADIO_LOG_ERROR("radio_hal_prepare_device error");
773                         return ret;
774                 }
775
776                 ret = radio_hal_open(radio->hal_inf);
777                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
778                         MMRADIO_LOG_WARNING("radio_hal_open is not supported");
779                 } else if (ret != MM_ERROR_NONE) {
780                         MMRADIO_LOG_ERROR("radio_hal_init error");
781                         MMRADIO_LOG_FLEAVE();
782                         return ret;
783                 }
784                 radio->is_ready = TRUE;
785         } else {
786                 MMRADIO_LOG_DEBUG("radio prepared and opened");
787         }
788
789         scan_tr_id = pthread_create(&radio->scan_thread, NULL, (void *)__mmradio_scan_thread, (void *)radio);
790
791         if (scan_tr_id != 0) {
792                 MMRADIO_LOG_DEBUG("failed to create thread : scan\n");
793                 return MM_ERROR_RADIO_NOT_INITIALIZED;
794         }
795
796         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
797
798         MMRADIO_LOG_FLEAVE();
799
800         return MM_ERROR_NONE;
801 }
802
803 int _mmradio_stop_scan(mm_radio_t *radio)
804 {
805         int ret = 0;
806         char str_error[READ_MAX_BUFFER_SIZE];
807         MMRADIO_LOG_FENTER();
808
809         MMRADIO_CHECK_INSTANCE(radio);
810         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP_SCAN);
811
812         radio->stop_scan = true;
813
814         if (radio->scan_thread > 0) {
815                 /* make sure all the search is stopped else we'll wait till search finish which is not ideal*/
816                 ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
817                 MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
818                 if (ret == EBUSY) { /* it was already locked by other */
819                         MMRADIO_LOG_DEBUG("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
820                 } else if (ret == 0) {
821                         MMRADIO_LOG_DEBUG("trylock is successful. unlock now");
822                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
823                 } else {
824                         MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
825                 }
826                 MMRADIO_LOG_DEBUG("pthread_join scan_thread");
827                 pthread_join(radio->scan_thread, NULL);
828                 radio->scan_thread = 0;
829         }
830
831         MMRADIO_LOG_FLEAVE();
832
833         return MM_ERROR_NONE;
834 }
835
836 int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value)
837 {
838         int ret = MM_ERROR_NONE;
839         uint32_t strength = 0;
840         MMRADIO_LOG_FENTER();
841         MMRADIO_CHECK_INSTANCE(radio);
842
843         return_val_if_fail(value, MM_ERROR_INVALID_ARGUMENT);
844
845         /* just return stored frequency if radio device is not ready */
846         ret = radio_hal_get_signal_strength(radio->hal_inf, &strength);
847         if (ret == MM_ERROR_NOT_SUPPORT_API) {
848                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
849         } else if (ret != MM_ERROR_NONE) {
850                 debug_error("radio_hal_get_signal_strength error\n");
851                 *value = 0;
852                 MMRADIO_LOG_FLEAVE();
853                 return ret;
854         }
855         *value = (int)strength;
856         MMRADIO_LOG_FLEAVE();
857         return MM_ERROR_NONE;
858 }
859
860 void __mmradio_scan_thread(mm_radio_t *radio)
861 {
862         int ret = MM_ERROR_NONE;
863         int prev_freq = 0;
864
865         MMRADIO_LOG_FENTER();
866         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
867
868         ret = radio_hal_mute(radio->hal_inf);
869
870         if (ret == MM_ERROR_NOT_SUPPORT_API) {
871                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
872         } else if (ret != MM_ERROR_NONE) {
873                 MMRADIO_LOG_ERROR("radio_hal_mute error");
874                 goto FINISHED;
875         }
876         ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min);
877
878         if (ret != MM_ERROR_NONE)
879                 goto FINISHED;
880
881         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL);
882         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
883
884         while (!radio->stop_scan) {
885                 uint32_t freq = 0;
886                 MMMessageParamType param = { 0, };
887
888                 MMRADIO_LOG_DEBUG("scanning....\n");
889
890                 pthread_mutex_lock(&radio->seek_cancel_mutex);
891
892                 if (radio->stop_scan) {
893                         MMRADIO_LOG_DEBUG("scan was canceled");
894                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
895                         goto FINISHED;
896                 }
897
898                 ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP);
899
900                 pthread_mutex_unlock(&radio->seek_cancel_mutex);
901
902                 if (ret != MM_ERROR_NONE) {
903                         MMRADIO_LOG_ERROR("radio scanning error");
904                         break;
905                 }
906
907                 /* now we can get new frequency from radio device */
908                 if (radio->stop_scan)
909                         break;
910
911                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
912                 if (ret != MM_ERROR_NONE) {
913                         MMRADIO_LOG_ERROR("failed to get current frequency\n");
914                 } else {
915                         if (freq < prev_freq) {
916                                 MMRADIO_LOG_DEBUG("scanning wrapped around. stopping scan\n");
917                                 break;
918                         }
919
920                         if (freq == prev_freq)
921                                 continue;
922
923                         prev_freq = param.radio_scan.frequency = (int)freq;
924                         MMRADIO_LOG_DEBUG("scanning : new frequency : [%d]\n", param.radio_scan.frequency);
925
926                         /* drop if max freq is scanned */
927                         if (param.radio_scan.frequency == radio->region_setting.band_max) {
928                                 MMRADIO_LOG_DEBUG("%d freq is dropping...and stopping scan\n", param.radio_scan.frequency);
929                                 break;
930                         }
931
932                         if (radio->stop_scan) {
933                                 /* doesn't need to post */
934                                 break;
935                         }
936
937                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, &param);
938                 }
939         }
940 FINISHED:
941         if (radio->old_state == MM_RADIO_STATE_READY) {
942                 MMRADIO_LOG_DEBUG("old state is ready");
943         } else if (radio->old_state == MM_RADIO_STATE_PLAYING) {
944                 MMRADIO_LOG_DEBUG("old state is playing");
945                 ret = radio_hal_unmute(radio->hal_inf);
946                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
947                         MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
948                 } else if (ret != MM_ERROR_NONE) {
949                         MMRADIO_LOG_ERROR("radio_hal_unmute error");
950                         goto FINISHED_ERR;
951                 }
952                 ret = radio_hal_set_frequency(radio->hal_inf, prev_freq);
953                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
954                         MMRADIO_LOG_WARNING("radio_hal_set_frequency is not supported");
955                 } else if (ret != MM_ERROR_NONE) {
956                         MMRADIO_LOG_ERROR("radio_hal_set_frequency error");
957                         goto FINISHED_ERR;
958                 }
959         }
960
961 FINISHED_ERR:
962
963         radio->scan_thread = 0;
964
965         if (radio->old_state == MM_RADIO_STATE_PLAYING) {
966                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
967         } else {
968                 /* close radio device here !!!! */
969                 ret = radio_hal_close(radio->hal_inf);
970                 if (ret == MM_ERROR_NOT_SUPPORT_API)
971                         MMRADIO_LOG_WARNING("radio_hal_close is not supported");
972                 else if (ret != MM_ERROR_NONE)
973                         MMRADIO_LOG_ERROR("radio_hal_close_device error");
974
975                 ret = radio_hal_unprepare(radio->hal_inf);
976                 if (ret == MM_ERROR_NOT_SUPPORT_API)
977                         MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
978                 else if (ret != MM_ERROR_NONE)
979                         MMRADIO_LOG_ERROR("radio_hal_close_device error");
980
981                 radio->is_ready = FALSE;
982
983                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
984         }
985
986         if (!radio->stop_scan)
987                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL);
988         else
989                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL);
990
991         MMRADIO_LOG_FLEAVE();
992
993         pthread_exit(NULL);
994
995         return;
996 }
997
998 bool __is_tunable_frequency(mm_radio_t *radio, int freq)
999 {
1000         MMRADIO_LOG_FENTER();
1001
1002         MMRADIO_CHECK_INSTANCE(radio);
1003
1004         if (freq >= radio->region_setting.band_max
1005                 || freq <= radio->region_setting.band_min)
1006                 return false;
1007
1008         MMRADIO_LOG_FLEAVE();
1009
1010         return true;
1011 }
1012
1013 void __mmradio_seek_thread(mm_radio_t *radio)
1014 {
1015         int ret = MM_ERROR_NONE;
1016         uint32_t freq = 0;
1017         MMMessageParamType param = {0, };
1018
1019         MMRADIO_LOG_FENTER();
1020         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1021
1022         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL);
1023
1024         MMRADIO_LOG_DEBUG("seeking....\n");
1025
1026         if (!radio->seek_cancel) {
1027
1028                 MMRADIO_LOG_DEBUG("try to seek ");
1029                 pthread_mutex_lock(&radio->seek_cancel_mutex);
1030                 MMRADIO_LOG_DEBUG("seek start\n");
1031
1032                 if (radio->seek_cancel) {
1033                         MMRADIO_LOG_DEBUG("seek was canceled so we return failure to application");
1034                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
1035                         goto SEEK_FAILED;
1036                 }
1037
1038                 ret = radio_hal_seek(radio->hal_inf, radio->seek_direction);
1039                 pthread_mutex_unlock(&radio->seek_cancel_mutex);
1040                 if (ret) {
1041                         MMRADIO_LOG_ERROR("radio_hal_seek failed\n");
1042                         goto SEEK_FAILED;
1043                 }
1044
1045                 /* now we can get new frequency from radio device */
1046                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
1047                 if (ret) {
1048                         MMRADIO_LOG_ERROR("failed to get current frequency\n");
1049                         goto SEEK_FAILED;
1050                 }
1051
1052                 MMRADIO_LOG_DEBUG("found frequency\n");
1053
1054                 /* if same freq is found, ignore it and search next one. */
1055                 if (freq == radio->prev_seek_freq) {
1056                         MMRADIO_LOG_DEBUG("It's same with previous found one. So, trying next one. \n");
1057                         goto SEEK_FAILED;
1058                 }
1059
1060                 /* check if it's limit freq or not */
1061                 if (__is_tunable_frequency(radio, freq)) {
1062                         /* now tune to new frequency */
1063                         ret = radio_hal_set_frequency(radio->hal_inf, freq);
1064                         if (ret) {
1065                                 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1066                                 goto SEEK_FAILED;
1067                         }
1068                 }
1069
1070                 if (radio->seek_unmute) {
1071                         /* now turn on radio
1072                          * In the case of limit freq, tuner should be unmuted.
1073                          * Otherwise, sound can't output even though application set new frequency.
1074                          */
1075                         ret = radio_hal_unmute(radio->hal_inf);
1076                         if (ret) {
1077                                 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1078                                 goto SEEK_FAILED;
1079                         }
1080                         radio->seek_unmute = FALSE;
1081                 }
1082
1083                 param.radio_scan.frequency = radio->prev_seek_freq = (int)freq;
1084                 MMRADIO_LOG_DEBUG("seeking : new frequency : [%d]\n", param.radio_scan.frequency);
1085                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1086         }
1087
1088         radio->seek_thread = 0;
1089         radio->is_seeking = FALSE;
1090
1091         MMRADIO_LOG_FLEAVE();
1092
1093         pthread_exit(NULL);
1094         return;
1095
1096 SEEK_FAILED:
1097
1098         if (radio->seek_unmute) {
1099                 /* now turn on radio
1100                 * In the case of limit freq, tuner should be unmuted.
1101                 * Otherwise, sound can't output even though application set new frequency.
1102                 */
1103                 ret = radio_hal_unmute(radio->hal_inf);
1104                 if (ret)
1105                         MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1106                 radio->seek_unmute = FALSE;
1107         }
1108         /* freq -1 means it's failed to seek */
1109         param.radio_scan.frequency = -1;
1110         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1111         radio->is_seeking = FALSE;
1112         pthread_exit(NULL);
1113         return;
1114 }
1115
1116 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param)
1117 {
1118         MMRADIO_CHECK_INSTANCE(radio);
1119
1120         MMRADIO_LOG_FENTER();
1121
1122         if (!radio->msg_cb) {
1123                 debug_warning("failed to post a message\n");
1124                 return false;
1125         }
1126
1127         MMRADIO_LOG_DEBUG("address of msg_cb : %p\n", radio->msg_cb);
1128
1129         radio->msg_cb(msgtype, param, radio->msg_cb_param);
1130
1131         MMRADIO_LOG_FLEAVE();
1132
1133         return true;
1134 }
1135
1136 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command)
1137 {
1138         MMRadioStateType radio_state = MM_RADIO_STATE_NUM;
1139
1140         MMRADIO_LOG_FENTER();
1141
1142         MMRADIO_CHECK_INSTANCE(radio);
1143
1144         radio_state = __mmradio_get_state(radio);
1145
1146         MMRADIO_LOG_DEBUG("incomming command : %d  current state : %d\n", command, radio_state);
1147
1148         switch (command) {
1149         case MMRADIO_COMMAND_CREATE:
1150                 {
1151                         if (radio_state != 0)
1152                                 goto NO_OP;
1153                 }
1154                 break;
1155
1156         case MMRADIO_COMMAND_REALIZE:
1157                 {
1158                         if (radio_state == MM_RADIO_STATE_READY ||
1159                                 radio_state == MM_RADIO_STATE_PLAYING ||
1160                                 radio_state == MM_RADIO_STATE_SCANNING)
1161                                 goto NO_OP;
1162
1163                         if (radio_state == 0)
1164                                 goto INVALID_STATE;
1165                 }
1166                 break;
1167
1168         case MMRADIO_COMMAND_UNREALIZE:
1169                 {
1170                         if (radio_state == MM_RADIO_STATE_NULL)
1171                                 goto NO_OP;
1172
1173                         /* we can call unrealize at any higher state */
1174                 }
1175                 break;
1176
1177         case MMRADIO_COMMAND_START:
1178                 {
1179                         if (radio_state == MM_RADIO_STATE_PLAYING)
1180                                 goto NO_OP;
1181
1182                         if (radio_state != MM_RADIO_STATE_READY)
1183                                 goto INVALID_STATE;
1184                 }
1185                 break;
1186
1187         case MMRADIO_COMMAND_STOP:
1188                 {
1189                         if (radio_state == MM_RADIO_STATE_READY)
1190                                 goto NO_OP;
1191
1192                         if (radio_state != MM_RADIO_STATE_PLAYING)
1193                                 goto INVALID_STATE;
1194                 }
1195                 break;
1196
1197         case MMRADIO_COMMAND_START_SCAN:
1198                 {
1199                         if (radio_state == MM_RADIO_STATE_SCANNING)
1200                                 goto NO_OP;
1201
1202                         if (radio_state == MM_RADIO_STATE_NULL)
1203                                 goto INVALID_STATE;
1204                 }
1205                 break;
1206
1207         case MMRADIO_COMMAND_STOP_SCAN:
1208                 {
1209                         if (radio_state == MM_RADIO_STATE_READY)
1210                                 goto NO_OP;
1211
1212                         if (radio_state != MM_RADIO_STATE_SCANNING)
1213                                 goto INVALID_STATE;
1214                 }
1215                 break;
1216
1217         case MMRADIO_COMMAND_DESTROY:
1218         case MMRADIO_COMMAND_MUTE:
1219         case MMRADIO_COMMAND_UNMUTE:
1220         case MMRADIO_COMMAND_SET_FREQ:
1221         case MMRADIO_COMMAND_GET_FREQ:
1222         case MMRADIO_COMMAND_SET_REGION:
1223         case MMRADIO_COMMAND_SET_VOLUME:
1224         case MMRADIO_COMMAND_GET_VOLUME:
1225                 {
1226                         /* we can do it at any state */
1227                 }
1228                 break;
1229
1230         case MMRADIO_COMMAND_SEEK:
1231                 {
1232                         if (radio_state != MM_RADIO_STATE_PLAYING)
1233                                 goto INVALID_STATE;
1234                 }
1235                 break;
1236
1237         case MMRADIO_COMMAND_GET_REGION:
1238                 {
1239                         if (radio_state == MM_RADIO_STATE_NULL)
1240                                 goto INVALID_STATE;
1241                 }
1242                 break;
1243
1244         default:
1245                 MMRADIO_LOG_DEBUG("not handled in FSM. don't care it\n");
1246                 break;
1247         }
1248
1249         MMRADIO_LOG_DEBUG("status OK\n");
1250
1251         radio->cmd = command;
1252
1253         MMRADIO_LOG_FLEAVE();
1254
1255         return MM_ERROR_NONE;
1256
1257  INVALID_STATE:
1258         debug_warning("invalid state. current : %d  command : %d\n", radio_state, command);
1259         MMRADIO_LOG_FLEAVE();
1260         return MM_ERROR_RADIO_INVALID_STATE;
1261
1262  NO_OP:
1263         debug_warning("mm-radio is in the desired state(%d). doing noting\n", radio_state);
1264         MMRADIO_LOG_FLEAVE();
1265         return MM_ERROR_RADIO_NO_OP;
1266
1267 }
1268
1269 static bool __mmradio_set_state(mm_radio_t *radio, int new_state)
1270 {
1271         MMMessageParamType msg = { 0, };
1272         int msg_type = MM_MESSAGE_UNKNOWN;
1273
1274         MMRADIO_LOG_FENTER();
1275         MMRADIO_CHECK_INSTANCE(radio);
1276
1277         if (!radio) {
1278                 debug_warning("calling set_state with invalid radio handle\n");
1279                 return false;
1280         }
1281
1282         if (radio->current_state == new_state && radio->pending_state == 0) {
1283                 debug_warning("we are in same state\n");
1284                 return true;
1285         }
1286
1287         /* set state */
1288         radio->old_state = radio->current_state;
1289         radio->current_state = new_state;
1290
1291         /* fill message param */
1292         msg.state.previous = radio->old_state;
1293         msg.state.current = radio->current_state;
1294
1295 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1296         /* post message to application */
1297         switch (radio->sound_focus.by_focus_cb) {
1298         case MMRADIO_FOCUS_CB_NONE:
1299                 {
1300                         msg_type = MM_MESSAGE_STATE_CHANGED;
1301                         MMRADIO_POST_MSG(radio, msg_type, &msg);
1302                 }
1303                 break;
1304
1305         case MMRADIO_FOCUS_CB_POSTMSG:
1306                 {
1307                         msg_type = MM_MESSAGE_STATE_INTERRUPTED;
1308                         msg.union_type = MM_MSG_UNION_CODE;
1309                         msg.code = radio->sound_focus.event_src;
1310                         MMRADIO_POST_MSG(radio, msg_type, &msg);
1311                 }
1312                 break;
1313
1314         case MMRADIO_FOCUS_CB_SKIP_POSTMSG:
1315         default:
1316                 break;
1317         }
1318 #else
1319         msg_type = MM_MESSAGE_STATE_CHANGED;
1320         MMRADIO_POST_MSG(radio, msg_type, &msg);
1321 #endif
1322
1323         MMRADIO_LOG_FLEAVE();
1324
1325         return true;
1326 }
1327
1328 static int __mmradio_get_state(mm_radio_t *radio)
1329 {
1330         MMRADIO_CHECK_INSTANCE(radio);
1331
1332         MMRADIO_LOG_DEBUG("radio state : current : [%d]   old : [%d]   pending : [%d]\n",
1333                 radio->current_state, radio->old_state, radio->pending_state);
1334
1335         return radio->current_state;
1336 }
1337
1338 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1339 static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
1340         mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
1341         const char *additional_info, void *user_data)
1342 {
1343         mm_radio_t *radio = (mm_radio_t *)user_data;
1344         enum MMMessageInterruptedCode event_source;
1345         int result = MM_ERROR_NONE;
1346         int postMsg = false;
1347
1348         MMRADIO_LOG_FENTER();
1349         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1350
1351         mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
1352         radio->sound_focus.event_src = event_source;
1353
1354         switch (focus_state) {
1355         case FOCUS_IS_RELEASED:{
1356                         radio->sound_focus.cur_focus_type &= ~focus_type;
1357                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
1358
1359                         result = _mmradio_stop(radio);
1360                         if (result)
1361                                 MMRADIO_LOG_ERROR("failed to stop radio\n");
1362
1363                         MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1364                 }
1365                 break;
1366
1367         case FOCUS_IS_ACQUIRED:{
1368                         MMMessageParamType msg = { 0, };
1369                         msg.union_type = MM_MSG_UNION_CODE;
1370                         msg.code = event_source;
1371
1372                         radio->sound_focus.cur_focus_type |= focus_type;
1373
1374                         if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1375                                 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1376
1377                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
1378
1379                         MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1380                 }
1381                 break;
1382
1383         default:
1384                 MMRADIO_LOG_DEBUG("Unknown focus_state\n");
1385                 break;
1386         }
1387
1388         MMRADIO_LOG_FLEAVE();
1389 }
1390
1391 static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
1392         mm_sound_focus_state_e focus_state, const char *reason_for_change,
1393         const char *additional_info, void *user_data)
1394 {
1395         mm_radio_t *radio = (mm_radio_t *)user_data;
1396         enum MMMessageInterruptedCode event_source;
1397         int result = MM_ERROR_NONE;
1398         int postMsg = false;
1399
1400         MMRADIO_LOG_FENTER();
1401         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1402
1403         mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
1404         radio->sound_focus.event_src = event_source;
1405
1406         switch (focus_state) {
1407         case FOCUS_IS_ACQUIRED: {
1408                         radio->sound_focus.cur_focus_type &= ~focus_type;
1409                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
1410
1411                         result = _mmradio_stop(radio);
1412                         if (result)
1413                                 MMRADIO_LOG_ERROR("failed to stop radio\n");
1414
1415                         MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1416                 }
1417                 break;
1418
1419         case FOCUS_IS_RELEASED: {
1420                         MMMessageParamType msg = { 0, };
1421                         msg.union_type = MM_MSG_UNION_CODE;
1422                         msg.code = event_source;
1423
1424                         radio->sound_focus.cur_focus_type |= focus_type;
1425
1426                         if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1427                                 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1428
1429                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
1430
1431                         MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1432                 }
1433                 break;
1434
1435         default:
1436                 MMRADIO_LOG_DEBUG("Unknown focus_state\n");
1437                 break;
1438         }
1439
1440         MMRADIO_LOG_FLEAVE();
1441 }
1442 #endif
1443
1444 static int __mmradio_set_total_volume(mm_radio_t *radio)
1445 {
1446         int ret = MM_ERROR_NONE;
1447         float total_volume = 0.0f;
1448
1449         MMRADIO_CHECK_INSTANCE(radio);
1450
1451         MMRADIO_VOLUME_LOCK(radio);
1452         if (radio->max_media_volume != 0)
1453                 total_volume = ((float)radio->media_volume / (float)radio->max_media_volume) * radio->local_volume;
1454         else
1455                 MMRADIO_LOG_WARNING("max media voulme is zero");
1456
1457         ret = radio_hal_set_volume(radio->hal_inf, total_volume);
1458         if (ret != MM_ERROR_NONE)
1459                 MMRADIO_LOG_ERROR("radio_hal_set_volume error");
1460
1461         MMRADIO_VOLUME_UNLOCK(radio);
1462         return ret;
1463
1464 }
1465
1466 static void __mmradio_volume_changed_cb(volume_type_t type, unsigned int volume, void *user_data)
1467 {
1468         mm_radio_t *radio = (mm_radio_t *)user_data;
1469         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1470         if (type == VOLUME_TYPE_MEDIA) {
1471                 MMRADIO_LOG_DEBUG("Change FM Radio volume to %d", volume);
1472                 MMRADIO_VOLUME_LOCK(radio);
1473                 radio->media_volume = volume;
1474                 MMRADIO_VOLUME_UNLOCK(radio);
1475                 __mmradio_set_total_volume(radio);
1476         }
1477 }
1478
1479 int _mmradio_get_region_type(mm_radio_t *radio, MMRadioRegionType *type)
1480 {
1481         MMRADIO_LOG_FENTER();
1482         MMRADIO_CHECK_INSTANCE(radio);
1483         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1484
1485         return_val_if_fail(type, MM_ERROR_INVALID_ARGUMENT);
1486
1487         *type = radio->region_setting.country;
1488
1489         MMRADIO_LOG_FLEAVE();
1490         return MM_ERROR_NONE;
1491 }
1492
1493 int _mmradio_get_region_frequency_range(mm_radio_t *radio, unsigned int *min_freq, unsigned int *max_freq)
1494 {
1495         MMRADIO_LOG_FENTER();
1496         MMRADIO_CHECK_INSTANCE(radio);
1497         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1498
1499         return_val_if_fail(min_freq && max_freq, MM_ERROR_INVALID_ARGUMENT);
1500
1501         *min_freq = radio->region_setting.band_min;
1502         *max_freq = radio->region_setting.band_max;
1503
1504         MMRADIO_LOG_FLEAVE();
1505         return MM_ERROR_NONE;
1506 }
1507
1508 int _mmradio_get_channel_spacing(mm_radio_t *radio, unsigned int *ch_spacing)
1509 {
1510         MMRADIO_LOG_FENTER();
1511         MMRADIO_CHECK_INSTANCE(radio);
1512         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1513
1514         return_val_if_fail(ch_spacing, MM_ERROR_INVALID_ARGUMENT);
1515
1516         *ch_spacing = radio->region_setting.channel_spacing;
1517
1518         MMRADIO_LOG_FLEAVE();
1519         return MM_ERROR_NONE;
1520 }
1521
1522 int _mmradio_set_volume(mm_radio_t *radio, float volume)
1523 {
1524         int ret = MM_ERROR_NONE;
1525
1526         MMRADIO_LOG_FENTER();
1527
1528         MMRADIO_CHECK_INSTANCE(radio);
1529         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME);
1530
1531         MMRADIO_LOG_DEBUG("Setting %f volume\n", volume);
1532
1533         MMRADIO_VOLUME_LOCK(radio);
1534         radio->local_volume = volume;
1535         MMRADIO_VOLUME_UNLOCK(radio);
1536
1537         ret = __mmradio_set_total_volume(radio);
1538
1539         MMRADIO_LOG_FLEAVE();
1540         return ret;
1541
1542 }
1543
1544 int _mmradio_get_volume(mm_radio_t *radio, float *pVolume)
1545 {
1546         int ret = MM_ERROR_NONE;
1547         float total_volume = 0.0;
1548         float volume = 0.0;
1549         MMRADIO_LOG_FENTER();
1550
1551         MMRADIO_CHECK_INSTANCE(radio);
1552         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_VOLUME);
1553
1554         return_val_if_fail(pVolume, MM_ERROR_INVALID_ARGUMENT);
1555
1556         ret = radio_hal_get_volume(radio->hal_inf, &total_volume);
1557         if (ret != MM_ERROR_NONE) {
1558                 MMRADIO_LOG_ERROR("radio_hal_get_volume error");
1559                 *pVolume = 0;
1560                 return ret;
1561         }
1562
1563         MMRADIO_VOLUME_LOCK(radio);
1564
1565         if (radio->media_volume)
1566                 volume = total_volume * ((float)radio->max_media_volume / (float)radio->media_volume);
1567
1568         MMRADIO_LOG_DEBUG("total_volume = %f, max_media_volue = %d, media_volume = %d, volume = %f",
1569                 total_volume, radio->max_media_volume, radio->media_volume, volume);
1570
1571         /* update volume in handle */
1572         if (fabs(radio->local_volume - volume) >= FLT_EPSILON) {
1573                 radio->local_volume = volume;
1574         }
1575
1576         *pVolume = (float)radio->local_volume;
1577         MMRADIO_VOLUME_UNLOCK(radio);
1578
1579         MMRADIO_LOG_FLEAVE();
1580
1581         return ret;
1582 }
1583