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