/* * mm_radio_priv_emulator.c * * Copyright (c) 2000 - 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_emul.h" /*=========================================================================================== LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE ========================================================================================== */ /*--------------------------------------------------------------------------- GLOBAL CONSTANT DEFINITIONS: ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- IMPORTED VARIABLE DECLARATIONS: ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- IMPORTED FUNCTION DECLARATIONS: ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- LOCAL #defines: ---------------------------------------------------------------------------*/ #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 EMULATOR_FREQ_MAX 5 #define RADIO_MIN_VOLUME 0.0 #define RADIO_MAX_VOLUME 1.0 #define RADIO_GST_STATE_CHANGE_TIMEOUT (10 * GST_SECOND) /*--------------------------------------------------------------------------- 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[] = { { /* North 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, }, }; static int MMRadioEmulatorFreq[EMULATOR_FREQ_MAX] = { 89100, 89900, 91900, 99900, 107700 }; /*--------------------------------------------------------------------------- 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); 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 __mmradio_set_deemphasis(mm_radio_t * radio); static int __mmradio_set_band_range(mm_radio_t * radio); static int __mmradio_get_wave_num(mm_radio_t * radio); 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); typedef void (*thread_function)(mm_radio_t *); thread_function __mmradio_thread_function[] = { &__mmradio_msg_thread, &__mmradio_seek_thread, &__mmradio_scan_thread }; /*=========================================================================== FUNCTION DEFINITIONS ========================================================================== */ /* -------------------------------------------------------------------------- * Name : _mmradio_apply_region() * Desc : update radio region information and set values to device * Param : * [in] radio : radio handle * [in] region : region type * [in] update : update region values or not * Return : zero on success, or negative value with error code *---------------------------------------------------------------------------*/ 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; } } } /* check device is opened or not. if it's not ready, skip to apply region to device now */ if (radio->radio_fd < 0) { MMRADIO_LOG_DEBUG("not opened device. just updating region info."); return MM_ERROR_NONE; } MMRADIO_SLOG_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); /* set de-emphasis to device */ ret = __mmradio_set_deemphasis(radio); MMRADIO_CHECK_RETURN_IF_FAIL(ret, "set de-emphasis"); /* set band range to device */ ret = __mmradio_set_band_range(radio); MMRADIO_CHECK_RETURN_IF_FAIL(ret, "set band range"); 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->radio_fd = -1; radio->freq = DEFAULT_FREQ; memset(&radio->region_setting, 0, sizeof(MMRadioRegion_t)); radio->local_volume = 1.0; /* 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; } MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; 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; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_REALIZE); /* open radio device */ if (radio->radio_fd == -1) { MMRadioRegionType region = MM_RADIO_REGION_GROUP_NONE; bool update = false; /* open device */ radio->radio_fd = 11; MMRADIO_LOG_DEBUG("radio device fd : %d", radio->radio_fd); /* check region country type if it's updated or not */ 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); MMRADIO_CHECK_RETURN_IF_FAIL(ret, "update region info"); } /* ready but no sound */ /* if( _mmradio_mute(radio) != MM_ERROR_NONE) */ /* goto error; */ MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY); ret = _mmradio_realize_pipeline(radio); if (ret) { MMRADIO_LOG_ERROR("failed to realize pipeline"); return ret; } 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*/ ret = _mmradio_stop_scan(radio); if (ret != MM_ERROR_NONE) MMRADIO_LOG_WARNING("failed to stop radio scan"); /*Stop radio if started*/ ret = _mmradio_stop(radio); if (ret != MM_ERROR_NONE) MMRADIO_LOG_WARNING("failed to stop radio"); /* close radio device here !!!! */ if (radio->radio_fd >= 0) radio->radio_fd = -1; MMRADIO_SET_STATE(radio, MM_RADIO_STATE_NULL); ret = _mmradio_destroy_pipeline(radio); if (ret) { MMRADIO_LOG_ERROR("failed to destroy pipeline"); return ret; } 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 = 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 val = 0; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_FREQ); MMRADIO_SLOG_DEBUG("Setting %d frequency", freq); MMRADIO_LOG_DEBUG("radio->freq: %d freq: %d", radio->freq, freq); if (radio->radio_fd < 0) { MMRADIO_LOG_DEBUG("radio device is not opened yet"); return MM_ERROR_NONE; } /* check frequency range */ if (freq < radio->region_setting.band_min || freq > radio->region_setting.band_max) { MMRADIO_LOG_ERROR("out of frequency range %d", freq); return MM_ERROR_INVALID_ARGUMENT; } radio->freq = freq; val = __mmradio_get_wave_num(radio); if (radio->pipeline && radio->pipeline->audiosrc) g_object_set(radio->pipeline->audiosrc, "wave", val, NULL); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_get_frequency(mm_radio_t * radio, int *pFreq) { 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); /* just return stored frequency if radio device is not ready */ if (radio->radio_fd < 0) { MMRADIO_SLOG_DEBUG("freq : %d", radio->freq); *pFreq = radio->freq; return MM_ERROR_NONE; } /* update freq in handle */ *pFreq = 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->radio_fd < 0) return MM_ERROR_RADIO_NOT_INITIALIZED; if (radio->pipeline && radio->pipeline->volume) { g_object_set(radio->pipeline->volume, "mute", 1, NULL); MMRADIO_LOG_DEBUG("g_object set mute"); } 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); MMRADIO_CHECK_DEVICE_STATE(radio); if (radio->pipeline && radio->pipeline->volume) { g_object_set(radio->pipeline->volume, "mute", 0, NULL); MMRADIO_LOG_DEBUG("g_object set unmute"); } MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } /* -------------------------------------------------------------------------- * Name : __mmradio_set_deemphasis * Desc : apply de-emphasis value to device * Param : * [in] radio : radio handle * Return : zero on success, or negative value with error code *---------------------------------------------------------------------------*/ int __mmradio_set_deemphasis(mm_radio_t * radio) { int value = 0; MMRADIO_LOG_FENTER(); return MM_ERROR_NONE; MMRADIO_CHECK_INSTANCE(radio); /* get de-emphasis */ switch (radio->region_setting.deemphasis) { case MM_RADIO_DEEMPHASIS_50_US: /* V4L2_DEEMPHASIS_50_uS; */ value = 1; break; case MM_RADIO_DEEMPHASIS_75_US: /* V4L2_DEEMPHASIS_75_uS; */ value = 2; break; default: MMRADIO_LOG_ERROR("not available de-emphasis value"); return MM_ERROR_COMMON_INVALID_ARGUMENT; } MMRADIO_LOG_DEBUG("set deemphasis %d", value); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } /* -------------------------------------------------------------------------- * Name : __mmradio_set_band_range * Desc : apply max and min frequency to device * Param : * [in] radio : radio handle * Return : zero on success, or negative value with error code *---------------------------------------------------------------------------*/ int __mmradio_set_band_range(mm_radio_t * radio) { MMRADIO_LOG_FENTER(); return MM_ERROR_NONE; MMRADIO_CHECK_INSTANCE(radio); 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_SLOG_DEBUG("now tune to frequency : %d", radio->freq); 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; } /* set stored frequency */ _mmradio_set_frequency(radio, radio->freq); _mmradio_set_volume(radio, radio->local_volume); ret = _mmradio_start_pipeline(radio); if (ret) { MMRADIO_LOG_ERROR("failed to start pipeline"); return ret; } MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING); MMRADIO_LOG_FLEAVE(); 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); /* if( _mmradio_mute(radio) != MM_ERROR_NONE) */ /* return MM_ERROR_RADIO_NOT_INITIALIZED; */ 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"); } MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY); ret = _mmradio_stop_pipeline(radio); if (ret) { MMRADIO_LOG_ERROR("failed to stop pipeline"); return ret; } MMRADIO_LOG_FLEAVE(); return ret; } int _mmradio_realize_pipeline(mm_radio_t * radio) { int ret = MM_ERROR_NONE; int val = 0; MMRADIO_LOG_FENTER(); gst_init(NULL, NULL); radio->pipeline = g_new0(mm_radio_gstreamer_s, 1); radio->pipeline->pipeline = gst_pipeline_new("fmradio"); radio->pipeline->audiosrc = gst_element_factory_make("audiotestsrc", "fm audio src"); radio->pipeline->converter = gst_element_factory_make("audioconvert", "audioconvert"); radio->pipeline->volume = gst_element_factory_make("volume", "audiovolume"); radio->pipeline->audiosink = gst_element_factory_make("pulsesink", "audio sink"); val = __mmradio_get_wave_num(radio); g_object_set(radio->pipeline->audiosrc, "wave", val, "volume", 0.8, NULL); if (!radio->pipeline->pipeline || !radio->pipeline->audiosrc || !radio->pipeline->converter || !radio->pipeline->volume || !radio->pipeline->audiosink) { MMRADIO_LOG_DEBUG("One element could not be created. Exiting."); return MM_ERROR_RADIO_NOT_INITIALIZED; } gst_bin_add_many(GST_BIN(radio->pipeline->pipeline), radio->pipeline->audiosrc, radio->pipeline->converter, radio->pipeline->volume, radio->pipeline->audiosink, NULL); if (!gst_element_link_many(radio->pipeline->audiosrc, radio->pipeline->converter, radio->pipeline->volume, radio->pipeline->audiosink, NULL)) { MMRADIO_LOG_DEBUG("failed to element link (src - queue - sink)"); return MM_ERROR_RADIO_NOT_INITIALIZED; } MMRADIO_LOG_FLEAVE(); return ret; } int _mmradio_start_pipeline(mm_radio_t * radio) { int ret = MM_ERROR_NONE; GstStateChangeReturn ret_state; MMRADIO_LOG_FENTER(); if (gst_element_set_state(radio->pipeline->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { MMRADIO_LOG_ERROR("failed to change pipeline state"); return MM_ERROR_RADIO_INVALID_STATE; } ret_state = gst_element_get_state(radio->pipeline->pipeline, NULL, NULL, RADIO_GST_STATE_CHANGE_TIMEOUT); if (ret_state == GST_STATE_CHANGE_FAILURE) { MMRADIO_LOG_ERROR("GST_STATE_CHANGE_FAILURE"); return MM_ERROR_RADIO_INVALID_STATE; } else { MMRADIO_LOG_DEBUG("GST_STATE_NULL ret_state = %d (GST_STATE_CHANGE_SUCCESS)", ret_state); } MMRADIO_LOG_FLEAVE(); return ret; } int _mmradio_stop_pipeline(mm_radio_t * radio) { int ret = MM_ERROR_NONE; GstStateChangeReturn ret_state; MMRADIO_LOG_FENTER(); if (gst_element_set_state(radio->pipeline->pipeline, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) { MMRADIO_LOG_ERROR("Fail to change pipeline state"); return MM_ERROR_RADIO_INVALID_STATE; } ret_state = gst_element_get_state(radio->pipeline->pipeline, NULL, NULL, RADIO_GST_STATE_CHANGE_TIMEOUT); if (ret_state == GST_STATE_CHANGE_FAILURE) { MMRADIO_LOG_ERROR("GST_STATE_CHANGE_FAILURE"); return MM_ERROR_RADIO_INVALID_STATE; } else { MMRADIO_LOG_DEBUG("GST_STATE_NULL ret_state = %d (GST_STATE_CHANGE_SUCCESS)", ret_state); } MMRADIO_LOG_FLEAVE(); return ret; } int _mmradio_destroy_pipeline(mm_radio_t * radio) { int ret = 0; GstStateChangeReturn ret_state; MMRADIO_LOG_FENTER(); MMRADIO_CHECK_ARG(radio->pipeline); if (gst_element_set_state(radio->pipeline->pipeline, GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE) { MMRADIO_LOG_DEBUG("failed to change pipeline state"); gst_object_unref(radio->pipeline->pipeline); MMRADIO_GFREEIF(radio->pipeline); return MM_ERROR_RADIO_INVALID_STATE; } ret_state = gst_element_get_state(radio->pipeline->pipeline, NULL, NULL, RADIO_GST_STATE_CHANGE_TIMEOUT); if (ret_state == GST_STATE_CHANGE_FAILURE) { MMRADIO_LOG_DEBUG("GST_STATE_CHANGE_FAILURE"); gst_object_unref(radio->pipeline->pipeline); MMRADIO_GFREEIF(radio->pipeline); return MM_ERROR_RADIO_INVALID_STATE; } else { MMRADIO_LOG_DEBUG("GST_STATE_NULL ret_state = %d (GST_STATE_CHANGE_SUCCESS)", ret_state); } gst_object_unref(radio->pipeline->pipeline); MMRADIO_GFREEIF(radio->pipeline); MMRADIO_LOG_FLEAVE(); return ret; } int _mmradio_seek(mm_radio_t * radio, MMRadioSeekDirectionType direction) { 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; } MMRADIO_SLOG_DEBUG("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_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_start_scan(mm_radio_t * radio) { 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; p_thread->is_running = true; MMRADIO_THREAD_SIGNAL(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) { 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 */ if (radio->radio_fd < 0) { MMRADIO_SLOG_DEBUG("Device not ready so sending 0"); *value = 0; return MM_ERROR_NONE; } unsigned int seed = (unsigned)time(NULL); *value = 0 - ((rand_r(&seed) % 20 + 1) + 80); MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } void __mmradio_scan_thread(mm_radio_t * radio) { int prev_freq = 0; int emulatoridx = 0; int 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); MMRADIO_LOG_DEBUG("scan thread started. got signal."); if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting scan thread"); goto EXIT; } if (p_thread->stop) { MMRADIO_LOG_INFO("scan was stopped"); goto FINISHED; } if (_mmradio_set_frequency(radio, radio->region_setting.band_min) != MM_ERROR_NONE) goto FINISHED; if (radio->old_state == MM_RADIO_STATE_PLAYING) _mmradio_mute(radio); MMRADIO_POST_MSG(radio, MM_MESSAGE_RADIO_SCAN_START, NULL); MMRADIO_SET_STATE(radio, MM_RADIO_STATE_SCANNING); prev_freq = 0; emulatoridx = 0; while (!p_thread->stop) { freq = 0; MMRADIO_LOG_DEBUG("scanning...."); /* now we can get new frequency from radio device */ if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting scan thread"); goto EXIT; } if (p_thread->stop) break; usleep(1000 * 1000); freq = MMRadioEmulatorFreq[emulatoridx]; MMRADIO_LOG_DEBUG("freq: %d", freq); if (freq < prev_freq) { MMRADIO_LOG_DEBUG("scanning wrapped around. stopping scan"); break; } if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting scan thread"); goto EXIT; } if (p_thread->stop) break; if (freq == prev_freq) continue; prev_freq = freq; MMRADIO_LOG_INFO("scanning : new frequency : [%d]", freq); /* drop if out of range freq is scanned */ if (freq >= radio->region_setting.band_max || freq < radio->region_setting.band_min) { MMRADIO_LOG_DEBUG("%d freq is dropping...and stopping scan", freq); break; } if (p_thread->stop) break; /* doesn't need to post */ __mmradio_msg_push(radio, MM_RADIO_MSG_SCAN_INFO, freq); emulatoridx++; if (emulatoridx >= EMULATOR_FREQ_MAX) break; } FINISHED: if (radio->old_state == MM_RADIO_STATE_READY) { MMRADIO_SET_STATE(radio, MM_RADIO_STATE_READY); } else if (radio->old_state == MM_RADIO_STATE_PLAYING) { _mmradio_unmute(radio); MMRADIO_SET_STATE(radio, MM_RADIO_STATE_PLAYING); /* check if it's limit freq or not */ if (__is_tunable_frequency(radio, freq)) { /* now tune to new frequency */ if (_mmradio_set_frequency(radio, freq)) MMRADIO_LOG_ERROR("failed to tune to new frequency"); } } 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: MMRADIO_THREAD_UNLOCK(p_thread); 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 freq = 0; int i = 0; int emulatoridx = 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.\n"); MMRADIO_THREAD_WAIT(p_thread); if (p_thread->thread_exit) { MMRADIO_LOG_DEBUG("exiting seek thread"); break; } 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; } emulatoridx = 0; freq = 0; MMRADIO_LOG_DEBUG("start radio->freq: %d", radio->freq); if (radio->seek_direction == MM_RADIO_SEEK_UP) { for (i = 0; i < EMULATOR_FREQ_MAX; i++) { if (radio->freq < MMRadioEmulatorFreq[i]) { freq = MMRadioEmulatorFreq[i]; emulatoridx = i; break; } } if (!freq) { freq = MMRadioEmulatorFreq[0]; emulatoridx = 0; } } else { for (i = EMULATOR_FREQ_MAX - 1; i >= 0; i--) { if (radio->freq > MMRadioEmulatorFreq[i]) { freq = MMRadioEmulatorFreq[i]; emulatoridx = i; break; } } if (!freq) { freq = MMRadioEmulatorFreq[EMULATOR_FREQ_MAX - 1]; emulatoridx = EMULATOR_FREQ_MAX - 1; } } radio->freq = freq; MMRADIO_LOG_DEBUG("radio->freq: %d emulatoridx: %d", radio->freq, emulatoridx); MMRADIO_LOG_DEBUG("found frequency"); /* 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."); goto SEEK_FAILED; } /* check if it's limit freq or not */ if (__is_tunable_frequency(radio, freq)) { /* now tune to new frequency */ if (_mmradio_set_frequency(radio, freq)) { MMRADIO_LOG_ERROR("failed to tune to new frequency"); goto SEEK_FAILED; } } radio->prev_seek_freq = 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); p_thread->stop = true; continue; SEEK_FAILED: /* freq -1 means it's failed to seek */ __mmradio_msg_push(radio, MM_RADIO_MSG_SEEK_FINISHED, -1); p_thread->stop = true; p_thread->is_running = false; } MMRADIO_THREAD_UNLOCK(p_thread); MMRADIO_LOG_FLEAVE(); 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) { 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_DEBUG("incoming 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: { /* 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_DEBUG("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; } static int __mmradio_get_wave_num(mm_radio_t * radio) { int val = 0; MMRADIO_LOG_FENTER(); if (radio->freq <= MMRadioEmulatorFreq[0]) val = 1; else if (radio->freq <= MMRadioEmulatorFreq[1]) val = 2; else if (radio->freq <= MMRadioEmulatorFreq[2]) val = 5; else if (radio->freq <= MMRadioEmulatorFreq[3]) val = 7; else if (radio->freq <= MMRadioEmulatorFreq[4]) val = 9; else val = 11; MMRADIO_LOG_DEBUG("freq: %d, val : %d", radio->freq, val); MMRADIO_LOG_FLEAVE(); return val; } 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; } int _mmradio_set_volume(mm_radio_t *radio, float volume) { MMRADIO_LOG_FENTER(); MMRADIO_CHECK_INSTANCE(radio); MMRADIO_CHECK_STATE_RETURN_IF_FAIL(radio, MMRADIO_COMMAND_SET_VOLUME); MMRADIO_SLOG_DEBUG("Setting %f volume", volume); /* check volume range */ if (volume < RADIO_MIN_VOLUME || volume > RADIO_MAX_VOLUME) { MMRADIO_LOG_ERROR("out of volume range"); return MM_ERROR_INVALID_ARGUMENT; } if (radio->radio_fd < 0) { MMRADIO_LOG_DEBUG("radio device is not opened yet"); radio->local_volume = volume; return MM_ERROR_NONE; } radio->local_volume = volume; if (radio->pipeline && radio->pipeline->volume) { g_object_set(radio->pipeline->volume, "volume", volume, NULL); MMRADIO_LOG_DEBUG("g_object set volume"); } MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } int _mmradio_get_volume(mm_radio_t *radio, float *pVolume) { 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_SLOG_DEBUG("volume : %f", radio->local_volume); *pVolume = radio->local_volume; MMRADIO_LOG_FLEAVE(); return MM_ERROR_NONE; } 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); 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); 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); 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); break; } } 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); 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); 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; 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("popped 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"); mm_radio_msg_t *msg_pop = NULL; 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 finished 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); }