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