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