summaryrefslogtreecommitdiff
path: root/src/mm_radio_priv_hal.c
diff options
context:
space:
mode:
authorGilbok Lee <gilbok.lee@samsung.com>2016-10-20 19:44:41 +0900
committerGilbok Lee <gilbok.lee@samsung.com>2016-11-03 19:25:54 +0900
commit4dd8d5309b074cab27a5dac23dd92cbc1d47803b (patch)
tree63d0e5232a97a964a613331b3f6ca82f28b991ed /src/mm_radio_priv_hal.c
parent6779ede5625e9c3003c06d8b8399a7cc9bcf1ed7 (diff)
downloadlibmm-radio-4dd8d5309b074cab27a5dac23dd92cbc1d47803b.tar.gz
libmm-radio-4dd8d5309b074cab27a5dac23dd92cbc1d47803b.tar.bz2
libmm-radio-4dd8d5309b074cab27a5dac23dd92cbc1d47803b.zip
First version of libmm-radio using radio-hal
[Version] 0.2.7 [Profile] Mobile [Issue Type] Refactoring Change-Id: I332bae2294a30988afb5a8c65864336277b1d5c9
Diffstat (limited to 'src/mm_radio_priv_hal.c')
-rw-r--r--src/mm_radio_priv_hal.c1438
1 files changed, 1438 insertions, 0 deletions
diff --git a/src/mm_radio_priv_hal.c b/src/mm_radio_priv_hal.c
new file mode 100644
index 0000000..6ac3757
--- /dev/null
+++ b/src/mm_radio_priv_hal.c
@@ -0,0 +1,1438 @@
+/*
+ * mm_radio_priv_hal.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*===========================================================================================
+| |
+| INCLUDE FILES |
+| |
+========================================================================================== */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <mm_error.h>
+#include <mm_debug.h>
+#include <mm_message.h>
+
+#include "mm_radio_priv_hal.h"
+
+/*===========================================================================================
+ LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE
+========================================================================================== */
+/*---------------------------------------------------------------------------
+ GLOBAL CONSTANT DEFINITIONS:
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ IMPORTED VARIABLE DECLARATIONS:
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ IMPORTED FUNCTION DECLARATIONS:
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ LOCAL #defines:
+---------------------------------------------------------------------------*/
+#define DEFAULT_DEVICE "/dev/radio0"
+#define TUNER_INDEX 0
+
+#define DEFAULT_FREQ 107700
+
+#define FREQ_FRAC 16
+#define RADIO_FREQ_FORMAT_SET(x_freq) ((x_freq) * FREQ_FRAC)
+#define RADIO_FREQ_FORMAT_GET(x_freq) ((x_freq) / FREQ_FRAC)
+/* If non-zero, wrap around when at the end of the frequency range, else stop seeking */
+#define DEFAULT_WRAP_AROUND 1
+
+#define RADIO_DEFAULT_REGION MM_RADIO_REGION_GROUP_USA
+#define READ_MAX_BUFFER_SIZE 1024
+/*---------------------------------------------------------------------------
+ LOCAL CONSTANT DEFINITIONS:
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ LOCAL DATA TYPE DEFINITIONS:
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ GLOBAL VARIABLE DEFINITIONS:
+---------------------------------------------------------------------------*/
+extern int errno;
+
+/*---------------------------------------------------------------------------
+ LOCAL VARIABLE DEFINITIONS:
+---------------------------------------------------------------------------*/
+/* radio region configuration table */
+static const MMRadioRegion_t region_table[] = {
+ { /* Notrh America, South America, South Korea, Taiwan, Australia */
+ MM_RADIO_REGION_GROUP_USA, /* region type */
+ MM_RADIO_DEEMPHASIS_75_US, /* de-emphasis */
+ MM_RADIO_FREQ_MIN_87500_KHZ, /* min freq. */
+ MM_RADIO_FREQ_MAX_108000_KHZ, /* max freq. */
+ 50,
+ },
+ { /* China, Europe, Africa, Middle East, Hong Kong, India, Indonesia, Russia, Singapore */
+ MM_RADIO_REGION_GROUP_EUROPE,
+ MM_RADIO_DEEMPHASIS_50_US,
+ MM_RADIO_FREQ_MIN_87500_KHZ,
+ MM_RADIO_FREQ_MAX_108000_KHZ,
+ 50,
+ },
+ {
+ MM_RADIO_REGION_GROUP_JAPAN,
+ MM_RADIO_DEEMPHASIS_50_US,
+ MM_RADIO_FREQ_MIN_76100_KHZ,
+ MM_RADIO_FREQ_MAX_89900_KHZ,
+ 50,
+ },
+};
+
+/*---------------------------------------------------------------------------
+ LOCAL FUNCTION PROTOTYPES:
+---------------------------------------------------------------------------*/
+static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param);
+static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command);
+static int __mmradio_get_state(mm_radio_t *radio);
+static bool __mmradio_set_state(mm_radio_t *radio, int new_state);
+void _mmradio_seek_cancel(mm_radio_t *radio);
+static void __mmradio_seek_thread(mm_radio_t *radio);
+static void __mmradio_scan_thread(mm_radio_t *radio);
+static bool __is_tunable_frequency(mm_radio_t *radio, int freq);
+
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
+ mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
+ const char *additional_info, void *user_data);
+static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
+ mm_sound_focus_state_e focus_state, const char *reason_for_change,
+ const char *additional_info, void *user_data);
+#endif
+
+int _mmradio_apply_region(mm_radio_t *radio, MMRadioRegionType region, bool update)
+{
+ int ret = MM_ERROR_NONE;
+ int count = 0;
+ int index = 0;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_REGION);
+
+ /* if needed, radio region must be updated.
+ * Otherwise, just applying settings to device without it.
+ */
+ if (update) {
+ count = ARRAY_SIZE(region_table);
+
+ /* TODO: if auto is supported...get the region info. here */
+
+ /* update radio region settings */
+ for (index = 0; index < count; index++) {
+ /* find the region from pre-defined table */
+ if (region_table[index].country == region) {
+ radio->region_setting.country = region_table[index].country;
+ radio->region_setting.deemphasis = region_table[index].deemphasis;
+ radio->region_setting.band_min = region_table[index].band_min;
+ radio->region_setting.band_max = region_table[index].band_max;
+ radio->region_setting.channel_spacing = region_table[index].channel_spacing;
+ }
+ }
+ }
+
+ MMRADIO_LOG_DEBUG("setting region - country: %d, de-emphasis: %d, band range: %d ~ %d KHz\n",
+ radio->region_setting.country, radio->region_setting.deemphasis,
+ radio->region_setting.band_min, radio->region_setting.band_max);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return ret;
+}
+
+int _mmradio_create_radio(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_CREATE);
+
+ /* set default value */
+ radio->freq = DEFAULT_FREQ;
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+ memset(&radio->sound_focus, 0, sizeof(mm_radio_sound_focus));
+#endif
+ memset(&radio->region_setting, 0, sizeof(MMRadioRegion_t));
+
+ /* create command lock */
+ ret = pthread_mutex_init(&radio->cmd_lock, NULL);
+ if (ret) {
+ MMRADIO_LOG_ERROR("mutex creation failed\n");
+ return MM_ERROR_RADIO_INTERNAL;
+ }
+
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
+
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+ ret = mmradio_sound_focus_register(&radio->sound_focus,
+ (mm_sound_focus_changed_cb)__mmradio_sound_focus_cb,
+ (mm_sound_focus_changed_watch_cb)__mmradio_sound_focus_watch_cb,
+ (void *)radio);
+
+ if (ret) {
+ /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
+ MMRADIO_LOG_ERROR("mmradio_audio_focus_register is failed\n");
+ return MM_ERROR_RADIO_INTERNAL;
+ }
+#endif
+
+ ret = radio_hal_interface_init(&(radio->hal_inf));
+ if (ret) {
+ MMRADIO_LOG_ERROR("mmradio hal interface init failed\n");
+ return ret;
+ }
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_realize(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ bool update = false;
+ MMRadioRegionType region = MM_RADIO_REGION_GROUP_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_REALIZE);
+
+ ret = pthread_mutex_init(&radio->seek_cancel_mutex, NULL);
+ if (ret < 0) {
+ MMRADIO_LOG_DEBUG("Mutex creation failed %d", ret);
+ }
+
+ if (radio->region_setting.country == MM_RADIO_REGION_GROUP_NONE) {
+ /* not initialized yet. set it with default region */
+ region = RADIO_DEFAULT_REGION;
+ update = true;
+ } else {
+ /* already initialized by application */
+ region = radio->region_setting.country;
+ }
+
+ ret = _mmradio_apply_region(radio, region, update);
+
+#ifdef TIZEN_FEATURE_SOUND_VSTREAM
+ ret = sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_RADIO, NULL, radio, &radio->stream_info);
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("sound_manager_create_stream_information_internal error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+ ret = sound_manager_create_virtual_stream(radio->stream_info, &radio->vstream);
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("sound_manager_create_virtual_stream error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+#endif
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_unrealize(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNREALIZE);
+
+ ret = radio_hal_unmute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_unmute error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+
+ /*Finish if there are scans*/
+ _mmradio_stop_scan(radio);
+
+ /*Stop radio if started*/
+ _mmradio_stop(radio);
+
+ /* close radio device here !!!! */
+ radio_hal_close(radio->hal_inf);
+ radio_hal_unprepare(radio->hal_inf);
+#ifdef TIZEN_FEATURE_SOUND_VSTREAM
+ sound_manager_destroy_virtual_stream(radio->vstream);
+ sound_manager_destroy_stream_information(radio->stream_info);
+#endif
+ pthread_mutex_destroy(&radio->seek_cancel_mutex);
+
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_destroy(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_DESTROY);
+
+ _mmradio_unrealize(radio);
+
+ ret = radio_hal_interface_deinit(radio->hal_inf);
+ if (ret) {
+ MMRADIO_LOG_ERROR("mmradio hal interface deinit failed\n");
+ return ret;
+ }
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+ ret = mmradio_sound_focus_deregister(&radio->sound_focus);
+ if (ret) {
+ MMRADIO_LOG_ERROR("failed to deregister sound focus\n");
+ return MM_ERROR_RADIO_INTERNAL;
+ }
+#endif
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+/* unit should be KHz */
+int _mmradio_set_frequency(mm_radio_t *radio, int freq)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_FREQ);
+
+ MMRADIO_LOG_DEBUG("Setting %d frequency\n", freq);
+
+ radio->freq = freq;
+
+ ret = radio_hal_set_frequency(radio->hal_inf, freq);
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_set_frequency error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+
+ MMRADIO_LOG_FLEAVE();
+
+ return ret;
+
+}
+
+int _mmradio_get_frequency(mm_radio_t *radio, int *pFreq)
+{
+ int ret = MM_ERROR_NONE;
+ uint32_t freq = 0;
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_FREQ);
+
+ return_val_if_fail(pFreq, MM_ERROR_INVALID_ARGUMENT);
+
+ ret = radio_hal_get_frequency(radio->hal_inf, &freq);
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_get_frequency error");
+ *pFreq = 0;
+ return ret;
+ }
+
+ /* update freq in handle */
+ radio->freq = freq;
+
+ *pFreq = (int)radio->freq;
+
+ MMRADIO_LOG_FLEAVE();
+
+ return ret;
+}
+
+int _mmradio_mute(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_MUTE);
+
+ ret = radio_hal_mute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_mute error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+
+ radio->is_muted = TRUE;
+ MMRADIO_LOG_FLEAVE();
+
+ return ret;
+}
+
+int _mmradio_unmute(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNMUTE);
+
+ ret = radio_hal_unmute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_unmute error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+
+ radio->is_muted = FALSE;
+
+ MMRADIO_LOG_FLEAVE();
+
+ return ret;
+}
+
+int _mmradio_set_message_callback(mm_radio_t *radio, MMMessageCallback callback, void *user_param)
+{
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ radio->msg_cb = callback;
+ radio->msg_cb_param = user_param;
+
+ MMRADIO_LOG_DEBUG("msg_cb : 0x%x msg_cb_param : 0x%x\n", callback, user_param);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_get_state(mm_radio_t *radio, int *pState)
+{
+ int state = 0;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ return_val_if_fail(pState, MM_ERROR_INVALID_ARGUMENT);
+
+ state = __mmradio_get_state(radio);
+
+ *pState = state;
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_start(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START);
+
+ MMRADIO_LOG_DEBUG("now tune to frequency : %d\n", radio->freq);
+
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+ if (radio->sound_focus.handle > 0) {
+ ret = mmradio_acquire_sound_focus(&radio->sound_focus);
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("failed to set sound focus");
+ return ret;
+ }
+ }
+#endif
+
+ if (!radio->is_ready) {
+ ret = radio_hal_prepare(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_prepare_device error");
+ goto error;
+ }
+
+ ret = radio_hal_open(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_open is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_init error");
+ goto error;
+ }
+ radio->is_ready = TRUE;
+ } else {
+ MMRADIO_LOG_DEBUG("radio prepared and opened");
+ }
+
+ ret = radio_hal_start(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_start is not supported");
+ } else if (ret) {
+ MMRADIO_LOG_ERROR("failed to radio_hal_start\n");
+ goto error;
+ }
+
+ /* set stored frequency */
+ ret = radio_hal_set_frequency(radio->hal_inf, radio->freq);
+ if (ret) {
+ MMRADIO_LOG_ERROR("failed to radio_hal_set_frequency\n");
+ goto error;
+ }
+
+#ifdef TIZEN_FEATURE_SOUND_VSTREAM
+ ret = sound_manager_start_virtual_stream(radio->vstream);
+ if (ret) {
+ MMRADIO_LOG_ERROR("failed to sound_manager_start_virtual_stream\n");
+ goto error;
+ }
+#endif
+
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+
+error:
+#ifdef TIZEN_FEATURE_SOUND_VSTREAM
+ sound_manager_stop_virtual_stream(radio->vstream);
+#endif
+ radio_hal_close(radio->hal_inf);
+ radio_hal_unprepare(radio->hal_inf);
+ return ret;
+}
+
+int _mmradio_stop(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP);
+
+ radio->seek_unmute = FALSE;
+ /*cancel if any seek*/
+ _mmradio_seek_cancel(radio);
+#ifdef TIZEN_FEATURE_SOUND_VSTREAM
+ ret = sound_manager_stop_virtual_stream(radio->vstream);
+#endif
+ ret = radio_hal_mute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
+ } else if (ret) {
+ MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
+ return ret;
+ }
+
+ ret = radio_hal_stop(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
+ } else if (ret) {
+ MMRADIO_LOG_ERROR("failed to radio_hal_stop\n");
+ return ret;
+ }
+
+ /* close radio device here !!!! */
+ ret = radio_hal_close(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_close is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_close_device error");
+ return ret;
+ }
+ ret = radio_hal_unprepare(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_close_device error");
+ return ret;
+ }
+
+ radio->is_ready = FALSE;
+
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+ if (radio->sound_focus.handle > 0) {
+ ret = mmradio_release_sound_focus(&radio->sound_focus);
+ if (ret) {
+ MMRADIO_LOG_ERROR("mmradio_release_audio_focus is failed\n");
+ return ret;
+ }
+ }
+#endif
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_seek(mm_radio_t *radio, MMRadioSeekDirectionType direction)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SEEK);
+
+ if (radio->is_seeking) {
+ MMRADIO_LOG_ERROR("[RADIO_ERROR_INVALID_OPERATION]radio is seeking, can't serve another request try again");
+ return MM_ERROR_RADIO_INTERNAL;
+ }
+
+ radio->seek_unmute = FALSE;
+ radio->is_seeking = TRUE;
+ radio->seek_cancel = FALSE;
+
+ if (!radio->is_muted) {
+ ret = radio_hal_mute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
+ } else if (ret) {
+ MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
+ return ret;
+ }
+ radio->seek_unmute = TRUE;
+ }
+
+ MMRADIO_LOG_DEBUG("trying to seek. direction[0:UP/1:DOWN) %d\n", direction);
+ radio->seek_direction = direction;
+
+ ret = pthread_create(&radio->seek_thread, NULL, (void *)__mmradio_seek_thread, (void *)radio);
+
+ if (ret) {
+ MMRADIO_LOG_DEBUG("failed create thread\n");
+ radio->is_seeking = FALSE;
+ radio->seek_cancel = TRUE;
+ if (radio->seek_unmute) {
+ ret = radio_hal_mute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
+ } else if (ret) {
+ MMRADIO_LOG_ERROR("failed to radio_hal_mute\n");
+ radio->seek_unmute = FALSE;
+ return ret;
+ }
+ }
+ return MM_ERROR_RADIO_INTERNAL;
+ }
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+void _mmradio_seek_cancel(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ char str_error[READ_MAX_BUFFER_SIZE];
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
+
+ /*cancel any outstanding seek request*/
+ radio->seek_cancel = TRUE;
+ if (radio->seek_thread) {
+ ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
+ MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
+ if (ret == EBUSY) { /* it was already locked by other */
+ MMRADIO_LOG_DEBUG("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
+ } else if (ret == 0) {
+ MMRADIO_LOG_DEBUG("trylock is successful. unlock now");
+ pthread_mutex_unlock(&radio->seek_cancel_mutex);
+ } else {
+ MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
+ }
+ MMRADIO_LOG_DEBUG("pthread_join seek_thread");
+ pthread_join(radio->seek_thread, NULL);
+ MMRADIO_LOG_DEBUG("done");
+ radio->is_seeking = FALSE;
+ radio->seek_thread = 0;
+ }
+ MMRADIO_LOG_FLEAVE();
+}
+
+
+int _mmradio_start_scan(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START_SCAN);
+
+ int scan_tr_id = 0;
+
+ radio->stop_scan = false;
+
+ if (!radio->is_ready) {
+ ret = radio_hal_prepare(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_prepare is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_prepare_device error");
+ return ret;
+ }
+
+ ret = radio_hal_open(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_open is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_init error");
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+ radio->is_ready = TRUE;
+ } else {
+ MMRADIO_LOG_DEBUG("radio prepared and opened");
+ }
+
+ scan_tr_id = pthread_create(&radio->scan_thread, NULL, (void *)__mmradio_scan_thread, (void *)radio);
+
+ if (scan_tr_id != 0) {
+ MMRADIO_LOG_DEBUG("failed to create thread : scan\n");
+ return MM_ERROR_RADIO_NOT_INITIALIZED;
+ }
+
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_stop_scan(mm_radio_t *radio)
+{
+ int ret = 0;
+ char str_error[READ_MAX_BUFFER_SIZE];
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP_SCAN);
+
+ radio->stop_scan = true;
+
+ if (radio->scan_thread > 0) {
+ /* make sure all the search is stopped else we'll wait till search finish which is not ideal*/
+ ret = pthread_mutex_trylock(&radio->seek_cancel_mutex);
+ MMRADIO_LOG_DEBUG("try lock ret: %s (%d)", strerror_r(ret, str_error, sizeof(str_error)), ret);
+ if (ret == EBUSY) { /* it was already locked by other */
+ MMRADIO_LOG_DEBUG("send SEEK ABORT with FMRX_PROPERTY_SEARCH_ABORT");
+ } else if (ret == 0) {
+ MMRADIO_LOG_DEBUG("trylock is successful. unlock now");
+ pthread_mutex_unlock(&radio->seek_cancel_mutex);
+ } else {
+ MMRADIO_LOG_ERROR("trylock is failed but Not EBUSY. ret: %d", ret);
+ }
+ MMRADIO_LOG_DEBUG("pthread_join scan_thread");
+ pthread_cancel(radio->scan_thread);
+ pthread_join(radio->scan_thread, NULL);
+ radio->scan_thread = 0;
+ }
+
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+}
+
+int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value)
+{
+ int ret = MM_ERROR_NONE;
+ uint32_t strength = 0;
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ return_val_if_fail(value, MM_ERROR_INVALID_ARGUMENT);
+
+ /* just return stored frequency if radio device is not ready */
+ ret = radio_hal_get_signal_strength(radio->hal_inf, &strength);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ debug_error("radio_hal_get_signal_strength error\n");
+ *value = 0;
+ MMRADIO_LOG_FLEAVE();
+ return ret;
+ }
+ *value = (int)strength;
+ MMRADIO_LOG_FLEAVE();
+ return MM_ERROR_NONE;
+}
+
+void __mmradio_scan_thread(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ int prev_freq = 0;
+
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
+
+ ret = radio_hal_mute(radio->hal_inf);
+
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_mute is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_mute error");
+ goto FINISHED;
+ }
+ ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min);
+
+ if (ret != MM_ERROR_NONE)
+ goto FINISHED;
+
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL);
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING);
+
+ while (!radio->stop_scan) {
+ uint32_t freq = 0;
+ MMMessageParamType param = { 0, };
+
+ MMRADIO_LOG_DEBUG("scanning....\n");
+
+ pthread_mutex_lock(&radio->seek_cancel_mutex);
+
+ if (radio->stop_scan) {
+ MMRADIO_LOG_DEBUG("scan was canceled");
+ pthread_mutex_unlock(&radio->seek_cancel_mutex);
+ goto FINISHED;
+ }
+
+ ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP);
+
+ pthread_mutex_unlock(&radio->seek_cancel_mutex);
+
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio scanning error");
+ break;
+ }
+
+ /* now we can get new frequency from radio device */
+ if (radio->stop_scan)
+ break;
+
+ ret = radio_hal_get_frequency(radio->hal_inf, &freq);
+ if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("failed to get current frequency\n");
+ } else {
+ if (freq < prev_freq) {
+ MMRADIO_LOG_DEBUG("scanning wrapped around. stopping scan\n");
+ break;
+ }
+
+ if (freq == prev_freq)
+ continue;
+
+ prev_freq = param.radio_scan.frequency = (int)freq;
+ MMRADIO_LOG_DEBUG("scanning : new frequency : [%d]\n", param.radio_scan.frequency);
+
+ /* drop if max freq is scanned */
+ if (param.radio_scan.frequency == radio->region_setting.band_max) {
+ MMRADIO_LOG_DEBUG("%d freq is dropping...and stopping scan\n", param.radio_scan.frequency);
+ break;
+ }
+
+ if (radio->stop_scan) {
+ /* doesn't need to post */
+ break;
+ }
+
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, &param);
+ }
+ }
+FINISHED:
+ if (radio->old_state == MM_RADIO_STATE_READY) {
+ MMRADIO_LOG_DEBUG("old state is ready");
+ } else if (radio->old_state == MM_RADIO_STATE_PLAYING) {
+ MMRADIO_LOG_DEBUG("old state is playing");
+ ret = radio_hal_unmute(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_unmute is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_unmute error");
+ goto FINISHED_ERR;
+ }
+ ret = radio_hal_set_frequency(radio->hal_inf, prev_freq);
+ if (ret == MM_ERROR_NOT_SUPPORT_API) {
+ MMRADIO_LOG_WARNING("radio_hal_set_frequency is not supported");
+ } else if (ret != MM_ERROR_NONE) {
+ MMRADIO_LOG_ERROR("radio_hal_set_frequency error");
+ goto FINISHED_ERR;
+ }
+ }
+
+FINISHED_ERR:
+
+ radio->scan_thread = 0;
+
+ if (radio->old_state == MM_RADIO_STATE_PLAYING) {
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING);
+ } else {
+ /* close radio device here !!!! */
+ ret = radio_hal_close(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API)
+ MMRADIO_LOG_WARNING("radio_hal_close is not supported");
+ else if (ret != MM_ERROR_NONE)
+ MMRADIO_LOG_ERROR("radio_hal_close_device error");
+
+ ret = radio_hal_unprepare(radio->hal_inf);
+ if (ret == MM_ERROR_NOT_SUPPORT_API)
+ MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported");
+ else if (ret != MM_ERROR_NONE)
+ MMRADIO_LOG_ERROR("radio_hal_close_device error");
+
+ radio->is_ready = FALSE;
+
+ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY);
+ }
+
+ if (!radio->stop_scan)
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL);
+
+ MMRADIO_LOG_FLEAVE();
+
+ pthread_exit(NULL);
+
+ return;
+}
+
+bool __is_tunable_frequency(mm_radio_t *radio, int freq)
+{
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ if (freq >= radio->region_setting.band_max
+ || freq <= radio->region_setting.band_min)
+ return false;
+
+ MMRADIO_LOG_FLEAVE();
+
+ return true;
+}
+
+void __mmradio_seek_thread(mm_radio_t *radio)
+{
+ int ret = MM_ERROR_NONE;
+ uint32_t freq = 0;
+ MMMessageParamType param = {0, };
+
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
+
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL);
+
+ MMRADIO_LOG_DEBUG("seeking....\n");
+
+ if (!radio->seek_cancel) {
+
+ MMRADIO_LOG_DEBUG("try to seek ");
+ pthread_mutex_lock(&radio->seek_cancel_mutex);
+ MMRADIO_LOG_DEBUG("seek start\n");
+
+ if (radio->seek_cancel) {
+ MMRADIO_LOG_DEBUG("seek was canceled so we return failure to application");
+ pthread_mutex_unlock(&radio->seek_cancel_mutex);
+ goto SEEK_FAILED;
+ }
+
+ ret = radio_hal_seek(radio->hal_inf, radio->seek_direction);
+ pthread_mutex_unlock(&radio->seek_cancel_mutex);
+ if (ret) {
+ MMRADIO_LOG_ERROR("radio_hal_seek failed\n");
+ goto SEEK_FAILED;
+ }
+
+ /* now we can get new frequency from radio device */
+ ret = radio_hal_get_frequency(radio->hal_inf, &freq);
+ if (ret) {
+ MMRADIO_LOG_ERROR("failed to get current frequency\n");
+ goto SEEK_FAILED;
+ }
+
+ MMRADIO_LOG_DEBUG("found frequency\n");
+
+ /* if same freq is found, ignore it and search next one. */
+ if (freq == radio->prev_seek_freq) {
+ MMRADIO_LOG_DEBUG("It's same with previous found one. So, trying next one. \n");
+ goto SEEK_FAILED;
+ }
+
+ /* check if it's limit freq or not */
+ if (__is_tunable_frequency(radio, freq)) {
+ /* now tune to new frequency */
+ ret = radio_hal_set_frequency(radio->hal_inf, freq);
+ if (ret) {
+ MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
+ goto SEEK_FAILED;
+ }
+ }
+
+ if (radio->seek_unmute) {
+ /* now turn on radio
+ * In the case of limit freq, tuner should be unmuted.
+ * Otherwise, sound can't output even though application set new frequency.
+ */
+ ret = radio_hal_unmute(radio->hal_inf);
+ if (ret) {
+ MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
+ goto SEEK_FAILED;
+ }
+ radio->seek_unmute = FALSE;
+ }
+
+ param.radio_scan.frequency = radio->prev_seek_freq = (int)freq;
+ MMRADIO_LOG_DEBUG("seeking : new frequency : [%d]\n", param.radio_scan.frequency);
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
+ }
+
+ radio->seek_thread = 0;
+ radio->is_seeking = FALSE;
+
+ MMRADIO_LOG_FLEAVE();
+
+ pthread_exit(NULL);
+ return;
+
+ SEEK_FAILED:
+
+ if (radio->seek_unmute) {
+ /* now turn on radio
+ * In the case of limit freq, tuner should be unmuted.
+ * Otherwise, sound can't output even though application set new frequency.
+ */
+ ret = radio_hal_unmute(radio->hal_inf);
+ if (ret)
+ MMRADIO_LOG_ERROR("failed to tune to new frequency\n");
+ radio->seek_unmute = FALSE;
+ }
+ /* freq -1 means it's failed to seek */
+ param.radio_scan.frequency = -1;
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, &param);
+ radio->is_seeking = FALSE;
+ pthread_exit(NULL);
+ return;
+}
+
+static bool __mmradio_post_message(mm_radio_t *radio, enum MMMessageType msgtype, MMMessageParamType *param)
+{
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ MMRADIO_LOG_FENTER();
+
+ if (!radio->msg_cb) {
+ debug_warning("failed to post a message\n");
+ return false;
+ }
+
+ MMRADIO_LOG_DEBUG("address of msg_cb : %p\n", radio->msg_cb);
+
+ radio->msg_cb(msgtype, param, radio->msg_cb_param);
+
+ MMRADIO_LOG_FLEAVE();
+
+ return true;
+}
+
+static int __mmradio_check_state(mm_radio_t *radio, MMRadioCommand command)
+{
+ MMRadioStateType radio_state = MM_RADIO_STATE_NUM;
+
+ MMRADIO_LOG_FENTER();
+
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ radio_state = __mmradio_get_state(radio);
+
+ MMRADIO_LOG_DEBUG("incomming command : %d current state : %d\n", command, radio_state);
+
+ switch (command) {
+ case MMRADIO_COMMAND_CREATE:
+ {
+ if (radio_state != 0)
+ goto NO_OP;
+ }
+ break;
+
+ case MMRADIO_COMMAND_REALIZE:
+ {
+ if (radio_state == MM_RADIO_STATE_READY ||
+ radio_state == MM_RADIO_STATE_PLAYING ||
+ radio_state == MM_RADIO_STATE_SCANNING)
+ goto NO_OP;
+
+ if (radio_state == 0)
+ goto INVALID_STATE;
+ }
+ break;
+
+ case MMRADIO_COMMAND_UNREALIZE:
+ {
+ if (radio_state == MM_RADIO_STATE_NULL)
+ goto NO_OP;
+
+ /* we can call unrealize at any higher state */
+ }
+ break;
+
+ case MMRADIO_COMMAND_START:
+ {
+ if (radio_state == MM_RADIO_STATE_PLAYING)
+ goto NO_OP;
+
+ if (radio_state != MM_RADIO_STATE_READY)
+ goto INVALID_STATE;
+ }
+ break;
+
+ case MMRADIO_COMMAND_STOP:
+ {
+ if (radio_state == MM_RADIO_STATE_READY)
+ goto NO_OP;
+
+ if (radio_state != MM_RADIO_STATE_PLAYING)
+ goto INVALID_STATE;
+ }
+ break;
+
+ case MMRADIO_COMMAND_START_SCAN:
+ {
+ if (radio_state == MM_RADIO_STATE_SCANNING)
+ goto NO_OP;
+
+ if (radio_state == MM_RADIO_STATE_NULL)
+ goto INVALID_STATE;
+ }
+ break;
+
+ case MMRADIO_COMMAND_STOP_SCAN:
+ {
+ if (radio_state == MM_RADIO_STATE_READY)
+ goto NO_OP;
+
+ if (radio_state != MM_RADIO_STATE_SCANNING)
+ goto INVALID_STATE;
+ }
+ break;
+
+ case MMRADIO_COMMAND_DESTROY:
+ case MMRADIO_COMMAND_MUTE:
+ case MMRADIO_COMMAND_UNMUTE:
+ case MMRADIO_COMMAND_SET_FREQ:
+ case MMRADIO_COMMAND_GET_FREQ:
+ case MMRADIO_COMMAND_SET_REGION:
+ {
+ /* we can do it at any state */
+ }
+ break;
+
+ case MMRADIO_COMMAND_SEEK:
+ {
+ if (radio_state != MM_RADIO_STATE_PLAYING)
+ goto INVALID_STATE;
+ }
+ break;
+
+ case MMRADIO_COMMAND_GET_REGION:
+ {
+ if (radio_state == MM_RADIO_STATE_NULL)
+ goto INVALID_STATE;
+ }
+ break;
+
+ default:
+ MMRADIO_LOG_DEBUG("not handled in FSM. don't care it\n");
+ break;
+ }
+
+ MMRADIO_LOG_DEBUG("status OK\n");
+
+ radio->cmd = command;
+
+ MMRADIO_LOG_FLEAVE();
+
+ return MM_ERROR_NONE;
+
+ INVALID_STATE:
+ debug_warning("invalid state. current : %d command : %d\n", radio_state, command);
+ MMRADIO_LOG_FLEAVE();
+ return MM_ERROR_RADIO_INVALID_STATE;
+
+ NO_OP:
+ debug_warning("mm-radio is in the desired state(%d). doing noting\n", radio_state);
+ MMRADIO_LOG_FLEAVE();
+ return MM_ERROR_RADIO_NO_OP;
+
+}
+
+static bool __mmradio_set_state(mm_radio_t *radio, int new_state)
+{
+ MMMessageParamType msg = { 0, };
+ int msg_type = MM_MESSAGE_UNKNOWN;
+
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ if (!radio) {
+ debug_warning("calling set_state with invalid radio handle\n");
+ return false;
+ }
+
+ if (radio->current_state == new_state && radio->pending_state == 0) {
+ debug_warning("we are in same state\n");
+ return true;
+ }
+
+ /* set state */
+ radio->old_state = radio->current_state;
+ radio->current_state = new_state;
+
+ /* fill message param */
+ msg.state.previous = radio->old_state;
+ msg.state.current = radio->current_state;
+
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+ /* post message to application */
+ switch (radio->sound_focus.by_focus_cb) {
+ case MMRADIO_FOCUS_CB_NONE:
+ {
+ msg_type = MM_MESSAGE_STATE_CHANGED;
+ MMRADIO_POST_MSG(radio, msg_type, &msg);
+ }
+ break;
+
+ case MMRADIO_FOCUS_CB_POSTMSG:
+ {
+ msg_type = MM_MESSAGE_STATE_INTERRUPTED;
+ msg.union_type = MM_MSG_UNION_CODE;
+ msg.code = radio->sound_focus.event_src;
+ MMRADIO_POST_MSG(radio, msg_type, &msg);
+ }
+ break;
+
+ case MMRADIO_FOCUS_CB_SKIP_POSTMSG:
+ default:
+ break;
+ }
+#else
+ msg_type = MM_MESSAGE_STATE_CHANGED;
+ MMRADIO_POST_MSG(radio, msg_type, &msg);
+#endif
+
+ MMRADIO_LOG_FLEAVE();
+
+ return true;
+}
+
+static int __mmradio_get_state(mm_radio_t *radio)
+{
+ MMRADIO_CHECK_INSTANCE(radio);
+
+ MMRADIO_LOG_DEBUG("radio state : current : [%d] old : [%d] pending : [%d]\n",
+ radio->current_state, radio->old_state, radio->pending_state);
+
+ return radio->current_state;
+}
+
+#ifdef TIZEN_FEATURE_SOUND_FOCUS
+static void __mmradio_sound_focus_cb(int id, mm_sound_focus_type_e focus_type,
+ mm_sound_focus_state_e focus_state, const char *reason_for_change, int option,
+ const char *additional_info, void *user_data)
+{
+ mm_radio_t *radio = (mm_radio_t *)user_data;
+ enum MMMessageInterruptedCode event_source;
+ int result = MM_ERROR_NONE;
+ int postMsg = false;
+
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
+
+ mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
+ radio->sound_focus.event_src = event_source;
+
+ switch (focus_state) {
+ case FOCUS_IS_RELEASED:{
+ radio->sound_focus.cur_focus_type &= ~focus_type;
+ radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
+
+ result = _mmradio_stop(radio);
+ if (result)
+ MMRADIO_LOG_ERROR("failed to stop radio\n");
+
+ MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
+ }
+ break;
+
+ case FOCUS_IS_ACQUIRED:{
+ MMMessageParamType msg = { 0, };
+ msg.union_type = MM_MSG_UNION_CODE;
+ msg.code = event_source;
+
+ radio->sound_focus.cur_focus_type |= focus_type;
+
+ if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
+
+ radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
+
+ MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
+ }
+ break;
+
+ default:
+ MMRADIO_LOG_DEBUG("Unknown focus_state\n");
+ break;
+ }
+
+ MMRADIO_LOG_FLEAVE();
+}
+
+static void __mmradio_sound_focus_watch_cb(int id, mm_sound_focus_type_e focus_type,
+ mm_sound_focus_state_e focus_state, const char *reason_for_change,
+ const char *additional_info, void *user_data)
+{
+ mm_radio_t *radio = (mm_radio_t *)user_data;
+ enum MMMessageInterruptedCode event_source;
+ int result = MM_ERROR_NONE;
+ int postMsg = false;
+
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio);
+
+ mmradio_get_sound_focus_reason(focus_state, reason_for_change, &event_source, &postMsg);
+ radio->sound_focus.event_src = event_source;
+
+ switch (focus_state) {
+ case FOCUS_IS_ACQUIRED: {
+ radio->sound_focus.cur_focus_type &= ~focus_type;
+ radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_POSTMSG;
+
+ result = _mmradio_stop(radio);
+ if (result)
+ MMRADIO_LOG_ERROR("failed to stop radio\n");
+
+ MMRADIO_LOG_DEBUG("FOCUS_IS_RELEASED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
+ }
+ break;
+
+ case FOCUS_IS_RELEASED: {
+ MMMessageParamType msg = { 0, };
+ msg.union_type = MM_MSG_UNION_CODE;
+ msg.code = event_source;
+
+ radio->sound_focus.cur_focus_type |= focus_type;
+
+ if ((postMsg) && (FOCUS_FOR_BOTH == radio->sound_focus.cur_focus_type))
+ MMRADIO_POST_MSG(radio, MM_MESSAGE_READY_TO_RESUME, &msg);
+
+ radio->sound_focus.by_focus_cb = MMRADIO_FOCUS_CB_NONE;
+
+ MMRADIO_LOG_DEBUG("FOCUS_IS_ACQUIRED cur_focus_type : %d\n", radio->sound_focus.cur_focus_type);
+ }
+ break;
+
+ default:
+ MMRADIO_LOG_DEBUG("Unknown focus_state\n");
+ break;
+ }
+
+ MMRADIO_LOG_FLEAVE();
+}
+#endif
+
+int _mmradio_get_region_type(mm_radio_t *radio, MMRadioRegionType *type)
+{
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
+
+ return_val_if_fail(type, MM_ERROR_INVALID_ARGUMENT);
+
+ *type = radio->region_setting.country;
+
+ MMRADIO_LOG_FLEAVE();
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_get_region_frequency_range(mm_radio_t *radio, unsigned int *min_freq, unsigned int *max_freq)
+{
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
+
+ return_val_if_fail(min_freq && max_freq, MM_ERROR_INVALID_ARGUMENT);
+
+ *min_freq = radio->region_setting.band_min;
+ *max_freq = radio->region_setting.band_max;
+
+ MMRADIO_LOG_FLEAVE();
+ return MM_ERROR_NONE;
+}
+
+int _mmradio_get_channel_spacing(mm_radio_t *radio, unsigned int *ch_spacing)
+{
+ MMRADIO_LOG_FENTER();
+ MMRADIO_CHECK_INSTANCE(radio);
+ MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_REGION);
+
+ return_val_if_fail(ch_spacing, MM_ERROR_INVALID_ARGUMENT);
+
+ *ch_spacing = radio->region_setting.channel_spacing;
+
+ MMRADIO_LOG_FLEAVE();
+ return MM_ERROR_NONE;
+}