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