/* * 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 #include #include #include #include #include #include #include #include #include #include #include #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 #define DEFAULT_MAX_MEDIA_VOLUME 15 /*--------------------------------------------------------------------------- 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); static int __mmradio_create_threads(mm_radio_t *radio); static void __mmradio_destroy_threads(mm_radio_t *radio); static int __mmradio_create_thread_type(mm_radio_t *radio, MMRadioThreadTypes type); static void __mmradio_destroy_thread_type(mm_radio_t *radio, MMRadioThreadTypes type); static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data); static void __mmradio_msg_thread(mm_radio_t *radio); static void __mmradio_msg_push(mm_radio_t *radio, MMRadioMsgTypes msg_type, int msg_data); static void __mmradio_close_radio_device(mm_radio_t *radio); typedef void (*thread_function)(mm_radio_t *); thread_function __mmradio_thread_function[] = { &__mmradio_msg_thread, &__mmradio_seek_thread, &__mmradio_scan_thread }; static int __convert_error_code(int code, char *func_name) { int ret = MM_ERROR_NONE; char *msg = "MM_ERROR_NONE"; MMRADIO_LOG_DEBUG("[%s] Enter code :%x", func_name, code); switch (code) { case RADIO_ERROR_NONE: ret = MM_ERROR_NONE; msg = "MM_ERROR_NONE"; break; case RADIO_ERROR_INVALID_PARAMETER: ret = MM_ERROR_INVALID_ARGUMENT; msg = "MM_ERROR_INVALID_ARGUMENT"; break; case RADIO_ERROR_PERMISSION_DENIED: ret = MM_ERROR_RADIO_PERMISSION_DENIED; msg = "MM_ERROR_RADIO_PERMISSION_DENIED"; break; case RADIO_ERROR_NOT_SUPPORTED: case RADIO_ERROR_NOT_IMPLEMENTED: ret = MM_ERROR_NOT_IMPLEMENTED; msg = "MM_ERROR_NOT_IMPLEMENTED"; break; case RADIO_ERROR_OUT_OF_MEMORY: ret = MM_ERROR_OUT_OF_MEMORY; msg = "MM_ERROR_OUT_OF_MEMORY"; break; case RADIO_ERROR_DEVICE_NOT_PREPARED: case RADIO_ERROR_DEVICE_NOT_OPENED: ret = MM_ERROR_RADIO_DEVICE_NOT_OPENED; msg = "MM_ERROR_RADIO_DEVICE_NOT_OPENED"; break; case RADIO_ERROR_DEVICE_NOT_FOUND: ret = MM_ERROR_RADIO_DEVICE_NOT_FOUND; msg = "MM_ERROR_RADIO_DEVICE_NOT_FOUND"; break; case RADIO_ERROR_NO_ANTENNA: ret = MM_ERROR_RADIO_NO_ANTENNA; msg = "MM_ERROR_RADIO_NO_ANTENNA"; break; case RADIO_ERROR_INVALID_OPERATION: case RADIO_ERROR_UNKNOWN: case RADIO_ERROR_INTERNAL: default: ret = MM_ERROR_RADIO_INTERNAL; msg = "MM_ERROR_RADIO_INTERNAL"; break; } MMRADIO_LOG_ERROR("[%s] %s(0x%08x) : core fw error(0x%x)", func_name, msg, ret, code); return ret; } 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_INFO("setting region - country: %d, de-emphasis: %d, band range: %d ~ %d KHz", 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; memset(&radio->region_setting, 0, sizeof(MMRadioRegion_t)); radio->local_volume = 1.0; radio->vstream = NULL; radio->stream_info = NULL; /* create msg queue for msg thread */ radio->msg_queue = g_async_queue_new(); if (!radio->msg_queue) { MMRADIO_LOG_ERROR("failed to get msg g_async_queue_new"); return MM_ERROR_RADIO_INTERNAL; } /* create mutex and thread */ ret = __mmradio_create_threads(radio); if (ret) { MMRADIO_LOG_ERROR("failed to create threads"); goto ERROR_THREAD; } MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL); /* initialize resource manager */ ret = mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, radio, &radio->resource_manager); if (ret) { MMRADIO_LOG_ERROR("failed to create resource manager"); ret = MM_ERROR_RADIO_INTERNAL; goto ERROR_RESOURCE; } ret = radio_hal_interface_init(&(radio->hal_inf)); if (ret) { MMRADIO_LOG_ERROR("failed to init mmradio hal interface"); ret = __convert_error_code(ret, (char *)__FUNCTION__); goto ERROR_HAL_INIT; } MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; ERROR_HAL_INIT: mm_resource_manager_destroy(radio->resource_manager); ERROR_RESOURCE: __mmradio_destroy_threads(radio); ERROR_THREAD: if (radio->msg_queue) g_async_queue_unref(radio->msg_queue); return ret; } 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); 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); ret = sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_RADIO, NULL, radio, &radio->stream_info); if (ret != MM_ERROR_NONE) { MMRADIO_LOG_ERROR("failed to create stream information"); 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; } 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); /*Finish if there are scans*/ _mmradio_stop_scan(radio); /*Stop radio if started*/ _mmradio_stop(radio); if (radio->vstream) { sound_manager_destroy_virtual_stream(radio->vstream); radio->vstream = NULL; } if (radio->stream_info) { sound_manager_destroy_stream_information(radio->stream_info); radio->stream_info = NULL; } MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL); MMRADIO_LOG_FLEAVE(); return ret; } 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); /* destroy mutex and thread */ __mmradio_destroy_threads(radio); if (radio->msg_queue) g_async_queue_unref(radio->msg_queue); ret = radio_hal_interface_deinit(radio->hal_inf); if (ret) { MMRADIO_LOG_ERROR("failed to deinitialize radio hal interface"); return __convert_error_code(ret, (char *)__FUNCTION__); } ret = mm_resource_manager_destroy(radio->resource_manager); if (ret) { MMRADIO_LOG_ERROR("failed to destroy resource manager"); return MM_ERROR_RADIO_INTERNAL; } 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_INFO("Setting %d frequency", freq); radio->freq = freq; ret = radio_hal_set_frequency(radio->hal_inf, freq); if (ret) { MMRADIO_LOG_ERROR("failed to set radio hal frequency"); return __convert_error_code(ret, (char *)__FUNCTION__); } MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } 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); MMRADIO_RETURN_VAL_IF_FAIL(pFreq, MM_ERROR_INVALID_ARGUMENT); ret = radio_hal_get_frequency(radio->hal_inf, &freq); if (ret) { MMRADIO_LOG_ERROR("failed to get radio hal frequency"); *pFreq = 0; return __convert_error_code(ret, (char *)__FUNCTION__); } /* update freq in handle */ MMRADIO_LOG_INFO("Updating %d frequency", freq); radio->freq = freq; *pFreq = (int)radio->freq; MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_mute(mm_radio_t *radio) { MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_MUTE); if (radio->vstream) sound_manager_set_virtual_stream_volume(radio->vstream, 0); radio->is_muted = true; MMRADIO_LOG_INFO("Radio mute state [%d]", radio->is_muted); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_unmute(mm_radio_t *radio) { MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_UNMUTE); if (radio->vstream) sound_manager_set_virtual_stream_volume(radio->vstream, (double)radio->local_volume); radio->is_muted = false; MMRADIO_LOG_INFO("Radio mute state [%d]", radio->is_muted); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } 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 : %p msg_cb_param : %p", 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); MMRADIO_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_INFO("now tune to frequency : %d", radio->freq); if (!radio->is_ready) { ret = mm_resource_manager_mark_for_acquire(radio->resource_manager, MM_RESOURCE_MANAGER_RES_TYPE_RADIO, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &radio->radio_resource); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { MMRADIO_LOG_ERROR("resource manager mark for acquire fail"); return MM_ERROR_RADIO_INTERNAL; } radio->interrupted_by_resource_conflict = FALSE; ret = mm_resource_manager_commit(radio->resource_manager); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { MMRADIO_LOG_ERROR("failed to commit resource manager"); mm_resource_manager_mark_for_release(radio->resource_manager, radio->radio_resource); radio->radio_resource = NULL; return ret; } ret = radio_hal_prepare(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) { MMRADIO_LOG_WARNING("radio_hal_prepare is not supported"); } else { MMRADIO_LOG_ERROR("failed to prepare radio hal"); goto error2; } } ret = radio_hal_open(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) { MMRADIO_LOG_WARNING("radio_hal_open is not supported"); } else { MMRADIO_LOG_ERROR("failed to open radio hal"); goto error1; } } radio->is_ready = true; } else { MMRADIO_LOG_DEBUG("radio prepared and opened"); } ret = radio_hal_start(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) { MMRADIO_LOG_WARNING("radio_hal_start is not supported"); } else { MMRADIO_LOG_ERROR("failed to start radio hal"); goto error1; } } /* set stored frequency */ ret = radio_hal_set_frequency(radio->hal_inf, radio->freq); if (ret) { MMRADIO_LOG_ERROR("failed to set radio hal frequency"); ret = __convert_error_code(ret, (char *)__FUNCTION__); goto error1; } ret = sound_manager_start_virtual_stream(radio->vstream); if (ret) { MMRADIO_LOG_ERROR("failed to start sound manager virtual stream"); goto error1; } if (radio->vstream) { double set_volume = 0; if (!radio->is_muted) set_volume = (double)radio->local_volume; sound_manager_set_virtual_stream_volume(radio->vstream, (double)set_volume); } MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; error1: radio_hal_close(radio->hal_inf); error2: radio_hal_unprepare(radio->hal_inf); radio->is_ready = false; 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); /*cancel if any seek*/ _mmradio_seek_cancel(radio); ret = sound_manager_stop_virtual_stream(radio->vstream); if (ret != MM_ERROR_NONE) { MMRADIO_LOG_ERROR("failed to stop virtual_stream"); return ret; } ret = radio_hal_stop(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) { MMRADIO_LOG_WARNING("radio_hal_stop is not supported"); } else { MMRADIO_LOG_ERROR("failed to stop radio hal"); return ret; } } if (radio->is_ready) { /* close radio device here !!!! */ ret = radio_hal_close(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_SUPPORT_API) { MMRADIO_LOG_WARNING("radio_hal_close is not supported"); } else { MMRADIO_LOG_ERROR("failed to close radio hal"); return ret; } } ret = radio_hal_unprepare(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_SUPPORT_API) { MMRADIO_LOG_WARNING("radio_hal_unprepare is not supported"); } else { MMRADIO_LOG_ERROR("failed to unprepare radio hal"); return ret; } } if (!radio->interrupted_by_resource_conflict && /* is being released */ radio->radio_resource != NULL) { ret = mm_resource_manager_mark_for_release(radio->resource_manager, radio->radio_resource); radio->radio_resource = NULL; if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { MMRADIO_LOG_ERROR("failed to mark resource for release, ret(0x%x)", ret); return ret; } ret = mm_resource_manager_commit(radio->resource_manager); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) MMRADIO_LOG_ERROR("resource manager commit fail"); } radio->is_ready = false; } 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; MMRadioThread_t *p_thread = NULL; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SEEK); p_thread = &radio->thread[MM_RADIO_THREAD_SEEK]; MMRADIO_CHECK_ARG(p_thread); if (p_thread->is_running) { 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; if (!radio->is_muted) { ret = _mmradio_mute(radio); if (ret) { MMRADIO_LOG_ERROR("failed to set radio mute"); return ret; } radio->seek_unmute = true; } MMRADIO_THREAD_LOCK(p_thread); MMRADIO_LOG_INFO("trying to seek. direction[0:UP/1:DOWN) %d", direction); radio->seek_direction = direction; p_thread->is_running = true; p_thread->stop = false; MMRADIO_THREAD_SIGNAL(p_thread); MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } void _mmradio_seek_cancel(mm_radio_t *radio) { MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); /* cancel any outstanding seek request */ radio->thread[MM_RADIO_THREAD_SEEK].stop = true; MMRADIO_LOG_FLEAVE(); } int _mmradio_start_scan(mm_radio_t *radio) { int ret = MM_ERROR_NONE; MMRadioThread_t *p_thread = NULL;; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_START_SCAN); p_thread = &radio->thread[MM_RADIO_THREAD_SCAN]; MMRADIO_CHECK_ARG(p_thread); p_thread->stop = false; if (!radio->is_ready) { ret = mm_resource_manager_mark_for_acquire(radio->resource_manager, MM_RESOURCE_MANAGER_RES_TYPE_RADIO, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &radio->radio_resource); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { MMRADIO_LOG_ERROR("resource manager mark for acquire fail"); return MM_ERROR_RADIO_INTERNAL; } radio->interrupted_by_resource_conflict = FALSE; ret = mm_resource_manager_commit(radio->resource_manager); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { MMRADIO_LOG_ERROR("failed to commit resource manager"); mm_resource_manager_mark_for_release(radio->resource_manager, radio->radio_resource); radio->radio_resource = NULL; return ret; } ret = radio_hal_prepare(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) { MMRADIO_LOG_WARNING("radio_hal_prepare is not supported"); } else { MMRADIO_LOG_ERROR("failed to prepare radio hal"); return ret; } } ret = radio_hal_open(radio->hal_inf); if (ret) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) { MMRADIO_LOG_WARNING("radio_hal_open is not supported"); } else { MMRADIO_LOG_ERROR("failed to open radio hal"); return ret; } } radio->is_ready = true; } else { MMRADIO_LOG_DEBUG("radio prepared and opened"); } MMRADIO_THREAD_LOCK(p_thread); p_thread->is_running = true; MMRADIO_THREAD_SIGNAL(p_thread); MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_stop_scan(mm_radio_t *radio) { MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_STOP_SCAN); radio->thread[MM_RADIO_THREAD_SCAN].stop = true; MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mm_radio_get_signal_strength(mm_radio_t *radio, int *value) { int ret = MM_ERROR_NONE; int32_t strength = 0; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_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) { ret = __convert_error_code(ret, (char *)__FUNCTION__); if (ret == MM_ERROR_NOT_IMPLEMENTED) MMRADIO_LOG_WARNING("radio_hal_get_signal_strength is not supported"); else MMRADIO_LOG_ERROR("failed to get radio hal signal strength"); *value = 0; 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; MMRadioThread_t *p_thread = NULL; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); p_thread = &radio->thread[MM_RADIO_THREAD_SCAN]; MMRADIO_CHECK_ARG_RETURN_VOID(p_thread); MMRADIO_THREAD_LOCK(p_thread); MMRADIO_THREAD_SIGNAL(p_thread); MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_THREAD_LOCK(p_thread); while (!p_thread->thread_exit) { MMRADIO_LOG_DEBUG("scan thread started. waiting for signal."); MMRADIO_THREAD_WAIT(p_thread); if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting scan thread"); goto EXIT; } if (radio->old_state == MM_RADIO_STATE_PLAYING) { ret = _mmradio_mute(radio); if (ret) { MMRADIO_LOG_ERROR("failed to set radio mute"); goto FINISHED; } } ret = radio_hal_set_frequency(radio->hal_inf, radio->region_setting.band_min); if (ret) goto FINISHED; MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL); MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING); prev_freq = 0; while (!p_thread->stop) { uint32_t freq = 0; MMRADIO_LOG_DEBUG("scanning...."); if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting scan thread"); goto EXIT; } if (p_thread->stop) { MMRADIO_LOG_INFO("scan was canceled"); goto FINISHED; } MMRADIO_HAL_SEEK_THREAD_LOCK(radio); ret = radio_hal_seek(radio->hal_inf, MM_RADIO_SEEK_UP); MMRADIO_HAL_SEEK_THREAD_UNLOCK(radio); if (ret) { MMRADIO_LOG_ERROR("radio scanning error"); break; } if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting scan thread"); goto EXIT; } if (p_thread->stop) { MMRADIO_LOG_INFO("scan was canceled"); goto FINISHED; } /* 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"); } else { if (freq <= prev_freq) { MMRADIO_LOG_ERROR("frequency is less than previous [%d] -> [%d] we wrapped around, we are finished scanning", prev_freq, freq); break; } prev_freq = (int)freq; MMRADIO_LOG_INFO("scanning : new frequency : [%d]", prev_freq); /* drop if max freq is scanned */ if (prev_freq >= radio->region_setting.band_max) { MMRADIO_LOG_WARNING("%d freq is dropping...and stopping scan", prev_freq); break; } if (p_thread->stop) { /* doesn't need to post */ break; } __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_INFO, freq); } } 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 = _mmradio_unmute(radio); if (ret) { MMRADIO_LOG_ERROR("failed to set radio unmute"); goto FINISHED_ERR; } ret = radio_hal_set_frequency(radio->hal_inf, prev_freq); if (ret) { MMRADIO_LOG_ERROR("failed to set radio hal frequency"); goto FINISHED_ERR; } } FINISHED_ERR: if (radio->old_state == MM_RADIO_STATE_PLAYING) { MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING); } else { /* close radio device here !!!! */ __mmradio_close_radio_device(radio); MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY); } p_thread->is_running = false; if (p_thread->stop) __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_STOPPED, 0); else __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_FINISHED, 0); /* reset thread stop flag */ p_thread->stop = false; } EXIT: /* close radio device here !!!! */ __mmradio_close_radio_device(radio); p_thread->is_running = false; MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_LOG_FLEAVE(); pthread_exit(NULL); } 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; MMRadioThread_t *p_thread = NULL; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); p_thread = &radio->thread[MM_RADIO_THREAD_SEEK]; MMRADIO_CHECK_ARG_RETURN_VOID(p_thread); MMRADIO_THREAD_LOCK(p_thread); MMRADIO_THREAD_SIGNAL(p_thread); MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_THREAD_LOCK(p_thread); while (!p_thread->thread_exit) { MMRADIO_LOG_DEBUG("seek thread started. waiting for signal."); MMRADIO_THREAD_WAIT(p_thread); if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting seek thread"); goto EXIT; } MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_START, NULL); MMRADIO_LOG_DEBUG("seeking...."); if (p_thread->stop) { MMRADIO_LOG_INFO("seek was canceled so we return failure to application"); goto SEEK_FAILED; } freq = 0; MMRADIO_LOG_DEBUG("try to seek "); MMRADIO_HAL_SEEK_THREAD_LOCK(radio); MMRADIO_LOG_DEBUG("seek start"); ret = radio_hal_seek(radio->hal_inf, radio->seek_direction); MMRADIO_HAL_SEEK_THREAD_UNLOCK(radio); if (ret) { MMRADIO_LOG_ERROR("failed to seek radio hal"); goto SEEK_FAILED; } if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting seek thread"); goto EXIT; } if (p_thread->stop) { MMRADIO_LOG_INFO("seek was canceled so we return failure to application"); 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"); goto SEEK_FAILED; } MMRADIO_LOG_DEBUG("found frequency"); /* if same freq is found, ignore it and search next one. */ if (freq == radio->prev_seek_freq) { MMRADIO_LOG_WARNING("It's same with previous found one. So, trying next one."); 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"); goto SEEK_FAILED; } radio->freq = (int)freq; MMRADIO_LOG_WARNING("setting frequency : [%d]", radio->freq); } 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 = _mmradio_unmute(radio); if (ret) { MMRADIO_LOG_ERROR("failed to set radio unmute"); goto SEEK_FAILED; } radio->seek_unmute = false; } radio->prev_seek_freq = (int)freq; MMRADIO_LOG_INFO("seeking : new frequency : [%d]", (int) freq); p_thread->is_running = false; __mmradio_msg_push(radio, MM_RADIO_MSG_SEEK_FINISHED, freq); continue; 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 = _mmradio_unmute(radio); if (ret) MMRADIO_LOG_ERROR("failed to set radio unmute"); radio->seek_unmute = false; } p_thread->is_running = false; /* freq -1 means it's failed to seek */ __mmradio_msg_push(radio, MM_RADIO_MSG_SEEK_FINISHED, -1); } EXIT: p_thread->is_running = false; MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_LOG_FLEAVE(); pthread_exit(NULL); } 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) { MMRADIO_LOG_WARNING("failed to post a message because msg cb didn't register"); return false; } MMRADIO_LOG_DEBUG("address of msg_cb : %p", 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_INFO("incomming command : %d current state : %d", 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: case MMRADIO_COMMAND_SET_VOLUME: case MMRADIO_COMMAND_GET_VOLUME: { /* 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"); break; } MMRADIO_LOG_DEBUG("status OK"); radio->cmd = command; MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; INVALID_STATE: MMRADIO_LOG_WARNING("invalid state. current : %d command : %d", radio_state, command); MMRADIO_LOG_FLEAVE(); return MM_ERROR_RADIO_INVALID_STATE; NO_OP: MMRADIO_LOG_WARNING("mm-radio is in the desired state(%d). doing noting", 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(); if (!radio) { MMRADIO_LOG_WARNING("calling set_state with invalid radio handle"); return false; } if (radio->current_state == new_state && radio->pending_state == 0) { MMRADIO_LOG_WARNING("we are in same state"); return true; } /* set state */ radio->old_state = radio->current_state; radio->current_state = new_state; /* fill message param */ msg.union_type = MM_MSG_UNION_STATE; msg.state.previous = radio->old_state; msg.state.current = radio->current_state; if (radio->interrupted_by_resource_conflict) { __mmradio_msg_push(radio, MM_RADIO_MSG_STATE_INTERRUPTED, MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT); } else { msg_type = MM_MESSAGE_STATE_CHANGED; MMRADIO_POST_MSG(radio, msg_type, &msg); } MMRADIO_LOG_FLEAVE(); return true; } static int __mmradio_get_state(mm_radio_t *radio) { MMRADIO_CHECK_INSTANCE(radio); MMRADIO_LOG_INFO("radio state : current : [%d] old : [%d] pending : [%d]", radio->current_state, radio->old_state, radio->pending_state); return radio->current_state; } 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); MMRADIO_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); MMRADIO_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); MMRADIO_RETURN_VAL_IF_FAIL(ch_spacing, MM_ERROR_INVALID_ARGUMENT); *ch_spacing = radio->region_setting.channel_spacing; MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_set_volume(mm_radio_t *radio, float volume) { int ret = MM_ERROR_NONE; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME); MMRADIO_LOG_INFO("Setting %f volume", volume); MMRADIO_VOLUME_LOCK(radio); radio->local_volume = volume; if (radio->vstream) sound_manager_set_virtual_stream_volume(radio->vstream, (double)radio->local_volume); MMRADIO_VOLUME_UNLOCK(radio); MMRADIO_LOG_FLEAVE(); return ret; } int _mmradio_get_volume(mm_radio_t *radio, float *pVolume) { int ret = MM_ERROR_NONE; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_GET_VOLUME); MMRADIO_RETURN_VAL_IF_FAIL(pVolume, MM_ERROR_INVALID_ARGUMENT); MMRADIO_VOLUME_LOCK(radio); *pVolume = radio->local_volume; MMRADIO_VOLUME_UNLOCK(radio); MMRADIO_LOG_FLEAVE(); return ret; } static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data) { mm_radio_t *radio = NULL; MMRADIO_LOG_FENTER(); if (!user_data) { MMRADIO_LOG_ERROR("user_data is null"); return FALSE; } radio = (mm_radio_t *)user_data; radio->radio_resource = NULL; MMRADIO_LOG_DEBUG("radio resource conflict so, resource will be freed by _mmradio_stop"); radio->interrupted_by_resource_conflict = TRUE; MMRADIO_CMD_LOCK(radio); if (_mmradio_stop(radio) != MM_ERROR_NONE) MMRADIO_LOG_ERROR("failed to stop radio"); MMRADIO_CMD_UNLOCK(radio); MMRADIO_LOG_FLEAVE(); return FALSE; } static int __mmradio_create_thread_type(mm_radio_t *radio, MMRadioThreadTypes type) { MMRadioThread_t *p_thread = NULL; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); if (type >= MM_RADIO_THREAD_NUM) { MMRADIO_LOG_WARNING("wrong argument thread type"); return MM_ERROR_RADIO_INTERNAL; } p_thread = &radio->thread[type]; MMRADIO_CHECK_ARG(p_thread); MMRADIO_INIT_MUTEX(p_thread->mutex); MMRADIO_INIT_COND(p_thread->cond); MMRADIO_THREAD_LOCK(p_thread); p_thread->thread_id = pthread_create(&p_thread->thread, NULL, (void *)__mmradio_thread_function[type], (void *)radio); if (p_thread->thread_id) { MMRADIO_LOG_DEBUG("failed to create thread : [%d]", type); MMRADIO_THREAD_UNLOCK(p_thread); return MM_ERROR_RADIO_INTERNAL; } MMRADIO_LOG_DEBUG("wait for [%d] thread", type); MMRADIO_THREAD_WAIT(p_thread); MMRADIO_LOG_DEBUG("[%d] thread started", type); MMRADIO_THREAD_UNLOCK(p_thread); return MM_ERROR_NONE; ERROR: pthread_mutex_destroy(&p_thread->mutex); pthread_cond_destroy(&p_thread->cond); return MM_ERROR_RADIO_INTERNAL; } static int __mmradio_create_threads(mm_radio_t *radio) { int ret = MM_ERROR_NONE; int type = 0; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_INIT_MUTEX(radio->cmd_lock); MMRADIO_INIT_MUTEX(radio->volume_lock); MMRADIO_INIT_MUTEX(radio->hal_seek_mutex); for (type = (int)MM_RADIO_THREAD_MSG; type < (int)MM_RADIO_THREAD_NUM; type++) { ret = __mmradio_create_thread_type(radio, (MMRadioThreadTypes)type); if (ret) { MMRADIO_LOG_ERROR("failed to create thread(%d)", type); while (--type >= (int)MM_RADIO_THREAD_MSG) __mmradio_destroy_thread_type(radio, (MMRadioThreadTypes)type); goto ERROR; } } MMRADIO_LOG_FLEAVE(); return ret; ERROR: pthread_mutex_destroy(&radio->cmd_lock); pthread_mutex_destroy(&radio->volume_lock); pthread_mutex_destroy(&radio->hal_seek_mutex); MMRADIO_LOG_FLEAVE(); return MM_ERROR_RADIO_INTERNAL; } static void __mmradio_destroy_thread_type(mm_radio_t *radio, MMRadioThreadTypes type) { MMRadioThread_t *p_thread = NULL; mm_radio_msg_t *msg = NULL; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); if (type >= MM_RADIO_THREAD_NUM) { MMRADIO_LOG_WARNING("wrong argument thread type"); return; } p_thread = &radio->thread[type]; MMRADIO_CHECK_ARG_RETURN_VOID(p_thread); if (p_thread->thread) { switch (type) { case MM_RADIO_THREAD_MSG: msg = g_slice_new0(mm_radio_msg_t); if (!msg) { MMRADIO_LOG_ERROR("failed to get mm_radio_msg_t"); } else { msg->msg_type = MM_RADIO_MSG_DESTROY; g_async_queue_push_front(radio->msg_queue, msg); pthread_join(p_thread->thread, NULL); p_thread->thread = 0; } break; case MM_RADIO_THREAD_SEEK: case MM_RADIO_THREAD_SCAN: MMRADIO_THREAD_LOCK(p_thread); p_thread->thread_exit = true; MMRADIO_THREAD_SIGNAL(p_thread); MMRADIO_THREAD_UNLOCK(p_thread); pthread_join(p_thread->thread, NULL); p_thread->thread = 0; break; default: MMRADIO_LOG_WARNING("(%d)type isn't handled", type); } } else { MMRADIO_LOG_WARNING("(%d)thread is zero", type); } pthread_mutex_destroy(&p_thread->mutex); pthread_cond_destroy(&p_thread->cond); MMRADIO_LOG_FLEAVE(); } static void __mmradio_destroy_threads(mm_radio_t *radio) { int type = (int)MM_RADIO_THREAD_NUM; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); while (--type >= 0) __mmradio_destroy_thread_type(radio, (MMRadioThreadTypes)type); pthread_mutex_destroy(&radio->cmd_lock); pthread_mutex_destroy(&radio->volume_lock); pthread_mutex_destroy(&radio->hal_seek_mutex); MMRADIO_LOG_FLEAVE(); } void __mmradio_msg_push(mm_radio_t *radio, MMRadioMsgTypes msg_type, int msg_data) { mm_radio_msg_t *msg = g_slice_new0(mm_radio_msg_t); if (!msg) { MMRADIO_LOG_ERROR("NULL msg pointer"); return; } msg->msg_type = msg_type; msg->data = msg_data; MMRADIO_LOG_INFO("push msg_type: %d, msg_data: %d", (int)msg->msg_type, msg->data); g_async_queue_push(radio->msg_queue, msg); } void __mmradio_msg_thread(mm_radio_t *radio) { mm_radio_msg_t *msg = NULL; mm_radio_msg_t *msg_pop = NULL; MMRadioThread_t *p_thread = NULL; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); p_thread = &radio->thread[MM_RADIO_THREAD_MSG]; MMRADIO_CHECK_ARG_RETURN_VOID(p_thread); p_thread->thread_exit = false; MMRADIO_THREAD_LOCK(p_thread); MMRADIO_THREAD_SIGNAL(p_thread); MMRADIO_THREAD_UNLOCK(p_thread); /* we run a while one loop*/ while (!p_thread->thread_exit) { msg = (mm_radio_msg_t *)g_async_queue_pop(radio->msg_queue); if (!msg) { MMRADIO_LOG_ERROR("poped message is NULL!"); break; } MMMessageParamType param = {0,}; switch (msg->msg_type) { case MM_RADIO_MSG_DESTROY: MMRADIO_LOG_INFO("get destroy msg. pop all event to finish this thread"); while ((msg_pop = (mm_radio_msg_t *)g_async_queue_try_pop(radio->msg_queue))) { if (msg_pop != NULL) { MMRADIO_LOG_DEBUG("drop this msg type: %d", msg_pop->msg_type); g_slice_free(mm_radio_msg_t, msg_pop); } } p_thread->thread_exit = true; break; case MM_RADIO_MSG_SCAN_INFO: MMRADIO_LOG_INFO("get scan info frequency: %d", msg->data); param.radio_scan.frequency = (int) msg->data; MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_INFO, ¶m); break; case MM_RADIO_MSG_SCAN_STOPPED: MMRADIO_LOG_INFO("get scan stopped"); MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_STOP, NULL); break; case MM_RADIO_MSG_SCAN_FINISHED: MMRADIO_LOG_INFO("get scan finished"); MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_FINISH, NULL); break; case MM_RADIO_MSG_SEEK_FINISHED: MMRADIO_LOG_INFO("get seek finish frequency: %d", msg->data); param.radio_scan.frequency = (int) msg->data; MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SEEK_FINISH, ¶m); break; case MM_RADIO_MSG_STATE_INTERRUPTED: MMRADIO_LOG_INFO("get state interrupted type: %d", msg->data); param.union_type = MM_MSG_UNION_STATE; param.state.previous = radio->old_state; param.state.current = radio->current_state; param.state.code = msg->data; MMRADIO_POST_MSG(radio, MM_MESSAGE_STATE_INTERRUPTED, ¶m); break; default: MMRADIO_LOG_ERROR("wrong msg_type : %d", msg->msg_type); break; } if (msg) g_slice_free(mm_radio_msg_t, msg); } MMRADIO_LOG_INFO("msg thread is finished"); MMRADIO_LOG_FLEAVE(); pthread_exit(NULL); } static void __mmradio_close_radio_device(mm_radio_t *radio) { int ret = MM_ERROR_NONE; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE_RETURN_VOID(radio); if (!radio->is_ready) { MMRADIO_LOG_DEBUG("radio device is already closed"); return; } ret = radio_hal_close(radio->hal_inf); if (ret) __convert_error_code(ret, (char *)__FUNCTION__); ret = radio_hal_unprepare(radio->hal_inf); if (ret) __convert_error_code(ret, (char *)__FUNCTION__); if (!radio->interrupted_by_resource_conflict && /* is being released */ radio->radio_resource != NULL) { ret = mm_resource_manager_mark_for_release(radio->resource_manager, radio->radio_resource); radio->radio_resource = NULL; if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) MMRADIO_LOG_ERROR("failed to mark resource for release, ret(0x%x)", ret); } ret = mm_resource_manager_commit(radio->resource_manager); if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) MMRADIO_LOG_ERROR("resource manager commit fail"); radio->is_ready = false; }