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