Merge branch 'tizen_3.0' into tizen
[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_cancel(radio->scan_thread);
828                 pthread_join(radio->scan_thread, NULL);
829                 radio->scan_thread = 0;
830         }
831
832         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
833         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL);
834
835         MMRADIO_LOG_FLEAVE();
836
837         return MM_ERROR_NONE;
838 }
839
840 int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value)
841 {
842         int ret = MM_ERROR_NONE;
843         uint32_t strength = 0;
844         MMRADIO_LOG_FENTER();
845         MMRADIO_CHECK_INSTANCE(radio);
846
847         return_val_if_fail(value, MM_ERROR_INVALID_ARGUMENT);
848
849         /* just return stored frequency if radio device is not ready */
850         ret = radio_hal_get_signal_strength(radio->hal_inf, &strength);
851         if (ret == MM_ERROR_NOT_SUPPORT_API) {
852                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
853         } else if (ret != MM_ERROR_NONE) {
854                 debug_error("radio_hal_get_signal_strength error\n");
855                 *value = 0;
856                 MMRADIO_LOG_FLEAVE();
857                 return ret;
858         }
859         *value = (int)strength;
860         MMRADIO_LOG_FLEAVE();
861         return MM_ERROR_NONE;
862 }
863
864 void __mmradio_scan_thread(mm_radio_t *radio)
865 {
866         int ret = MM_ERROR_NONE;
867         int prev_freq = 0;
868
869         MMRADIO_LOG_FENTER();
870         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
871
872         ret = radio_hal_mute(radio->hal_inf);
873
874         if (ret == MM_ERROR_NOT_SUPPORT_API) {
875                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
876         } else if (ret != MM_ERROR_NONE) {
877                 MMRADIO_LOG_ERROR("radio_hal_mute error");
878                 goto FINISHED;
879         }
880         ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min);
881
882         if (ret != MM_ERROR_NONE)
883                 goto FINISHED;
884
885         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL);
886         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
887
888         while (!radio->stop_scan) {
889                 uint32_t freq = 0;
890                 MMMessageParamType param = { 0, };
891
892                 MMRADIO_LOG_DEBUG("scanning....\n");
893
894                 pthread_mutex_lock(&radio->seek_cancel_mutex);
895
896                 if (radio->stop_scan) {
897                         MMRADIO_LOG_DEBUG("scan was canceled");
898                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
899                         goto FINISHED;
900                 }
901
902                 ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP);
903
904                 pthread_mutex_unlock(&radio->seek_cancel_mutex);
905
906                 if (ret != MM_ERROR_NONE) {
907                         MMRADIO_LOG_ERROR("radio scanning error");
908                         break;
909                 }
910
911                 /* now we can get new frequency from radio device */
912                 if (radio->stop_scan)
913                         break;
914
915                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
916                 if (ret != MM_ERROR_NONE) {
917                         MMRADIO_LOG_ERROR("failed to get current frequency\n");
918                 } else {
919                         if (freq < prev_freq) {
920                                 MMRADIO_LOG_DEBUG("scanning wrapped around. stopping scan\n");
921                                 break;
922                         }
923
924                         if (freq == prev_freq)
925                                 continue;
926
927                         prev_freq = param.radio_scan.frequency = (int)freq;
928                         MMRADIO_LOG_DEBUG("scanning : new frequency : [%d]\n", param.radio_scan.frequency);
929
930                         /* drop if max freq is scanned */
931                         if (param.radio_scan.frequency == radio->region_setting.band_max) {
932                                 MMRADIO_LOG_DEBUG("%d freq is dropping...and stopping scan\n", param.radio_scan.frequency);
933                                 break;
934                         }
935
936                         if (radio->stop_scan) {
937                                 /* doesn't need to post */
938                                 break;
939                         }
940
941                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, &param);
942                 }
943         }
944 FINISHED:
945         if (radio->old_state == MM_RADIO_STATE_READY) {
946                 MMRADIO_LOG_DEBUG("old state is ready");
947         } else if (radio->old_state == MM_RADIO_STATE_PLAYING) {
948                 MMRADIO_LOG_DEBUG("old state is playing");
949                 ret = radio_hal_unmute(radio->hal_inf);
950                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
951                         MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
952                 } else if (ret != MM_ERROR_NONE) {
953                         MMRADIO_LOG_ERROR("radio_hal_unmute error");
954                         goto FINISHED_ERR;
955                 }
956                 ret = radio_hal_set_frequency(radio->hal_inf, prev_freq);
957                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
958                         MMRADIO_LOG_WARNING("radio_hal_set_frequency is not supported");
959                 } else if (ret != MM_ERROR_NONE) {
960                         MMRADIO_LOG_ERROR("radio_hal_set_frequency error");
961                         goto FINISHED_ERR;
962                 }
963         }
964
965 FINISHED_ERR:
966
967         radio->scan_thread = 0;
968
969         if (radio->old_state == MM_RADIO_STATE_PLAYING) {
970                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
971         } else {
972                 /* close radio device here !!!! */
973                 ret = radio_hal_close(radio->hal_inf);
974                 if (ret == MM_ERROR_NOT_SUPPORT_API)
975                         MMRADIO_LOG_WARNING("radio_hal_close is not supported");
976                 else if (ret != MM_ERROR_NONE)
977                         MMRADIO_LOG_ERROR("radio_hal_close_device error");
978
979                 ret = radio_hal_unprepare(radio->hal_inf);
980                 if (ret == MM_ERROR_NOT_SUPPORT_API)
981                         MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
982                 else if (ret != MM_ERROR_NONE)
983                         MMRADIO_LOG_ERROR("radio_hal_close_device error");
984
985                 radio->is_ready = FALSE;
986
987                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
988         }
989
990         if (!radio->stop_scan)
991                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL);
992
993         MMRADIO_LOG_FLEAVE();
994
995         pthread_exit(NULL);
996
997         return;
998 }
999
1000 bool __is_tunable_frequency(mm_radio_t *radio, int freq)
1001 {
1002         MMRADIO_LOG_FENTER();
1003
1004         MMRADIO_CHECK_INSTANCE(radio);
1005
1006         if (freq >= radio->region_setting.band_max
1007                 || freq <= radio->region_setting.band_min)
1008                 return false;
1009
1010         MMRADIO_LOG_FLEAVE();
1011
1012         return true;
1013 }
1014
1015 void __mmradio_seek_thread(mm_radio_t *radio)
1016 {
1017         int ret = MM_ERROR_NONE;
1018         uint32_t freq = 0;
1019         MMMessageParamType param = {0, };
1020
1021         MMRADIO_LOG_FENTER();
1022         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1023
1024         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL);
1025
1026         MMRADIO_LOG_DEBUG("seeking....\n");
1027
1028         if (!radio->seek_cancel) {
1029
1030                 MMRADIO_LOG_DEBUG("try to seek ");
1031                 pthread_mutex_lock(&radio->seek_cancel_mutex);
1032                 MMRADIO_LOG_DEBUG("seek start\n");
1033
1034                 if (radio->seek_cancel) {
1035                         MMRADIO_LOG_DEBUG("seek was canceled so we return failure to application");
1036                         pthread_mutex_unlock(&radio->seek_cancel_mutex);
1037                         goto SEEK_FAILED;
1038                 }
1039
1040                 ret = radio_hal_seek(radio->hal_inf, radio->seek_direction);
1041                 pthread_mutex_unlock(&radio->seek_cancel_mutex);
1042                 if (ret) {
1043                         MMRADIO_LOG_ERROR("radio_hal_seek failed\n");
1044                         goto SEEK_FAILED;
1045                 }
1046
1047                 /* now we can get new frequency from radio device */
1048                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
1049                 if (ret) {
1050                         MMRADIO_LOG_ERROR("failed to get current frequency\n");
1051                         goto SEEK_FAILED;
1052                 }
1053
1054                 MMRADIO_LOG_DEBUG("found frequency\n");
1055
1056                 /* if same freq is found, ignore it and search next one. */
1057                 if (freq == radio->prev_seek_freq) {
1058                         MMRADIO_LOG_DEBUG("It's same with previous found one. So, trying next one. \n");
1059                         goto SEEK_FAILED;
1060                 }
1061
1062                 /* check if it's limit freq or not */
1063                 if (__is_tunable_frequency(radio, freq)) {
1064                         /* now tune to new frequency */
1065                         ret = radio_hal_set_frequency(radio->hal_inf, freq);
1066                         if (ret) {
1067                                 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1068                                 goto SEEK_FAILED;
1069                         }
1070                 }
1071
1072                 if (radio->seek_unmute) {
1073                         /* now turn on radio
1074                          * In the case of limit freq, tuner should be unmuted.
1075                          * Otherwise, sound can't output even though application set new frequency.
1076                          */
1077                         ret = radio_hal_unmute(radio->hal_inf);
1078                         if (ret) {
1079                                 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1080                                 goto SEEK_FAILED;
1081                         }
1082                         radio->seek_unmute = FALSE;
1083                 }
1084
1085                 param.radio_scan.frequency = radio->prev_seek_freq = (int)freq;
1086                 MMRADIO_LOG_DEBUG("seeking : new frequency : [%d]\n", param.radio_scan.frequency);
1087                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1088         }
1089
1090         radio->seek_thread = 0;
1091         radio->is_seeking = FALSE;
1092
1093         MMRADIO_LOG_FLEAVE();
1094
1095         pthread_exit(NULL);
1096         return;
1097
1098 SEEK_FAILED:
1099
1100         if (radio->seek_unmute) {
1101                 /* now turn on radio
1102                 * In the case of limit freq, tuner should be unmuted.
1103                 * Otherwise, sound can't output even though application set new frequency.
1104                 */
1105                 ret = radio_hal_unmute(radio->hal_inf);
1106                 if (ret)
1107                         MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1108                 radio->seek_unmute = FALSE;
1109         }
1110         /* freq -1 means it's failed to seek */
1111         param.radio_scan.frequency = -1;
1112         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1113         radio->is_seeking = FALSE;
1114         pthread_exit(NULL);
1115         return;
1116 }
1117
1118 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param)
1119 {
1120         MMRADIO_CHECK_INSTANCE(radio);
1121
1122         MMRADIO_LOG_FENTER();
1123
1124         if (!radio->msg_cb) {
1125                 debug_warning("failed to post a message\n");
1126                 return false;
1127         }
1128
1129         MMRADIO_LOG_DEBUG("address of msg_cb : %p\n", radio->msg_cb);
1130
1131         radio->msg_cb(msgtype, param, radio->msg_cb_param);
1132
1133         MMRADIO_LOG_FLEAVE();
1134
1135         return true;
1136 }
1137
1138 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command)
1139 {
1140         MMRadioStateType radio_state = MM_RADIO_STATE_NUM;
1141
1142         MMRADIO_LOG_FENTER();
1143
1144         MMRADIO_CHECK_INSTANCE(radio);
1145
1146         radio_state = __mmradio_get_state(radio);
1147
1148         MMRADIO_LOG_DEBUG("incomming command : %d  current state : %d\n", command, radio_state);
1149
1150         switch (command) {
1151         case MMRADIO_COMMAND_CREATE:
1152                 {
1153                         if (radio_state != 0)
1154                                 goto NO_OP;
1155                 }
1156                 break;
1157
1158         case MMRADIO_COMMAND_REALIZE:
1159                 {
1160                         if (radio_state == MM_RADIO_STATE_READY ||
1161                                 radio_state == MM_RADIO_STATE_PLAYING ||
1162                                 radio_state == MM_RADIO_STATE_SCANNING)
1163                                 goto NO_OP;
1164
1165                         if (radio_state == 0)
1166                                 goto INVALID_STATE;
1167                 }
1168                 break;
1169
1170         case MMRADIO_COMMAND_UNREALIZE:
1171                 {
1172                         if (radio_state == MM_RADIO_STATE_NULL)
1173                                 goto NO_OP;
1174
1175                         /* we can call unrealize at any higher state */
1176                 }
1177                 break;
1178
1179         case MMRADIO_COMMAND_START:
1180                 {
1181                         if (radio_state == MM_RADIO_STATE_PLAYING)
1182                                 goto NO_OP;
1183
1184                         if (radio_state != MM_RADIO_STATE_READY)
1185                                 goto INVALID_STATE;
1186                 }
1187                 break;
1188
1189         case MMRADIO_COMMAND_STOP:
1190                 {
1191                         if (radio_state == MM_RADIO_STATE_READY)
1192                                 goto NO_OP;
1193
1194                         if (radio_state != MM_RADIO_STATE_PLAYING)
1195                                 goto INVALID_STATE;
1196                 }
1197                 break;
1198
1199         case MMRADIO_COMMAND_START_SCAN:
1200                 {
1201                         if (radio_state == MM_RADIO_STATE_SCANNING)
1202                                 goto NO_OP;
1203
1204                         if (radio_state == MM_RADIO_STATE_NULL)
1205                                 goto INVALID_STATE;
1206                 }
1207                 break;
1208
1209         case MMRADIO_COMMAND_STOP_SCAN:
1210                 {
1211                         if (radio_state == MM_RADIO_STATE_READY)
1212                                 goto NO_OP;
1213
1214                         if (radio_state != MM_RADIO_STATE_SCANNING)
1215                                 goto INVALID_STATE;
1216                 }
1217                 break;
1218
1219         case MMRADIO_COMMAND_DESTROY:
1220         case MMRADIO_COMMAND_MUTE:
1221         case MMRADIO_COMMAND_UNMUTE:
1222         case MMRADIO_COMMAND_SET_FREQ:
1223         case MMRADIO_COMMAND_GET_FREQ:
1224         case MMRADIO_COMMAND_SET_REGION:
1225         case MMRADIO_COMMAND_SET_VOLUME:
1226         case MMRADIO_COMMAND_GET_VOLUME:
1227                 {
1228                         /* we can do it at any state */
1229                 }
1230                 break;
1231
1232         case MMRADIO_COMMAND_SEEK:
1233                 {
1234                         if (radio_state != MM_RADIO_STATE_PLAYING)
1235                                 goto INVALID_STATE;
1236                 }
1237                 break;
1238
1239         case MMRADIO_COMMAND_GET_REGION:
1240                 {
1241                         if (radio_state == MM_RADIO_STATE_NULL)
1242                                 goto INVALID_STATE;
1243                 }
1244                 break;
1245
1246         default:
1247                 MMRADIO_LOG_DEBUG("not handled in FSM. don't care it\n");
1248                 break;
1249         }
1250
1251         MMRADIO_LOG_DEBUG("status OK\n");
1252
1253         radio->cmd = command;
1254
1255         MMRADIO_LOG_FLEAVE();
1256
1257         return MM_ERROR_NONE;
1258
1259  INVALID_STATE:
1260         debug_warning("invalid state. current : %d  command : %d\n", radio_state, command);
1261         MMRADIO_LOG_FLEAVE();
1262         return MM_ERROR_RADIO_INVALID_STATE;
1263
1264  NO_OP:
1265         debug_warning("mm-radio is in the desired state(%d). doing noting\n", radio_state);
1266         MMRADIO_LOG_FLEAVE();
1267         return MM_ERROR_RADIO_NO_OP;
1268
1269 }
1270
1271 static bool __mmradio_set_state(mm_radio_t *radio, int new_state)
1272 {
1273         MMMessageParamType msg = { 0, };
1274         int msg_type = MM_MESSAGE_UNKNOWN;
1275
1276         MMRADIO_LOG_FENTER();
1277         MMRADIO_CHECK_INSTANCE(radio);
1278
1279         if (!radio) {
1280                 debug_warning("calling set_state with invalid radio handle\n");
1281                 return false;
1282         }
1283
1284         if (radio->current_state == new_state && radio->pending_state == 0) {
1285                 debug_warning("we are in same state\n");
1286                 return true;
1287         }
1288
1289         /* set state */
1290         radio->old_state = radio->current_state;
1291         radio->current_state = new_state;
1292
1293         /* fill message param */
1294         msg.state.previous = radio->old_state;
1295         msg.state.current = radio->current_state;
1296
1297 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1298         /* post message to application */
1299         switch (radio->sound_focus.by_focus_cb) {
1300         case MMRADIO_FOCUS_CB_NONE:
1301                 {
1302                         msg_type = MM_MESSAGE_STATE_CHANGED;
1303                         MMRADIO_POST_MSG(radio, msg_type, &msg);
1304                 }
1305                 break;
1306
1307         case MMRADIO_FOCUS_CB_POSTMSG:
1308                 {
1309                         msg_type = MM_MESSAGE_STATE_INTERRUPTED;
1310                         msg.union_type = MM_MSG_UNION_CODE;
1311                         msg.code = radio->sound_focus.event_src;
1312                         MMRADIO_POST_MSG(radio, msg_type, &msg);
1313                 }
1314                 break;
1315
1316         case MMRADIO_FOCUS_CB_SKIP_POSTMSG:
1317         default:
1318                 break;
1319         }
1320 #else
1321         msg_type = MM_MESSAGE_STATE_CHANGED;
1322         MMRADIO_POST_MSG(radio, msg_type, &msg);
1323 #endif
1324
1325         MMRADIO_LOG_FLEAVE();
1326
1327         return true;
1328 }
1329
1330 static int __mmradio_get_state(mm_radio_t *radio)
1331 {
1332         MMRADIO_CHECK_INSTANCE(radio);
1333
1334         MMRADIO_LOG_DEBUG("radio state : current : [%d]   old : [%d]   pending : [%d]\n",
1335                 radio->current_state, radio->old_state, radio->pending_state);
1336
1337         return radio->current_state;
1338 }
1339
1340 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1341 static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
1342         mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
1343         const char *additional_info, void *user_data)
1344 {
1345         mm_radio_t *radio = (mm_radio_t *)user_data;
1346         enum MMMessageInterruptedCode event_source;
1347         int result = MM_ERROR_NONE;
1348         int postMsg = false;
1349
1350         MMRADIO_LOG_FENTER();
1351         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1352
1353         mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
1354         radio->sound_focus.event_src = event_source;
1355
1356         switch (focus_state) {
1357         case FOCUS_IS_RELEASED:{
1358                         radio->sound_focus.cur_focus_type &= ~focus_type;
1359                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
1360
1361                         result = _mmradio_stop(radio);
1362                         if (result)
1363                                 MMRADIO_LOG_ERROR("failed to stop radio\n");
1364
1365                         MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1366                 }
1367                 break;
1368
1369         case FOCUS_IS_ACQUIRED:{
1370                         MMMessageParamType msg = { 0, };
1371                         msg.union_type = MM_MSG_UNION_CODE;
1372                         msg.code = event_source;
1373
1374                         radio->sound_focus.cur_focus_type |= focus_type;
1375
1376                         if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1377                                 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1378
1379                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
1380
1381                         MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1382                 }
1383                 break;
1384
1385         default:
1386                 MMRADIO_LOG_DEBUG("Unknown focus_state\n");
1387                 break;
1388         }
1389
1390         MMRADIO_LOG_FLEAVE();
1391 }
1392
1393 static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
1394         mm_sound_focus_state_e focus_state, const char *reason_for_change,
1395         const char *additional_info, void *user_data)
1396 {
1397         mm_radio_t *radio = (mm_radio_t *)user_data;
1398         enum MMMessageInterruptedCode event_source;
1399         int result = MM_ERROR_NONE;
1400         int postMsg = false;
1401
1402         MMRADIO_LOG_FENTER();
1403         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1404
1405         mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
1406         radio->sound_focus.event_src = event_source;
1407
1408         switch (focus_state) {
1409         case FOCUS_IS_ACQUIRED: {
1410                         radio->sound_focus.cur_focus_type &= ~focus_type;
1411                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
1412
1413                         result = _mmradio_stop(radio);
1414                         if (result)
1415                                 MMRADIO_LOG_ERROR("failed to stop radio\n");
1416
1417                         MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1418                 }
1419                 break;
1420
1421         case FOCUS_IS_RELEASED: {
1422                         MMMessageParamType msg = { 0, };
1423                         msg.union_type = MM_MSG_UNION_CODE;
1424                         msg.code = event_source;
1425
1426                         radio->sound_focus.cur_focus_type |= focus_type;
1427
1428                         if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1429                                 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1430
1431                         radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
1432
1433                         MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1434                 }
1435                 break;
1436
1437         default:
1438                 MMRADIO_LOG_DEBUG("Unknown focus_state\n");
1439                 break;
1440         }
1441
1442         MMRADIO_LOG_FLEAVE();
1443 }
1444 #endif
1445
1446 static int __mmradio_set_total_volume(mm_radio_t *radio)
1447 {
1448         int ret = MM_ERROR_NONE;
1449         float total_volume = 0.0f;
1450
1451         MMRADIO_CHECK_INSTANCE(radio);
1452
1453         MMRADIO_VOLUME_LOCK(radio);
1454         if (radio->max_media_volume != 0)
1455                 total_volume = ((float)radio->media_volume / (float)radio->max_media_volume) * radio->local_volume;
1456         else
1457                 MMRADIO_LOG_WARNING("max media voulme is zero");
1458
1459         ret = radio_hal_set_volume(radio->hal_inf, total_volume);
1460         if (ret != MM_ERROR_NONE)
1461                 MMRADIO_LOG_ERROR("radio_hal_set_volume error");
1462
1463         MMRADIO_VOLUME_UNLOCK(radio);
1464         return ret;
1465
1466 }
1467
1468 static void __mmradio_volume_changed_cb(volume_type_t type, unsigned int volume, void *user_data)
1469 {
1470         mm_radio_t *radio = (mm_radio_t *)user_data;
1471         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1472         if (type == VOLUME_TYPE_MEDIA) {
1473                 MMRADIO_LOG_DEBUG("Change FM Radio volume to %d", volume);
1474                 MMRADIO_VOLUME_LOCK(radio);
1475                 radio->media_volume = volume;
1476                 MMRADIO_VOLUME_UNLOCK(radio);
1477                 __mmradio_set_total_volume(radio);
1478         }
1479 }
1480
1481 int _mmradio_get_region_type(mm_radio_t *radio, MMRadioRegionType *type)
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(type, MM_ERROR_INVALID_ARGUMENT);
1488
1489         *type = radio->region_setting.country;
1490
1491         MMRADIO_LOG_FLEAVE();
1492         return MM_ERROR_NONE;
1493 }
1494
1495 int _mmradio_get_region_frequency_range(mm_radio_t *radio, unsigned int *min_freq, unsigned int *max_freq)
1496 {
1497         MMRADIO_LOG_FENTER();
1498         MMRADIO_CHECK_INSTANCE(radio);
1499         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1500
1501         return_val_if_fail(min_freq && max_freq, MM_ERROR_INVALID_ARGUMENT);
1502
1503         *min_freq = radio->region_setting.band_min;
1504         *max_freq = radio->region_setting.band_max;
1505
1506         MMRADIO_LOG_FLEAVE();
1507         return MM_ERROR_NONE;
1508 }
1509
1510 int _mmradio_get_channel_spacing(mm_radio_t *radio, unsigned int *ch_spacing)
1511 {
1512         MMRADIO_LOG_FENTER();
1513         MMRADIO_CHECK_INSTANCE(radio);
1514         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1515
1516         return_val_if_fail(ch_spacing, MM_ERROR_INVALID_ARGUMENT);
1517
1518         *ch_spacing = radio->region_setting.channel_spacing;
1519
1520         MMRADIO_LOG_FLEAVE();
1521         return MM_ERROR_NONE;
1522 }
1523
1524 int _mmradio_set_volume(mm_radio_t *radio, float volume)
1525 {
1526         int ret = MM_ERROR_NONE;
1527
1528         MMRADIO_LOG_FENTER();
1529
1530         MMRADIO_CHECK_INSTANCE(radio);
1531         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME);
1532
1533         MMRADIO_LOG_DEBUG("Setting %f volume\n", volume);
1534
1535         MMRADIO_VOLUME_LOCK(radio);
1536         radio->local_volume = volume;
1537         MMRADIO_VOLUME_UNLOCK(radio);
1538
1539         ret = __mmradio_set_total_volume(radio);
1540
1541         MMRADIO_LOG_FLEAVE();
1542         return ret;
1543
1544 }
1545
1546 int _mmradio_get_volume(mm_radio_t *radio, float *pVolume)
1547 {
1548         int ret = MM_ERROR_NONE;
1549         float total_volume = 0.0;
1550         float volume = 0.0;
1551         MMRADIO_LOG_FENTER();
1552
1553         MMRADIO_CHECK_INSTANCE(radio);
1554         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_VOLUME);
1555
1556         return_val_if_fail(pVolume, MM_ERROR_INVALID_ARGUMENT);
1557
1558         ret = radio_hal_get_volume(radio->hal_inf, &total_volume);
1559         if (ret != MM_ERROR_NONE) {
1560                 MMRADIO_LOG_ERROR("radio_hal_get_volume error");
1561                 *pVolume = 0;
1562                 return ret;
1563         }
1564
1565         MMRADIO_VOLUME_LOCK(radio);
1566
1567         if (radio->media_volume)
1568                 volume = total_volume * ((float)radio->max_media_volume / (float)radio->media_volume);
1569
1570         MMRADIO_LOG_DEBUG("total_volume = %f, max_media_volue = %d, media_volume = %d, volume = %f",
1571                 total_volume, radio->max_media_volume, radio->media_volume, volume);
1572
1573         /* update volume in handle */
1574         if (fabs(radio->local_volume - volume) >= FLT_EPSILON) {
1575                 radio->local_volume = volume;
1576         }
1577
1578         *pVolume = (float)radio->local_volume;
1579         MMRADIO_VOLUME_UNLOCK(radio);
1580
1581         MMRADIO_LOG_FLEAVE();
1582
1583         return ret;
1584 }
1585