Add support for radio 69/73369/3 accepted/tizen/mobile/20160608.084539 submit/tizen/20160608.063231
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 8 Jun 2016 01:54:15 +0000 (10:54 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 8 Jun 2016 06:09:56 +0000 (15:09 +0900)
[Version] 0.1.11
[Profile] Mobile
[Issue Type] Feature Enhancement

Change-Id: I1ac916a95a2b3dceeb4243a4b6f41e6d0feccc41
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/audio-hal-sc7727.spec
tizen-audio-impl-pcm.c
tizen-audio-impl-ucm.c
tizen-audio-impl.h
tizen-audio-internal.h
tizen-audio-modem.c
tizen-audio-pcm.c
tizen-audio-routing.c
tizen-audio-stream.c
tizen-audio-volume.c

index 4bb1fe2..9adb3dc 100644 (file)
@@ -1,6 +1,6 @@
 Name:       audio-hal-sc7727
 Summary:    TIZEN Audio HAL for SC7727
-Version:    0.1.10
+Version:    0.1.11
 Release:    0
 Group:      System/Libraries
 License:    Apache-2.0
index a478143..efb62fc 100644 (file)
@@ -183,16 +183,83 @@ static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
 }
 #endif
 
-int _voice_pcm_open(audio_hal_t *ah)
+audio_return_t _fmradio_pcm_open(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+    int ret = 0;
+    const char *device_name = NULL;
+    audio_pcm_sample_spec_t sample_spec;
+    uint8_t use_mmap = 0;
+    sample_spec.rate = 44100;
+    sample_spec.channels = 2;
+    sample_spec.format = SND_PCM_FORMAT_S16_LE;
+
+    if ((audio_ret = _ucm_get_device_name(ah, AUDIO_USE_CASE_VERB_FMRADIO, AUDIO_DIRECTION_OUT, &device_name)))
+        goto error_exit;
+
+#ifdef __USE_TINYALSA__
+    AUDIO_LOG_WARN("need implementation for tinyAlsa");
+    return AUDIO_ERR_NOT_IMPLEMENTED;
+#else
+    if (device_name) {
+        if((ret = snd_pcm_open((snd_pcm_t **)&ah->device.fmradio_pcm_out, (char *)device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+            AUDIO_LOG_ERROR("[%s] out pcm_open failed", device_name);
+            audio_ret = AUDIO_ERR_IOCTL;
+            goto error_exit;
+        }
+        AUDIO_LOG_INFO("[%s] out pcm_open success:%p", device_name, ah->device.fmradio_pcm_out);
+
+        if ((audio_ret = _pcm_set_hw_params(ah->device.fmradio_pcm_out, &sample_spec, &use_mmap, NULL, NULL)) < 0) {
+            AUDIO_LOG_ERROR("[%s] out __set_pcm_hw_params failed", device_name);
+            if ((audio_ret = _pcm_close(ah->device.pcm_out)))
+                AUDIO_LOG_ERROR("failed to _pcm_close(), ret(0x%x)", audio_ret);
+            ah->device.fmradio_pcm_out = NULL;
+            goto error_exit;
+        }
+    }
+#endif
+
+error_exit:
+    if (device_name)
+        free((void*)device_name);
+
+    return audio_ret;
+}
+
+audio_return_t _fmradio_pcm_close(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    AUDIO_LOG_INFO("close fmradio pcm handles");
+
+    if (ah->device.fmradio_pcm_out) {
+        if ((audio_ret = _pcm_close(ah->device.fmradio_pcm_out)))
+            AUDIO_LOG_ERROR("failed to _fmradio_pcm_close() for pcm_out, ret(0x%x)", audio_ret);
+        else {
+            ah->device.fmradio_pcm_out = NULL;
+            AUDIO_LOG_INFO("fmradio pcm_out handle close success");
+        }
+    }
+
+    return audio_ret;
+}
+
+audio_return_t _voice_pcm_open(audio_hal_t *ah)
 {
     int err, ret = 0;
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
+#ifdef __USE_TINYALSA__
+    AUDIO_LOG_WARN("need implementation for tinyAlsa");
+    return AUDIO_ERR_NOT_IMPLEMENTED;
+#else
     AUDIO_LOG_INFO("open voice pcm handles");
 
     /* Get playback voice-pcm from ucm conf. Open and set-params */
-    if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
+    if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
         AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
         return AUDIO_ERR_IOCTL;
     }
@@ -201,51 +268,70 @@ int _voice_pcm_open(audio_hal_t *ah)
     AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
 
     /* Get capture voice-pcm from ucm conf. Open and set-params */
-    if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
+    if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
         AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
         return AUDIO_ERR_IOCTL;
     }
     ret = __voice_pcm_set_params(ah, ah->device.pcm_in);
     AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
+#endif
 
-    return ret;
+    return (ret == 0 ? AUDIO_RET_OK : AUDIO_ERR_INTERNAL);
 }
 
-int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
+audio_return_t _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
 {
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
     AUDIO_LOG_INFO("close voice pcm handles");
 
     if (ah->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
-        _pcm_close(ah->device.pcm_out);
-        ah->device.pcm_out = NULL;
-        AUDIO_LOG_INFO("voice pcm_out handle close success");
+        if ((audio_ret = _pcm_close(ah->device.pcm_out)))
+            AUDIO_LOG_ERROR("failed to _pcm_close() for pcm_out, ret(0x%x)", audio_ret);
+        else {
+            ah->device.pcm_out = NULL;
+            AUDIO_LOG_INFO("voice pcm_out handle close success");
+        }
     } else if (ah->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
-        _pcm_close(ah->device.pcm_in);
-        ah->device.pcm_in = NULL;
-        AUDIO_LOG_INFO("voice pcm_in handle close success");
+        if ((audio_ret = _pcm_close(ah->device.pcm_in)))
+            AUDIO_LOG_ERROR("failed to _pcm_close() for pcm_in, ret(0x%x)", audio_ret);
+        else {
+            ah->device.pcm_in = NULL;
+            AUDIO_LOG_INFO("voice pcm_in handle close success");
+        }
     }
 
-    return AUDIO_RET_OK;
+    return audio_ret;
 }
 
-void _reset_pcm_devices(audio_hal_t *ah)
+audio_return_t _reset_pcm_devices(audio_hal_t *ah)
 {
-    AUDIO_RETURN_IF_FAIL(ah);
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
     if (ah->device.pcm_out) {
-        _pcm_close(ah->device.pcm_out);
-        ah->device.pcm_out = NULL;
-        AUDIO_LOG_INFO("pcm_out handle close success");
+        if (!(audio_ret = _pcm_close(ah->device.pcm_out))) {
+            ah->device.pcm_out = NULL;
+            AUDIO_LOG_INFO("pcm_out handle close success");
+        }
     }
     if (ah->device.pcm_in) {
-        _pcm_close(ah->device.pcm_in);
-        ah->device.pcm_in = NULL;
-        AUDIO_LOG_INFO("pcm_in handle close success");
+        if (!(audio_ret = _pcm_close(ah->device.pcm_in))) {
+            ah->device.pcm_in = NULL;
+            AUDIO_LOG_INFO("pcm_in handle close success");
+        }
+    }
+    if (ah->device.fmradio_pcm_out) {
+        if (!(audio_ret = _pcm_close(ah->device.fmradio_pcm_out))) {
+            ah->device.fmradio_pcm_out = NULL;
+            AUDIO_LOG_INFO("fmradio_pcm_out handle close success");
+        }
     }
 
-    return;
+    return audio_ret;
 }
 
 audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
index 1dfe50a..23ce1a0 100644 (file)
@@ -122,6 +122,24 @@ audio_return_t _ucm_deinit(audio_hal_t *ah)
     return AUDIO_RET_OK;
 }
 
+audio_return_t _ucm_get_device_name(audio_hal_t *ah, const char *use_case, audio_direction_t direction, const char **value)
+{
+    char identifier[70] = { 0, };
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(use_case, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+
+    snprintf(identifier, sizeof(identifier), "%sPCM//%s",
+             (direction == AUDIO_DIRECTION_IN) ? "Capture" : "Playback", use_case);
+
+    snd_use_case_get(ah->ucm.uc_mgr, identifier, value);
+
+    AUDIO_LOG_INFO("get device name : [%s]", *value);
+
+    return AUDIO_RET_OK;
+}
+
 /* UCM sequence
     1) If verb is null or verb is not changed
     1-1) If device is changed
index 4410541..26a54a5 100644 (file)
  */
 
 /* PCM */
-int _voice_pcm_open(audio_hal_t *ah);
-int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
-void _reset_pcm_devices(audio_hal_t *ah);
+audio_return_t _fmradio_pcm_open(audio_hal_t *ah);
+audio_return_t _fmradio_pcm_close(audio_hal_t *ah);
+audio_return_t _voice_pcm_open(audio_hal_t *ah);
+audio_return_t _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
+audio_return_t _reset_pcm_devices(audio_hal_t *ah);
 audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
 audio_return_t _pcm_start(void *pcm_handle);
 audio_return_t _pcm_stop(void *pcm_handle);
@@ -39,6 +41,23 @@ audio_return_t _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, u
 audio_return_t _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size);
 
 /* Control */
+#define VBC_TD_CHANNELID                     0  /*  cp [3g] */
+#define VBC_ARM_CHANNELID                    2  /*  ap */
+#define MIXER_VBC_SWITCH                     "VBC Switch"
+#define PIN_SWITCH_IIS0_SYS_SEL              "IIS0 pin select"
+#define PIN_SWITCH_IIS0_AP_ID                0
+#define PIN_SWITCH_IIS0_CP0_ID               1
+#define PIN_SWITCH_IIS0_CP1_ID               2
+#define PIN_SWITCH_IIS0_CP2_ID               3
+#define PIN_SWITCH_IIS0_VBC_ID               4
+#define PIN_SWITCH_BT_IIS_SYS_SEL            "BT IIS pin select"
+#define PIN_SWITCH_BT_IIS_CP0_IIS0_ID        0
+#define PIN_SWITCH_BT_IIS_CP1_IIS0_ID        4
+#define PIN_SWITCH_BT_IIS_AP_IIS0_ID         8
+#define PIN_SWITCH_BT_IIS_CON_SWITCH         "BT IIS con switch"
+#define MIXER_FMRADIO_L_VOLUME               "VBC STR DG Set"
+#define MIXER_FMRADIO_R_VOLUME               "VBC STL DG Set"
+#define MIXER_FMRADIO_MUTE                   "Digital FM Function"
 audio_return_t _control_init(audio_hal_t *ah);
 audio_return_t _control_deinit(audio_hal_t *ah);
 audio_return_t _mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
@@ -50,6 +69,7 @@ audio_return_t _mixer_control_get_element(audio_hal_t *ah, const char *ctl_name,
 /* UCM  */
 audio_return_t _ucm_init(audio_hal_t *ah);
 audio_return_t _ucm_deinit(audio_hal_t *ah);
+audio_return_t _ucm_get_device_name(audio_hal_t *ah, const char *use_case, audio_direction_t direction, const char **value);
 #define _ucm_update_use_case _ucm_set_use_case
 audio_return_t _ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[]);
 audio_return_t _ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[]);
index e9f0647..2b44f37 100644 (file)
@@ -143,7 +143,7 @@ typedef struct device_type {
 #define AUDIO_USE_CASE_VERB_VOICECALL               "Voice"
 #define AUDIO_USE_CASE_VERB_VIDEOCALL               "Video"
 #define AUDIO_USE_CASE_VERB_VOIP                    "VoIP"
-#define AUDIO_USE_CASE_VERB_LOOPBACK                "Loopback"
+#define AUDIO_USE_CASE_VERB_FMRADIO                 "DigitalFM"
 
 /* Modifiers */
 #define AUDIO_USE_CASE_MODIFIER_VOICESEARCH              "VoiceSearch"
@@ -183,7 +183,8 @@ typedef enum audio_route_mode {
     VERB_NORMAL,
     VERB_VOICECALL,
     VERB_VIDEOCALL,
-    VERB_VOIP
+    VERB_VOIP,
+    VERB_RADIO
 } audio_route_mode_t;
 
 typedef struct audio_hal_device {
@@ -191,17 +192,20 @@ typedef struct audio_hal_device {
     uint32_t active_out;
     snd_pcm_t *pcm_in;
     snd_pcm_t *pcm_out;
+    snd_pcm_t *fmradio_pcm_out;
     pthread_mutex_t pcm_lock;
     uint32_t pcm_count;
     device_info_t *init_call_devices;
     uint32_t num_of_call_devices;
     audio_route_mode_t mode;
+    uint32_t is_radio_on;
     pthread_cond_t device_cond;
     pthread_mutex_t device_lock;
 } audio_hal_device_t;
 
 /* Volume */
 #define AUDIO_VOLUME_LEVEL_MAX 16
+#define RADIO_VOLUME_MAX 16
 
 typedef enum audio_volume {
     AUDIO_VOLUME_TYPE_SYSTEM,           /**< System volume type */
@@ -244,6 +248,7 @@ enum {
 typedef struct audio_hal_volume {
     uint32_t volume_level[AUDIO_VOLUME_TYPE_MAX];
     audio_volume_value_table_t *volume_value_table;
+    int32_t radio_volume_value_table[RADIO_VOLUME_MAX];
 } audio_hal_volume_t;
 
 /* UCM */
@@ -337,6 +342,7 @@ audio_return_t _audio_comm_deinit(audio_hal_t *ah);
 audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices);
 int _audio_modem_is_call_connected(audio_hal_t *ah);
 audio_return_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value);
+audio_return_t _audio_volume_set_level_radio(audio_hal_t *ah, uint32_t level);
 
 typedef struct _dump_data {
     char *strbuf;
index 9ad85a7..31b5d2a 100644 (file)
 #include "tizen-audio-impl.h"
 
 #define vbc_thread_new pthread_create
-#define MIXER_VBC_SWITCH                            "VBC Switch"
-/* pin_switch */
-#define PIN_SWITCH_IIS0_SYS_SEL              "IIS0 pin select"
-#define PIN_SWITCH_IIS0_AP_ID                0
-#define PIN_SWITCH_IIS0_CP0_ID               1
-#define PIN_SWITCH_IIS0_CP1_ID               2
-#define PIN_SWITCH_IIS0_CP2_ID               3
-#define PIN_SWITCH_IIS0_VBC_ID               4
-
-#define PIN_SWITCH_BT_IIS_SYS_SEL            "BT IIS pin select"
-#define PIN_SWITCH_BT_IIS_CP0_IIS0_ID        0
-#define PIN_SWITCH_BT_IIS_CP1_IIS0_ID        4
-#define PIN_SWITCH_BT_IIS_AP_IIS0_ID         8
-
-#define PIN_SWITCH_BT_IIS_CON_SWITCH         "BT IIS con switch"
-
-#define VBC_TD_CHANNELID                            0  /*  cp [3g] */
-#define VBC_ARM_CHANNELID                           2  /*  ap */
-
 #define VBPIPE_DEVICE           "/dev/spipe_w6"
 #define VBPIPE_VOIP_DEVICE      "/dev/spipe_w4"
 #define VBC_CMD_TAG             "VBC"
@@ -173,16 +154,6 @@ static int __write_nonblock(int fd, void *buf, int bytes)
 
 }
 
-int _audio_modem_is_call_connected(audio_hal_t *ah)
-{
-    int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
-
-    _mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
-    AUDIO_LOG_INFO("modem is connected for call = %d", (val == VBC_TD_CHANNELID));
-
-    return (val == VBC_TD_CHANNELID) ? 1 : 0;
-}
-
 static int __vbc_write_response(int fd, unsigned int cmd, uint32_t paras_size)
 {
     int ret = 0;
@@ -202,7 +173,16 @@ static int __vbc_write_response(int fd, unsigned int cmd, uint32_t paras_size)
     return 0;
 }
 
-#define FM_IIS                                      0x10
+int _audio_modem_is_call_connected(audio_hal_t *ah)
+{
+    int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
+
+    _mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
+    AUDIO_LOG_INFO("modem is connected for call = %d", (val == VBC_TD_CHANNELID));
+
+    return (val == VBC_TD_CHANNELID) ? 1 : 0;
+}
+
 static void __i2s_pin_mux_sel(audio_hal_t *ah, int type)
 {
     audio_return_t ret = AUDIO_RET_OK;
@@ -216,11 +196,6 @@ static void __i2s_pin_mux_sel(audio_hal_t *ah, int type)
     AUDIO_LOG_INFO("type is %d",type);
     modem = ah->modem.cp;
 
-    if (type == FM_IIS) {
-        _mixer_control_set_value(ah,
-                    PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
-        return;
-    }
     if (type == 0) {
        if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
             if(modem->i2s_bt.is_ext) {
index 08dc5ab..de97595 100644 (file)
@@ -30,6 +30,7 @@ audio_return_t _audio_pcm_init(audio_hal_t *ah)
 
     ah->device.pcm_in = NULL;
     ah->device.pcm_out = NULL;
+    ah->device.fmradio_pcm_out = NULL;
     pthread_mutex_init(&ah->device.pcm_lock, NULL);
     pthread_mutex_init(&ah->device.device_lock, NULL);
     pthread_cond_init(&ah->device.device_cond, NULL);
index c2d03ea..ce0971e 100644 (file)
@@ -52,6 +52,7 @@ static const char* mode_to_verb_str[] = {
     AUDIO_USE_CASE_VERB_VOICECALL,
     AUDIO_USE_CASE_VERB_VIDEOCALL,
     AUDIO_USE_CASE_VERB_VOIP,
+    AUDIO_USE_CASE_VERB_FMRADIO,
 };
 
 static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
@@ -162,33 +163,51 @@ static audio_return_t __set_devices(audio_hal_t *ah, const char *verb, device_in
     return audio_ret;
 }
 
+static audio_return_t __connect_fm_radio(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    audio_ret = _mixer_control_set_value(ah,
+                    PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
+    return audio_ret;
+}
+
 static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
     device_info_t *devices = NULL;
     const char *verb = mode_to_verb_str[VERB_NORMAL];
-#if 0  /* Disable setting modifiers, because driver does not support it yet */
-    int mod_idx = 0;
-    const char *modifiers[MAX_MODIFIERS] = {NULL,};
-#endif
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
 
     if (ah->modem.is_connected) {
-        AUDIO_LOG_INFO("modem is connected, skip verb[%s]", verb);
+        AUDIO_LOG_WARN("modem is connected, skip verb[%s]", verb);
         return audio_ret;
     }
 
     if (ah->device.mode != VERB_NORMAL) {
-        if (ah->device.mode == VERB_VOICECALL) {
-            __reset_voice_devices_info(ah);
-            COND_SIGNAL(ah->device.device_cond, "device_cond");
+        if (ah->device.mode == VERB_RADIO) {
+            if (ah->device.is_radio_on && !ah->modem.is_connected) {
+                /* Skip setting NORMAL VERB and keep going with RADIO VERB */
+                AUDIO_LOG_WARN("radio is in progress, skip verb[%s]", verb);
+                verb = mode_to_verb_str[VERB_RADIO];
+            } else if (!ah->device.is_radio_on) {
+                if ((audio_ret = _fmradio_pcm_close(ah)))
+                    AUDIO_LOG_ERROR("failed to _fmradio_pcm_close(), ret(0x%x)", audio_ret);
+            }
+        } else {
+            if (ah->device.mode == VERB_VOICECALL) {
+                __reset_voice_devices_info(ah);
+                COND_SIGNAL(ah->device.device_cond, "device_cond");
+            }
+            _reset_pcm_devices(ah);
+            ah->device.mode = VERB_NORMAL;
         }
-        _reset_pcm_devices(ah);
-        ah->device.mode = VERB_NORMAL;
     }
 
-    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-    AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
-
     devices = route_info->device_infos;
 
     AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
@@ -198,28 +217,7 @@ static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_
         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
         return audio_ret;
     }
-    ah->device.mode = VERB_NORMAL;
 
-#if 0 /* Disable setting modifiers, because driver does not support it yet */
-    /* Set modifiers */
-    if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
-        modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
-    } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
-        if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
-            modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
-        else
-            modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
-    } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
-        if (ah->device.active_out)
-            modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
-    } else {
-        if (ah->device.active_in)
-            modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
-        else
-            modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
-    }
-    audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
-#endif
     return audio_ret;
 }
 
@@ -273,6 +271,40 @@ static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *device
     return audio_ret;
 }
 
+static audio_return_t __update_route_fmradio(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+    const char *verb = mode_to_verb_str[VERB_RADIO];
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+    AUDIO_LOG_INFO("update_route_fmradio++");
+
+    if (!ah->device.fmradio_pcm_out) {
+        if ((audio_ret = _fmradio_pcm_open(ah))) {
+            AUDIO_LOG_ERROR("Failed to _fmradio_pcm_open(): error = 0x%x", audio_ret);
+            return audio_ret;
+        }
+        _audio_volume_set_level_radio(ah, 0);
+    }
+
+    audio_ret = __set_devices(ah, verb, devices, num_of_devices);
+    if (audio_ret) {
+        AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+        return audio_ret;
+    }
+    /* FIXME. If necessary, set VERB_VOIP */
+    ah->device.mode = VERB_RADIO;
+
+    _audio_volume_set_level_radio(ah, ah->volume.volume_level[AUDIO_VOLUME_TYPE_MEDIA]);
+    if ((audio_ret = __connect_fm_radio(ah)))
+        AUDIO_LOG_ERROR("failed to __connect_fm_radio(), ret(0x%x)", audio_ret);
+
+    /* TO DO: Set modifiers */
+    return audio_ret;
+}
+
 static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
@@ -307,11 +339,16 @@ static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
         }
     }
     if (ah->device.mode == VERB_VOICECALL) {
-        _voice_pcm_close(ah, direction);
+        if ((audio_ret = _voice_pcm_close(ah, direction)))
+            AUDIO_LOG_ERROR("failed to _voice_pcm_close(), ret(0x%x)", audio_ret);
         if (!ah->device.active_in && !ah->device.active_out)
             ah->device.mode = VERB_NORMAL;
         __reset_voice_devices_info(ah);
         COND_SIGNAL(ah->device.device_cond, "device_cond");
+    } else if (ah->device.mode == VERB_RADIO) {
+        if ((audio_ret = _fmradio_pcm_close(ah)))
+            AUDIO_LOG_ERROR("failed to _fmradio_pcm_close(), ret(0x%x)", audio_ret);
+        ah->device.mode = VERB_NORMAL;
     }
 
     if (active_devices[0] == NULL) {
@@ -339,6 +376,7 @@ audio_return_t _audio_routing_init(audio_hal_t *ah)
     ah->device.active_in = 0x0;
     ah->device.active_out = 0x0;
     ah->device.mode = VERB_NORMAL;
+    ah->device.is_radio_on = 0;
 
     if ((audio_ret = _ucm_init(ah)))
         AUDIO_LOG_ERROR("failed to _ucm_init(), ret(0x%x)", audio_ret);
@@ -432,6 +470,10 @@ audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
         if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
             AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
 
+    } else if (!strncmp("radio", info->role, MAX_NAME_LEN)) {
+        if ((audio_ret = __update_route_fmradio(ah, devices, info->num_of_devices)))
+            AUDIO_LOG_WARN("update radio route return 0x%x", audio_ret);
+
     } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
         if ((audio_ret = __update_route_reset(ah, devices->direction)))
             AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
index f89a0b6..582b1aa 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 
 #include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
 
 /* Audio latency */
 static const char* AUDIO_LATENCY_LOW  = "low";
@@ -108,6 +109,12 @@ audio_return_t audio_notify_stream_connection_changed(void *audio_handle, audio_
     AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
 
     AUDIO_LOG_INFO("role:%s, direction:%u, idx:%u, is_connected:%d", info->role, info->direction, info->idx, is_connected);
+    if (streq(info->role, "radio")) {
+        if (is_connected)
+            ah->device.is_radio_on = 1;
+        else
+            ah->device.is_radio_on = 0;
+    }
 
     return audio_ret;
 }
index 6d83d29..904e720 100644 (file)
 #include <iniparser.h>
 
 #include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
 
 #define VOLUME_INI_DEFAULT_PATH     SYSCONFDIR"/multimedia/mmfw_audio_volume.ini" /* SYSCONFDIR is defined at .spec */
 #define VOLUME_INI_TEMP_PATH        "/opt/system/mmfw_audio_volume.ini"
 #define VOLUME_VALUE_MAX            (1.0f)
 #define GAIN_VALUE_MAX              (1.0f)
+#define RADIO_TUNING_DEFUALT_FILE   SYSCONFDIR"/multimedia/mmfw_fmradio.ini"
+#define RADIO_TUNING_TEMP_FILE      "/opt/system/.mmfw_fmradio.ini"
+#define RADIO_TUNING_ENABLE         "tuning:enable"
+#define RADIO_TUNING_VOLUME_LEVELS  "fmradio:volume_levels"
+#define RADIO_TUNING_VOLUME_TABLE   "fmradio:volume_table"
 
 static const char *g_volume_vconf[AUDIO_VOLUME_TYPE_MAX] = {
     "file/private/sound/volume/system",         /* AUDIO_VOLUME_TYPE_SYSTEM */
@@ -252,12 +258,139 @@ static audio_return_t __load_volume_value_table_from_ini(audio_hal_t *ah)
     return AUDIO_RET_OK;
 }
 
+static audio_return_t __load_radio_volume_table(int** volume_table, int *number_of_elements)
+{
+    dictionary * dict = NULL;
+    const char delimiter[] = ", ";
+    char* ptr = NULL;
+    char* token = NULL;
+    char* list_str = NULL;
+    int* temp_table = NULL;
+    int index = 0;
+    int ret = 0;
+
+    bool tuning_enable = 0;
+    int not_found = -1;
+    int value = 0;
+
+    dict = iniparser_load(RADIO_TUNING_DEFUALT_FILE);
+    if (dict == NULL) {
+        AUDIO_LOG_ERROR("%s load failed", RADIO_TUNING_DEFUALT_FILE);
+        return AUDIO_ERR_UNDEFINED;
+    } else {
+        /*tuning enable */
+        value = iniparser_getboolean(dict, RADIO_TUNING_ENABLE, not_found);
+        if (value == not_found) {
+            AUDIO_LOG_ERROR("Can't get Tuning Enable value");
+        } else {
+            tuning_enable = value;
+            AUDIO_LOG_INFO("Tuning enabled.");
+        }
+        iniparser_freedict(dict); /*Cleanup*/
+    }
+
+    if (tuning_enable) {
+        AUDIO_LOG_INFO("Tuning enabled. load temp tuning file.");
+        dict = iniparser_load(RADIO_TUNING_TEMP_FILE);
+        if (!dict) {
+            AUDIO_LOG_WARN("%s load failed. Tuning enabled but there is not tuning temp file.  Use temporary file", RADIO_TUNING_TEMP_FILE);
+            dict = iniparser_load(RADIO_TUNING_DEFUALT_FILE);
+            if (!dict) {
+                AUDIO_LOG_ERROR("%s load failed", RADIO_TUNING_DEFUALT_FILE);
+                return AUDIO_ERR_UNDEFINED;
+            }
+        }
+    } else {
+        AUDIO_LOG_INFO("Tuning diabled. load default tuning file.");
+        dict = iniparser_load(RADIO_TUNING_DEFUALT_FILE);
+        if (!dict) {
+            AUDIO_LOG_ERROR("%s load failed", RADIO_TUNING_DEFUALT_FILE);
+            return AUDIO_ERR_UNDEFINED;
+        }
+    }
+
+    *number_of_elements = iniparser_getint(dict, RADIO_TUNING_VOLUME_LEVELS, -1);
+    if (*number_of_elements == -1) {
+        ret = AUDIO_ERR_INTERNAL;
+        goto error;
+    }
+        temp_table = (int *)malloc ((*number_of_elements) * sizeof(int));
+    if (!temp_table) {
+        goto error;
+    }
+    *volume_table = temp_table;
+
+    list_str = iniparser_getstring(dict, RADIO_TUNING_VOLUME_TABLE, NULL);
+    if (list_str) {
+        token = strtok_r(list_str, delimiter, &ptr);
+        while (token) {
+            temp_table[index] = atoi(token);
+            AUDIO_LOG_INFO("fm volume index %d is %d", index, temp_table[index]);
+            index++;
+            token = strtok_r(NULL, delimiter, &ptr);
+        }
+    }
+error:
+    iniparser_freedict(dict);
+    return ret;
+}
+
+audio_return_t _audio_volume_set_level_radio(audio_hal_t *ah, uint32_t level)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    int volume = 0;
+    int mute = -1;
+
+    /* Applying mute at volume zero */
+    if (level == 0) {
+        if ((audio_ret = _mixer_control_set_value(ah, MIXER_FMRADIO_MUTE, 0)))
+            AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_MUTE);
+
+    } else {
+        if ((audio_ret = _mixer_control_get_value(ah, MIXER_FMRADIO_MUTE, &mute))) {
+            AUDIO_LOG_ERROR("get mixer(%s) failed", MIXER_FMRADIO_MUTE);
+            return audio_ret;
+        }
+        if (mute == 0) {
+            if ((audio_ret = _mixer_control_set_value(ah, MIXER_FMRADIO_MUTE, 1))) {
+                AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_MUTE);
+                return audio_ret;
+            }
+        }
+    }
+
+    if ((_mixer_control_get_value(ah, MIXER_FMRADIO_L_VOLUME, &volume)))
+        AUDIO_LOG_ERROR("get mixer(%s) failed", MIXER_FMRADIO_L_VOLUME);
+    else {
+        if (volume != ah->volume.radio_volume_value_table[level]) {
+            if ((audio_ret = _mixer_control_set_value(ah, MIXER_FMRADIO_L_VOLUME, ah->volume.radio_volume_value_table[level]))) {
+                AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_L_VOLUME);
+                return audio_ret;
+            }
+        }
+    }
+
+    if ((_mixer_control_get_value(ah, MIXER_FMRADIO_R_VOLUME, &volume)))
+        AUDIO_LOG_ERROR("get mixer(%s) failed", MIXER_FMRADIO_R_VOLUME);
+    else {
+        if (volume != ah->volume.radio_volume_value_table[level]) {
+            if ((audio_ret = _mixer_control_set_value(ah, MIXER_FMRADIO_R_VOLUME, ah->volume.radio_volume_value_table[level])))
+                AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_R_VOLUME);
+        }
+    }
+
+    return audio_ret;
+}
+
 audio_return_t _audio_volume_init(audio_hal_t *ah)
 {
     int i;
     int val = 0;
     audio_return_t audio_ret = AUDIO_RET_OK;
     int init_value[AUDIO_VOLUME_TYPE_MAX] = { 9, 11, 7, 11, 7, 4, 4, 7 };
+    int* fm_table = NULL;
+    int number_of_steps = 0;
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
@@ -287,6 +420,18 @@ audio_return_t _audio_volume_init(audio_hal_t *ah)
         return AUDIO_ERR_UNDEFINED;
     }
 
+    /* radio volume table */
+    __load_radio_volume_table(&fm_table, &number_of_steps);
+    if (fm_table) {
+        AUDIO_LOG_DEBUG("number of steps -> %d", number_of_steps);
+        /*copy from temp structure to main strcture*/
+        for (i = 0; i < number_of_steps; i++) {
+            ah->volume.radio_volume_value_table[i] = fm_table[i];
+        }
+        free(fm_table);
+        fm_table = NULL;
+    }
+
     return audio_ret;
 }
 
@@ -366,6 +511,8 @@ audio_return_t audio_set_volume_level(void *audio_handle, audio_volume_info_t *i
     AUDIO_LOG_INFO("set [%s] volume_level: %d, direction(%d)", info->type, level, info->direction);
 
     /* set mixer related to H/W volume if needed */
+    if ((__get_volume_idx_by_string_type(info->type) == AUDIO_VOLUME_TYPE_MEDIA) && ah->device.is_radio_on)
+        audio_ret = _audio_volume_set_level_radio(ah, level);
 
     return audio_ret;
 }