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