5dab31bd28729b1ef7cdad6da70a5172d3b99787
[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 static int __mmradio_create_thread(mm_radio_t *radio);
127 static void __mmradio_destroy_thread(mm_radio_t *radio);
128
129 static void __mmradio_volume_changed_cb(volume_type_t type, unsigned int volume, void *user_data);
130 static int __mmradio_set_media_volume(mm_radio_t *radio, unsigned int level);
131 static int __resource_release_cb(mm_resource_manager_h rm,
132         mm_resource_manager_res_h res, void *user_data);
133 static void __mmradio_msg_thread(mm_radio_t *radio);
134 static void __mmradio_msg_push(mm_radio_t *radio, MMRadioMsgTypes msg_type, int msg_data);
135
136 int _mmradio_apply_region(mm_radio_t *radio, MMRadioRegionType region, bool update)
137 {
138         int ret = MM_ERROR_NONE;
139         int count = 0;
140         int index = 0;
141
142         MMRADIO_LOG_FENTER();
143
144         MMRADIO_CHECK_INSTANCE(radio);
145         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_REGION);
146
147         /* if needed, radio region must be updated.
148          * Otherwise, just applying settings to device without it.
149          */
150         if (update) {
151                 count = ARRAY_SIZE(region_table);
152
153                 /* TODO: if auto is supported...get the region info. here */
154
155                 /* update radio region settings */
156                 for (index = 0; index < count; index++) {
157                         /* find the region from pre-defined table */
158                         if (region_table[index].country == region) {
159                                 radio->region_setting.country = region_table[index].country;
160                                 radio->region_setting.deemphasis = region_table[index].deemphasis;
161                                 radio->region_setting.band_min = region_table[index].band_min;
162                                 radio->region_setting.band_max = region_table[index].band_max;
163                                 radio->region_setting.channel_spacing = region_table[index].channel_spacing;
164                         }
165                 }
166         }
167
168         MMRADIO_LOG_INFO("setting region - country: %d, de-emphasis: %d, band range: %d ~ %d KHz",
169                 radio->region_setting.country, radio->region_setting.deemphasis,
170                 radio->region_setting.band_min, radio->region_setting.band_max);
171
172         MMRADIO_LOG_FLEAVE();
173
174         return ret;
175 }
176
177 int _mmradio_create_radio(mm_radio_t *radio)
178 {
179         int ret = MM_ERROR_NONE;
180
181         MMRADIO_LOG_FENTER();
182
183         MMRADIO_CHECK_INSTANCE(radio);
184         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_CREATE);
185
186         /* set default value */
187         radio->freq = DEFAULT_FREQ;
188         memset(&radio->region_setting, 0, sizeof(MMRadioRegion_t));
189         radio->local_volume = 1.0;
190
191         /* create msg queue for msg thread */
192         radio->msg_queue = g_async_queue_new();
193         if (!radio->msg_queue) {
194                 MMRADIO_LOG_ERROR("failed to get msg g_async_queue_new");
195                 return  MM_ERROR_RADIO_INTERNAL;
196         }
197
198         /* create mutex and thread */
199         ret = __mmradio_create_thread(radio);
200         if (ret) {
201                 MMRADIO_LOG_ERROR("failed to create threads");
202                 goto ERROR_THREAD;
203         }
204
205         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
206
207         /* initialize resource manager */
208         ret = mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
209                         __resource_release_cb, radio, &radio->resource_manager);
210         if (ret) {
211                 MMRADIO_LOG_ERROR("failed to create resource manager");
212                 ret = MM_ERROR_RADIO_INTERNAL;
213                 goto ERROR_RESOURCE;
214         }
215
216         ret = radio_hal_interface_init(&(radio->hal_inf));
217         if (ret) {
218                 MMRADIO_LOG_ERROR("failed to init mmradio hal interface");
219                 goto ERROR_HAL_INIT;
220         }
221
222         MMRADIO_LOG_FLEAVE();
223
224         return MM_ERROR_NONE;
225
226 ERROR_HAL_INIT:
227         mm_resource_manager_destroy(radio->resource_manager);
228 ERROR_RESOURCE:
229         __mmradio_destroy_thread(radio);
230 ERROR_THREAD:
231         if (radio->msg_queue)
232                 g_async_queue_unref(radio->msg_queue);
233         return ret;
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         if (radio->region_setting.country == MM_RADIO_REGION_GROUP_NONE) {
250                 /* not initialized      yet. set it with default region */
251                 region = RADIO_DEFAULT_REGION;
252                 update = true;
253         } else {
254                 /* already initialized by application */
255                 region = radio->region_setting.country;
256         }
257
258         ret = _mmradio_apply_region(radio, region, update);
259
260 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
261         ret = sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_RADIO, NULL, radio, &radio->stream_info);
262         if (ret != MM_ERROR_NONE) {
263                 MMRADIO_LOG_ERROR("failed to create stream information");
264                 MMRADIO_LOG_FLEAVE();
265                 return ret;
266         }
267         ret = sound_manager_create_virtual_stream(radio->stream_info, &radio->vstream);
268         if (ret != MM_ERROR_NONE) {
269                 MMRADIO_LOG_ERROR("sound_manager_create_virtual_stream error");
270                 MMRADIO_LOG_FLEAVE();
271                 return ret;
272         }
273 #endif
274
275         ret = sound_manager_get_max_volume(SOUND_TYPE_MEDIA, &max);
276         if (ret != MM_ERROR_NONE) {
277                 MMRADIO_LOG_WARNING("failed to get max volume");
278                 radio->max_media_volume = DEFAULT_MAX_MEDIA_VOLUME;
279         } else {
280                 radio->max_media_volume = max;
281         }
282
283         ret = mm_sound_volume_get_value(VOLUME_TYPE_MEDIA, &volume);
284
285         if (ret != MM_ERROR_NONE)
286                 MMRADIO_LOG_WARNING("failed to get media volume");
287
288         MMRADIO_VOLUME_LOCK(radio);
289         radio->media_volume = volume;
290         MMRADIO_VOLUME_UNLOCK(radio);
291
292         ret = mm_sound_add_volume_changed_callback(__mmradio_volume_changed_cb, (void *)radio, &radio->volume_subs_id);
293         if (ret != MM_ERROR_NONE)
294                 MMRADIO_LOG_WARNING("failed to register volume changed callback");
295
296         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
297
298         MMRADIO_LOG_FLEAVE();
299
300         return MM_ERROR_NONE;
301 }
302
303 int _mmradio_unrealize(mm_radio_t *radio)
304 {
305         int ret = MM_ERROR_NONE;
306
307         MMRADIO_LOG_FENTER();
308
309         MMRADIO_CHECK_INSTANCE(radio);
310         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNREALIZE);
311
312         ret = mm_sound_remove_volume_changed_callback(radio->volume_subs_id);
313         if (ret != MM_ERROR_NONE)
314                 MMRADIO_LOG_WARNING("mm_sound_remove_volume_changed_callback error");
315
316         /*Finish if there are scans*/
317         _mmradio_stop_scan(radio);
318
319         /*Stop radio if started*/
320         _mmradio_stop(radio);
321
322 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
323         sound_manager_destroy_virtual_stream(radio->vstream);
324         sound_manager_destroy_stream_information(radio->stream_info);
325 #endif
326
327         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
328
329         MMRADIO_LOG_FLEAVE();
330
331         return ret;
332 }
333
334 int _mmradio_destroy(mm_radio_t *radio)
335 {
336         int ret = MM_ERROR_NONE;
337         MMRADIO_LOG_FENTER();
338
339         MMRADIO_CHECK_INSTANCE(radio);
340         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_DESTROY);
341
342         _mmradio_unrealize(radio);
343
344         /* destroy mutex and thread */
345         __mmradio_destroy_thread(radio);
346
347         if (radio->msg_queue)
348                 g_async_queue_unref(radio->msg_queue);
349
350         ret = radio_hal_interface_deinit(radio->hal_inf);
351         if (ret) {
352                 MMRADIO_LOG_ERROR("failed to deinitialize radio hal interface");
353                 return ret;
354         }
355
356         ret = mm_resource_manager_destroy(radio->resource_manager);
357         if (ret) {
358                 MMRADIO_LOG_ERROR("failed to destroy resource manager");
359                 return MM_ERROR_RADIO_INTERNAL;
360         }
361
362         MMRADIO_LOG_FLEAVE();
363
364         return MM_ERROR_NONE;
365 }
366
367 /* unit should be KHz */
368 int _mmradio_set_frequency(mm_radio_t *radio, int freq)
369 {
370         int ret = MM_ERROR_NONE;
371
372         MMRADIO_LOG_FENTER();
373
374         MMRADIO_CHECK_INSTANCE(radio);
375         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_FREQ);
376
377         MMRADIO_LOG_INFO("Setting %d frequency", freq);
378
379         radio->freq = freq;
380
381         ret = radio_hal_set_frequency(radio->hal_inf, freq);
382         if (ret != MM_ERROR_NONE) {
383                 MMRADIO_LOG_ERROR("failed to set radio hal frequency");
384                 MMRADIO_LOG_FLEAVE();
385                 return ret;
386         }
387
388         MMRADIO_LOG_FLEAVE();
389
390         return ret;
391
392 }
393
394 int _mmradio_get_frequency(mm_radio_t *radio, int *pFreq)
395 {
396         int ret = MM_ERROR_NONE;
397         uint32_t freq = 0;
398         MMRADIO_LOG_FENTER();
399
400         MMRADIO_CHECK_INSTANCE(radio);
401         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_FREQ);
402
403         MMRADIO_RETURN_VAL_IF_FAIL(pFreq, MM_ERROR_INVALID_ARGUMENT);
404
405         ret = radio_hal_get_frequency(radio->hal_inf, &freq);
406         if (ret != MM_ERROR_NONE) {
407                 MMRADIO_LOG_ERROR("failed to get radio hal frequency");
408                 *pFreq = 0;
409                 return ret;
410         }
411
412         /* update freq in handle */
413         MMRADIO_LOG_INFO("Updating %d frequency", freq);
414         radio->freq = freq;
415
416         *pFreq = (int)radio->freq;
417
418         MMRADIO_LOG_FLEAVE();
419
420         return ret;
421 }
422
423 int _mmradio_mute(mm_radio_t *radio)
424 {
425         int ret = MM_ERROR_NONE;
426         MMRADIO_LOG_FENTER();
427
428         MMRADIO_CHECK_INSTANCE(radio);
429         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_MUTE);
430
431         ret = radio_hal_mute(radio->hal_inf);
432         if (ret == MM_ERROR_NOT_SUPPORT_API) {
433                 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
434         } else if (ret != MM_ERROR_NONE) {
435                 MMRADIO_LOG_ERROR("failed to set radio hal mute");
436                 MMRADIO_LOG_FLEAVE();
437                 return ret;
438         }
439
440         radio->is_muted = true;
441         MMRADIO_LOG_INFO("Radio mute state [%d]", radio->is_muted);
442         MMRADIO_LOG_FLEAVE();
443
444         return ret;
445 }
446
447 int _mmradio_unmute(mm_radio_t *radio)
448 {
449         int ret = MM_ERROR_NONE;
450         MMRADIO_LOG_FENTER();
451
452         MMRADIO_CHECK_INSTANCE(radio);
453         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNMUTE);
454
455         ret = radio_hal_unmute(radio->hal_inf);
456         if (ret == MM_ERROR_NOT_SUPPORT_API) {
457                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
458         } else if (ret != MM_ERROR_NONE) {
459                 MMRADIO_LOG_ERROR("failed to set radio hal unmute");
460                 MMRADIO_LOG_FLEAVE();
461                 return ret;
462         }
463
464         radio->is_muted = false;
465         MMRADIO_LOG_INFO("Radio mute state [%d]", radio->is_muted);
466         MMRADIO_LOG_FLEAVE();
467
468         return ret;
469 }
470
471 int _mmradio_set_message_callback(mm_radio_t *radio, MMMessageCallback callback, void *user_param)
472 {
473         MMRADIO_LOG_FENTER();
474
475         MMRADIO_CHECK_INSTANCE(radio);
476
477         radio->msg_cb = callback;
478         radio->msg_cb_param = user_param;
479
480         MMRADIO_LOG_DEBUG("msg_cb : 0x%x msg_cb_param : 0x%x", callback, user_param);
481
482         MMRADIO_LOG_FLEAVE();
483
484         return MM_ERROR_NONE;
485 }
486
487 int _mmradio_get_state(mm_radio_t *radio, int *pState)
488 {
489         int state = 0;
490
491         MMRADIO_LOG_FENTER();
492
493         MMRADIO_CHECK_INSTANCE(radio);
494         MMRADIO_RETURN_VAL_IF_FAIL(pState, MM_ERROR_INVALID_ARGUMENT);
495
496         state = __mmradio_get_state(radio);
497
498         *pState = state;
499
500         MMRADIO_LOG_FLEAVE();
501
502         return MM_ERROR_NONE;
503 }
504
505 int _mmradio_start(mm_radio_t *radio)
506 {
507         int ret = MM_ERROR_NONE;
508         unsigned int volume = 0;
509
510         MMRADIO_LOG_FENTER();
511
512         MMRADIO_CHECK_INSTANCE(radio);
513         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START);
514
515         MMRADIO_LOG_INFO("now tune to frequency : %d", radio->freq);
516
517         if (!radio->is_ready) {
518                 ret = mm_resource_manager_mark_for_acquire(radio->resource_manager,
519                         MM_RESOURCE_MANAGER_RES_TYPE_RADIO,
520                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &radio->radio_resource);
521                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
522                         MMRADIO_LOG_ERROR("resource manager mark for acquire fail");
523                         return MM_ERROR_RADIO_INTERNAL;
524                 }
525
526                 radio->interrupted_by_resource_conflict = FALSE;
527                 ret = mm_resource_manager_commit(radio->resource_manager);
528                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
529                         MMRADIO_LOG_ERROR("failed to commit resource manager");
530                         mm_resource_manager_mark_for_release(radio->resource_manager,
531                                 radio->radio_resource);
532                         radio->radio_resource = NULL;
533                         return ret;
534                 }
535
536                 ret = radio_hal_prepare(radio->hal_inf);
537                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
538                         MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
539                 } else if (ret != MM_ERROR_NONE) {
540                         MMRADIO_LOG_ERROR("failed to prepare radio hal");
541                         goto error2;
542                 }
543
544                 ret = radio_hal_open(radio->hal_inf);
545                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
546                         MMRADIO_LOG_WARNING("radio_hal_open is not supported");
547                 } else if (ret != MM_ERROR_NONE) {
548                         MMRADIO_LOG_ERROR("failed to open radio hal");
549                         goto error1;
550                 }
551                 radio->is_ready = true;
552         } else {
553                 MMRADIO_LOG_DEBUG("radio prepared and opened");
554         }
555
556         ret = mm_sound_volume_get_value(VOLUME_TYPE_MEDIA, &volume);
557         if (ret != MM_ERROR_NONE)
558                 MMRADIO_LOG_WARNING("failed to get media volume");
559
560         ret = __mmradio_set_media_volume(radio, volume);
561         if (ret != MM_ERROR_NONE) {
562                 MMRADIO_LOG_ERROR("failed to set media volume");
563                 goto error1;
564         }
565
566         ret = radio_hal_start(radio->hal_inf);
567         if (ret == MM_ERROR_NOT_SUPPORT_API) {
568                 MMRADIO_LOG_WARNING("radio_hal_start is not supported");
569         } else if (ret) {
570                 MMRADIO_LOG_ERROR("failed to start radio hal");
571                 goto error1;
572         }
573
574         /* set stored frequency */
575         ret = radio_hal_set_frequency(radio->hal_inf, radio->freq);
576         if (ret) {
577                 MMRADIO_LOG_ERROR("failed to set radio hal frequency");
578                 goto error1;
579         }
580
581 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
582         ret = sound_manager_start_virtual_stream(radio->vstream);
583         if (ret) {
584                 MMRADIO_LOG_ERROR("failed to start sound manager virtual stream");
585                 goto error1;
586         }
587 #endif
588
589         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
590
591         MMRADIO_LOG_FLEAVE();
592
593         return MM_ERROR_NONE;
594
595 error1:
596         radio_hal_close(radio->hal_inf);
597 error2:
598         radio_hal_unprepare(radio->hal_inf);
599         radio->is_ready = false;
600         return ret;
601 }
602
603 int _mmradio_stop(mm_radio_t *radio)
604 {
605         int ret = MM_ERROR_NONE;
606
607         MMRADIO_LOG_FENTER();
608
609         MMRADIO_CHECK_INSTANCE(radio);
610         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP);
611
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 stop radio hal");
627                 return ret;
628         }
629
630         if (radio->is_ready) {
631                 /* close radio device here !!!! */
632                 ret = radio_hal_close(radio->hal_inf);
633                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
634                         MMRADIO_LOG_WARNING("radio_hal_close is not supported");
635                 } else if (ret != MM_ERROR_NONE) {
636                         MMRADIO_LOG_ERROR("failed to close radio hal");
637                         return ret;
638                 }
639
640                 ret = radio_hal_unprepare(radio->hal_inf);
641                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
642                         MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
643                 } else if (ret != MM_ERROR_NONE) {
644                         MMRADIO_LOG_ERROR("failed to unprepare radio hal");
645                         return ret;
646                 }
647
648                 if (!radio->interrupted_by_resource_conflict && /* is being released */
649                                 radio->radio_resource != NULL) {
650                         ret = mm_resource_manager_mark_for_release(radio->resource_manager,
651                                         radio->radio_resource);
652                         radio->radio_resource = NULL;
653                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
654                                 MMRADIO_LOG_ERROR("failed to mark resource for release, ret(0x%x)", ret);
655                                 return ret;
656                         }
657
658                         ret = mm_resource_manager_commit(radio->resource_manager);
659                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
660                                 MMRADIO_LOG_ERROR("resource manager commit fail");
661                 }
662
663                 radio->is_ready = false;
664         }
665
666         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
667
668         MMRADIO_LOG_FLEAVE();
669
670         return MM_ERROR_NONE;
671 }
672
673 int _mmradio_seek(mm_radio_t *radio, MMRadioSeekDirectionType direction)
674 {
675         int ret = MM_ERROR_NONE;
676
677         MMRADIO_LOG_FENTER();
678
679         MMRADIO_CHECK_INSTANCE(radio);
680         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SEEK);
681
682         if (radio->seek.is_running) {
683                 MMRADIO_LOG_ERROR("[RADIO_ERROR_INVALID_OPERATION]radio is seeking, can't serve another request try again");
684                 return MM_ERROR_RADIO_INTERNAL;
685         }
686
687         radio->seek_unmute = false;
688
689         if (!radio->is_muted) {
690                 ret = radio_hal_mute(radio->hal_inf);
691                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
692                         MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
693                 } else if (ret) {
694                         MMRADIO_LOG_ERROR("failed to set radio hal mute");
695                         return ret;
696                 }
697                 radio->seek_unmute = true;
698         }
699
700         MMRADIO_LOG_INFO("trying to seek. direction[0:UP/1:DOWN) %d", direction);
701         radio->seek_direction = direction;
702         radio->seek.is_running = true;
703         radio->seek.stop = false;
704
705         MMRADIO_SEEK_THREAD_SIGNAL(radio);
706
707         MMRADIO_LOG_FLEAVE();
708
709         return MM_ERROR_NONE;
710 }
711
712 void _mmradio_seek_cancel(mm_radio_t *radio)
713 {
714         MMRADIO_LOG_FENTER();
715
716         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
717
718         /* cancel any outstanding seek request */
719         radio->seek.stop = true;
720
721         MMRADIO_LOG_FLEAVE();
722 }
723
724 int _mmradio_start_scan(mm_radio_t *radio)
725 {
726         int ret = MM_ERROR_NONE;
727
728         MMRADIO_LOG_FENTER();
729
730         MMRADIO_CHECK_INSTANCE(radio);
731         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START_SCAN);
732
733         radio->scan.stop = false;
734
735         if (!radio->is_ready) {
736                 ret = mm_resource_manager_mark_for_acquire(radio->resource_manager,
737                         MM_RESOURCE_MANAGER_RES_TYPE_RADIO,
738                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &radio->radio_resource);
739                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
740                         MMRADIO_LOG_ERROR("resource manager mark for acquire fail");
741                         return MM_ERROR_RADIO_INTERNAL;
742                 }
743
744                 radio->interrupted_by_resource_conflict = FALSE;
745                 ret = mm_resource_manager_commit(radio->resource_manager);
746                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
747                         MMRADIO_LOG_ERROR("failed to commit resource manager");
748                         mm_resource_manager_mark_for_release(radio->resource_manager,
749                                 radio->radio_resource);
750                         radio->radio_resource = NULL;
751                         return ret;
752                 }
753
754                 ret = radio_hal_prepare(radio->hal_inf);
755                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
756                         MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
757                 } else if (ret != MM_ERROR_NONE) {
758                         MMRADIO_LOG_ERROR("failed to prepare radio hal");
759                         return ret;
760                 }
761
762                 ret = radio_hal_open(radio->hal_inf);
763                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
764                         MMRADIO_LOG_WARNING("radio_hal_open is not supported");
765                 } else if (ret != MM_ERROR_NONE) {
766                         MMRADIO_LOG_ERROR("failed to open radio hal");
767                         MMRADIO_LOG_FLEAVE();
768                         return ret;
769                 }
770                 radio->is_ready = true;
771         } else {
772                 MMRADIO_LOG_DEBUG("radio prepared and opened");
773         }
774
775         radio->scan.is_running = true;
776
777         MMRADIO_SCAN_THREAD_SIGNAL(radio);
778
779         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
780
781         MMRADIO_LOG_FLEAVE();
782
783         return MM_ERROR_NONE;
784 }
785
786 int _mmradio_stop_scan(mm_radio_t *radio)
787 {
788         MMRADIO_LOG_FENTER();
789
790         MMRADIO_CHECK_INSTANCE(radio);
791         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP_SCAN);
792
793         radio->scan.stop = true;
794
795         MMRADIO_LOG_FLEAVE();
796
797         return MM_ERROR_NONE;
798 }
799
800 int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value)
801 {
802         int ret = MM_ERROR_NONE;
803         int32_t strength = 0;
804         MMRADIO_LOG_FENTER();
805         MMRADIO_CHECK_INSTANCE(radio);
806
807         MMRADIO_RETURN_VAL_IF_FAIL(value, MM_ERROR_INVALID_ARGUMENT);
808
809         /* just return stored frequency if radio device is not ready */
810         ret = radio_hal_get_signal_strength(radio->hal_inf, &strength);
811         if (ret == MM_ERROR_NOT_SUPPORT_API) {
812                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
813         } else if (ret != MM_ERROR_NONE) {
814                 MMRADIO_LOG_ERROR("failed to get radio hal signal strength");
815                 *value = 0;
816                 MMRADIO_LOG_FLEAVE();
817                 return ret;
818         }
819         *value = (int)strength;
820         MMRADIO_LOG_FLEAVE();
821         return MM_ERROR_NONE;
822 }
823
824 void __mmradio_scan_thread(mm_radio_t *radio)
825 {
826         int ret = MM_ERROR_NONE;
827         int prev_freq = 0;
828
829         MMRADIO_LOG_FENTER();
830         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
831
832         MMRADIO_SCAN_THREAD_LOCK(radio);
833
834         while (!radio->scan.thread_exit) {
835                 MMRADIO_LOG_DEBUG("scan thread started. waiting for signal.");
836                 MMRADIO_SCAN_THREAD_WAIT(radio);
837
838                 if (radio->scan.thread_exit) {
839                         MMRADIO_LOG_DEBUG("exiting scan thread");
840                         goto EXIT;
841                 }
842
843                 ret = radio_hal_mute(radio->hal_inf);
844                 if (ret == MM_ERROR_NOT_SUPPORT_API) {
845                         MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
846                 } else if (ret != MM_ERROR_NONE) {
847                         MMRADIO_LOG_ERROR("faied to set radio hal mute");
848                         goto FINISHED;
849                 }
850
851                 ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min);
852                 if (ret != MM_ERROR_NONE)
853                         goto FINISHED;
854
855                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL);
856                 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
857
858                 prev_freq = 0;
859                 while (!radio->scan.stop) {
860                         uint32_t freq = 0;
861
862                         MMRADIO_LOG_DEBUG("scanning....");
863
864                         if (radio->scan.thread_exit) {
865                                 MMRADIO_LOG_DEBUG("exiting scan thread");
866                                 goto EXIT;
867                         }
868
869                         if (radio->scan.stop) {
870                                 MMRADIO_LOG_INFO("scan was canceled");
871                                 goto FINISHED;
872                         }
873
874                         MMRADIO_HAL_SEEK_THREAD_LOCK(radio);
875                         ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP);
876                         MMRADIO_HAL_SEEK_THREAD_UNLOCK(radio);
877                         if (ret != MM_ERROR_NONE) {
878                                 MMRADIO_LOG_ERROR("radio scanning error");
879                                 break;
880                         }
881
882                         if (radio->scan.thread_exit) {
883                                 MMRADIO_LOG_DEBUG("exiting scan thread");
884                                 goto EXIT;
885                         }
886
887                         if (radio->scan.stop) {
888                                 MMRADIO_LOG_INFO("scan was canceled");
889                                 goto FINISHED;
890                         }
891
892                         /* now we can get new frequency from radio device */
893                         ret = radio_hal_get_frequency(radio->hal_inf, &freq);
894                         if (ret != MM_ERROR_NONE) {
895                                 MMRADIO_LOG_ERROR("failed to get current frequency");
896                         } else {
897                                 if (freq <= prev_freq) {
898                                         MMRADIO_LOG_ERROR("frequency is less than previous [%d] -> [%d] we wrapped around, we are finished scanning", prev_freq, freq);
899                                         break;
900                                 }
901
902                                 prev_freq = (int)freq;
903                                 MMRADIO_LOG_INFO("scanning : new frequency : [%d]", prev_freq);
904
905                                 /* drop if max freq is scanned */
906                                 if (prev_freq >= radio->region_setting.band_max) {
907                                         MMRADIO_LOG_WARNING("%d freq is dropping...and stopping scan", prev_freq);
908                                         break;
909                                 }
910
911                                 if (radio->scan.stop) {
912                                         /* doesn't need to post */
913                                         break;
914                                 }
915
916                                 __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_INFO, freq);
917                         }
918                 }
919
920 FINISHED:
921                 if (radio->old_state == MM_RADIO_STATE_READY) {
922                         MMRADIO_LOG_DEBUG("old state is ready");
923                 } else if (radio->old_state == MM_RADIO_STATE_PLAYING) {
924                         MMRADIO_LOG_DEBUG("old state is playing");
925                         ret = radio_hal_unmute(radio->hal_inf);
926                         if (ret == MM_ERROR_NOT_SUPPORT_API) {
927                                 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
928                         } else if (ret != MM_ERROR_NONE) {
929                                 MMRADIO_LOG_ERROR("failed to set radio hal unmute");
930                                 goto FINISHED_ERR;
931                         }
932                         ret = radio_hal_set_frequency(radio->hal_inf, prev_freq);
933                         if (ret == MM_ERROR_NOT_SUPPORT_API) {
934                                 MMRADIO_LOG_WARNING("radio_hal_set_frequency is not supported");
935                         } else if (ret != MM_ERROR_NONE) {
936                                 MMRADIO_LOG_ERROR("failed to set radio hal frequency");
937                                 goto FINISHED_ERR;
938                         }
939                 }
940
941 FINISHED_ERR:
942                 if (radio->old_state == MM_RADIO_STATE_PLAYING) {
943                         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
944                 } else {
945                         /* close radio device here !!!! */
946                         if (radio->is_ready) {
947                                 ret = radio_hal_close(radio->hal_inf);
948                                 if (ret == MM_ERROR_NOT_SUPPORT_API)
949                                         MMRADIO_LOG_WARNING("radio_hal_close is not supported");
950                                 else if (ret != MM_ERROR_NONE)
951                                         MMRADIO_LOG_ERROR("failed to close radio hal");
952
953                                 ret = radio_hal_unprepare(radio->hal_inf);
954                                 if (ret == MM_ERROR_NOT_SUPPORT_API)
955                                         MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
956                                 else if (ret != MM_ERROR_NONE)
957                                         MMRADIO_LOG_ERROR("failed to unprepare radio hal");
958
959                                 if (!radio->interrupted_by_resource_conflict && /* is being released */
960                                                 radio->radio_resource != NULL) {
961                                         ret = mm_resource_manager_mark_for_release(radio->resource_manager,
962                                                         radio->radio_resource);
963                                         radio->radio_resource = NULL;
964                                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
965                                                 MMRADIO_LOG_ERROR("failed to mark resource for release, ret(0x%x)", ret);
966                                 }
967
968                                 ret = mm_resource_manager_commit(radio->resource_manager);
969                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
970                                         MMRADIO_LOG_ERROR("resource manager commit fail");
971                                 radio->is_ready = false;
972                         }
973                         MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
974                 }
975
976                 if (!radio->scan.stop)
977                         __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_FINISHED, 0);
978                 else
979                         __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_STOPPED, 0);
980
981                 radio->scan.is_running = false;
982
983         }
984
985 EXIT:
986         radio->scan.is_running = false;
987
988         MMRADIO_SCAN_THREAD_UNLOCK(radio);
989
990         MMRADIO_LOG_FLEAVE();
991
992         pthread_exit(NULL);
993
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
1016         MMRADIO_LOG_FENTER();
1017         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1018
1019         MMRADIO_SEEK_THREAD_LOCK(radio);
1020
1021         while (!radio->seek.thread_exit) {
1022                 MMRADIO_LOG_DEBUG("seek thread started. waiting for signal.");
1023                 MMRADIO_SEEK_THREAD_WAIT(radio);
1024
1025                 if (radio->seek.thread_exit) {
1026                         MMRADIO_LOG_DEBUG("exiting seek thread");
1027                         goto EXIT;
1028                 }
1029
1030                 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL);
1031                 MMRADIO_LOG_DEBUG("seeking....");
1032
1033                 if (radio->seek.stop) {
1034                         MMRADIO_LOG_INFO("seek was canceled so we return failure to application");
1035                         goto SEEK_FAILED;
1036                 }
1037                 freq = 0;
1038                 MMRADIO_LOG_DEBUG("try to seek ");
1039                 MMRADIO_HAL_SEEK_THREAD_LOCK(radio);
1040                 MMRADIO_LOG_DEBUG("seek start");
1041                 ret = radio_hal_seek(radio->hal_inf, radio->seek_direction);
1042                 MMRADIO_HAL_SEEK_THREAD_UNLOCK(radio);
1043                 if (ret) {
1044                         MMRADIO_LOG_ERROR("failed to seek radio hal");
1045                         goto SEEK_FAILED;
1046                 }
1047
1048                 if (radio->seek.thread_exit) {
1049                         MMRADIO_LOG_DEBUG("exiting seek thread");
1050                         goto EXIT;
1051                 }
1052
1053                 if (radio->seek.stop) {
1054                         MMRADIO_LOG_INFO("seek was canceled so we return failure to application");
1055                         goto SEEK_FAILED;
1056                 }
1057
1058                 /* now we can get new frequency from radio device */
1059                 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
1060                 if (ret) {
1061                         MMRADIO_LOG_ERROR("failed to get current frequency");
1062                         goto SEEK_FAILED;
1063                 }
1064
1065                 MMRADIO_LOG_DEBUG("found frequency");
1066
1067                 /* if same freq is found, ignore it and search next one. */
1068                 if (freq == radio->prev_seek_freq) {
1069                         MMRADIO_LOG_WARNING("It's same with previous found one. So, trying next one.");
1070                         goto SEEK_FAILED;
1071                 }
1072
1073                 /* check if it's limit freq or not */
1074                 if (__is_tunable_frequency(radio, freq)) {
1075                         /* now tune to new frequency */
1076                         ret = radio_hal_set_frequency(radio->hal_inf, freq);
1077                         if (ret) {
1078                                 MMRADIO_LOG_ERROR("failed to tune to new frequency");
1079                                 goto SEEK_FAILED;
1080                         }
1081                         radio->freq = (int)freq;
1082                         MMRADIO_LOG_WARNING("setting frequency : [%d]", radio->freq);
1083                 }
1084
1085                 if (radio->seek_unmute) {
1086                         /* now turn on radio
1087                          * In the case of limit freq, tuner should be unmuted.
1088                          * Otherwise, sound can't output even though application set new frequency.
1089                          */
1090                         ret = radio_hal_unmute(radio->hal_inf);
1091                         if (ret) {
1092                                 MMRADIO_LOG_ERROR("failed to set unmute radio hal");
1093                                 goto SEEK_FAILED;
1094                         }
1095                         radio->seek_unmute = false;
1096                 }
1097
1098                 radio->prev_seek_freq = (int)freq;
1099                 MMRADIO_LOG_INFO("seeking : new frequency : [%d]", (int) freq);
1100                 __mmradio_msg_push(radio, MM_RADIO_MSG_SEEK_FINISHED, freq);
1101                 radio->seek.is_running = false;
1102                 continue;
1103
1104 SEEK_FAILED:
1105                 if (radio->seek_unmute) {
1106                         /* now turn on radio
1107                         * In the case of limit freq, tuner should be unmuted.
1108                         * Otherwise, sound can't output even though application set new frequency.
1109                         */
1110                         ret = radio_hal_unmute(radio->hal_inf);
1111                         if (ret)
1112                                 MMRADIO_LOG_ERROR("failed to set unmute radio hal");
1113                         radio->seek_unmute = false;
1114                 }
1115                 /* freq -1 means it's failed to seek */
1116                 __mmradio_msg_push(radio, MM_RADIO_MSG_SEEK_FINISHED, -1);
1117                 radio->seek.is_running = false;
1118         }
1119
1120 EXIT:
1121         radio->seek.is_running = false;
1122         MMRADIO_SEEK_THREAD_UNLOCK(radio);
1123         MMRADIO_LOG_FLEAVE();
1124         pthread_exit(NULL);
1125 }
1126
1127 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param)
1128 {
1129         MMRADIO_CHECK_INSTANCE(radio);
1130
1131         MMRADIO_LOG_FENTER();
1132
1133         if (!radio->msg_cb) {
1134                 MMRADIO_LOG_WARNING("failed to post a message because msg cb didn't register");
1135                 return false;
1136         }
1137
1138         MMRADIO_LOG_DEBUG("address of msg_cb : %p", radio->msg_cb);
1139
1140         radio->msg_cb(msgtype, param, radio->msg_cb_param);
1141
1142         MMRADIO_LOG_FLEAVE();
1143
1144         return true;
1145 }
1146
1147 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command)
1148 {
1149         MMRadioStateType radio_state = MM_RADIO_STATE_NUM;
1150
1151         MMRADIO_LOG_FENTER();
1152
1153         MMRADIO_CHECK_INSTANCE(radio);
1154
1155         radio_state = __mmradio_get_state(radio);
1156
1157         MMRADIO_LOG_INFO("incomming command : %d  current state : %d", command, radio_state);
1158
1159         switch (command) {
1160         case MMRADIO_COMMAND_CREATE:
1161                 {
1162                         if (radio_state != 0)
1163                                 goto NO_OP;
1164                 }
1165                 break;
1166
1167         case MMRADIO_COMMAND_REALIZE:
1168                 {
1169                         if (radio_state == MM_RADIO_STATE_READY ||
1170                                 radio_state == MM_RADIO_STATE_PLAYING ||
1171                                 radio_state == MM_RADIO_STATE_SCANNING)
1172                                 goto NO_OP;
1173
1174                         if (radio_state == 0)
1175                                 goto INVALID_STATE;
1176                 }
1177                 break;
1178
1179         case MMRADIO_COMMAND_UNREALIZE:
1180                 {
1181                         if (radio_state == MM_RADIO_STATE_NULL)
1182                                 goto NO_OP;
1183
1184                         /* we can call unrealize at any higher state */
1185                 }
1186                 break;
1187
1188         case MMRADIO_COMMAND_START:
1189                 {
1190                         if (radio_state == MM_RADIO_STATE_PLAYING)
1191                                 goto NO_OP;
1192
1193                         if (radio_state != MM_RADIO_STATE_READY)
1194                                 goto INVALID_STATE;
1195                 }
1196                 break;
1197
1198         case MMRADIO_COMMAND_STOP:
1199                 {
1200                         if (radio_state == MM_RADIO_STATE_READY)
1201                                 goto NO_OP;
1202
1203                         if (radio_state != MM_RADIO_STATE_PLAYING)
1204                                 goto INVALID_STATE;
1205                 }
1206                 break;
1207
1208         case MMRADIO_COMMAND_START_SCAN:
1209                 {
1210                         if (radio_state == MM_RADIO_STATE_SCANNING)
1211                                 goto NO_OP;
1212
1213                         if (radio_state == MM_RADIO_STATE_NULL)
1214                                 goto INVALID_STATE;
1215                 }
1216                 break;
1217
1218         case MMRADIO_COMMAND_STOP_SCAN:
1219                 {
1220                         if (radio_state == MM_RADIO_STATE_READY)
1221                                 goto NO_OP;
1222
1223                         if (radio_state != MM_RADIO_STATE_SCANNING)
1224                                 goto INVALID_STATE;
1225                 }
1226                 break;
1227
1228         case MMRADIO_COMMAND_DESTROY:
1229         case MMRADIO_COMMAND_MUTE:
1230         case MMRADIO_COMMAND_UNMUTE:
1231         case MMRADIO_COMMAND_SET_FREQ:
1232         case MMRADIO_COMMAND_GET_FREQ:
1233         case MMRADIO_COMMAND_SET_REGION:
1234         case MMRADIO_COMMAND_SET_VOLUME:
1235         case MMRADIO_COMMAND_GET_VOLUME:
1236                 {
1237                         /* we can do it at any state */
1238                 }
1239                 break;
1240
1241         case MMRADIO_COMMAND_SEEK:
1242                 {
1243                         if (radio_state != MM_RADIO_STATE_PLAYING)
1244                                 goto INVALID_STATE;
1245                 }
1246                 break;
1247
1248         case MMRADIO_COMMAND_GET_REGION:
1249                 {
1250                         if (radio_state == MM_RADIO_STATE_NULL)
1251                                 goto INVALID_STATE;
1252                 }
1253                 break;
1254
1255         default:
1256                 MMRADIO_LOG_DEBUG("not handled in FSM. don't care it");
1257                 break;
1258         }
1259
1260         MMRADIO_LOG_DEBUG("status OK");
1261
1262         radio->cmd = command;
1263
1264         MMRADIO_LOG_FLEAVE();
1265
1266         return MM_ERROR_NONE;
1267
1268 INVALID_STATE:
1269         MMRADIO_LOG_WARNING("invalid state. current : %d  command : %d", radio_state, command);
1270         MMRADIO_LOG_FLEAVE();
1271         return MM_ERROR_RADIO_INVALID_STATE;
1272
1273 NO_OP:
1274         MMRADIO_LOG_WARNING("mm-radio is in the desired state(%d). doing noting", radio_state);
1275         MMRADIO_LOG_FLEAVE();
1276         return MM_ERROR_RADIO_NO_OP;
1277
1278 }
1279
1280 static bool __mmradio_set_state(mm_radio_t *radio, int new_state)
1281 {
1282         MMMessageParamType msg = { 0, };
1283         int msg_type = MM_MESSAGE_UNKNOWN;
1284
1285         MMRADIO_LOG_FENTER();
1286
1287         if (!radio) {
1288                 MMRADIO_LOG_WARNING("calling set_state with invalid radio handle");
1289                 return false;
1290         }
1291
1292         if (radio->current_state == new_state && radio->pending_state == 0) {
1293                 MMRADIO_LOG_WARNING("we are in same state");
1294                 return true;
1295         }
1296
1297         /* set state */
1298         radio->old_state = radio->current_state;
1299         radio->current_state = new_state;
1300
1301         /* fill message param */
1302         msg.union_type = MM_MSG_UNION_STATE;
1303         msg.state.previous = radio->old_state;
1304         msg.state.current = radio->current_state;
1305
1306         if (radio->interrupted_by_resource_conflict) {
1307                 __mmradio_msg_push(radio, MM_RADIO_MSG_STATE_INTERRUPTED,
1308                         MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT);
1309         } else {
1310                 msg_type = MM_MESSAGE_STATE_CHANGED;
1311                 MMRADIO_POST_MSG(radio, msg_type, &msg);
1312         }
1313
1314         MMRADIO_LOG_FLEAVE();
1315
1316         return true;
1317 }
1318
1319 static int __mmradio_get_state(mm_radio_t *radio)
1320 {
1321         MMRADIO_CHECK_INSTANCE(radio);
1322
1323         MMRADIO_LOG_INFO("radio state : current : [%d]   old : [%d]   pending : [%d]",
1324                 radio->current_state, radio->old_state, radio->pending_state);
1325
1326         return radio->current_state;
1327 }
1328
1329 static void __mmradio_volume_changed_cb(volume_type_t type, unsigned int volume, void *user_data)
1330 {
1331         mm_radio_t *radio = (mm_radio_t *)user_data;
1332         int ret = MM_ERROR_NONE;
1333         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1334         if (type == VOLUME_TYPE_MEDIA) {
1335                 MMRADIO_LOG_INFO("Change FM Radio volume to %d", volume);
1336                 ret = __mmradio_set_media_volume(radio, volume);
1337                 if (ret != MM_ERROR_NONE)
1338                         MMRADIO_LOG_ERROR("failed to set media volume");
1339                 return;
1340         }
1341 }
1342
1343 int _mmradio_get_region_type(mm_radio_t *radio, MMRadioRegionType *type)
1344 {
1345         MMRADIO_LOG_FENTER();
1346         MMRADIO_CHECK_INSTANCE(radio);
1347         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1348
1349         MMRADIO_RETURN_VAL_IF_FAIL(type, MM_ERROR_INVALID_ARGUMENT);
1350
1351         *type = radio->region_setting.country;
1352
1353         MMRADIO_LOG_FLEAVE();
1354         return MM_ERROR_NONE;
1355 }
1356
1357 int _mmradio_get_region_frequency_range(mm_radio_t *radio, unsigned int *min_freq, unsigned int *max_freq)
1358 {
1359         MMRADIO_LOG_FENTER();
1360         MMRADIO_CHECK_INSTANCE(radio);
1361         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1362
1363         MMRADIO_RETURN_VAL_IF_FAIL(min_freq && max_freq, MM_ERROR_INVALID_ARGUMENT);
1364
1365         *min_freq = radio->region_setting.band_min;
1366         *max_freq = radio->region_setting.band_max;
1367
1368         MMRADIO_LOG_FLEAVE();
1369         return MM_ERROR_NONE;
1370 }
1371
1372 int _mmradio_get_channel_spacing(mm_radio_t *radio, unsigned int *ch_spacing)
1373 {
1374         MMRADIO_LOG_FENTER();
1375         MMRADIO_CHECK_INSTANCE(radio);
1376         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1377
1378         MMRADIO_RETURN_VAL_IF_FAIL(ch_spacing, MM_ERROR_INVALID_ARGUMENT);
1379
1380         *ch_spacing = radio->region_setting.channel_spacing;
1381
1382         MMRADIO_LOG_FLEAVE();
1383         return MM_ERROR_NONE;
1384 }
1385
1386 int _mmradio_set_volume(mm_radio_t *radio, float volume)
1387 {
1388         int ret = MM_ERROR_NONE;
1389
1390         MMRADIO_LOG_FENTER();
1391
1392         MMRADIO_CHECK_INSTANCE(radio);
1393         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME);
1394
1395         MMRADIO_LOG_INFO("Setting %f volume", volume);
1396
1397         MMRADIO_VOLUME_LOCK(radio);
1398         radio->local_volume = volume;
1399         MMRADIO_VOLUME_UNLOCK(radio);
1400
1401         ret = radio_hal_set_volume(radio->hal_inf, volume);
1402         if (ret != MM_ERROR_NONE)
1403                 MMRADIO_LOG_ERROR("failed to set radio hal volume");
1404
1405         MMRADIO_LOG_FLEAVE();
1406
1407         return ret;
1408 }
1409
1410 int _mmradio_get_volume(mm_radio_t *radio, float *pVolume)
1411 {
1412         int ret = MM_ERROR_NONE;
1413         float volume = 0.0;
1414         MMRADIO_LOG_FENTER();
1415
1416         MMRADIO_CHECK_INSTANCE(radio);
1417         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_VOLUME);
1418
1419         MMRADIO_RETURN_VAL_IF_FAIL(pVolume, MM_ERROR_INVALID_ARGUMENT);
1420
1421         ret = radio_hal_get_volume(radio->hal_inf, &volume);
1422         if (ret != MM_ERROR_NONE) {
1423                 MMRADIO_LOG_ERROR("failed to get radio hal volume");
1424                 *pVolume = 0;
1425                 return ret;
1426         }
1427
1428         MMRADIO_VOLUME_LOCK(radio);
1429         radio->local_volume = volume;
1430         *pVolume = (float)radio->local_volume;
1431         MMRADIO_VOLUME_UNLOCK(radio);
1432
1433         MMRADIO_LOG_FLEAVE();
1434
1435         return ret;
1436 }
1437
1438 static int __mmradio_set_media_volume(mm_radio_t *radio, unsigned int level)
1439 {
1440         int ret = MM_ERROR_NONE;
1441
1442         MMRADIO_LOG_FENTER();
1443
1444         MMRADIO_CHECK_INSTANCE(radio);
1445         MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME);
1446
1447         MMRADIO_LOG_INFO("Setting %d volume", level);
1448
1449         MMRADIO_VOLUME_LOCK(radio);
1450         radio->media_volume = level;
1451         MMRADIO_VOLUME_UNLOCK(radio);
1452
1453         ret = radio_hal_set_media_volume(radio->hal_inf, level);
1454         if (ret != MM_ERROR_NONE)
1455                 MMRADIO_LOG_ERROR("failed to set radio hal media volume");
1456
1457         MMRADIO_LOG_FLEAVE();
1458
1459         return ret;
1460 }
1461
1462 static int __resource_release_cb(mm_resource_manager_h rm,
1463         mm_resource_manager_res_h res, void *user_data)
1464 {
1465         mm_radio_t *radio = NULL;
1466
1467         MMRADIO_LOG_FENTER();
1468
1469         if (!user_data) {
1470                 MMRADIO_LOG_ERROR("user_data is null");
1471                 return FALSE;
1472         }
1473
1474         radio = (mm_radio_t *)user_data;
1475         radio->radio_resource = NULL;
1476
1477         MMRADIO_LOG_DEBUG("radio resource conflict so, resource will be freed by _mmradio_stop");
1478
1479         radio->interrupted_by_resource_conflict = TRUE;
1480
1481         MMRADIO_CMD_LOCK(radio);
1482         if (_mmradio_stop(radio) != MM_ERROR_NONE)
1483                 MMRADIO_LOG_ERROR("failed to stop radio");
1484         MMRADIO_CMD_UNLOCK(radio);
1485
1486         MMRADIO_LOG_FLEAVE();
1487
1488         return FALSE;
1489 }
1490
1491 static int __mmradio_create_thread(mm_radio_t *radio)
1492 {
1493         int ret = MM_ERROR_NONE;
1494
1495         MMRADIO_LOG_FENTER();
1496
1497         MMRADIO_CHECK_INSTANCE(radio);
1498
1499         MMRADIO_INIT_MUTEX(radio->cmd_lock);
1500         MMRADIO_INIT_MUTEX(radio->volume_lock);
1501         MMRADIO_INIT_MUTEX(radio->hal_seek_mutex);
1502
1503         radio->msg.thread_id = pthread_create(&radio->msg.thread, NULL,
1504                 (void *)__mmradio_msg_thread, (void *)radio);
1505         if (radio->msg.thread_id) {
1506                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
1507                 MMRADIO_LOG_ERROR("failed to create thread : msg");
1508                 goto ERROR;
1509         }
1510
1511         MMRADIO_INIT_MUTEX(radio->seek.mutex);
1512         MMRADIO_INIT_COND(radio->seek.cond);
1513
1514         radio->seek.thread_id = pthread_create(&radio->seek.thread, NULL,
1515                 (void *)__mmradio_seek_thread, (void *)radio);
1516         if (radio->seek.thread_id) {
1517                 MMRADIO_LOG_DEBUG("failed to create thread : seek");
1518                 goto ERROR;
1519         }
1520
1521         MMRADIO_INIT_MUTEX(radio->scan.mutex);
1522         MMRADIO_INIT_COND(radio->scan.cond);
1523
1524         radio->scan.thread_id = pthread_create(&radio->scan.thread, NULL,
1525                 (void *)__mmradio_scan_thread, (void *)radio);
1526         if (radio->scan.thread_id) {
1527                 MMRADIO_LOG_ERROR("failed to create thread : scan");
1528                 goto ERROR;
1529         }
1530
1531         MMRADIO_LOG_FLEAVE();
1532         return ret;
1533
1534 ERROR:
1535         if (radio->seek.thread) {
1536                 MMRADIO_SEEK_THREAD_LOCK(radio);
1537                 radio->seek.thread_exit = true;
1538                 MMRADIO_SEEK_THREAD_SIGNAL(radio);
1539                 MMRADIO_SEEK_THREAD_UNLOCK(radio);
1540                 pthread_join(radio->seek.thread, NULL);
1541                 radio->seek.thread = 0;
1542         }
1543
1544         if (radio->msg.thread) {
1545                 mm_radio_msg_t *msg = g_slice_new0(mm_radio_msg_t);
1546                 if (!msg) {
1547                         MMRADIO_LOG_ERROR("failed to get mm_radio_msg_t");
1548                 } else {
1549                         msg->msg_type = MM_RADIO_MSG_DESTROY;
1550                         g_async_queue_push_front(radio->msg_queue, msg);
1551                         pthread_join(radio->msg.thread, NULL);
1552                         radio->msg.thread = 0;
1553                 }
1554         }
1555
1556         pthread_mutex_destroy(&radio->cmd_lock);
1557         pthread_mutex_destroy(&radio->volume_lock);
1558         pthread_mutex_destroy(&radio->hal_seek_mutex);
1559         pthread_mutex_destroy(&radio->seek.mutex);
1560         pthread_cond_destroy(&radio->seek.cond);
1561         pthread_mutex_destroy(&radio->scan.mutex);
1562         pthread_cond_destroy(&radio->scan.cond);
1563
1564         return MM_ERROR_RADIO_INTERNAL;
1565 }
1566
1567 static void __mmradio_destroy_thread(mm_radio_t *radio)
1568 {
1569         MMRADIO_LOG_FENTER();
1570
1571         MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1572
1573         if (radio->seek.thread) {
1574                 MMRADIO_SEEK_THREAD_LOCK(radio);
1575                 radio->seek.thread_exit = true;
1576                 MMRADIO_SEEK_THREAD_SIGNAL(radio);
1577                 MMRADIO_SEEK_THREAD_UNLOCK(radio);
1578                 pthread_join(radio->seek.thread, NULL);
1579                 radio->seek.thread = 0;
1580         }
1581
1582         if (radio->scan.thread) {
1583                 MMRADIO_SCAN_THREAD_LOCK(radio);
1584                 radio->scan.thread_exit = true;
1585                 MMRADIO_SCAN_THREAD_SIGNAL(radio);
1586                 MMRADIO_SCAN_THREAD_UNLOCK(radio);
1587                 pthread_join(radio->scan.thread, NULL);
1588                 radio->scan.thread = 0;
1589         }
1590
1591         if (radio->msg.thread) {
1592                 mm_radio_msg_t *msg = g_slice_new0(mm_radio_msg_t);
1593                 if (!msg) {
1594                         MMRADIO_LOG_ERROR("failed to get mm_radio_msg_t");
1595                 } else {
1596                         msg->msg_type = MM_RADIO_MSG_DESTROY;
1597                         g_async_queue_push_front(radio->msg_queue, msg);
1598                         pthread_join(radio->msg.thread, NULL);
1599                         radio->msg.thread = 0;
1600                 }
1601         }
1602
1603         pthread_mutex_destroy(&radio->cmd_lock);
1604         pthread_mutex_destroy(&radio->volume_lock);
1605         pthread_mutex_destroy(&radio->hal_seek_mutex);
1606
1607         pthread_mutex_destroy(&radio->seek.mutex);
1608         pthread_cond_destroy(&radio->seek.cond);
1609
1610         pthread_mutex_destroy(&radio->scan.mutex);
1611         pthread_cond_destroy(&radio->scan.cond);
1612
1613         MMRADIO_LOG_FLEAVE();
1614 }
1615
1616 void __mmradio_msg_push(mm_radio_t *radio, MMRadioMsgTypes msg_type, int msg_data)
1617 {
1618         mm_radio_msg_t *msg = g_slice_new0(mm_radio_msg_t);
1619         if (!msg) {
1620                 MMRADIO_LOG_ERROR("NULL msg pointer");
1621                 return;
1622         }
1623
1624         msg->msg_type = msg_type;
1625         msg->data = msg_data;
1626
1627         MMRADIO_LOG_INFO("push msg_type: %d, msg_data: %d", (int)msg->msg_type, msg->data);
1628         g_async_queue_push(radio->msg_queue, msg);
1629 }
1630
1631 void __mmradio_msg_thread(mm_radio_t *radio)
1632 {
1633         MMMessageParamType param = {0,};
1634         mm_radio_msg_t *msg = NULL;
1635         int exit_msg_thread = 0;
1636
1637         /*we run a while one loop*/
1638         while (exit_msg_thread == 0) {
1639                 msg = (mm_radio_msg_t *)g_async_queue_pop(radio->msg_queue);
1640                 if (!msg) {
1641                         MMRADIO_LOG_ERROR("poped message is NULL!");
1642                         break;
1643                 }
1644
1645                 switch (msg->msg_type) {
1646                 case MM_RADIO_MSG_DESTROY:
1647                         MMRADIO_LOG_INFO("get destroy msg. pop all event to finish this thread");
1648                         mm_radio_msg_t *msg_pop = NULL;
1649                         while ((msg_pop = (mm_radio_msg_t *)g_async_queue_try_pop(radio->msg_queue))) {
1650                                 if (msg_pop != NULL) {
1651                                         MMRADIO_LOG_DEBUG("drop this msg type: %d", msg_pop->msg_type);
1652                                         g_slice_free(mm_radio_msg_t, msg_pop);
1653                                 }
1654                         }
1655                         exit_msg_thread = 1;
1656                         break;
1657                 case MM_RADIO_MSG_SCAN_INFO:
1658                         MMRADIO_LOG_INFO("get scan info frequency: %d", msg->data);
1659                         param.radio_scan.frequency = (int) msg->data;
1660                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, &param);
1661                         break;
1662                 case MM_RADIO_MSG_SCAN_STOPPED:
1663                         MMRADIO_LOG_INFO("get scan stopped");
1664                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL);
1665                         break;
1666                 case MM_RADIO_MSG_SCAN_FINISHED:
1667                         MMRADIO_LOG_INFO("get scan finished");
1668                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL);
1669                         break;
1670                 case MM_RADIO_MSG_SEEK_FINISHED:
1671                         MMRADIO_LOG_INFO("get seek finish frequency: %d", msg->data);
1672                         param.radio_scan.frequency = (int) msg->data;
1673                         MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
1674                         break;
1675                 case MM_RADIO_MSG_STATE_INTERRUPTED:
1676                         MMRADIO_LOG_INFO("get state interrupted type: %d", msg->data);
1677                         param.union_type = MM_MSG_UNION_STATE;
1678                         param.state.previous = radio->old_state;
1679                         param.state.current = radio->current_state;
1680                         param.state.code = msg->data;
1681                         MMRADIO_POST_MSG(radio, MM_MESSAGE_STATE_INTERRUPTED, &param);
1682                         break;
1683                 default:
1684                         MMRADIO_LOG_ERROR("wrong msg_type : %d", msg->msg_type);
1685                         break;
1686                 }
1687
1688                 if (msg)
1689                         g_slice_free(mm_radio_msg_t, msg);
1690
1691         }
1692
1693         MMRADIO_LOG_INFO("msg thread is finished");
1694 }