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