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