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