4 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 /*===========================================================================================
24 ========================================================================================== */
31 #include <sys/ioctl.h>
37 #include <mm_message.h>
39 #include "mm_radio_priv_hal.h"
41 /*===========================================================================================
42 LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE
43 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 GLOBAL CONSTANT DEFINITIONS:
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 IMPORTED VARIABLE DECLARATIONS:
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 IMPORTED FUNCTION DECLARATIONS:
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
59 #define DEFAULT_DEVICE "/dev/radio0"
62 #define DEFAULT_FREQ 107700
65 #define RADIO_FREQ_FORMAT_SET(x_freq) ((x_freq) * FREQ_FRAC)
66 #define RADIO_FREQ_FORMAT_GET(x_freq) ((x_freq) / FREQ_FRAC)
67 /* If non-zero, wrap around when at the end of the frequency range, else stop seeking */
68 #define DEFAULT_WRAP_AROUND 1
70 #define RADIO_DEFAULT_REGION MM_RADIO_REGION_GROUP_USA
71 #define READ_MAX_BUFFER_SIZE 1024
72 /*---------------------------------------------------------------------------
73 LOCAL CONSTANT DEFINITIONS:
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 LOCAL DATA TYPE DEFINITIONS:
78 ---------------------------------------------------------------------------*/
80 /*---------------------------------------------------------------------------
81 GLOBAL VARIABLE DEFINITIONS:
82 ---------------------------------------------------------------------------*/
85 /*---------------------------------------------------------------------------
86 LOCAL VARIABLE DEFINITIONS:
87 ---------------------------------------------------------------------------*/
88 /* radio region configuration table */
89 static const MMRadioRegion_t region_table[] = {
90 { /* Notrh America, South America, South Korea, Taiwan, Australia */
91 MM_RADIO_REGION_GROUP_USA, /* region type */
92 MM_RADIO_DEEMPHASIS_75_US, /* de-emphasis */
93 MM_RADIO_FREQ_MIN_87500_KHZ, /* min freq. */
94 MM_RADIO_FREQ_MAX_108000_KHZ, /* max freq. */
97 { /* China, Europe, Africa, Middle East, Hong Kong, India, Indonesia, Russia, Singapore */
98 MM_RADIO_REGION_GROUP_EUROPE,
99 MM_RADIO_DEEMPHASIS_50_US,
100 MM_RADIO_FREQ_MIN_87500_KHZ,
101 MM_RADIO_FREQ_MAX_108000_KHZ,
105 MM_RADIO_REGION_GROUP_JAPAN,
106 MM_RADIO_DEEMPHASIS_50_US,
107 MM_RADIO_FREQ_MIN_76100_KHZ,
108 MM_RADIO_FREQ_MAX_89900_KHZ,
113 /*---------------------------------------------------------------------------
114 LOCAL FUNCTION PROTOTYPES:
115 ---------------------------------------------------------------------------*/
116 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param);
117 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command);
118 static int __mmradio_get_state(mm_radio_t *radio);
119 static bool __mmradio_set_state(mm_radio_t *radio, int new_state);
120 void _mmradio_seek_cancel(mm_radio_t *radio);
121 static void __mmradio_seek_thread(mm_radio_t *radio);
122 static void __mmradio_scan_thread(mm_radio_t *radio);
123 static bool __is_tunable_frequency(mm_radio_t *radio, int freq);
125 #ifdef TIZEN_FEATURE_SOUND_FOCUS
126 static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
127 mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
128 const char *additional_info, void *user_data);
129 static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
130 mm_sound_focus_state_e focus_state, const char *reason_for_change,
131 const char *additional_info, void *user_data);
134 int _mmradio_apply_region(mm_radio_t *radio, MMRadioRegionType region, bool update)
136 int ret = MM_ERROR_NONE;
140 MMRADIO_LOG_FENTER();
142 MMRADIO_CHECK_INSTANCE(radio);
143 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_REGION);
145 /* if needed, radio region must be updated.
146 * Otherwise, just applying settings to device without it.
149 count = ARRAY_SIZE(region_table);
151 /* TODO: if auto is supported...get the region info. here */
153 /* update radio region settings */
154 for (index = 0; index < count; index++) {
155 /* find the region from pre-defined table */
156 if (region_table[index].country == region) {
157 radio->region_setting.country = region_table[index].country;
158 radio->region_setting.deemphasis = region_table[index].deemphasis;
159 radio->region_setting.band_min = region_table[index].band_min;
160 radio->region_setting.band_max = region_table[index].band_max;
161 radio->region_setting.channel_spacing = region_table[index].channel_spacing;
166 MMRADIO_LOG_DEBUG("setting region - country: %d, de-emphasis: %d, band range: %d ~ %d KHz\n",
167 radio->region_setting.country, radio->region_setting.deemphasis,
168 radio->region_setting.band_min, radio->region_setting.band_max);
170 MMRADIO_LOG_FLEAVE();
175 int _mmradio_create_radio(mm_radio_t *radio)
177 int ret = MM_ERROR_NONE;
179 MMRADIO_LOG_FENTER();
181 MMRADIO_CHECK_INSTANCE(radio);
182 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_CREATE);
184 /* set default value */
185 radio->freq = DEFAULT_FREQ;
186 #ifdef TIZEN_FEATURE_SOUND_FOCUS
187 memset(&radio->sound_focus, 0, sizeof(mm_radio_sound_focus));
189 memset(&radio->region_setting, 0, sizeof(MMRadioRegion_t));
191 /* create command lock */
192 ret = pthread_mutex_init(&radio->cmd_lock, NULL);
194 MMRADIO_LOG_ERROR("mutex creation failed\n");
195 return MM_ERROR_RADIO_INTERNAL;
198 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
200 #ifdef TIZEN_FEATURE_SOUND_FOCUS
201 ret = mmradio_sound_focus_register(&radio->sound_focus,
202 (mm_sound_focus_changed_cb)__mmradio_sound_focus_cb,
203 (mm_sound_focus_changed_watch_cb)__mmradio_sound_focus_watch_cb,
207 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
208 MMRADIO_LOG_ERROR("mmradio_audio_focus_register is failed\n");
209 return MM_ERROR_RADIO_INTERNAL;
213 ret = radio_hal_interface_init(&(radio->hal_inf));
215 MMRADIO_LOG_ERROR("mmradio hal interface init failed\n");
219 MMRADIO_LOG_FLEAVE();
221 return MM_ERROR_NONE;
224 int _mmradio_realize(mm_radio_t *radio)
226 int ret = MM_ERROR_NONE;
228 MMRadioRegionType region = MM_RADIO_REGION_GROUP_NONE;
230 MMRADIO_LOG_FENTER();
232 MMRADIO_CHECK_INSTANCE(radio);
233 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_REALIZE);
235 ret = pthread_mutex_init(&radio->seek_cancel_mutex, NULL);
237 MMRADIO_LOG_DEBUG("Mutex creation failed %d", ret);
240 if (radio->region_setting.country == MM_RADIO_REGION_GROUP_NONE) {
241 /* not initialized yet. set it with default region */
242 region = RADIO_DEFAULT_REGION;
245 /* already initialized by application */
246 region = radio->region_setting.country;
249 ret = _mmradio_apply_region(radio, region, update);
251 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
252 ret = sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_RADIO, NULL, radio, &radio->stream_info);
253 if (ret != MM_ERROR_NONE) {
254 MMRADIO_LOG_ERROR("sound_manager_create_stream_information_internal error");
255 MMRADIO_LOG_FLEAVE();
258 ret = sound_manager_create_virtual_stream(radio->stream_info, &radio->vstream);
259 if (ret != MM_ERROR_NONE) {
260 MMRADIO_LOG_ERROR("sound_manager_create_virtual_stream error");
261 MMRADIO_LOG_FLEAVE();
265 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
267 MMRADIO_LOG_FLEAVE();
269 return MM_ERROR_NONE;
272 int _mmradio_unrealize(mm_radio_t *radio)
274 int ret = MM_ERROR_NONE;
276 MMRADIO_LOG_FENTER();
278 MMRADIO_CHECK_INSTANCE(radio);
279 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNREALIZE);
281 ret = radio_hal_unmute(radio->hal_inf);
282 if (ret == MM_ERROR_NOT_SUPPORT_API) {
283 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
284 } else if (ret != MM_ERROR_NONE) {
285 MMRADIO_LOG_ERROR("radio_hal_unmute error");
286 MMRADIO_LOG_FLEAVE();
290 /*Finish if there are scans*/
291 _mmradio_stop_scan(radio);
293 /*Stop radio if started*/
294 _mmradio_stop(radio);
296 /* close radio device here !!!! */
297 radio_hal_close(radio->hal_inf);
298 radio_hal_unprepare(radio->hal_inf);
299 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
300 sound_manager_destroy_virtual_stream(radio->vstream);
301 sound_manager_destroy_stream_information(radio->stream_info);
303 pthread_mutex_destroy(&radio->seek_cancel_mutex);
305 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
307 MMRADIO_LOG_FLEAVE();
309 return MM_ERROR_NONE;
312 int _mmradio_destroy(mm_radio_t *radio)
314 int ret = MM_ERROR_NONE;
315 MMRADIO_LOG_FENTER();
317 MMRADIO_CHECK_INSTANCE(radio);
318 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_DESTROY);
320 _mmradio_unrealize(radio);
322 ret = radio_hal_interface_deinit(radio->hal_inf);
324 MMRADIO_LOG_ERROR("mmradio hal interface deinit failed\n");
327 #ifdef TIZEN_FEATURE_SOUND_FOCUS
328 ret = mmradio_sound_focus_deregister(&radio->sound_focus);
330 MMRADIO_LOG_ERROR("failed to deregister sound focus\n");
331 return MM_ERROR_RADIO_INTERNAL;
334 MMRADIO_LOG_FLEAVE();
336 return MM_ERROR_NONE;
339 /* unit should be KHz */
340 int _mmradio_set_frequency(mm_radio_t *radio, int freq)
342 int ret = MM_ERROR_NONE;
344 MMRADIO_LOG_FENTER();
346 MMRADIO_CHECK_INSTANCE(radio);
347 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_FREQ);
349 MMRADIO_LOG_DEBUG("Setting %d frequency\n", freq);
353 ret = radio_hal_set_frequency(radio->hal_inf, freq);
354 if (ret != MM_ERROR_NONE) {
355 MMRADIO_LOG_ERROR("radio_hal_set_frequency error");
356 MMRADIO_LOG_FLEAVE();
360 MMRADIO_LOG_FLEAVE();
366 int _mmradio_get_frequency(mm_radio_t *radio, int *pFreq)
368 int ret = MM_ERROR_NONE;
370 MMRADIO_LOG_FENTER();
372 MMRADIO_CHECK_INSTANCE(radio);
373 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_FREQ);
375 return_val_if_fail(pFreq, MM_ERROR_INVALID_ARGUMENT);
377 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
378 if (ret != MM_ERROR_NONE) {
379 MMRADIO_LOG_ERROR("radio_hal_get_frequency error");
384 /* update freq in handle */
387 *pFreq = (int)radio->freq;
389 MMRADIO_LOG_FLEAVE();
394 int _mmradio_mute(mm_radio_t *radio)
396 int ret = MM_ERROR_NONE;
397 MMRADIO_LOG_FENTER();
399 MMRADIO_CHECK_INSTANCE(radio);
400 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_MUTE);
402 ret = radio_hal_mute(radio->hal_inf);
403 if (ret == MM_ERROR_NOT_SUPPORT_API) {
404 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
405 } else if (ret != MM_ERROR_NONE) {
406 MMRADIO_LOG_ERROR("radio_hal_mute error");
407 MMRADIO_LOG_FLEAVE();
411 radio->is_muted = TRUE;
412 MMRADIO_LOG_FLEAVE();
417 int _mmradio_unmute(mm_radio_t *radio)
419 int ret = MM_ERROR_NONE;
420 MMRADIO_LOG_FENTER();
422 MMRADIO_CHECK_INSTANCE(radio);
423 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNMUTE);
425 ret = radio_hal_unmute(radio->hal_inf);
426 if (ret == MM_ERROR_NOT_SUPPORT_API) {
427 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
428 } else if (ret != MM_ERROR_NONE) {
429 MMRADIO_LOG_ERROR("radio_hal_unmute error");
430 MMRADIO_LOG_FLEAVE();
434 radio->is_muted = FALSE;
436 MMRADIO_LOG_FLEAVE();
441 int _mmradio_set_message_callback(mm_radio_t *radio, MMMessageCallback callback, void *user_param)
443 MMRADIO_LOG_FENTER();
445 MMRADIO_CHECK_INSTANCE(radio);
447 radio->msg_cb = callback;
448 radio->msg_cb_param = user_param;
450 MMRADIO_LOG_DEBUG("msg_cb : 0x%x msg_cb_param : 0x%x\n", callback, user_param);
452 MMRADIO_LOG_FLEAVE();
454 return MM_ERROR_NONE;
457 int _mmradio_get_state(mm_radio_t *radio, int *pState)
461 MMRADIO_LOG_FENTER();
463 MMRADIO_CHECK_INSTANCE(radio);
464 return_val_if_fail(pState, MM_ERROR_INVALID_ARGUMENT);
466 state = __mmradio_get_state(radio);
470 MMRADIO_LOG_FLEAVE();
472 return MM_ERROR_NONE;
475 int _mmradio_start(mm_radio_t *radio)
477 int ret = MM_ERROR_NONE;
479 MMRADIO_LOG_FENTER();
481 MMRADIO_CHECK_INSTANCE(radio);
482 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START);
484 MMRADIO_LOG_DEBUG("now tune to frequency : %d\n", radio->freq);
486 #ifdef TIZEN_FEATURE_SOUND_FOCUS
487 if (radio->sound_focus.handle > 0) {
488 ret = mmradio_acquire_sound_focus(&radio->sound_focus);
489 if (ret != MM_ERROR_NONE) {
490 MMRADIO_LOG_ERROR("failed to set sound focus");
496 if (!radio->is_ready) {
497 ret = radio_hal_prepare(radio->hal_inf);
498 if (ret == MM_ERROR_NOT_SUPPORT_API) {
499 MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
500 } else if (ret != MM_ERROR_NONE) {
501 MMRADIO_LOG_ERROR("radio_hal_prepare_device error");
505 ret = radio_hal_open(radio->hal_inf);
506 if (ret == MM_ERROR_NOT_SUPPORT_API) {
507 MMRADIO_LOG_WARNING("radio_hal_open is not supported");
508 } else if (ret != MM_ERROR_NONE) {
509 MMRADIO_LOG_ERROR("radio_hal_init error");
512 radio->is_ready = TRUE;
514 MMRADIO_LOG_DEBUG("radio prepared and opened");
517 ret = radio_hal_start(radio->hal_inf);
518 if (ret == MM_ERROR_NOT_SUPPORT_API) {
519 MMRADIO_LOG_WARNING("radio_hal_start is not supported");
521 MMRADIO_LOG_ERROR("failed to radio_hal_start\n");
525 /* set stored frequency */
526 ret = radio_hal_set_frequency(radio->hal_inf, radio->freq);
528 MMRADIO_LOG_ERROR("failed to radio_hal_set_frequency\n");
532 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
533 ret = sound_manager_start_virtual_stream(radio->vstream);
535 MMRADIO_LOG_ERROR("failed to sound_manager_start_virtual_stream\n");
540 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
542 MMRADIO_LOG_FLEAVE();
544 return MM_ERROR_NONE;
547 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
548 sound_manager_stop_virtual_stream(radio->vstream);
550 radio_hal_close(radio->hal_inf);
551 radio_hal_unprepare(radio->hal_inf);
555 int _mmradio_stop(mm_radio_t *radio)
557 int ret = MM_ERROR_NONE;
559 MMRADIO_LOG_FENTER();
561 MMRADIO_CHECK_INSTANCE(radio);
562 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP);
564 radio->seek_unmute = FALSE;
565 /*cancel if any seek*/
566 _mmradio_seek_cancel(radio);
567 #ifdef TIZEN_FEATURE_SOUND_VSTREAM
568 ret = sound_manager_stop_virtual_stream(radio->vstream);
570 ret = radio_hal_mute(radio->hal_inf);
571 if (ret == MM_ERROR_NOT_SUPPORT_API) {
572 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
574 MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
578 ret = radio_hal_stop(radio->hal_inf);
579 if (ret == MM_ERROR_NOT_SUPPORT_API) {
580 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
582 MMRADIO_LOG_ERROR("failed to radio_hal_stop\n");
586 /* close radio device here !!!! */
587 ret = radio_hal_close(radio->hal_inf);
588 if (ret == MM_ERROR_NOT_SUPPORT_API) {
589 MMRADIO_LOG_WARNING("radio_hal_close is not supported");
590 } else if (ret != MM_ERROR_NONE) {
591 MMRADIO_LOG_ERROR("radio_hal_close_device error");
594 ret = radio_hal_unprepare(radio->hal_inf);
595 if (ret == MM_ERROR_NOT_SUPPORT_API) {
596 MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
597 } else if (ret != MM_ERROR_NONE) {
598 MMRADIO_LOG_ERROR("radio_hal_close_device error");
602 radio->is_ready = FALSE;
604 #ifdef TIZEN_FEATURE_SOUND_FOCUS
605 if (radio->sound_focus.handle > 0) {
606 ret = mmradio_release_sound_focus(&radio->sound_focus);
608 MMRADIO_LOG_ERROR("mmradio_release_audio_focus is failed\n");
613 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
615 MMRADIO_LOG_FLEAVE();
617 return MM_ERROR_NONE;
620 int _mmradio_seek(mm_radio_t *radio, MMRadioSeekDirectionType direction)
622 int ret = MM_ERROR_NONE;
624 MMRADIO_LOG_FENTER();
626 MMRADIO_CHECK_INSTANCE(radio);
627 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SEEK);
629 if (radio->is_seeking) {
630 MMRADIO_LOG_ERROR("[RADIO_ERROR_INVALID_OPERATION]radio is seeking, can't serve another request try again");
631 return MM_ERROR_RADIO_INTERNAL;
634 radio->seek_unmute = FALSE;
635 radio->is_seeking = TRUE;
636 radio->seek_cancel = FALSE;
638 if (!radio->is_muted) {
639 ret = radio_hal_mute(radio->hal_inf);
640 if (ret == MM_ERROR_NOT_SUPPORT_API) {
641 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
643 MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
646 radio->seek_unmute = TRUE;
649 MMRADIO_LOG_DEBUG("trying to seek. direction[0:UP/1:DOWN) %d\n", direction);
650 radio->seek_direction = direction;
652 ret = pthread_create(&radio->seek_thread, NULL, (void *)__mmradio_seek_thread, (void *)radio);
655 MMRADIO_LOG_DEBUG("failed create thread\n");
656 radio->is_seeking = FALSE;
657 radio->seek_cancel = TRUE;
658 if (radio->seek_unmute) {
659 ret = radio_hal_mute(radio->hal_inf);
660 if (ret == MM_ERROR_NOT_SUPPORT_API) {
661 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
663 MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
664 radio->seek_unmute = FALSE;
668 return MM_ERROR_RADIO_INTERNAL;
671 MMRADIO_LOG_FLEAVE();
673 return MM_ERROR_NONE;
676 void _mmradio_seek_cancel(mm_radio_t *radio)
678 int ret = MM_ERROR_NONE;
679 char str_error[READ_MAX_BUFFER_SIZE];
680 MMRADIO_LOG_FENTER();
682 MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
684 /*cancel any outstanding seek request*/
685 radio->seek_cancel = TRUE;
686 if (radio->seek_thread) {
687 ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
688 MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
689 if (ret == EBUSY) { /* it was already locked by other */
690 MMRADIO_LOG_DEBUG("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
691 } else if (ret == 0) {
692 MMRADIO_LOG_DEBUG("trylock is successful. unlock now");
693 pthread_mutex_unlock(&radio->seek_cancel_mutex);
695 MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
697 MMRADIO_LOG_DEBUG("pthread_join seek_thread");
698 pthread_join(radio->seek_thread, NULL);
699 MMRADIO_LOG_DEBUG("done");
700 radio->is_seeking = FALSE;
701 radio->seek_thread = 0;
703 MMRADIO_LOG_FLEAVE();
707 int _mmradio_start_scan(mm_radio_t *radio)
709 int ret = MM_ERROR_NONE;
711 MMRADIO_LOG_FENTER();
713 MMRADIO_CHECK_INSTANCE(radio);
714 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START_SCAN);
718 radio->stop_scan = false;
720 if (!radio->is_ready) {
721 ret = radio_hal_prepare(radio->hal_inf);
722 if (ret == MM_ERROR_NOT_SUPPORT_API) {
723 MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
724 } else if (ret != MM_ERROR_NONE) {
725 MMRADIO_LOG_ERROR("radio_hal_prepare_device error");
729 ret = radio_hal_open(radio->hal_inf);
730 if (ret == MM_ERROR_NOT_SUPPORT_API) {
731 MMRADIO_LOG_WARNING("radio_hal_open is not supported");
732 } else if (ret != MM_ERROR_NONE) {
733 MMRADIO_LOG_ERROR("radio_hal_init error");
734 MMRADIO_LOG_FLEAVE();
737 radio->is_ready = TRUE;
739 MMRADIO_LOG_DEBUG("radio prepared and opened");
742 scan_tr_id = pthread_create(&radio->scan_thread, NULL, (void *)__mmradio_scan_thread, (void *)radio);
744 if (scan_tr_id != 0) {
745 MMRADIO_LOG_DEBUG("failed to create thread : scan\n");
746 return MM_ERROR_RADIO_NOT_INITIALIZED;
749 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
751 MMRADIO_LOG_FLEAVE();
753 return MM_ERROR_NONE;
756 int _mmradio_stop_scan(mm_radio_t *radio)
759 char str_error[READ_MAX_BUFFER_SIZE];
760 MMRADIO_LOG_FENTER();
762 MMRADIO_CHECK_INSTANCE(radio);
763 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP_SCAN);
765 radio->stop_scan = true;
767 if (radio->scan_thread > 0) {
768 /* make sure all the search is stopped else we'll wait till search finish which is not ideal*/
769 ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
770 MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
771 if (ret == EBUSY) { /* it was already locked by other */
772 MMRADIO_LOG_DEBUG("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
773 } else if (ret == 0) {
774 MMRADIO_LOG_DEBUG("trylock is successful. unlock now");
775 pthread_mutex_unlock(&radio->seek_cancel_mutex);
777 MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
779 MMRADIO_LOG_DEBUG("pthread_join scan_thread");
780 pthread_cancel(radio->scan_thread);
781 pthread_join(radio->scan_thread, NULL);
782 radio->scan_thread = 0;
785 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
786 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL);
788 MMRADIO_LOG_FLEAVE();
790 return MM_ERROR_NONE;
793 int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value)
795 int ret = MM_ERROR_NONE;
796 uint32_t strength = 0;
797 MMRADIO_LOG_FENTER();
798 MMRADIO_CHECK_INSTANCE(radio);
800 return_val_if_fail(value, MM_ERROR_INVALID_ARGUMENT);
802 /* just return stored frequency if radio device is not ready */
803 ret = radio_hal_get_signal_strength(radio->hal_inf, &strength);
804 if (ret == MM_ERROR_NOT_SUPPORT_API) {
805 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
806 } else if (ret != MM_ERROR_NONE) {
807 debug_error("radio_hal_get_signal_strength error\n");
809 MMRADIO_LOG_FLEAVE();
812 *value = (int)strength;
813 MMRADIO_LOG_FLEAVE();
814 return MM_ERROR_NONE;
817 void __mmradio_scan_thread(mm_radio_t *radio)
819 int ret = MM_ERROR_NONE;
822 MMRADIO_LOG_FENTER();
823 MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
825 ret = radio_hal_mute(radio->hal_inf);
827 if (ret == MM_ERROR_NOT_SUPPORT_API) {
828 MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
829 } else if (ret != MM_ERROR_NONE) {
830 MMRADIO_LOG_ERROR("radio_hal_mute error");
833 ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min);
835 if (ret != MM_ERROR_NONE)
838 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL);
839 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
841 while (!radio->stop_scan) {
843 MMMessageParamType param = { 0, };
845 MMRADIO_LOG_DEBUG("scanning....\n");
847 pthread_mutex_lock(&radio->seek_cancel_mutex);
849 if (radio->stop_scan) {
850 MMRADIO_LOG_DEBUG("scan was canceled");
851 pthread_mutex_unlock(&radio->seek_cancel_mutex);
855 ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP);
857 pthread_mutex_unlock(&radio->seek_cancel_mutex);
859 if (ret != MM_ERROR_NONE) {
860 MMRADIO_LOG_ERROR("radio scanning error");
864 /* now we can get new frequency from radio device */
865 if (radio->stop_scan)
868 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
869 if (ret != MM_ERROR_NONE) {
870 MMRADIO_LOG_ERROR("failed to get current frequency\n");
872 if (freq < prev_freq) {
873 MMRADIO_LOG_DEBUG("scanning wrapped around. stopping scan\n");
877 if (freq == prev_freq)
880 prev_freq = param.radio_scan.frequency = (int)freq;
881 MMRADIO_LOG_DEBUG("scanning : new frequency : [%d]\n", param.radio_scan.frequency);
883 /* drop if max freq is scanned */
884 if (param.radio_scan.frequency == radio->region_setting.band_max) {
885 MMRADIO_LOG_DEBUG("%d freq is dropping...and stopping scan\n", param.radio_scan.frequency);
889 if (radio->stop_scan) {
890 /* doesn't need to post */
894 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, ¶m);
898 if (radio->old_state == MM_RADIO_STATE_READY) {
899 MMRADIO_LOG_DEBUG("old state is ready");
900 } else if (radio->old_state == MM_RADIO_STATE_PLAYING) {
901 MMRADIO_LOG_DEBUG("old state is playing");
902 ret = radio_hal_unmute(radio->hal_inf);
903 if (ret == MM_ERROR_NOT_SUPPORT_API) {
904 MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
905 } else if (ret != MM_ERROR_NONE) {
906 MMRADIO_LOG_ERROR("radio_hal_unmute error");
909 ret = radio_hal_set_frequency(radio->hal_inf, prev_freq);
910 if (ret == MM_ERROR_NOT_SUPPORT_API) {
911 MMRADIO_LOG_WARNING("radio_hal_set_frequency is not supported");
912 } else if (ret != MM_ERROR_NONE) {
913 MMRADIO_LOG_ERROR("radio_hal_set_frequency error");
920 radio->scan_thread = 0;
922 if (radio->old_state == MM_RADIO_STATE_PLAYING) {
923 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
925 /* close radio device here !!!! */
926 ret = radio_hal_close(radio->hal_inf);
927 if (ret == MM_ERROR_NOT_SUPPORT_API)
928 MMRADIO_LOG_WARNING("radio_hal_close is not supported");
929 else if (ret != MM_ERROR_NONE)
930 MMRADIO_LOG_ERROR("radio_hal_close_device error");
932 ret = radio_hal_unprepare(radio->hal_inf);
933 if (ret == MM_ERROR_NOT_SUPPORT_API)
934 MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
935 else if (ret != MM_ERROR_NONE)
936 MMRADIO_LOG_ERROR("radio_hal_close_device error");
938 radio->is_ready = FALSE;
940 MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
943 if (!radio->stop_scan)
944 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL);
946 MMRADIO_LOG_FLEAVE();
953 bool __is_tunable_frequency(mm_radio_t *radio, int freq)
955 MMRADIO_LOG_FENTER();
957 MMRADIO_CHECK_INSTANCE(radio);
959 if (freq >= radio->region_setting.band_max
960 || freq <= radio->region_setting.band_min)
963 MMRADIO_LOG_FLEAVE();
968 void __mmradio_seek_thread(mm_radio_t *radio)
970 int ret = MM_ERROR_NONE;
972 MMMessageParamType param = {0, };
974 MMRADIO_LOG_FENTER();
975 MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
977 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL);
979 MMRADIO_LOG_DEBUG("seeking....\n");
981 if (!radio->seek_cancel) {
983 MMRADIO_LOG_DEBUG("try to seek ");
984 pthread_mutex_lock(&radio->seek_cancel_mutex);
985 MMRADIO_LOG_DEBUG("seek start\n");
987 if (radio->seek_cancel) {
988 MMRADIO_LOG_DEBUG("seek was canceled so we return failure to application");
989 pthread_mutex_unlock(&radio->seek_cancel_mutex);
993 ret = radio_hal_seek(radio->hal_inf, radio->seek_direction);
994 pthread_mutex_unlock(&radio->seek_cancel_mutex);
996 MMRADIO_LOG_ERROR("radio_hal_seek failed\n");
1000 /* now we can get new frequency from radio device */
1001 ret = radio_hal_get_frequency(radio->hal_inf, &freq);
1003 MMRADIO_LOG_ERROR("failed to get current frequency\n");
1007 MMRADIO_LOG_DEBUG("found frequency\n");
1009 /* if same freq is found, ignore it and search next one. */
1010 if (freq == radio->prev_seek_freq) {
1011 MMRADIO_LOG_DEBUG("It's same with previous found one. So, trying next one. \n");
1015 /* check if it's limit freq or not */
1016 if (__is_tunable_frequency(radio, freq)) {
1017 /* now tune to new frequency */
1018 ret = radio_hal_set_frequency(radio->hal_inf, freq);
1020 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1025 if (radio->seek_unmute) {
1026 /* now turn on radio
1027 * In the case of limit freq, tuner should be unmuted.
1028 * Otherwise, sound can't output even though application set new frequency.
1030 ret = radio_hal_unmute(radio->hal_inf);
1032 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1035 radio->seek_unmute = FALSE;
1038 param.radio_scan.frequency = radio->prev_seek_freq = (int)freq;
1039 MMRADIO_LOG_DEBUG("seeking : new frequency : [%d]\n", param.radio_scan.frequency);
1040 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, ¶m);
1043 radio->seek_thread = 0;
1044 radio->is_seeking = FALSE;
1046 MMRADIO_LOG_FLEAVE();
1053 if (radio->seek_unmute) {
1054 /* now turn on radio
1055 * In the case of limit freq, tuner should be unmuted.
1056 * Otherwise, sound can't output even though application set new frequency.
1058 ret = radio_hal_unmute(radio->hal_inf);
1060 MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
1061 radio->seek_unmute = FALSE;
1063 /* freq -1 means it's failed to seek */
1064 param.radio_scan.frequency = -1;
1065 MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, ¶m);
1066 radio->is_seeking = FALSE;
1071 static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param)
1073 MMRADIO_CHECK_INSTANCE(radio);
1075 MMRADIO_LOG_FENTER();
1077 if (!radio->msg_cb) {
1078 debug_warning("failed to post a message\n");
1082 MMRADIO_LOG_DEBUG("address of msg_cb : %p\n", radio->msg_cb);
1084 radio->msg_cb(msgtype, param, radio->msg_cb_param);
1086 MMRADIO_LOG_FLEAVE();
1091 static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command)
1093 MMRadioStateType radio_state = MM_RADIO_STATE_NUM;
1095 MMRADIO_LOG_FENTER();
1097 MMRADIO_CHECK_INSTANCE(radio);
1099 radio_state = __mmradio_get_state(radio);
1101 MMRADIO_LOG_DEBUG("incomming command : %d current state : %d\n", command, radio_state);
1104 case MMRADIO_COMMAND_CREATE:
1106 if (radio_state != 0)
1111 case MMRADIO_COMMAND_REALIZE:
1113 if (radio_state == MM_RADIO_STATE_READY ||
1114 radio_state == MM_RADIO_STATE_PLAYING ||
1115 radio_state == MM_RADIO_STATE_SCANNING)
1118 if (radio_state == 0)
1123 case MMRADIO_COMMAND_UNREALIZE:
1125 if (radio_state == MM_RADIO_STATE_NULL)
1128 /* we can call unrealize at any higher state */
1132 case MMRADIO_COMMAND_START:
1134 if (radio_state == MM_RADIO_STATE_PLAYING)
1137 if (radio_state != MM_RADIO_STATE_READY)
1142 case MMRADIO_COMMAND_STOP:
1144 if (radio_state == MM_RADIO_STATE_READY)
1147 if (radio_state != MM_RADIO_STATE_PLAYING)
1152 case MMRADIO_COMMAND_START_SCAN:
1154 if (radio_state == MM_RADIO_STATE_SCANNING)
1157 if (radio_state == MM_RADIO_STATE_NULL)
1162 case MMRADIO_COMMAND_STOP_SCAN:
1164 if (radio_state == MM_RADIO_STATE_READY)
1167 if (radio_state != MM_RADIO_STATE_SCANNING)
1172 case MMRADIO_COMMAND_DESTROY:
1173 case MMRADIO_COMMAND_MUTE:
1174 case MMRADIO_COMMAND_UNMUTE:
1175 case MMRADIO_COMMAND_SET_FREQ:
1176 case MMRADIO_COMMAND_GET_FREQ:
1177 case MMRADIO_COMMAND_SET_REGION:
1179 /* we can do it at any state */
1183 case MMRADIO_COMMAND_SEEK:
1185 if (radio_state != MM_RADIO_STATE_PLAYING)
1190 case MMRADIO_COMMAND_GET_REGION:
1192 if (radio_state == MM_RADIO_STATE_NULL)
1198 MMRADIO_LOG_DEBUG("not handled in FSM. don't care it\n");
1202 MMRADIO_LOG_DEBUG("status OK\n");
1204 radio->cmd = command;
1206 MMRADIO_LOG_FLEAVE();
1208 return MM_ERROR_NONE;
1211 debug_warning("invalid state. current : %d command : %d\n", radio_state, command);
1212 MMRADIO_LOG_FLEAVE();
1213 return MM_ERROR_RADIO_INVALID_STATE;
1216 debug_warning("mm-radio is in the desired state(%d). doing noting\n", radio_state);
1217 MMRADIO_LOG_FLEAVE();
1218 return MM_ERROR_RADIO_NO_OP;
1222 static bool __mmradio_set_state(mm_radio_t *radio, int new_state)
1224 MMMessageParamType msg = { 0, };
1225 int msg_type = MM_MESSAGE_UNKNOWN;
1227 MMRADIO_LOG_FENTER();
1228 MMRADIO_CHECK_INSTANCE(radio);
1231 debug_warning("calling set_state with invalid radio handle\n");
1235 if (radio->current_state == new_state && radio->pending_state == 0) {
1236 debug_warning("we are in same state\n");
1241 radio->old_state = radio->current_state;
1242 radio->current_state = new_state;
1244 /* fill message param */
1245 msg.state.previous = radio->old_state;
1246 msg.state.current = radio->current_state;
1248 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1249 /* post message to application */
1250 switch (radio->sound_focus.by_focus_cb) {
1251 case MMRADIO_FOCUS_CB_NONE:
1253 msg_type = MM_MESSAGE_STATE_CHANGED;
1254 MMRADIO_POST_MSG(radio, msg_type, &msg);
1258 case MMRADIO_FOCUS_CB_POSTMSG:
1260 msg_type = MM_MESSAGE_STATE_INTERRUPTED;
1261 msg.union_type = MM_MSG_UNION_CODE;
1262 msg.code = radio->sound_focus.event_src;
1263 MMRADIO_POST_MSG(radio, msg_type, &msg);
1267 case MMRADIO_FOCUS_CB_SKIP_POSTMSG:
1272 msg_type = MM_MESSAGE_STATE_CHANGED;
1273 MMRADIO_POST_MSG(radio, msg_type, &msg);
1276 MMRADIO_LOG_FLEAVE();
1281 static int __mmradio_get_state(mm_radio_t *radio)
1283 MMRADIO_CHECK_INSTANCE(radio);
1285 MMRADIO_LOG_DEBUG("radio state : current : [%d] old : [%d] pending : [%d]\n",
1286 radio->current_state, radio->old_state, radio->pending_state);
1288 return radio->current_state;
1291 #ifdef TIZEN_FEATURE_SOUND_FOCUS
1292 static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
1293 mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
1294 const char *additional_info, void *user_data)
1296 mm_radio_t *radio = (mm_radio_t *)user_data;
1297 enum MMMessageInterruptedCode event_source;
1298 int result = MM_ERROR_NONE;
1299 int postMsg = false;
1301 MMRADIO_LOG_FENTER();
1302 MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1304 mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
1305 radio->sound_focus.event_src = event_source;
1307 switch (focus_state) {
1308 case FOCUS_IS_RELEASED:{
1309 radio->sound_focus.cur_focus_type &= ~focus_type;
1310 radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
1312 result = _mmradio_stop(radio);
1314 MMRADIO_LOG_ERROR("failed to stop radio\n");
1316 MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1320 case FOCUS_IS_ACQUIRED:{
1321 MMMessageParamType msg = { 0, };
1322 msg.union_type = MM_MSG_UNION_CODE;
1323 msg.code = event_source;
1325 radio->sound_focus.cur_focus_type |= focus_type;
1327 if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1328 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1330 radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
1332 MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1337 MMRADIO_LOG_DEBUG("Unknown focus_state\n");
1341 MMRADIO_LOG_FLEAVE();
1344 static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
1345 mm_sound_focus_state_e focus_state, const char *reason_for_change,
1346 const char *additional_info, void *user_data)
1348 mm_radio_t *radio = (mm_radio_t *)user_data;
1349 enum MMMessageInterruptedCode event_source;
1350 int result = MM_ERROR_NONE;
1351 int postMsg = false;
1353 MMRADIO_LOG_FENTER();
1354 MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
1356 mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
1357 radio->sound_focus.event_src = event_source;
1359 switch (focus_state) {
1360 case FOCUS_IS_ACQUIRED: {
1361 radio->sound_focus.cur_focus_type &= ~focus_type;
1362 radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
1364 result = _mmradio_stop(radio);
1366 MMRADIO_LOG_ERROR("failed to stop radio\n");
1368 MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1372 case FOCUS_IS_RELEASED: {
1373 MMMessageParamType msg = { 0, };
1374 msg.union_type = MM_MSG_UNION_CODE;
1375 msg.code = event_source;
1377 radio->sound_focus.cur_focus_type |= focus_type;
1379 if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
1380 MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
1382 radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
1384 MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
1389 MMRADIO_LOG_DEBUG("Unknown focus_state\n");
1393 MMRADIO_LOG_FLEAVE();
1397 int _mmradio_get_region_type(mm_radio_t *radio, MMRadioRegionType *type)
1399 MMRADIO_LOG_FENTER();
1400 MMRADIO_CHECK_INSTANCE(radio);
1401 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1403 return_val_if_fail(type, MM_ERROR_INVALID_ARGUMENT);
1405 *type = radio->region_setting.country;
1407 MMRADIO_LOG_FLEAVE();
1408 return MM_ERROR_NONE;
1411 int _mmradio_get_region_frequency_range(mm_radio_t *radio, unsigned int *min_freq, unsigned int *max_freq)
1413 MMRADIO_LOG_FENTER();
1414 MMRADIO_CHECK_INSTANCE(radio);
1415 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1417 return_val_if_fail(min_freq && max_freq, MM_ERROR_INVALID_ARGUMENT);
1419 *min_freq = radio->region_setting.band_min;
1420 *max_freq = radio->region_setting.band_max;
1422 MMRADIO_LOG_FLEAVE();
1423 return MM_ERROR_NONE;
1426 int _mmradio_get_channel_spacing(mm_radio_t *radio, unsigned int *ch_spacing)
1428 MMRADIO_LOG_FENTER();
1429 MMRADIO_CHECK_INSTANCE(radio);
1430 MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
1432 return_val_if_fail(ch_spacing, MM_ERROR_INVALID_ARGUMENT);
1434 *ch_spacing = radio->region_setting.channel_spacing;
1436 MMRADIO_LOG_FLEAVE();
1437 return MM_ERROR_NONE;