From d2f3c3b46baa2caadbbecdeb3ff65472102ae6ba Mon Sep 17 00:00:00 2001 From: Shashank Mittal Date: Thu, 2 May 2013 20:27:47 -0700 Subject: [PATCH 001/298] audio: msm8974: Fix device number for voice call usecase. Change-Id: I55e69cb64cc061fabed08fcacb5145dcf4530c7b --- hal/audio_hw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c5acd17e5..64c313c1f 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -78,7 +78,11 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1}, [USECASE_AUDIO_RECORD] = {0, 0}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {14, 14}, +#ifdef MSM8974 + [USECASE_VOICE_CALL] = {2, 2}, +#else [USECASE_VOICE_CALL] = {12, 12}, +#endif }; /* Array to store sound devices */ -- GitLab From 87f6ee0a0074149c8060a4c1672d2907d1a50a1a Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Tue, 7 May 2013 14:20:11 -0700 Subject: [PATCH 002/298] hal: Add support for voice call volume and mute - Set mixer controls to support mute/unmute and volume for voice call for non-fusion targets. - Non-fusion targets do not need CSD library for voice call functionality. Change-Id: Ie232d89691c3ca91a9a366ece020588d82fba679 --- hal/audio_hw.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- hal/audio_hw.h | 1 + 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 64c313c1f..49b04348a 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -93,6 +93,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_SPEAKER] = "speaker", [SND_DEVICE_OUT_HEADPHONES] = "headphones", [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones", + [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset", [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker", [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones", [SND_DEVICE_OUT_HDMI] = "hdmi", @@ -131,13 +132,26 @@ static const char * const device_table[SND_DEVICE_MAX] = { static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_NONE] = -1, [SND_DEVICE_OUT_HANDSET] = 7, +#ifdef MSM8974 + [SND_DEVICE_OUT_SPEAKER] = 15, +#else [SND_DEVICE_OUT_SPEAKER] = 14, +#endif [SND_DEVICE_OUT_HEADPHONES] = 10, [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, + [SND_DEVICE_OUT_VOICE_HANDSET] = 7, +#ifdef MSM8974 + [SND_DEVICE_OUT_VOICE_SPEAKER] = 15, +#else [SND_DEVICE_OUT_VOICE_SPEAKER] = 14, +#endif [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10, [SND_DEVICE_OUT_HDMI] = 18, +#ifdef MSM8974 + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, +#else [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14, +#endif [SND_DEVICE_OUT_BT_SCO] = 22, [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81, [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, @@ -145,7 +159,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, [SND_DEVICE_IN_HANDSET_MIC] = 4, - [SND_DEVICE_IN_SPEAKER_MIC] = 4, + [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */ [SND_DEVICE_IN_HEADSET_MIC] = 8, [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, @@ -483,6 +497,38 @@ static int read_hdmi_channel_masks(struct stream_out *out) return ret; } +static int set_voice_volume(struct mixer *mixer, + int volume) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voice Rx Volume"; + ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting voice volume: %d", volume); + mixer_ctl_set_value(ctl, 0, volume); + return 0; +} + +static int set_mic_mute(struct mixer *mixer, + int mute) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voice Tx Mute"; + ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting mic mute: %d", mute); + mixer_ctl_set_value(ctl, 0, mute); + return 0; +} + static snd_device_t get_output_snd_device(struct audio_device *adev, audio_devices_t devices) { @@ -1845,7 +1891,9 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 // So adjust the volume to get the correct volume index in driver vol = 100 - vol; - +#ifdef MSM8974 + set_voice_volume(adev->mixer, vol); +#else if (adev->csd_client) { if (adev->csd_volume == NULL) { ALOGE("%s: dlsym error for csd_client_volume", __func__); @@ -1858,6 +1906,7 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) } else { ALOGE("%s: No CSD Client present", __func__); } +#endif } pthread_mutex_unlock(&adev->lock); return err; @@ -1904,6 +1953,9 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) pthread_mutex_lock(&adev->lock); adev->mic_mute = state; if (adev->mode == AUDIO_MODE_IN_CALL) { +#ifdef MSM8974 + set_mic_mute(adev->mixer, state); +#else if (adev->csd_client) { if (adev->csd_mic_mute == NULL) { ALOGE("%s: dlsym error for csd_mic_mute", __func__); @@ -1916,6 +1968,7 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) } else { ALOGE("%s: No CSD Client present", __func__); } +#endif } pthread_mutex_unlock(&adev->lock); return err; diff --git a/hal/audio_hw.h b/hal/audio_hw.h index dec6ef206..1c34b91c3 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -50,6 +50,7 @@ typedef enum { SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_VOICE_HANDSET, SND_DEVICE_OUT_VOICE_SPEAKER, SND_DEVICE_OUT_VOICE_HEADPHONES, SND_DEVICE_OUT_HDMI, -- GitLab From fbf5d518e04ce4145db1c90965223cb64a40435e Mon Sep 17 00:00:00 2001 From: sangwoo Date: Mon, 20 May 2013 11:38:45 +0900 Subject: [PATCH 003/298] audio: Fix to send voice calibration during voice call To voice cal, use the acdb_send_voice_cal interface. Bug: 8966887 Change-Id: I95361d90bd74e4b8096bd2eb109e3eba05951fd9 --- hal/audio_hw.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 9b3ec13a8..92809c877 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -524,6 +524,12 @@ static int set_voice_volume(struct mixer *mixer, { struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Rx Volume"; + + // Voice volume levels are mapped to adsp volume levels as follows. + // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 + // But this values don't changed in kernel. So, below change is need. + volume = volume / 20; + ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); if (!ctl) { ALOGE("%s: Could not get ctl for mixer cmd - %s", @@ -953,6 +959,19 @@ static int select_devices(struct audio_device *adev, acdb_rx_id, acdb_tx_id); } } + } else if (usecase->type == VOICE_CALL) { + if (adev->acdb_send_voice_cal == NULL) { + ALOGE("%s: dlsym error for acdb_send_voice_call", __func__); + } else { + acdb_rx_id = get_acdb_device_id(out_snd_device); + acdb_tx_id = get_acdb_device_id(in_snd_device); + + if (acdb_rx_id > 0 && acdb_tx_id > 0) + adev->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id); + else + ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, + acdb_rx_id, acdb_tx_id); + } } return status; -- GitLab From 75ebaa052d5cad1b3b46c7beb40c9022b5806f04 Mon Sep 17 00:00:00 2001 From: Sungmin Choi Date: Wed, 22 May 2013 13:14:28 -0700 Subject: [PATCH 004/298] audio: Remove specific library path Some devices use /system/lib, others do /vendor/lib. Both are located in LD_LIBRARY_PATH whicn is defined in init.rc. So it doesn't need to use specific library path. Change-Id: I97e3abf3f84e8fe2d280d0714a32dd6861b5b937 --- hal/audio_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 92809c877..7ded47171 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -33,8 +33,8 @@ #include "audio_hw.h" -#define LIB_ACDB_LOADER "/system/lib/libacdbloader.so" -#define LIB_CSD_CLIENT "/system/lib/libcsd-client.so" +#define LIB_ACDB_LOADER "libacdbloader.so" +#define LIB_CSD_CLIENT "libcsd-client.so" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define MIXER_CARD 0 -- GitLab From c56336bfad4661796b749fc4db7de3a1e6aba06f Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 24 May 2013 16:55:17 -0700 Subject: [PATCH 005/298] QC audio HAL handles device rotation Use the "speaker-reverse" configuration when the device rotation requires it. Device rotation is received through a parameter to parse. Bug 9095903 Change-Id: Ie24a625a18e1fc1093f6f564ba0ff0f5cbb5cce0 --- hal/audio_hw.c | 44 +++++++++++++++++++++++++++++++++++++++++++- hal/audio_hw.h | 2 ++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c874aa822..7eef1f7a8 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -87,6 +87,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { /* Playback sound devices */ [SND_DEVICE_OUT_HANDSET] = "handset", [SND_DEVICE_OUT_SPEAKER] = "speaker", + [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse", [SND_DEVICE_OUT_HEADPHONES] = "headphones", [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones", [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker", @@ -131,6 +132,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_NONE] = -1, [SND_DEVICE_OUT_HANDSET] = 7, [SND_DEVICE_OUT_SPEAKER] = 14, + [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14, [SND_DEVICE_OUT_HEADPHONES] = 10, [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, [SND_DEVICE_OUT_VOICE_SPEAKER] = 14, @@ -568,7 +570,11 @@ static snd_device_t get_output_snd_device(struct audio_device *adev, devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_OUT_HEADPHONES; } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { - snd_device = SND_DEVICE_OUT_SPEAKER; + if (adev->speaker_lr_swap) { + snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE; + } else { + snd_device = SND_DEVICE_OUT_SPEAKER; + } } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { @@ -1839,6 +1845,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) struct str_parms *parms; char *str; char value[32]; + int val; int ret; ALOGD("%s: enter: %s", __func__, kvpairs); @@ -1888,6 +1895,40 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->screen_off = true; } + ret = str_parms_get_int(parms, "rotation", &val); + if (ret >= 0) { + bool reverse_speakers = false; + switch(val) { + // FIXME: note that the code below assumes that the speakers are in the correct placement + // relative to the user when the device is rotated 90deg from its default rotation. This + // assumption is device-specific, not platform-specific like this code. + case 270: + reverse_speakers = true; + break; + case 0: + case 90: + case 180: + break; + default: + ALOGE("%s: unexpected rotation of %d", __func__, val); + } + pthread_mutex_lock(&adev->lock); + if (adev->speaker_lr_swap != reverse_speakers) { + adev->speaker_lr_swap = reverse_speakers; + // only update the selected device if there is active pcm playback + struct audio_usecase *usecase; + struct listnode *node; + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK) { + select_devices(adev, usecase->id); + break; + } + } + } + pthread_mutex_unlock(&adev->lock); + } + str_parms_destroy(parms); ALOGD("%s: exit with code(%d)", __func__, ret); return ret; @@ -2264,6 +2305,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->bluetooth_nrec = true; adev->in_call = false; adev->acdb_settings = TTY_MODE_OFF; + adev->speaker_lr_swap = false; for (i = 0; i < SND_DEVICE_MAX; i++) { adev->snd_dev_ref_cnt[i] = 0; } diff --git a/hal/audio_hw.h b/hal/audio_hw.h index cb2f817b9..08426de60 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -51,6 +51,7 @@ typedef enum { SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN, SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN, SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_REVERSE, SND_DEVICE_OUT_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, SND_DEVICE_OUT_VOICE_SPEAKER, @@ -253,6 +254,7 @@ struct audio_device { struct listnode usecase_list; struct audio_route *audio_route; int acdb_settings; + bool speaker_lr_swap; bool mic_type_analog; bool fluence_in_spkr_mode; -- GitLab From bdfd2924d535d8d3de1bd63c407568134641ef18 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 28 May 2013 15:02:50 -0700 Subject: [PATCH 006/298] add device specific voice processing descriptors Add the possibility to define device specific effect descriptors in libqcomvoiceprocessingdescriptors.so. This will allow exposing different implementation UUISs according to device tuning so that applications can distinguish one from the other. Bug: 9126576. Change-Id: I8e6ca00cbc6386498a5df99b514b1c7b7b1fd82c --- voice_processing/voice_processing.c | 52 +++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c index f4120909e..b8b1e1b0a 100644 --- a/voice_processing/voice_processing.c +++ b/voice_processing/voice_processing.c @@ -16,6 +16,7 @@ #define LOG_TAG "voice_processing" /*#define LOG_NDEBUG 0*/ +#include #include #include #include @@ -28,6 +29,8 @@ // local definitions //------------------------------------------------------------------------------ +#define EFFECTS_DESCRIPTOR_LIBRARY_PATH "/system/lib/soundfx/libqcomvoiceprocessingdescriptors.so" + // types of pre processing modules enum effect_id { @@ -74,14 +77,15 @@ struct session_s { //------------------------------------------------------------------------------ -// Effect descriptors +// Default Effect descriptors. Device specific descriptors should be defined in +// libqcomvoiceprocessing..so if needed. //------------------------------------------------------------------------------ // UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html // as the pre processing effects are not defined by OpenSL ES // Acoustic Echo Cancellation -static const effect_descriptor_t aec_descriptor = { +static const effect_descriptor_t qcom_default_aec_descriptor = { { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type { 0x0f8d0d2a, 0x59e5, 0x45fe, 0xb6e4, { 0x24, 0x8c, 0x8a, 0x79, 0x91, 0x09 } }, // uuid EFFECT_CONTROL_API_VERSION, @@ -93,7 +97,7 @@ static const effect_descriptor_t aec_descriptor = { }; // Noise suppression -static const effect_descriptor_t ns_descriptor = { +static const effect_descriptor_t qcom_default_ns_descriptor = { { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type { 0x1d97bb0b, 0x9e2f, 0x4403, 0x9ae3, { 0x58, 0xc2, 0x55, 0x43, 0x06, 0xf8 } }, // uuid EFFECT_CONTROL_API_VERSION, @@ -106,7 +110,7 @@ static const effect_descriptor_t ns_descriptor = { //ENABLE_AGC // Automatic Gain Control -//static const effect_descriptor_t agc_descriptor = { +//static const effect_descriptor_t qcom_default_agc_descriptor = { // { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type // { 0x0dd49521, 0x8c59, 0x40b1, 0xb403, { 0xe0, 0x8d, 0x5f, 0x01, 0x87, 0x5e } }, // uuid // EFFECT_CONTROL_API_VERSION, @@ -117,10 +121,10 @@ static const effect_descriptor_t ns_descriptor = { // "Qualcomm Fluence" //}; -static const effect_descriptor_t *descriptors[NUM_ID] = { - &aec_descriptor, - &ns_descriptor, -//ENABLE_AGC &agc_descriptor, +const effect_descriptor_t *descriptors[NUM_ID] = { + &qcom_default_aec_descriptor, + &qcom_default_ns_descriptor, +//ENABLE_AGC &qcom_default_agc_descriptor, }; @@ -415,14 +419,39 @@ static struct session_s *get_session(int32_t id, int32_t sessionId, int32_t io } static int init() { - size_t i; - int status = 0; + void *lib_handle; + const effect_descriptor_t *desc; if (init_status <= 0) return init_status; + if (access(EFFECTS_DESCRIPTOR_LIBRARY_PATH, R_OK) == 0) { + lib_handle = dlopen(EFFECTS_DESCRIPTOR_LIBRARY_PATH, RTLD_NOW); + if (lib_handle == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, EFFECTS_DESCRIPTOR_LIBRARY_PATH); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, EFFECTS_DESCRIPTOR_LIBRARY_PATH); + desc = (const effect_descriptor_t *)dlsym(lib_handle, + "qcom_product_aec_descriptor"); + if (desc) + descriptors[AEC_ID] = desc; + + desc = (const effect_descriptor_t *)dlsym(lib_handle, + "qcom_product_ns_descriptor"); + if (desc) + descriptors[NS_ID] = desc; + +//ENABLE_AGC +// desc = (const effect_descriptor_t *)dlsym(lib_handle, +// "qcom_product_agc_descriptor"); +// if (desc) +// descriptors[AGC_ID] = desc; + } + } + uuid_to_id_table[AEC_ID] = FX_IID_AEC; uuid_to_id_table[NS_ID] = FX_IID_NS; +//ENABLE_AGC uuid_to_id_table[AGC_ID] = FX_IID_AGC; list_init(&session_list); @@ -700,6 +729,9 @@ static int lib_get_descriptor(const effect_uuid_t *uuid, if (pDescriptor == NULL || uuid == NULL) return -EINVAL; + if (init() != 0) + return init_status; + desc = get_descriptor(uuid); if (desc == NULL) { ALOGV("lib_get_descriptor() not found"); -- GitLab From c4ba743cc4e48b9feabccf03959642d63cf7076e Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 5 Jun 2013 14:11:39 -0700 Subject: [PATCH 007/298] hal: Fix Hangout and Voice call concurrency issue - While a hangout is in progress, if the user accepts an incoming voice call, there is no audio heard on the far-end. - The tx path for hangout is using voice-speaker-mic device and the voice call tx path tries to enable the voice-dmic-ef device. But both these device use same physical mic and same codec backend. When the Hangout is terminated it tries to disable the speaker-mic which disables mixer controls that are common with voice-dmic-ef. - Fix the issue by making sure all the capture usecases are routed to same input sound device always. Bug: 9228503 Change-Id: Iaf1b0e61d10437e2d9deeeffd7ca67770b6e00f6 --- hal/audio_hw.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 7eef1f7a8..275272ab8 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -426,6 +426,72 @@ static void check_usecases_codec_backend(struct audio_device *adev, } } +static void check_and_route_capture_usecases(struct audio_device *adev, + struct audio_usecase *uc_info, + snd_device_t snd_device) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool switch_device[AUDIO_USECASE_MAX]; + int i, num_uc_to_switch = 0; + + /* + * This function is to make sure that all the active capture usecases + * are always routed to the same input sound device. + * For example, if audio-record and voice-call usecases are currently + * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece) + * is received for voice call then we have to make sure that audio-record + * usecase is also switched to earpiece i.e. voice-dmic-ef, + * because of the limitation that two devices cannot be enabled + * at the same time if they share the same backend. + */ + for (i = 0; i < AUDIO_USECASE_MAX; i++) + switch_device[i] = false; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type != PCM_PLAYBACK && + usecase != uc_info && + usecase->in_snd_device != snd_device) { + ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", + __func__, use_case_table[usecase->id], + device_table[usecase->in_snd_device]); + disable_audio_route(adev, usecase, false); + switch_device[usecase->id] = true; + num_uc_to_switch++; + } + } + + if (num_uc_to_switch) { + /* Make sure all the streams are de-routed before disabling the device */ + audio_route_update_mixer(adev->audio_route); + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { + disable_snd_device(adev, usecase->in_snd_device, false); + enable_snd_device(adev, snd_device, false); + } + } + + /* Make sure new snd device is enabled before re-routing the streams */ + audio_route_update_mixer(adev->audio_route); + + /* Re-route all the usecases on the shared backend other than the + specified usecase to new snd devices */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + /* Update the in_snd_device only before enabling the audio route */ + if (switch_device[usecase->id] ) { + usecase->in_snd_device = snd_device; + enable_audio_route(adev, usecase, false); + } + } + + audio_route_update_mixer(adev->audio_route); + } +} + static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -879,8 +945,10 @@ static int select_devices(struct audio_device *adev, enable_snd_device(adev, out_snd_device, false); } - if (in_snd_device != SND_DEVICE_NONE) + if (in_snd_device != SND_DEVICE_NONE) { + check_and_route_capture_usecases(adev, usecase, in_snd_device); enable_snd_device(adev, in_snd_device, false); + } audio_route_update_mixer(adev->audio_route); -- GitLab From 518da37222759a15a9c6c7a564c6c2de4920aec2 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 5 Jun 2013 14:11:39 -0700 Subject: [PATCH 008/298] hal: Fix Hangout and Voice call concurrency issue - While a hangout is in progress, if the user accepts an incoming voice call, there is no audio heard on the far-end. - The tx path for hangout is using voice-speaker-mic device and the voice call tx path tries to enable the voice-dmic-ef device. But both these device use same physical mic and same codec backend. When the Hangout is terminated it tries to disable the speaker-mic which disables mixer controls that are common with voice-dmic-ef. - Fix the issue by making sure all the capture usecases are routed to same input sound device always. Bug: 9228503 Change-Id: Iaf1b0e61d10437e2d9deeeffd7ca67770b6e00f6 --- hal/audio_hw.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 7eef1f7a8..275272ab8 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -426,6 +426,72 @@ static void check_usecases_codec_backend(struct audio_device *adev, } } +static void check_and_route_capture_usecases(struct audio_device *adev, + struct audio_usecase *uc_info, + snd_device_t snd_device) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool switch_device[AUDIO_USECASE_MAX]; + int i, num_uc_to_switch = 0; + + /* + * This function is to make sure that all the active capture usecases + * are always routed to the same input sound device. + * For example, if audio-record and voice-call usecases are currently + * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece) + * is received for voice call then we have to make sure that audio-record + * usecase is also switched to earpiece i.e. voice-dmic-ef, + * because of the limitation that two devices cannot be enabled + * at the same time if they share the same backend. + */ + for (i = 0; i < AUDIO_USECASE_MAX; i++) + switch_device[i] = false; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type != PCM_PLAYBACK && + usecase != uc_info && + usecase->in_snd_device != snd_device) { + ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", + __func__, use_case_table[usecase->id], + device_table[usecase->in_snd_device]); + disable_audio_route(adev, usecase, false); + switch_device[usecase->id] = true; + num_uc_to_switch++; + } + } + + if (num_uc_to_switch) { + /* Make sure all the streams are de-routed before disabling the device */ + audio_route_update_mixer(adev->audio_route); + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { + disable_snd_device(adev, usecase->in_snd_device, false); + enable_snd_device(adev, snd_device, false); + } + } + + /* Make sure new snd device is enabled before re-routing the streams */ + audio_route_update_mixer(adev->audio_route); + + /* Re-route all the usecases on the shared backend other than the + specified usecase to new snd devices */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + /* Update the in_snd_device only before enabling the audio route */ + if (switch_device[usecase->id] ) { + usecase->in_snd_device = snd_device; + enable_audio_route(adev, usecase, false); + } + } + + audio_route_update_mixer(adev->audio_route); + } +} + static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -879,8 +945,10 @@ static int select_devices(struct audio_device *adev, enable_snd_device(adev, out_snd_device, false); } - if (in_snd_device != SND_DEVICE_NONE) + if (in_snd_device != SND_DEVICE_NONE) { + check_and_route_capture_usecases(adev, usecase, in_snd_device); enable_snd_device(adev, in_snd_device, false); + } audio_route_update_mixer(adev->audio_route); -- GitLab From ea6ef9d15574f1406940fae42914ffc49c85d659 Mon Sep 17 00:00:00 2001 From: sangwoo Date: Mon, 3 Jun 2013 10:37:22 +0900 Subject: [PATCH 009/298] audio: msm8974: change the ACDB ID for voice call msm8974 uses fluence version 5 in voice call. So, ACDB ID for handset and speaker voice call should be changed to 41 and 43. It depends on ACDB mapping table. Change-Id: I13990299230daa4cd0ade037d3c224f50013d9e9 --- hal/audio_hw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index d2bd9d02e..84daaada9 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -174,10 +174,18 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_HDMI_MIC] = 4, [SND_DEVICE_IN_BT_SCO_MIC] = 21, [SND_DEVICE_IN_CAMCORDER_MIC] = 61, +#ifdef MSM8974 + [SND_DEVICE_IN_VOICE_DMIC_EF] = 41, +#else [SND_DEVICE_IN_VOICE_DMIC_EF] = 6, +#endif [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91, +#ifdef MSM8974 + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43, +#else [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 13, +#endif [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, -- GitLab From 170731f27d4be8575249d95c116560f82f5661a3 Mon Sep 17 00:00:00 2001 From: sangwoo Date: Sat, 8 Jun 2013 15:36:36 +0900 Subject: [PATCH 010/298] audio: Change to perform voice calibration before update audio route If audio route is set before voice calibration, the TX and RX device tap is swapped in calibration tool. So, this sequence is changed to perform voice calibration before update audio route. Bug: 9363506 Change-Id: Ic7687a92f0d3c3faea0cf48f9d56e5877ba6255b --- hal/audio_hw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 92e24e78c..d96b1ea53 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1014,13 +1014,6 @@ static int select_devices(struct audio_device *adev, enable_snd_device(adev, in_snd_device, false); } - audio_route_update_mixer(adev->audio_route); - - usecase->in_snd_device = in_snd_device; - usecase->out_snd_device = out_snd_device; - - enable_audio_route(adev, usecase, true); - if (usecase->type == VOICE_CALL && adev->csd_client) { if (adev->csd_enable_device == NULL) { ALOGE("%s: dlsym error for csd_client_enable_device", @@ -1056,6 +1049,13 @@ static int select_devices(struct audio_device *adev, } } + audio_route_update_mixer(adev->audio_route); + + usecase->in_snd_device = in_snd_device; + usecase->out_snd_device = out_snd_device; + + enable_audio_route(adev, usecase, true); + return status; } -- GitLab From b23d5286490ad2dc0edf919d52428fa02dc2b2dc Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 14 May 2013 15:27:20 -0700 Subject: [PATCH 011/298] audio HAL: separate platform specific code Separate platform specific code from generic audio HAL code. Platform specific code is: - platform initialization - pcm device selection - pcm stream configuration - sound device selection - acdb ID selection - HDMI configuration Change-Id: Iaf327943fa8674aad0c22a71e7cbf4288a138c7d Conflicts: hal/audio_hw.c hal/audio_hw.h --- hal/Android.mk | 8 +- hal/audio_hw.c | 904 +++++------------------------------------ hal/audio_hw.h | 213 +--------- hal/edid.c | 93 ----- hal/msm8960/platform.c | 868 +++++++++++++++++++++++++++++++++++++++ hal/msm8960/platform.h | 117 ++++++ hal/msm8974/platform.c | 754 ++++++++++++++++++++++++++++++++++ hal/msm8974/platform.h | 118 ++++++ hal/platform_api.h | 39 ++ 9 files changed, 2024 insertions(+), 1090 deletions(-) delete mode 100644 hal/edid.c create mode 100644 hal/msm8960/platform.c create mode 100644 hal/msm8960/platform.h create mode 100644 hal/msm8974/platform.c create mode 100644 hal/msm8974/platform.h create mode 100644 hal/platform_api.h diff --git a/hal/Android.mk b/hal/Android.mk index 6db96a9d0..9e3c89779 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -8,7 +8,7 @@ LOCAL_ARM_MODE := arm LOCAL_SRC_FILES := \ audio_hw.c \ - edid.c + $(TARGET_BOARD_PLATFORM)/platform.c LOCAL_SHARED_LIBRARIES := \ liblog \ @@ -17,14 +17,12 @@ LOCAL_SHARED_LIBRARIES := \ libaudioroute \ libdl -ifeq ($(TARGET_BOARD_PLATFORM), msm8974) -LOCAL_CFLAGS += -DMSM8974 -endif LOCAL_C_INCLUDES += \ external/tinyalsa/include \ $(call include-path-for, audio-route) \ - $(call include-path-for, audio-effects) + $(call include-path-for, audio-effects) \ + $(LOCAL_PATH)/$(TARGET_BOARD_PLATFORM) LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index d96b1ea53..b73c95e02 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -23,40 +23,67 @@ #include #include #include -#include #include #include #include #include -#include +#include +#include +#include #include "audio_hw.h" +#include "platform_api.h" +#include -#define LIB_ACDB_LOADER "libacdbloader.so" -#define LIB_CSD_CLIENT "libcsd-client.so" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" -#define MIXER_CARD 0 -#define STRING_TO_ENUM(string) { #string, string } +struct pcm_config pcm_config_deep_buffer = { + .channels = 2, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, + .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, +}; -/* Flags used to initialize acdb_settings variable that goes to ACDB library */ -#define DMIC_FLAG 0x00000002 -#define TTY_MODE_OFF 0x00000010 -#define TTY_MODE_FULL 0x00000020 -#define TTY_MODE_VCO 0x00000040 -#define TTY_MODE_HCO 0x00000080 -#define TTY_MODE_CLEAR 0xFFFFFF0F +struct pcm_config pcm_config_low_latency = { + .channels = 2, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, + .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, +}; -struct string_to_enum { - const char *name; - uint32_t value; +struct pcm_config pcm_config_hdmi_multi = { + .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */ + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */ + .period_size = HDMI_MULTI_PERIOD_SIZE, + .period_count = HDMI_MULTI_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = 0, + .stop_threshold = INT_MAX, + .avail_min = 0, }; -static const struct string_to_enum out_channels_name_to_enum_table[] = { - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +struct pcm_config pcm_config_audio_capture = { + .channels = 2, + .period_size = AUDIO_CAPTURE_PERIOD_SIZE, + .period_count = AUDIO_CAPTURE_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_voice_call = { + .channels = 1, + .rate = 8000, + .period_size = 160, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, }; static const char * const use_case_table[AUDIO_USECASE_MAX] = { @@ -68,193 +95,20 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_VOICE_CALL] = "voice-call", }; -static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { - [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0}, -#ifdef MSM8974 - [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15}, -#else - [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {14, 14}, -#endif - [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1}, - [USECASE_AUDIO_RECORD] = {0, 0}, - [USECASE_AUDIO_RECORD_LOW_LATENCY] = {14, 14}, -#ifdef MSM8974 - [USECASE_VOICE_CALL] = {2, 2}, -#else - [USECASE_VOICE_CALL] = {12, 12}, -#endif -}; -/* Array to store sound devices */ -static const char * const device_table[SND_DEVICE_MAX] = { - [SND_DEVICE_NONE] = "none", - /* Playback sound devices */ - [SND_DEVICE_OUT_HANDSET] = "handset", - [SND_DEVICE_OUT_SPEAKER] = "speaker", - [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse", - [SND_DEVICE_OUT_HEADPHONES] = "headphones", - [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones", - [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset", - [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker", - [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones", - [SND_DEVICE_OUT_HDMI] = "hdmi", - [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", - [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus", - [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", - [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", - [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", - - /* Capture sound devices */ - [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", - [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", - [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", - [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic", - [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "voice-speaker-mic", - [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic", - [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", - [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", - [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", - [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", - [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", - [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef", - [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs", - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus", - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef", - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs", - [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", - [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", - [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", - [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", - [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef", - [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs", - [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence", - [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence", -}; +#define STRING_TO_ENUM(string) { #string, string } -/* ACDB IDs (audio DSP path configuration IDs) for each sound device */ -static const int acdb_device_table[SND_DEVICE_MAX] = { - [SND_DEVICE_NONE] = -1, - [SND_DEVICE_OUT_HANDSET] = 7, -#ifdef MSM8974 - [SND_DEVICE_OUT_SPEAKER] = 15, -#else - [SND_DEVICE_OUT_SPEAKER] = 14, -#endif - [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14, - [SND_DEVICE_OUT_HEADPHONES] = 10, - [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, - [SND_DEVICE_OUT_VOICE_HANDSET] = 7, -#ifdef MSM8974 - [SND_DEVICE_OUT_VOICE_SPEAKER] = 15, -#else - [SND_DEVICE_OUT_VOICE_SPEAKER] = 14, -#endif - [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10, - [SND_DEVICE_OUT_HDMI] = 18, -#ifdef MSM8974 - [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, -#else - [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14, -#endif - [SND_DEVICE_OUT_BT_SCO] = 22, - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81, - [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, - [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, - [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, - - [SND_DEVICE_IN_HANDSET_MIC] = 4, - [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */ - [SND_DEVICE_IN_HEADSET_MIC] = 8, - [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40, - [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42, - [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47, - [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, - [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, - [SND_DEVICE_IN_HDMI_MIC] = 4, - [SND_DEVICE_IN_BT_SCO_MIC] = 21, - [SND_DEVICE_IN_CAMCORDER_MIC] = 61, -#ifdef MSM8974 - [SND_DEVICE_IN_VOICE_DMIC_EF] = 41, -#else - [SND_DEVICE_IN_VOICE_DMIC_EF] = 6, -#endif - [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91, -#ifdef MSM8974 - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43, -#else - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 13, -#endif - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, - [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, - [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, - [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, - [SND_DEVICE_IN_VOICE_REC_MIC] = 62, - /* TODO: Update with proper acdb ids */ - [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6, - [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, +struct string_to_enum { + const char *name; + uint32_t value; }; -int edid_get_max_channels(void); - -static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; -static bool is_tmus = false; - -static void check_operator() -{ - char value[PROPERTY_VALUE_MAX]; - int mccmnc; - property_get("gsm.sim.operator.numeric",value,"0"); - mccmnc = atoi(value); - ALOGD("%s: tmus mccmnc %d", __func__, mccmnc); - switch(mccmnc) { - /* TMUS MCC(310), MNC(490, 260, 026) */ - case 310490: - case 310260: - case 310026: - is_tmus = true; - break; - } -} - -static bool is_operator_tmus() -{ - pthread_once(&check_op_once_ctl, check_operator); - return is_tmus; -} - -static int get_pcm_device_id(struct audio_route *ar, - audio_usecase_t usecase, - int device_type) -{ - int device_id; - if (device_type == PCM_PLAYBACK) - device_id = pcm_device_table[usecase][0]; - else - device_id = pcm_device_table[usecase][1]; - return device_id; -} - -static int get_acdb_device_id(snd_device_t snd_device) -{ - return acdb_device_table[snd_device]; -} +static const struct string_to_enum out_channels_name_to_enum_table[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; -static void add_backend_name(char *mixer_path, - snd_device_t snd_device) -{ - if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) - strcat(mixer_path, " bt-sco"); - else if(snd_device == SND_DEVICE_OUT_BT_SCO) - strcat(mixer_path, " bt-sco"); - else if (snd_device == SND_DEVICE_OUT_HDMI) - strcat(mixer_path, " hdmi"); - else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) - strcat(mixer_path, " speaker-and-hdmi"); -} static int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, @@ -274,7 +128,7 @@ static int enable_audio_route(struct audio_device *adev, snd_device = usecase->out_snd_device; strcpy(mixer_path, use_case_table[usecase->id]); - add_backend_name(mixer_path, snd_device); + platform_add_backend_name(mixer_path, snd_device); ALOGD("%s: apply mixer path: %s", __func__, mixer_path); audio_route_apply_path(adev->audio_route, mixer_path); if (update_mixer) @@ -300,7 +154,7 @@ static int disable_audio_route(struct audio_device *adev, else snd_device = usecase->out_snd_device; strcpy(mixer_path, use_case_table[usecase->id]); - add_backend_name(mixer_path, snd_device); + platform_add_backend_name(mixer_path, snd_device); ALOGD("%s: reset mixer path: %s", __func__, mixer_path); audio_route_reset_path(adev->audio_route, mixer_path); if (update_mixer) @@ -314,8 +168,6 @@ static int enable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool update_mixer) { - int acdb_dev_id, acdb_dev_type; - if (snd_device < SND_DEVICE_MIN || snd_device >= SND_DEVICE_MAX) { ALOGE("%s: Invalid sound device %d", __func__, snd_device); @@ -325,34 +177,18 @@ static int enable_snd_device(struct audio_device *adev, adev->snd_dev_ref_cnt[snd_device]++; if (adev->snd_dev_ref_cnt[snd_device] > 1) { ALOGD("%s: snd_device(%d: %s) is already active", - __func__, snd_device, device_table[snd_device]); + __func__, snd_device, platform_get_snd_device_name(snd_device)); return 0; } - acdb_dev_id = get_acdb_device_id(snd_device); - if (acdb_dev_id < 0) { - ALOGE("%s: Could not find acdb id for device(%d)", - __func__, snd_device); + if (platform_send_audio_calibration(adev->platform, snd_device) < 0) { adev->snd_dev_ref_cnt[snd_device]--; return -EINVAL; } - if (adev->acdb_send_audio_cal) { - ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", - __func__, snd_device, acdb_dev_id); - if (snd_device >= SND_DEVICE_OUT_BEGIN && - snd_device < SND_DEVICE_OUT_END) - acdb_dev_type = ACDB_DEV_TYPE_OUT; - else - acdb_dev_type = ACDB_DEV_TYPE_IN; - adev->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type); - } else { - ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s", - __func__, LIB_ACDB_LOADER); - } ALOGD("%s: snd_device(%d: %s)", __func__, - snd_device, device_table[snd_device]); - audio_route_apply_path(adev->audio_route, device_table[snd_device]); + snd_device, platform_get_snd_device_name(snd_device)); + audio_route_apply_path(adev->audio_route, platform_get_snd_device_name(snd_device)); if (update_mixer) audio_route_update_mixer(adev->audio_route); @@ -375,8 +211,8 @@ static int disable_snd_device(struct audio_device *adev, adev->snd_dev_ref_cnt[snd_device]--; if (adev->snd_dev_ref_cnt[snd_device] == 0) { ALOGD("%s: snd_device(%d: %s)", __func__, - snd_device, device_table[snd_device]); - audio_route_reset_path(adev->audio_route, device_table[snd_device]); + snd_device, platform_get_snd_device_name(snd_device)); + audio_route_reset_path(adev->audio_route, platform_get_snd_device_name(snd_device)); if (update_mixer) audio_route_update_mixer(adev->audio_route); } @@ -415,7 +251,7 @@ static void check_usecases_codec_backend(struct audio_device *adev, usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", __func__, use_case_table[usecase->id], - device_table[usecase->out_snd_device]); + platform_get_snd_device_name(usecase->out_snd_device)); disable_audio_route(adev, usecase, false); switch_device[usecase->id] = true; num_uc_to_switch++; @@ -518,60 +354,12 @@ static void check_and_route_capture_usecases(struct audio_device *adev, } } -static int set_echo_reference(struct mixer *mixer, const char* ec_ref) -{ - struct mixer_ctl *ctl; - const char *mixer_ctl_name = "EC_REF_RX"; - - ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("Setting EC Reference: %s", ec_ref); - mixer_ctl_set_enum_by_string(ctl, ec_ref); - return 0; -} - -static int set_hdmi_channels(struct mixer *mixer, - int channel_count) -{ - struct mixer_ctl *ctl; - const char *channel_cnt_str = NULL; - const char *mixer_ctl_name = "HDMI_RX Channels"; - switch (channel_count) { - case 8: - channel_cnt_str = "Eight"; break; - case 7: - channel_cnt_str = "Seven"; break; - case 6: - channel_cnt_str = "Six"; break; - case 5: - channel_cnt_str = "Five"; break; - case 4: - channel_cnt_str = "Four"; break; - case 3: - channel_cnt_str = "Three"; break; - default: - channel_cnt_str = "Two"; break; - } - ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("HDMI channel count: %s", channel_cnt_str); - mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); - return 0; -} /* must be called with hw device mutex locked */ static int read_hdmi_channel_masks(struct stream_out *out) { int ret = 0; - int channels = edid_get_max_channels(); + int channels = platform_edid_get_max_channels(); switch (channels) { /* @@ -595,296 +383,6 @@ static int read_hdmi_channel_masks(struct stream_out *out) return ret; } -static int set_voice_volume(struct mixer *mixer, - int volume) -{ - struct mixer_ctl *ctl; - const char *mixer_ctl_name = "Voice Rx Volume"; - - // Voice volume levels are mapped to adsp volume levels as follows. - // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 - // But this values don't changed in kernel. So, below change is need. - volume = volume / 20; - - ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("Setting voice volume: %d", volume); - mixer_ctl_set_value(ctl, 0, volume); - return 0; -} - -static int set_mic_mute(struct mixer *mixer, - int mute) -{ - struct mixer_ctl *ctl; - const char *mixer_ctl_name = "Voice Tx Mute"; - ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("Setting mic mute: %d", mute); - mixer_ctl_set_value(ctl, 0, mute); - return 0; -} - -static snd_device_t get_output_snd_device(struct audio_device *adev, - audio_devices_t devices) -{ - audio_mode_t mode = adev->mode; - snd_device_t snd_device = SND_DEVICE_NONE; - - ALOGV("%s: enter: output devices(%#x)", __func__, devices); - if (devices == AUDIO_DEVICE_NONE || - devices & AUDIO_DEVICE_BIT_IN) { - ALOGV("%s: Invalid output devices (%#x)", __func__, devices); - goto exit; - } - - if (mode == AUDIO_MODE_IN_CALL) { - if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || - devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - if (adev->tty_mode == TTY_MODE_FULL) - snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES; - else if (adev->tty_mode == TTY_MODE_VCO) - snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; - else if (adev->tty_mode == TTY_MODE_HCO) - snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; - else - snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES; - } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_OUT_BT_SCO; - } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { - snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; - } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { - if (is_operator_tmus()) - snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; - else - snd_device = SND_DEVICE_OUT_HANDSET; - } - if (snd_device != SND_DEVICE_NONE) { - goto exit; - } - } - - if (popcount(devices) == 2) { - if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; - } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; - } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; - } else { - ALOGE("%s: Invalid combo device(%#x)", __func__, devices); - goto exit; - } - if (snd_device != SND_DEVICE_NONE) { - goto exit; - } - } - - if (popcount(devices) != 1) { - ALOGE("%s: Invalid output devices(%#x)", __func__, devices); - goto exit; - } - - if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || - devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - snd_device = SND_DEVICE_OUT_HEADPHONES; - } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { - if (adev->speaker_lr_swap) { - snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE; - } else { - snd_device = SND_DEVICE_OUT_SPEAKER; - } - } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_OUT_BT_SCO; - } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - snd_device = SND_DEVICE_OUT_HDMI ; - } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { - snd_device = SND_DEVICE_OUT_HANDSET; - } else { - ALOGE("%s: Unknown device(s) %#x", __func__, devices); - } -exit: - ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]); - return snd_device; -} - -static snd_device_t get_input_snd_device(struct audio_device *adev, - audio_devices_t out_device) -{ - audio_source_t source = (adev->active_input == NULL) ? - AUDIO_SOURCE_DEFAULT : adev->active_input->source; - - audio_mode_t mode = adev->mode; - audio_devices_t in_device = ((adev->active_input == NULL) ? - AUDIO_DEVICE_NONE : adev->active_input->device) - & ~AUDIO_DEVICE_BIT_IN; - audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? - AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; - snd_device_t snd_device = SND_DEVICE_NONE; - - ALOGV("%s: enter: out_device(%#x) in_device(%#x)", - __func__, out_device, in_device); - if (mode == AUDIO_MODE_IN_CALL) { - if (out_device == AUDIO_DEVICE_NONE) { - ALOGE("%s: No output device set for voice call", __func__); - goto exit; - } - if (adev->tty_mode != TTY_MODE_OFF) { - if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || - out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - switch (adev->tty_mode) { - case TTY_MODE_FULL: - snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC; - break; - case TTY_MODE_VCO: - snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC; - break; - case TTY_MODE_HCO: - snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC; - break; - default: - ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode); - } - goto exit; - } - } - if (out_device & AUDIO_DEVICE_OUT_EARPIECE || - out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { - if (adev->mic_type_analog || adev->fluence_in_voice_call == false) { - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } else { - if (adev->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - if (is_operator_tmus()) - snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS; - else - snd_device = SND_DEVICE_IN_VOICE_DMIC_EF; - } else if(adev->dualmic_config == DUALMIC_CONFIG_BROADSIDE) - snd_device = SND_DEVICE_IN_VOICE_DMIC_BS; - else - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } - } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC ; - } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { - if (adev->fluence_in_voice_call && adev->fluence_in_spkr_mode && - adev->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF; - } else if (adev->fluence_in_voice_call && adev->fluence_in_spkr_mode && - adev->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS; - } else { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; - } - } - } else if (source == AUDIO_SOURCE_CAMCORDER) { - if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC || - in_device & AUDIO_DEVICE_IN_BACK_MIC) { - snd_device = SND_DEVICE_IN_CAMCORDER_MIC; - } - } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { - if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - if (adev->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF; - else if (adev->fluence_in_voice_rec) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE; - } else if (adev->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS; - else if (adev->fluence_in_voice_rec) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE; - } - - if (snd_device == SND_DEVICE_NONE) { - snd_device = SND_DEVICE_IN_VOICE_REC_MIC; - } - } - } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { - if (out_device & AUDIO_DEVICE_OUT_SPEAKER) - in_device = AUDIO_DEVICE_IN_BACK_MIC; - if (adev->active_input) { - if (adev->active_input->enable_aec) { - if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { - if (adev->mic_type_analog) - snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; - else - snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; - } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; - } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { - snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC; - } - set_echo_reference(adev->mixer, "SLIM_RX"); - } else - set_echo_reference(adev->mixer, "NONE"); - } - } else if (source == AUDIO_SOURCE_DEFAULT) { - goto exit; - } - - - if (snd_device != SND_DEVICE_NONE) { - goto exit; - } - - if (in_device != AUDIO_DEVICE_NONE && - !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) && - !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) { - if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { - if (adev->mic_type_analog) - snd_device = SND_DEVICE_IN_HANDSET_MIC; - else - snd_device = SND_DEVICE_IN_SPEAKER_MIC; - } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { - snd_device = SND_DEVICE_IN_HEADSET_MIC; - } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC ; - } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { - snd_device = SND_DEVICE_IN_HDMI_MIC; - } else { - ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); - ALOGW("%s: Using default handset-mic", __func__); - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } - } else { - if (out_device & AUDIO_DEVICE_OUT_EARPIECE) { - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - snd_device = SND_DEVICE_IN_HEADSET_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { - snd_device = SND_DEVICE_IN_SPEAKER_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - snd_device = SND_DEVICE_IN_HDMI_MIC; - } else { - ALOGE("%s: Unknown output device(s) %#x", __func__, out_device); - ALOGW("%s: Using default handset-mic", __func__); - snd_device = SND_DEVICE_IN_HANDSET_MIC; - } - } -exit: - ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]); - return snd_device; -} - static struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id) { @@ -907,7 +405,6 @@ static int select_devices(struct audio_device *adev, struct audio_usecase *usecase = NULL; struct audio_usecase *vc_usecase = NULL; struct listnode *node; - int acdb_rx_id, acdb_tx_id; int status = 0; usecase = get_usecase_from_list(adev, uc_id); @@ -917,8 +414,9 @@ static int select_devices(struct audio_device *adev, } if (usecase->type == VOICE_CALL) { - out_snd_device = get_output_snd_device(adev, usecase->stream.out->devices); - in_snd_device = get_input_snd_device(adev, usecase->stream.out->devices); + out_snd_device = platform_get_output_snd_device(adev->platform, + usecase->stream.out->devices); + in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices); usecase->devices = usecase->stream.out->devices; } else { /* @@ -939,7 +437,7 @@ static int select_devices(struct audio_device *adev, usecase->devices = usecase->stream.out->devices; in_snd_device = SND_DEVICE_NONE; if (out_snd_device == SND_DEVICE_NONE) { - out_snd_device = get_output_snd_device(adev, + out_snd_device = platform_get_output_snd_device(adev->platform, usecase->stream.out->devices); if (usecase->stream.out == adev->primary_output && adev->active_input && @@ -953,10 +451,11 @@ static int select_devices(struct audio_device *adev, if (in_snd_device == SND_DEVICE_NONE) { if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION && adev->primary_output && !adev->primary_output->standby) { - in_snd_device = get_input_snd_device(adev, + in_snd_device = platform_get_input_snd_device(adev->platform, adev->primary_output->devices); } else { - in_snd_device = get_input_snd_device(adev, AUDIO_DEVICE_NONE); + in_snd_device = platform_get_input_snd_device(adev->platform, + AUDIO_DEVICE_NONE); } } } @@ -968,27 +467,16 @@ static int select_devices(struct audio_device *adev, } ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__, - out_snd_device, device_table[out_snd_device], - in_snd_device, device_table[in_snd_device]); + out_snd_device, platform_get_snd_device_name(out_snd_device), + in_snd_device, platform_get_snd_device_name(in_snd_device)); /* * Limitation: While in call, to do a device switch we need to disable * and enable both RX and TX devices though one of them is same as current * device. */ - if (usecase->type == VOICE_CALL && adev->csd_client != NULL && - usecase->in_snd_device != SND_DEVICE_NONE && - usecase->out_snd_device != SND_DEVICE_NONE) { - /* This must be called before disabling the mixer controls on APQ side */ - if (adev->csd_disable_device == NULL) { - ALOGE("%s: dlsym error for csd_client_disable_device", __func__); - } else { - status = adev->csd_disable_device(); - if (status < 0) { - ALOGE("%s: csd_client_disable_device, failed, error %d", - __func__, status); - } - } + if (usecase->type == VOICE_CALL) { + status = platform_switch_voice_call_device_pre(adev->platform); } /* Disable current sound devices */ @@ -1014,40 +502,10 @@ static int select_devices(struct audio_device *adev, enable_snd_device(adev, in_snd_device, false); } - if (usecase->type == VOICE_CALL && adev->csd_client) { - if (adev->csd_enable_device == NULL) { - ALOGE("%s: dlsym error for csd_client_enable_device", - __func__); - } else { - acdb_rx_id = get_acdb_device_id(out_snd_device); - acdb_tx_id = get_acdb_device_id(in_snd_device); - - if (acdb_rx_id > 0 || acdb_tx_id > 0) { - status = adev->csd_enable_device(acdb_rx_id, acdb_tx_id, - adev->acdb_settings); - if (status < 0) { - ALOGE("%s: csd_client_enable_device, failed, error %d", - __func__, status); - } - } else { - ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, - acdb_rx_id, acdb_tx_id); - } - } - } else if (usecase->type == VOICE_CALL) { - if (adev->acdb_send_voice_cal == NULL) { - ALOGE("%s: dlsym error for acdb_send_voice_call", __func__); - } else { - acdb_rx_id = get_acdb_device_id(out_snd_device); - acdb_tx_id = get_acdb_device_id(in_snd_device); - - if (acdb_rx_id > 0 && acdb_tx_id > 0) - adev->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id); - else - ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, - acdb_rx_id, acdb_tx_id); - } - } + if (usecase->type == VOICE_CALL) + status = platform_switch_voice_call_device_post(adev->platform, + out_snd_device, + in_snd_device); audio_route_update_mixer(adev->audio_route); @@ -1097,9 +555,7 @@ int start_input_stream(struct stream_in *in) struct audio_device *adev = in->dev; ALOGD("%s: enter: usecase(%d)", __func__, in->usecase); - in->pcm_device_id = get_pcm_device_id(adev->audio_route, - in->usecase, - PCM_CAPTURE); + in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); if (in->pcm_device_id < 0) { ALOGE("%s: Could not find PCM device id for the usecase(%d)", __func__, in->usecase); @@ -1179,9 +635,7 @@ int start_output_stream(struct stream_out *out) ALOGD("%s: enter: usecase(%d: %s) devices(%#x)", __func__, out->usecase, use_case_table[out->usecase], out->devices); - out->pcm_device_id = get_pcm_device_id(adev->audio_route, - out->usecase, - PCM_PLAYBACK); + out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); if (out->pcm_device_id < 0) { ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", __func__, out->pcm_device_id, out->usecase); @@ -1227,16 +681,8 @@ static int stop_voice_call(struct audio_device *adev) ALOGD("%s: enter", __func__); adev->in_call = false; - if (adev->csd_client) { - if (adev->csd_stop_voice == NULL) { - ALOGE("dlsym error for csd_client_disable_device"); - } else { - ret = adev->csd_stop_voice(); - if (ret < 0) { - ALOGE("%s: csd_client error %d\n", __func__, ret); - } - } - } + + ret = platform_stop_voice_call(adev->platform); /* 1. Close the PCM devices */ if (adev->voice_call_rx) { @@ -1289,10 +735,8 @@ static int start_voice_call(struct audio_device *adev) select_devices(adev, USECASE_VOICE_CALL); - pcm_dev_rx_id = get_pcm_device_id(adev->audio_route, uc_info->id, - PCM_PLAYBACK); - pcm_dev_tx_id = get_pcm_device_id(adev->audio_route, uc_info->id, - PCM_CAPTURE); + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", @@ -1325,17 +769,10 @@ static int start_voice_call(struct audio_device *adev) pcm_start(adev->voice_call_rx); pcm_start(adev->voice_call_tx); - if (adev->csd_client) { - if (adev->csd_start_voice == NULL) { - ALOGE("dlsym error for csd_client_start_voice"); - goto error_start_voice; - } else { - ret = adev->csd_start_voice(); - if (ret < 0) { - ALOGE("%s: csd_start_voice error %d\n", __func__, ret); - goto error_start_voice; - } - } + ret = platform_start_voice_call(adev->platform); + if (ret < 0) { + ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); + goto error_start_voice; } adev->in_call = true; @@ -1894,7 +1331,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (ret != 0) { /* If HDMI does not support multi channel playback, set the default */ out->config.channels = popcount(out->channel_mask); - set_hdmi_channels(adev->mixer, out->config.channels); + platform_set_hdmi_channels(adev->platform, out->config.channels); goto error_open; } @@ -1909,7 +1346,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config.rate = config->sample_rate; out->config.channels = popcount(out->channel_mask); out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); - set_hdmi_channels(adev->mixer, out->config.channels); + platform_set_hdmi_channels(adev->platform, out->config.channels); } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; out->config = pcm_config_deep_buffer; @@ -2110,22 +1547,8 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 // So adjust the volume to get the correct volume index in driver vol = 100 - vol; -#ifdef MSM8974 - set_voice_volume(adev->mixer, vol); -#else - if (adev->csd_client) { - if (adev->csd_volume == NULL) { - ALOGE("%s: dlsym error for csd_client_volume", __func__); - } else { - err = adev->csd_volume(vol); - if (err < 0) { - ALOGE("%s: csd_client error %d", __func__, err); - } - } - } else { - ALOGE("%s: No CSD Client present", __func__); - } -#endif + + err = platform_set_voice_volume(adev->platform, vol); } pthread_mutex_unlock(&adev->lock); return err; @@ -2171,24 +1594,8 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) pthread_mutex_lock(&adev->lock); adev->mic_mute = state; - if (adev->mode == AUDIO_MODE_IN_CALL) { -#ifdef MSM8974 - set_mic_mute(adev->mixer, state); -#else - if (adev->csd_client) { - if (adev->csd_mic_mute == NULL) { - ALOGE("%s: dlsym error for csd_mic_mute", __func__); - } else { - err = adev->csd_mic_mute(state); - if (err < 0) { - ALOGE("%s: csd_client error %d", __func__, err); - } - } - } else { - ALOGE("%s: No CSD Client present", __func__); - } -#endif - } + + err = platform_set_mic_mute(adev->platform, state); pthread_mutex_unlock(&adev->lock); return err; } @@ -2292,110 +1699,12 @@ static int adev_close(hw_device_t *device) { struct audio_device *adev = (struct audio_device *)device; audio_route_free(adev->audio_route); + free(adev->snd_dev_ref_cnt); + platform_deinit(adev->platform); free(device); return 0; } -static void init_platform_data(struct audio_device *adev) -{ - char platform[PROPERTY_VALUE_MAX]; - char baseband[PROPERTY_VALUE_MAX]; - char value[PROPERTY_VALUE_MAX]; - - adev->dualmic_config = DUALMIC_CONFIG_NONE; - adev->fluence_in_spkr_mode = false; - adev->fluence_in_voice_call = false; - adev->fluence_in_voice_rec = false; - adev->mic_type_analog = false; - - property_get("persist.audio.handset.mic.type",value,""); - if (!strcmp("analog", value)) - adev->mic_type_analog = true; - - property_get("persist.audio.dualmic.config",value,""); - if (!strcmp("broadside", value)) { - adev->dualmic_config = DUALMIC_CONFIG_BROADSIDE; - adev->acdb_settings |= DMIC_FLAG; - } else if (!strcmp("endfire", value)) { - adev->dualmic_config = DUALMIC_CONFIG_ENDFIRE; - adev->acdb_settings |= DMIC_FLAG; - } - - if (adev->dualmic_config != DUALMIC_CONFIG_NONE) { - property_get("persist.audio.fluence.voicecall",value,""); - if (!strcmp("true", value)) { - adev->fluence_in_voice_call = true; - } - - property_get("persist.audio.fluence.voicerec",value,""); - if (!strcmp("true", value)) { - adev->fluence_in_voice_rec = true; - } - - property_get("persist.audio.fluence.speaker",value,""); - if (!strcmp("true", value)) { - adev->fluence_in_spkr_mode = true; - } - } - - adev->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW); - if (adev->acdb_handle == NULL) { - ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER); - } else { - ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER); - adev->acdb_deallocate = (acdb_deallocate_t)dlsym(adev->acdb_handle, - "acdb_loader_deallocate_ACDB"); - adev->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(adev->acdb_handle, - "acdb_loader_send_audio_cal"); - adev->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(adev->acdb_handle, - "acdb_loader_send_voice_cal"); - adev->acdb_init = (acdb_init_t)dlsym(adev->acdb_handle, - "acdb_loader_init_ACDB"); - if (adev->acdb_init == NULL) - ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror()); - else - adev->acdb_init(); - } - - /* If platform is Fusion3, load CSD Client specific symbols - * Voice call is handled by MDM and apps processor talks to - * MDM through CSD Client - */ - property_get("ro.board.platform", platform, ""); - property_get("ro.baseband", baseband, ""); - if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) { - adev->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW); - if (adev->csd_client == NULL) - ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT); - } - - if (adev->csd_client) { - ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT); - adev->csd_client_deinit = (csd_client_deinit_t)dlsym(adev->csd_client, - "csd_client_deinit"); - adev->csd_disable_device = (csd_disable_device_t)dlsym(adev->csd_client, - "csd_client_disable_device"); - adev->csd_enable_device = (csd_enable_device_t)dlsym(adev->csd_client, - "csd_client_enable_device"); - adev->csd_start_voice = (csd_start_voice_t)dlsym(adev->csd_client, - "csd_client_start_voice"); - adev->csd_stop_voice = (csd_stop_voice_t)dlsym(adev->csd_client, - "csd_client_stop_voice"); - adev->csd_volume = (csd_volume_t)dlsym(adev->csd_client, - "csd_client_volume"); - adev->csd_mic_mute = (csd_mic_mute_t)dlsym(adev->csd_client, - "csd_client_mic_mute"); - adev->csd_client_init = (csd_client_init_t)dlsym(adev->csd_client, - "csd_client_init"); - - if (adev->csd_client_init == NULL) { - ALOGE("%s: dlsym error %s for csd_client_init", __func__, dlerror()); - } else { - adev->csd_client_init(); - } - } -} - static int adev_open(const hw_module_t *module, const char *name, hw_device_t **device) { @@ -2457,16 +1766,19 @@ static int adev_open(const hw_module_t *module, const char *name, adev->bluetooth_nrec = true; adev->in_call = false; adev->acdb_settings = TTY_MODE_OFF; - adev->speaker_lr_swap = false; - for (i = 0; i < SND_DEVICE_MAX; i++) { - adev->snd_dev_ref_cnt[i] = 0; - } + adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); list_init(&adev->usecase_list); pthread_mutex_unlock(&adev->lock); /* Loads platform specific libraries dynamically */ - init_platform_data(adev); - + adev->platform = platform_init(adev); + if (!adev->platform) { + free(adev->snd_dev_ref_cnt); + free(adev); + ALOGE("%s: Failed to init platform data, aborting.", __func__); + *device = NULL; + return -EINVAL; + } *device = &adev->device.common; ALOGD("%s: exit", __func__); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 5c326e9a1..5702f373f 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -14,94 +14,30 @@ * limitations under the License. */ +#ifndef QCOM_AUDIO_HW_H +#define QCOM_AUDIO_HW_H + +#include #include -#include -#include -#include #include #include +/* Flags used to initialize acdb_settings variable that goes to ACDB library */ +#define DMIC_FLAG 0x00000002 +#define TTY_MODE_OFF 0x00000010 +#define TTY_MODE_FULL 0x00000020 +#define TTY_MODE_VCO 0x00000040 +#define TTY_MODE_HCO 0x00000080 +#define TTY_MODE_CLEAR 0xFFFFFF0F + #define ACDB_DEV_TYPE_OUT 1 #define ACDB_DEV_TYPE_IN 2 -#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ -#define DUALMIC_CONFIG_ENDFIRE 1 -#define DUALMIC_CONFIG_BROADSIDE 2 - -/* - * Below are the devices for which is back end is same, SLIMBUS_0_RX. - * All these devices are handled by the internal HW codec. We can - * enable any one of these devices at any time - */ -#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \ - (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \ - AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE) - -/* Sound devices specific to the platform - * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound - * devices to enable corresponding mixer paths - */ -typedef enum { - SND_DEVICE_NONE = 0, - - /* Playback devices */ - SND_DEVICE_MIN, - SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN, - SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN, - SND_DEVICE_OUT_SPEAKER, - SND_DEVICE_OUT_SPEAKER_REVERSE, - SND_DEVICE_OUT_HEADPHONES, - SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, - SND_DEVICE_OUT_VOICE_HANDSET, - SND_DEVICE_OUT_VOICE_SPEAKER, - SND_DEVICE_OUT_VOICE_HEADPHONES, - SND_DEVICE_OUT_HDMI, - SND_DEVICE_OUT_SPEAKER_AND_HDMI, - SND_DEVICE_OUT_BT_SCO, - SND_DEVICE_OUT_VOICE_HANDSET_TMUS, - SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, - SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, - SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, - SND_DEVICE_OUT_END, - - /* - * Note: IN_BEGIN should be same as OUT_END because total number of devices - * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices. - */ - /* Capture devices */ - SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END, - SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN, - SND_DEVICE_IN_SPEAKER_MIC, - SND_DEVICE_IN_HEADSET_MIC, - SND_DEVICE_IN_HANDSET_MIC_AEC, - SND_DEVICE_IN_SPEAKER_MIC_AEC, - SND_DEVICE_IN_HEADSET_MIC_AEC, - SND_DEVICE_IN_VOICE_SPEAKER_MIC, - SND_DEVICE_IN_VOICE_HEADSET_MIC, - SND_DEVICE_IN_HDMI_MIC, - SND_DEVICE_IN_BT_SCO_MIC, - SND_DEVICE_IN_CAMCORDER_MIC, - SND_DEVICE_IN_VOICE_DMIC_EF, - SND_DEVICE_IN_VOICE_DMIC_BS, - SND_DEVICE_IN_VOICE_DMIC_EF_TMUS, - SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF, - SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS, - SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, - SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, - SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, - SND_DEVICE_IN_VOICE_REC_MIC, - SND_DEVICE_IN_VOICE_REC_DMIC_EF, - SND_DEVICE_IN_VOICE_REC_DMIC_BS, - SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE, - SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE, - SND_DEVICE_IN_END, - - SND_DEVICE_MAX = SND_DEVICE_IN_END, - -} snd_device_t; +#define MAX_SUPPORTED_CHANNEL_MASKS 2 +typedef int snd_device_t; /* These are the supported use cases by the hardware. * Each usecase is mapped to a specific PCM device. @@ -125,10 +61,6 @@ typedef enum { #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#define SOUND_CARD 0 - -#define DEFAULT_OUTPUT_SAMPLING_RATE 48000 - /* * tinyAlsa library interprets period size as number of frames * one frame = channel_count * sizeof (pcm sample) @@ -137,34 +69,6 @@ typedef enum { * We should take care of returning proper size when AudioFlinger queries for * the buffer size of an input/output stream */ -#ifdef MSM8974 -#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1024 -#else -#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 -#endif -#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8 - -#ifdef MSM8974 -#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 256 -#else -#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240 -#endif -#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 - -#define HDMI_MULTI_PERIOD_SIZE 336 -#define HDMI_MULTI_PERIOD_COUNT 8 -#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 -#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2) - -#ifdef MSM8974 -#define AUDIO_CAPTURE_PERIOD_SIZE 512 -#define AUDIO_CAPTURE_PERIOD_COUNT 16 -#else -#define AUDIO_CAPTURE_PERIOD_SIZE 320 -#define AUDIO_CAPTURE_PERIOD_COUNT 2 -#endif - -#define MAX_SUPPORTED_CHANNEL_MASKS 2 struct stream_out { struct audio_stream_out stream; @@ -221,20 +125,6 @@ struct audio_usecase { union stream_ptr stream; }; -typedef void (*acdb_deallocate_t)(); -typedef int (*acdb_init_t)(); -typedef void (*acdb_send_audio_cal_t)(int, int); -typedef void (*acdb_send_voice_cal_t)(int, int); - -typedef int (*csd_client_init_t)(); -typedef int (*csd_client_deinit_t)(); -typedef int (*csd_disable_device_t)(); -typedef int (*csd_enable_device_t)(int, int, uint32_t); -typedef int (*csd_volume_t)(int); -typedef int (*csd_mic_mute_t)(int); -typedef int (*csd_start_voice_t)(); -typedef int (*csd_stop_voice_t)(); - struct audio_device { struct audio_hw_device device; pthread_mutex_t lock; /* see note below on mutex acquisition order */ @@ -251,35 +141,13 @@ struct audio_device { bool screen_off; struct pcm *voice_call_rx; struct pcm *voice_call_tx; - int snd_dev_ref_cnt[SND_DEVICE_MAX]; + int *snd_dev_ref_cnt; struct listnode usecase_list; struct audio_route *audio_route; int acdb_settings; bool speaker_lr_swap; - bool mic_type_analog; - bool fluence_in_spkr_mode; - bool fluence_in_voice_call; - bool fluence_in_voice_rec; - int dualmic_config; - - /* Audio calibration related functions */ - void *acdb_handle; - acdb_init_t acdb_init; - acdb_deallocate_t acdb_deallocate; - acdb_send_audio_cal_t acdb_send_audio_cal; - acdb_send_voice_cal_t acdb_send_voice_cal; - - /* CSD Client related functions for voice call */ - void *csd_client; - csd_client_init_t csd_client_init; - csd_client_deinit_t csd_client_deinit; - csd_disable_device_t csd_disable_device; - csd_enable_device_t csd_enable_device; - csd_volume_t csd_volume; - csd_mic_mute_t csd_mic_mute; - csd_start_voice_t csd_start_voice; - csd_stop_voice_t csd_stop_voice; + void *platform; }; /* @@ -287,51 +155,4 @@ struct audio_device { * stream_in or stream_out mutex first, followed by the audio_device mutex. */ -struct pcm_config pcm_config_deep_buffer = { - .channels = 2, - .rate = DEFAULT_OUTPUT_SAMPLING_RATE, - .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, - .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, - .stop_threshold = INT_MAX, - .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, -}; - -struct pcm_config pcm_config_low_latency = { - .channels = 2, - .rate = DEFAULT_OUTPUT_SAMPLING_RATE, - .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, - .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, - .stop_threshold = INT_MAX, - .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, -}; - -struct pcm_config pcm_config_hdmi_multi = { - .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */ - .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */ - .period_size = HDMI_MULTI_PERIOD_SIZE, - .period_count = HDMI_MULTI_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = 0, - .stop_threshold = INT_MAX, - .avail_min = 0, -}; - -struct pcm_config pcm_config_audio_capture = { - .channels = 2, - .period_size = AUDIO_CAPTURE_PERIOD_SIZE, - .period_count = AUDIO_CAPTURE_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, -}; - -struct pcm_config pcm_config_voice_call = { - .channels = 1, - .rate = 8000, - .period_size = 160, - .period_count = 2, - .format = PCM_FORMAT_S16_LE, -}; - +#endif // QCOM_AUDIO_HW_H diff --git a/hal/edid.c b/hal/edid.c deleted file mode 100644 index 7894ab801..000000000 --- a/hal/edid.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "audio_hw_primary" - -#include -#include - -#include - -/* - * This is the sysfs path for the HDMI audio data block - */ -#define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" - -/* - * This file will have a maximum of 38 bytes: - * - * 4 bytes: number of audio blocks - * 4 bytes: total length of Short Audio Descriptor (SAD) blocks - * Maximum 10 * 3 bytes: SAD blocks - */ -#define MAX_SAD_BLOCKS 10 -#define SAD_BLOCK_SIZE 3 - -/* EDID format ID for LPCM audio */ -#define EDID_FORMAT_LPCM 1 - -struct audio_block_header -{ - int reserved; - int length; -}; - -int edid_get_max_channels(void) -{ - FILE *file; - struct audio_block_header header; - char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE]; - char *sad = block; - int num_audio_blocks; - int channel_count; - int max_channels = 0; - int i; - - file = fopen(AUDIO_DATA_BLOCK_PATH, "rb"); - if (file == NULL) { - ALOGE("Unable to open '%s'", AUDIO_DATA_BLOCK_PATH); - return 0; - } - - /* Read audio block header */ - fread(&header, 1, sizeof(header), file); - - /* Read SAD blocks, clamping the maximum size for safety */ - if (header.length > (int)sizeof(block)) - header.length = (int)sizeof(block); - fread(&block, header.length, 1, file); - - fclose(file); - - /* Calculate the number of SAD blocks */ - num_audio_blocks = header.length / SAD_BLOCK_SIZE; - - for (i = 0; i < num_audio_blocks; i++) { - /* Only consider LPCM blocks */ - if ((sad[0] >> 3) != EDID_FORMAT_LPCM) - continue; - - channel_count = (sad[0] & 0x7) + 1; - if (channel_count > max_channels) - max_channels = channel_count; - - /* Advance to next block */ - sad += 3; - } - - return max_channels; -} - diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c new file mode 100644 index 000000000..7052d68e3 --- /dev/null +++ b/hal/msm8960/platform.c @@ -0,0 +1,868 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "msm8960_platform" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include "platform.h" + +#define LIB_ACDB_LOADER "libacdbloader.so" +#define LIB_CSD_CLIENT "libcsd-client.so" + +#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ +#define DUALMIC_CONFIG_ENDFIRE 1 +#define DUALMIC_CONFIG_BROADSIDE 2 + +/* + * This is the sysfs path for the HDMI audio data block + */ +#define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" + +/* + * This file will have a maximum of 38 bytes: + * + * 4 bytes: number of audio blocks + * 4 bytes: total length of Short Audio Descriptor (SAD) blocks + * Maximum 10 * 3 bytes: SAD blocks + */ +#define MAX_SAD_BLOCKS 10 +#define SAD_BLOCK_SIZE 3 + +/* EDID format ID for LPCM audio */ +#define EDID_FORMAT_LPCM 1 + +struct audio_block_header +{ + int reserved; + int length; +}; + + +typedef void (*acdb_deallocate_t)(); +typedef int (*acdb_init_t)(); +typedef void (*acdb_send_audio_cal_t)(int, int); +typedef void (*acdb_send_voice_cal_t)(int, int); + +typedef int (*csd_client_init_t)(); +typedef int (*csd_client_deinit_t)(); +typedef int (*csd_disable_device_t)(); +typedef int (*csd_enable_device_t)(int, int, uint32_t); +typedef int (*csd_volume_t)(int); +typedef int (*csd_mic_mute_t)(int); +typedef int (*csd_start_voice_t)(); +typedef int (*csd_stop_voice_t)(); + + +/* Audio calibration related functions */ +struct platform_data { + struct audio_device *adev; + bool fluence_in_spkr_mode; + bool fluence_in_voice_call; + bool fluence_in_voice_rec; + int dualmic_config; + + void *acdb_handle; + acdb_init_t acdb_init; + acdb_deallocate_t acdb_deallocate; + acdb_send_audio_cal_t acdb_send_audio_cal; + acdb_send_voice_cal_t acdb_send_voice_cal; + + /* CSD Client related functions for voice call */ + void *csd_client; + csd_client_init_t csd_client_init; + csd_client_deinit_t csd_client_deinit; + csd_disable_device_t csd_disable_device; + csd_enable_device_t csd_enable_device; + csd_volume_t csd_volume; + csd_mic_mute_t csd_mic_mute; + csd_start_voice_t csd_start_voice; + csd_stop_voice_t csd_stop_voice; +}; + +static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0}, + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {14, 14}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1}, + [USECASE_AUDIO_RECORD] = {0, 0}, + [USECASE_AUDIO_RECORD_LOW_LATENCY] = {14, 14}, + [USECASE_VOICE_CALL] = {12, 12}, +}; + +/* Array to store sound devices */ +static const char * const device_table[SND_DEVICE_MAX] = { + [SND_DEVICE_NONE] = "none", + /* Playback sound devices */ + [SND_DEVICE_OUT_HANDSET] = "handset", + [SND_DEVICE_OUT_SPEAKER] = "speaker", + [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse", + [SND_DEVICE_OUT_HEADPHONES] = "headphones", + [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones", + [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker", + [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones", + [SND_DEVICE_OUT_HDMI] = "hdmi", + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", + [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", + [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus", + [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", + [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", + [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + + /* Capture sound devices */ + [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", + [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", + [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", + [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic", + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "voice-speaker-mic", + [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic", + [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", + [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", + [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", + [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", + [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", + [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef", + [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs", + [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs", + [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", + [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", + [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", + [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", + [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef", + [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs", + [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence", + [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence", +}; + +/* ACDB IDs (audio DSP path configuration IDs) for each sound device */ +static const int acdb_device_table[SND_DEVICE_MAX] = { + [SND_DEVICE_NONE] = -1, + [SND_DEVICE_OUT_HANDSET] = 7, + [SND_DEVICE_OUT_SPEAKER] = 14, + [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14, + [SND_DEVICE_OUT_HEADPHONES] = 10, + [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, + [SND_DEVICE_OUT_VOICE_SPEAKER] = 14, + [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10, + [SND_DEVICE_OUT_HDMI] = 18, + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14, + [SND_DEVICE_OUT_BT_SCO] = 22, + [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81, + [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, + [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, + [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + + [SND_DEVICE_IN_HANDSET_MIC] = 4, + [SND_DEVICE_IN_SPEAKER_MIC] = 4, + [SND_DEVICE_IN_HEADSET_MIC] = 8, + [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40, + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42, + [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47, + [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, + [SND_DEVICE_IN_HDMI_MIC] = 4, + [SND_DEVICE_IN_BT_SCO_MIC] = 21, + [SND_DEVICE_IN_CAMCORDER_MIC] = 61, + [SND_DEVICE_IN_VOICE_DMIC_EF] = 6, + [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, + [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 13, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, + [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, + [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_REC_MIC] = 62, + /* TODO: Update with proper acdb ids */ + [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62, + [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62, + [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6, + [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, +}; + +static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; +static bool is_tmus = false; + +static void check_operator() +{ + char value[PROPERTY_VALUE_MAX]; + int mccmnc; + property_get("gsm.sim.operator.numeric",value,"0"); + mccmnc = atoi(value); + ALOGD("%s: tmus mccmnc %d", __func__, mccmnc); + switch(mccmnc) { + /* TMUS MCC(310), MNC(490, 260, 026) */ + case 310490: + case 310260: + case 310026: + is_tmus = true; + break; + } +} + +bool is_operator_tmus() +{ + pthread_once(&check_op_once_ctl, check_operator); + return is_tmus; +} + +static int set_echo_reference(struct mixer *mixer, const char* ec_ref) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "EC_REF_RX"; + + ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting EC Reference: %s", ec_ref); + mixer_ctl_set_enum_by_string(ctl, ec_ref); + return 0; +} + +void *platform_init(struct audio_device *adev) +{ + char platform[PROPERTY_VALUE_MAX]; + char baseband[PROPERTY_VALUE_MAX]; + char value[PROPERTY_VALUE_MAX]; + struct platform_data *my_data; + + my_data = calloc(1, sizeof(struct platform_data)); + + my_data->adev = adev; + my_data->dualmic_config = DUALMIC_CONFIG_NONE; + my_data->fluence_in_spkr_mode = false; + my_data->fluence_in_voice_call = false; + my_data->fluence_in_voice_rec = false; + + property_get("persist.audio.dualmic.config",value,""); + if (!strcmp("broadside", value)) { + my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE; + adev->acdb_settings |= DMIC_FLAG; + } else if (!strcmp("endfire", value)) { + my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE; + adev->acdb_settings |= DMIC_FLAG; + } + + if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) { + property_get("persist.audio.fluence.voicecall",value,""); + if (!strcmp("true", value)) { + my_data->fluence_in_voice_call = true; + } + + property_get("persist.audio.fluence.voicerec",value,""); + if (!strcmp("true", value)) { + my_data->fluence_in_voice_rec = true; + } + + property_get("persist.audio.fluence.speaker",value,""); + if (!strcmp("true", value)) { + my_data->fluence_in_spkr_mode = true; + } + } + + my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW); + if (my_data->acdb_handle == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER); + my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle, + "acdb_loader_deallocate_ACDB"); + my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle, + "acdb_loader_send_audio_cal"); + if (!my_data->acdb_send_audio_cal) + ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s", + __func__, LIB_ACDB_LOADER); + my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle, + "acdb_loader_send_voice_cal"); + my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle, + "acdb_loader_init_ACDB"); + if (my_data->acdb_init == NULL) + ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror()); + else + my_data->acdb_init(); + } + + /* If platform is Fusion3, load CSD Client specific symbols + * Voice call is handled by MDM and apps processor talks to + * MDM through CSD Client + */ + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) { + my_data->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW); + if (my_data->csd_client == NULL) + ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT); + } + + if (my_data->csd_client) { + ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT); + my_data->csd_client_deinit = (csd_client_deinit_t)dlsym(my_data->csd_client, + "csd_client_deinit"); + my_data->csd_disable_device = (csd_disable_device_t)dlsym(my_data->csd_client, + "csd_client_disable_device"); + my_data->csd_enable_device = (csd_enable_device_t)dlsym(my_data->csd_client, + "csd_client_enable_device"); + my_data->csd_start_voice = (csd_start_voice_t)dlsym(my_data->csd_client, + "csd_client_start_voice"); + my_data->csd_stop_voice = (csd_stop_voice_t)dlsym(my_data->csd_client, + "csd_client_stop_voice"); + my_data->csd_volume = (csd_volume_t)dlsym(my_data->csd_client, + "csd_client_volume"); + my_data->csd_mic_mute = (csd_mic_mute_t)dlsym(my_data->csd_client, + "csd_client_mic_mute"); + my_data->csd_client_init = (csd_client_init_t)dlsym(my_data->csd_client, + "csd_client_init"); + + if (my_data->csd_client_init == NULL) { + ALOGE("%s: dlsym error %s for csd_client_init", __func__, dlerror()); + } else { + my_data->csd_client_init(); + } + } + + return my_data; +} + +void platform_deinit(void *platform) +{ + free(platform); +} + +const char *platform_get_snd_device_name(snd_device_t snd_device) +{ + if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) + return device_table[snd_device]; + else + return ""; +} + +void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) +{ + if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) + strcat(mixer_path, " bt-sco"); + else if(snd_device == SND_DEVICE_OUT_BT_SCO) + strcat(mixer_path, " bt-sco"); + else if (snd_device == SND_DEVICE_OUT_HDMI) + strcat(mixer_path, " hdmi"); + else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) + strcat(mixer_path, " speaker-and-hdmi"); +} + +int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) +{ + int device_id; + if (device_type == PCM_PLAYBACK) + device_id = pcm_device_table[usecase][0]; + else + device_id = pcm_device_table[usecase][1]; + return device_id; +} + +int platform_send_audio_calibration(void *platform, snd_device_t snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_dev_id, acdb_dev_type; + + acdb_dev_id = acdb_device_table[snd_device]; + if (acdb_dev_id < 0) { + ALOGE("%s: Could not find acdb id for device(%d)", + __func__, snd_device); + return -EINVAL; + } + if (my_data->acdb_send_audio_cal) { + ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", + __func__, snd_device, acdb_dev_id); + if (snd_device >= SND_DEVICE_OUT_BEGIN && + snd_device < SND_DEVICE_OUT_END) + acdb_dev_type = ACDB_DEV_TYPE_OUT; + else + acdb_dev_type = ACDB_DEV_TYPE_IN; + my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type); + } + return 0; +} + +int platform_switch_voice_call_device_pre(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd_client != NULL) { + /* This must be called before disabling the mixer controls on APQ side */ + if (my_data->csd_disable_device == NULL) { + ALOGE("%s: dlsym error for csd_disable_device", __func__); + } else { + ret = my_data->csd_disable_device(); + if (ret < 0) { + ALOGE("%s: csd_client_disable_device, failed, error %d", + __func__, ret); + } + } + } + return ret; +} + +int platform_switch_voice_call_device_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_rx_id, acdb_tx_id; + int ret = 0; + + if (my_data->csd_client) { + if (my_data->csd_enable_device == NULL) { + ALOGE("%s: dlsym error for csd_enable_device", + __func__); + } else { + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; + + if (acdb_rx_id > 0 || acdb_tx_id > 0) { + ret = my_data->csd_enable_device(acdb_rx_id, acdb_tx_id, + my_data->adev->acdb_settings); + if (ret < 0) { + ALOGE("%s: csd_enable_device, failed, error %d", + __func__, ret); + } + } else { + ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, + acdb_rx_id, acdb_tx_id); + } + } + } + + return ret; +} + +int platform_start_voice_call(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd_client) { + if (my_data->csd_start_voice == NULL) { + ALOGE("dlsym error for csd_client_start_voice"); + ret = -ENOSYS; + } else { + ret = my_data->csd_start_voice(); + if (ret < 0) { + ALOGE("%s: csd_start_voice error %d\n", __func__, ret); + } + } + } + + return ret; +} + +int platform_stop_voice_call(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd_client) { + if (my_data->csd_stop_voice == NULL) { + ALOGE("dlsym error for csd_stop_voice"); + } else { + ret = my_data->csd_stop_voice(); + if (ret < 0) { + ALOGE("%s: csd_stop_voice error %d\n", __func__, ret); + } + } + } + + return ret; +} + +int platform_set_voice_volume(void *platform, int volume) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd_client) { + if (my_data->csd_volume == NULL) { + ALOGE("%s: dlsym error for csd_volume", __func__); + } else { + ret = my_data->csd_volume(volume); + if (ret < 0) { + ALOGE("%s: csd_volume error %d", __func__, ret); + } + } + } else { + ALOGE("%s: No CSD Client present", __func__); + } + + return ret; +} + +int platform_set_mic_mute(void *platform, bool state) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->adev->mode == AUDIO_MODE_IN_CALL) { + if (my_data->csd_client) { + if (my_data->csd_mic_mute == NULL) { + ALOGE("%s: dlsym error for csd_mic_mute", __func__); + } else { + ret = my_data->csd_mic_mute(state); + if (ret < 0) { + ALOGE("%s: csd_mic_mute error %d", __func__, ret); + } + } + } else { + ALOGE("%s: No CSD Client present", __func__); + } + } + + return ret; +} + +snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + audio_mode_t mode = adev->mode; + snd_device_t snd_device = SND_DEVICE_NONE; + + ALOGV("%s: enter: output devices(%#x)", __func__, devices); + if (devices == AUDIO_DEVICE_NONE || + devices & AUDIO_DEVICE_BIT_IN) { + ALOGV("%s: Invalid output devices (%#x)", __func__, devices); + goto exit; + } + + if (mode == AUDIO_MODE_IN_CALL) { + if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + if (adev->tty_mode == TTY_MODE_FULL) + snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES; + else if (adev->tty_mode == TTY_MODE_VCO) + snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; + else if (adev->tty_mode == TTY_MODE_HCO) + snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; + else + snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES; + } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_OUT_BT_SCO; + } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { + snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { + if (is_operator_tmus()) + snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; + else + snd_device = SND_DEVICE_OUT_HANDSET; + } + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + } + + if (popcount(devices) == 2) { + if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; + } else { + ALOGE("%s: Invalid combo device(%#x)", __func__, devices); + goto exit; + } + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + } + + if (popcount(devices) != 1) { + ALOGE("%s: Invalid output devices(%#x)", __func__, devices); + goto exit; + } + + if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_OUT_HEADPHONES; + } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { + if (adev->speaker_lr_swap) + snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE; + else + snd_device = SND_DEVICE_OUT_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_OUT_BT_SCO; + } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + snd_device = SND_DEVICE_OUT_HDMI ; + } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { + snd_device = SND_DEVICE_OUT_HANDSET; + } else { + ALOGE("%s: Unknown device(s) %#x", __func__, devices); + } +exit: + ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]); + return snd_device; +} + +snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + audio_source_t source = (adev->active_input == NULL) ? + AUDIO_SOURCE_DEFAULT : adev->active_input->source; + + audio_mode_t mode = adev->mode; + audio_devices_t in_device = ((adev->active_input == NULL) ? + AUDIO_DEVICE_NONE : adev->active_input->device) + & ~AUDIO_DEVICE_BIT_IN; + audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? + AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; + snd_device_t snd_device = SND_DEVICE_NONE; + + ALOGV("%s: enter: out_device(%#x) in_device(%#x)", + __func__, out_device, in_device); + if (mode == AUDIO_MODE_IN_CALL) { + if (out_device == AUDIO_DEVICE_NONE) { + ALOGE("%s: No output device set for voice call", __func__); + goto exit; + } + if (adev->tty_mode != TTY_MODE_OFF) { + if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + switch (adev->tty_mode) { + case TTY_MODE_FULL: + snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC; + break; + case TTY_MODE_VCO: + snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC; + break; + case TTY_MODE_HCO: + snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC; + break; + default: + ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode); + } + goto exit; + } + } + if (out_device & AUDIO_DEVICE_OUT_EARPIECE || + out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + if (my_data->fluence_in_voice_call == false) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else { + if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { + if (is_operator_tmus()) + snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS; + else + snd_device = SND_DEVICE_IN_VOICE_DMIC_EF; + } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) + snd_device = SND_DEVICE_IN_VOICE_DMIC_BS; + else + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC ; + } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { + if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && + my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF; + } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && + my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS; + } else { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; + } + } + } else if (source == AUDIO_SOURCE_CAMCORDER) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC || + in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_CAMCORDER_MIC; + } + } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { + if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF; + else if (my_data->fluence_in_voice_rec) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE; + } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { + if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS; + else if (my_data->fluence_in_voice_rec) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE; + } + + if (snd_device == SND_DEVICE_NONE) { + snd_device = SND_DEVICE_IN_VOICE_REC_MIC; + } + } + } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { + if (out_device & AUDIO_DEVICE_OUT_SPEAKER) + in_device = AUDIO_DEVICE_IN_BACK_MIC; + if (adev->active_input) { + if (adev->active_input->enable_aec) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC; + } + set_echo_reference(adev->mixer, "SLIM_RX"); + } else + set_echo_reference(adev->mixer, "NONE"); + } + } else if (source == AUDIO_SOURCE_DEFAULT) { + goto exit; + } + + + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + + if (in_device != AUDIO_DEVICE_NONE && + !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) && + !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC ; + } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { + snd_device = SND_DEVICE_IN_HDMI_MIC; + } else { + ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); + ALOGW("%s: Using default handset-mic", __func__); + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } else { + if (out_device & AUDIO_DEVICE_OUT_EARPIECE) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + snd_device = SND_DEVICE_IN_HDMI_MIC; + } else { + ALOGE("%s: Unknown output device(s) %#x", __func__, out_device); + ALOGW("%s: Using default handset-mic", __func__); + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } +exit: + ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]); + return snd_device; +} + +int platform_set_hdmi_channels(void *platform, int channel_count) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *channel_cnt_str = NULL; + const char *mixer_ctl_name = "HDMI_RX Channels"; + switch (channel_count) { + case 8: + channel_cnt_str = "Eight"; break; + case 7: + channel_cnt_str = "Seven"; break; + case 6: + channel_cnt_str = "Six"; break; + case 5: + channel_cnt_str = "Five"; break; + case 4: + channel_cnt_str = "Four"; break; + case 3: + channel_cnt_str = "Three"; break; + default: + channel_cnt_str = "Two"; break; + } + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("HDMI channel count: %s", channel_cnt_str); + mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); + return 0; +} + +int platform_edid_get_max_channels(void) +{ + FILE *file; + struct audio_block_header header; + char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE]; + char *sad = block; + int num_audio_blocks; + int channel_count; + int max_channels = 0; + int i; + + file = fopen(AUDIO_DATA_BLOCK_PATH, "rb"); + if (file == NULL) { + ALOGE("Unable to open '%s'", AUDIO_DATA_BLOCK_PATH); + return 0; + } + + /* Read audio block header */ + fread(&header, 1, sizeof(header), file); + + /* Read SAD blocks, clamping the maximum size for safety */ + if (header.length > (int)sizeof(block)) + header.length = (int)sizeof(block); + fread(&block, header.length, 1, file); + + fclose(file); + + /* Calculate the number of SAD blocks */ + num_audio_blocks = header.length / SAD_BLOCK_SIZE; + + for (i = 0; i < num_audio_blocks; i++) { + /* Only consider LPCM blocks */ + if ((sad[0] >> 3) != EDID_FORMAT_LPCM) + continue; + + channel_count = (sad[0] & 0x7) + 1; + if (channel_count > max_channels) + max_channels = channel_count; + + /* Advance to next block */ + sad += 3; + } + + return max_channels; +} diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h new file mode 100644 index 000000000..e77f939c6 --- /dev/null +++ b/hal/msm8960/platform.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef QCOM_AUDIO_PLATFORM_H +#define QCOM_AUDIO_PLATFORM_H + +/* + * Below are the devices for which is back end is same, SLIMBUS_0_RX. + * All these devices are handled by the internal HW codec. We can + * enable any one of these devices at any time + */ +#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \ + (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \ + AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE) + +/* Sound devices specific to the platform + * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound + * devices to enable corresponding mixer paths + */ +enum { + SND_DEVICE_NONE = 0, + + /* Playback devices */ + SND_DEVICE_MIN, + SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN, + SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN, + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_REVERSE, + SND_DEVICE_OUT_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_VOICE_SPEAKER, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_HDMI, + SND_DEVICE_OUT_SPEAKER_AND_HDMI, + SND_DEVICE_OUT_BT_SCO, + SND_DEVICE_OUT_VOICE_HANDSET_TMUS, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_END, + + /* + * Note: IN_BEGIN should be same as OUT_END because total number of devices + * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices. + */ + /* Capture devices */ + SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END, + SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN, + SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_HANDSET_MIC_AEC, + SND_DEVICE_IN_SPEAKER_MIC_AEC, + SND_DEVICE_IN_HEADSET_MIC_AEC, + SND_DEVICE_IN_VOICE_SPEAKER_MIC, + SND_DEVICE_IN_VOICE_HEADSET_MIC, + SND_DEVICE_IN_HDMI_MIC, + SND_DEVICE_IN_BT_SCO_MIC, + SND_DEVICE_IN_CAMCORDER_MIC, + SND_DEVICE_IN_VOICE_DMIC_EF, + SND_DEVICE_IN_VOICE_DMIC_BS, + SND_DEVICE_IN_VOICE_DMIC_EF_TMUS, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS, + SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, + SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, + SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, + SND_DEVICE_IN_VOICE_REC_MIC, + SND_DEVICE_IN_VOICE_REC_DMIC_EF, + SND_DEVICE_IN_VOICE_REC_DMIC_BS, + SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE, + SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE, + SND_DEVICE_IN_END, + + SND_DEVICE_MAX = SND_DEVICE_IN_END, + +}; + +#define MIXER_CARD 0 +#define SOUND_CARD 0 + +#define DEFAULT_OUTPUT_SAMPLING_RATE 48000 + +/* + * tinyAlsa library interprets period size as number of frames + * one frame = channel_count * sizeof (pcm sample) + * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes + * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes + * We should take care of returning proper size when AudioFlinger queries for + * the buffer size of an input/output stream + */ +#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 +#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8 +#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240 +#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 + +#define HDMI_MULTI_PERIOD_SIZE 336 +#define HDMI_MULTI_PERIOD_COUNT 8 +#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 +#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2) + +#define AUDIO_CAPTURE_PERIOD_SIZE 320 +#define AUDIO_CAPTURE_PERIOD_COUNT 2 + +#endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c new file mode 100644 index 000000000..d563288fc --- /dev/null +++ b/hal/msm8974/platform.c @@ -0,0 +1,754 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "msm8974_platform" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include "platform.h" + +#define LIB_ACDB_LOADER "libacdbloader.so" + +#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ +#define DUALMIC_CONFIG_ENDFIRE 1 +#define DUALMIC_CONFIG_BROADSIDE 2 + +/* + * This is the sysfs path for the HDMI audio data block + */ +#define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" + +/* + * This file will have a maximum of 38 bytes: + * + * 4 bytes: number of audio blocks + * 4 bytes: total length of Short Audio Descriptor (SAD) blocks + * Maximum 10 * 3 bytes: SAD blocks + */ +#define MAX_SAD_BLOCKS 10 +#define SAD_BLOCK_SIZE 3 + +/* EDID format ID for LPCM audio */ +#define EDID_FORMAT_LPCM 1 + +struct audio_block_header +{ + int reserved; + int length; +}; + +typedef void (*acdb_deallocate_t)(); +typedef int (*acdb_init_t)(); +typedef void (*acdb_send_audio_cal_t)(int, int); +typedef void (*acdb_send_voice_cal_t)(int, int); + +/* Audio calibration related functions */ +struct platform_data { + struct audio_device *adev; + bool fluence_in_spkr_mode; + bool fluence_in_voice_call; + bool fluence_in_voice_rec; + int dualmic_config; + + void *acdb_handle; + acdb_init_t acdb_init; + acdb_deallocate_t acdb_deallocate; + acdb_send_audio_cal_t acdb_send_audio_cal; + acdb_send_voice_cal_t acdb_send_voice_cal; +}; + +static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0}, + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1}, + [USECASE_AUDIO_RECORD] = {0, 0}, + [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15}, + [USECASE_VOICE_CALL] = {2, 2}, +}; + +/* Array to store sound devices */ +static const char * const device_table[SND_DEVICE_MAX] = { + [SND_DEVICE_NONE] = "none", + /* Playback sound devices */ + [SND_DEVICE_OUT_HANDSET] = "handset", + [SND_DEVICE_OUT_SPEAKER] = "speaker", + [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse", + [SND_DEVICE_OUT_HEADPHONES] = "headphones", + [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones", + [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset", + [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker", + [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones", + [SND_DEVICE_OUT_HDMI] = "hdmi", + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", + [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", + [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus", + [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", + [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", + [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + + /* Capture sound devices */ + [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", + [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", + [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", + [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic", + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "voice-speaker-mic", + [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic", + [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", + [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", + [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", + [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", + [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", + [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef", + [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs", + [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs", + [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", + [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", + [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", + [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", + [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef", + [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs", + [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence", + [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence", +}; + +/* ACDB IDs (audio DSP path configuration IDs) for each sound device */ +static const int acdb_device_table[SND_DEVICE_MAX] = { + [SND_DEVICE_NONE] = -1, + [SND_DEVICE_OUT_HANDSET] = 7, + [SND_DEVICE_OUT_SPEAKER] = 15, + [SND_DEVICE_OUT_SPEAKER_REVERSE] = 15, + [SND_DEVICE_OUT_HEADPHONES] = 10, + [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, + [SND_DEVICE_OUT_VOICE_HANDSET] = 7, + [SND_DEVICE_OUT_VOICE_SPEAKER] = 15, + [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10, + [SND_DEVICE_OUT_HDMI] = 18, + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, + [SND_DEVICE_OUT_BT_SCO] = 22, + [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81, + [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, + [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, + [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + + [SND_DEVICE_IN_HANDSET_MIC] = 4, + [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */ + [SND_DEVICE_IN_HEADSET_MIC] = 8, + [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40, + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42, + [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47, + [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, + [SND_DEVICE_IN_HDMI_MIC] = 4, + [SND_DEVICE_IN_BT_SCO_MIC] = 21, + [SND_DEVICE_IN_CAMCORDER_MIC] = 61, + [SND_DEVICE_IN_VOICE_DMIC_EF] = 41, + [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, + [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, + [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, + [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_REC_MIC] = 62, + /* TODO: Update with proper acdb ids */ + [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62, + [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62, + [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6, + [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, +}; + +static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; +static bool is_tmus = false; + +static void check_operator() +{ + char value[PROPERTY_VALUE_MAX]; + int mccmnc; + property_get("gsm.sim.operator.numeric",value,"0"); + mccmnc = atoi(value); + ALOGD("%s: tmus mccmnc %d", __func__, mccmnc); + switch(mccmnc) { + /* TMUS MCC(310), MNC(490, 260, 026) */ + case 310490: + case 310260: + case 310026: + is_tmus = true; + break; + } +} + +bool is_operator_tmus() +{ + pthread_once(&check_op_once_ctl, check_operator); + return is_tmus; +} + +static int set_echo_reference(struct mixer *mixer, const char* ec_ref) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "EC_REF_RX"; + + ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting EC Reference: %s", ec_ref); + mixer_ctl_set_enum_by_string(ctl, ec_ref); + return 0; +} + +void *platform_init(struct audio_device *adev) +{ + char value[PROPERTY_VALUE_MAX]; + struct platform_data *my_data; + + my_data = calloc(1, sizeof(struct platform_data)); + + my_data->adev = adev; + my_data->dualmic_config = DUALMIC_CONFIG_NONE; + my_data->fluence_in_spkr_mode = false; + my_data->fluence_in_voice_call = false; + my_data->fluence_in_voice_rec = false; + + property_get("persist.audio.dualmic.config",value,""); + if (!strcmp("broadside", value)) { + my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE; + adev->acdb_settings |= DMIC_FLAG; + } else if (!strcmp("endfire", value)) { + my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE; + adev->acdb_settings |= DMIC_FLAG; + } + + if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) { + property_get("persist.audio.fluence.voicecall",value,""); + if (!strcmp("true", value)) { + my_data->fluence_in_voice_call = true; + } + + property_get("persist.audio.fluence.voicerec",value,""); + if (!strcmp("true", value)) { + my_data->fluence_in_voice_rec = true; + } + + property_get("persist.audio.fluence.speaker",value,""); + if (!strcmp("true", value)) { + my_data->fluence_in_spkr_mode = true; + } + } + + my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW); + if (my_data->acdb_handle == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER); + my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle, + "acdb_loader_deallocate_ACDB"); + my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle, + "acdb_loader_send_audio_cal"); + if (!my_data->acdb_send_audio_cal) + ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s", + __func__, LIB_ACDB_LOADER); + my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle, + "acdb_loader_send_voice_cal"); + my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle, + "acdb_loader_init_ACDB"); + if (my_data->acdb_init == NULL) + ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror()); + else + my_data->acdb_init(); + } + + return my_data; +} + +void platform_deinit(void *platform) +{ + free(platform); +} + +const char *platform_get_snd_device_name(snd_device_t snd_device) +{ + if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) + return device_table[snd_device]; + else + return ""; +} + +void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) +{ + if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) + strcat(mixer_path, " bt-sco"); + else if(snd_device == SND_DEVICE_OUT_BT_SCO) + strcat(mixer_path, " bt-sco"); + else if (snd_device == SND_DEVICE_OUT_HDMI) + strcat(mixer_path, " hdmi"); + else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) + strcat(mixer_path, " speaker-and-hdmi"); +} + +int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) +{ + int device_id; + if (device_type == PCM_PLAYBACK) + device_id = pcm_device_table[usecase][0]; + else + device_id = pcm_device_table[usecase][1]; + return device_id; +} + +int platform_send_audio_calibration(void *platform, snd_device_t snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_dev_id, acdb_dev_type; + + acdb_dev_id = acdb_device_table[snd_device]; + if (acdb_dev_id < 0) { + ALOGE("%s: Could not find acdb id for device(%d)", + __func__, snd_device); + return -EINVAL; + } + if (my_data->acdb_send_audio_cal) { + ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", + __func__, snd_device, acdb_dev_id); + if (snd_device >= SND_DEVICE_OUT_BEGIN && + snd_device < SND_DEVICE_OUT_END) + acdb_dev_type = ACDB_DEV_TYPE_OUT; + else + acdb_dev_type = ACDB_DEV_TYPE_IN; + my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type); + } + return 0; +} + +int platform_switch_voice_call_device_pre(void *platform) +{ + return 0; +} + +int platform_switch_voice_call_device_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_rx_id, acdb_tx_id; + + if (my_data->acdb_send_voice_cal == NULL) { + ALOGE("%s: dlsym error for acdb_send_voice_call", __func__); + } else { + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; + + if (acdb_rx_id > 0 && acdb_tx_id > 0) + my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id); + else + ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, + acdb_rx_id, acdb_tx_id); + } + + return 0; +} + +int platform_start_voice_call(void *platform) +{ + return 0; +} + +int platform_stop_voice_call(void *platform) +{ + return 0; +} + +int platform_set_voice_volume(void *platform, int volume) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voice Rx Volume"; + + // Voice volume levels are mapped to adsp volume levels as follows. + // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 + // But this values don't changed in kernel. So, below change is need. + volume = volume / 20; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting voice volume: %d", volume); + mixer_ctl_set_value(ctl, 0, volume); + + return 0; +} + +int platform_set_mic_mute(void *platform, bool state) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voice Tx Mute"; + + if (adev->mode == AUDIO_MODE_IN_CALL) { + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting mic mute: %d", state); + mixer_ctl_set_value(ctl, 0, state); + } + + return 0; +} + +snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + audio_mode_t mode = adev->mode; + snd_device_t snd_device = SND_DEVICE_NONE; + + ALOGV("%s: enter: output devices(%#x)", __func__, devices); + if (devices == AUDIO_DEVICE_NONE || + devices & AUDIO_DEVICE_BIT_IN) { + ALOGV("%s: Invalid output devices (%#x)", __func__, devices); + goto exit; + } + + if (mode == AUDIO_MODE_IN_CALL) { + if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + if (adev->tty_mode == TTY_MODE_FULL) + snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES; + else if (adev->tty_mode == TTY_MODE_VCO) + snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; + else if (adev->tty_mode == TTY_MODE_HCO) + snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; + else + snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES; + } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_OUT_BT_SCO; + } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { + snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { + if (is_operator_tmus()) + snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; + else + snd_device = SND_DEVICE_OUT_HANDSET; + } + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + } + + if (popcount(devices) == 2) { + if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; + } else { + ALOGE("%s: Invalid combo device(%#x)", __func__, devices); + goto exit; + } + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + } + + if (popcount(devices) != 1) { + ALOGE("%s: Invalid output devices(%#x)", __func__, devices); + goto exit; + } + + if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_OUT_HEADPHONES; + } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { + if (adev->speaker_lr_swap) + snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE; + else + snd_device = SND_DEVICE_OUT_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_OUT_BT_SCO; + } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + snd_device = SND_DEVICE_OUT_HDMI ; + } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { + snd_device = SND_DEVICE_OUT_HANDSET; + } else { + ALOGE("%s: Unknown device(s) %#x", __func__, devices); + } +exit: + ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]); + return snd_device; +} + +snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + audio_source_t source = (adev->active_input == NULL) ? + AUDIO_SOURCE_DEFAULT : adev->active_input->source; + + audio_mode_t mode = adev->mode; + audio_devices_t in_device = ((adev->active_input == NULL) ? + AUDIO_DEVICE_NONE : adev->active_input->device) + & ~AUDIO_DEVICE_BIT_IN; + audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? + AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; + snd_device_t snd_device = SND_DEVICE_NONE; + + ALOGV("%s: enter: out_device(%#x) in_device(%#x)", + __func__, out_device, in_device); + if (mode == AUDIO_MODE_IN_CALL) { + if (out_device == AUDIO_DEVICE_NONE) { + ALOGE("%s: No output device set for voice call", __func__); + goto exit; + } + if (adev->tty_mode != TTY_MODE_OFF) { + if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + switch (adev->tty_mode) { + case TTY_MODE_FULL: + snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC; + break; + case TTY_MODE_VCO: + snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC; + break; + case TTY_MODE_HCO: + snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC; + break; + default: + ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode); + } + goto exit; + } + } + if (out_device & AUDIO_DEVICE_OUT_EARPIECE || + out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + if (my_data->fluence_in_voice_call == false) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else { + if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { + if (is_operator_tmus()) + snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS; + else + snd_device = SND_DEVICE_IN_VOICE_DMIC_EF; + } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) + snd_device = SND_DEVICE_IN_VOICE_DMIC_BS; + else + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC ; + } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { + if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && + my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF; + } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && + my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS; + } else { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; + } + } + } else if (source == AUDIO_SOURCE_CAMCORDER) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC || + in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_CAMCORDER_MIC; + } + } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { + if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF; + else if (my_data->fluence_in_voice_rec) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE; + } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { + if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS; + else if (my_data->fluence_in_voice_rec) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE; + } + + if (snd_device == SND_DEVICE_NONE) { + snd_device = SND_DEVICE_IN_VOICE_REC_MIC; + } + } + } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { + if (out_device & AUDIO_DEVICE_OUT_SPEAKER) + in_device = AUDIO_DEVICE_IN_BACK_MIC; + if (adev->active_input) { + if (adev->active_input->enable_aec) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC; + } + set_echo_reference(adev->mixer, "SLIM_RX"); + } else + set_echo_reference(adev->mixer, "NONE"); + } + } else if (source == AUDIO_SOURCE_DEFAULT) { + goto exit; + } + + + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + + if (in_device != AUDIO_DEVICE_NONE && + !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) && + !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC ; + } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { + snd_device = SND_DEVICE_IN_HDMI_MIC; + } else { + ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); + ALOGW("%s: Using default handset-mic", __func__); + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } else { + if (out_device & AUDIO_DEVICE_OUT_EARPIECE) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + snd_device = SND_DEVICE_IN_HDMI_MIC; + } else { + ALOGE("%s: Unknown output device(s) %#x", __func__, out_device); + ALOGW("%s: Using default handset-mic", __func__); + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } +exit: + ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]); + return snd_device; +} + +int platform_set_hdmi_channels(void *platform, int channel_count) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *channel_cnt_str = NULL; + const char *mixer_ctl_name = "HDMI_RX Channels"; + switch (channel_count) { + case 8: + channel_cnt_str = "Eight"; break; + case 7: + channel_cnt_str = "Seven"; break; + case 6: + channel_cnt_str = "Six"; break; + case 5: + channel_cnt_str = "Five"; break; + case 4: + channel_cnt_str = "Four"; break; + case 3: + channel_cnt_str = "Three"; break; + default: + channel_cnt_str = "Two"; break; + } + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("HDMI channel count: %s", channel_cnt_str); + mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); + return 0; +} + +int platform_edid_get_max_channels(void) +{ + FILE *file; + struct audio_block_header header; + char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE]; + char *sad = block; + int num_audio_blocks; + int channel_count; + int max_channels = 0; + int i; + + file = fopen(AUDIO_DATA_BLOCK_PATH, "rb"); + if (file == NULL) { + ALOGE("Unable to open '%s'", AUDIO_DATA_BLOCK_PATH); + return 0; + } + + /* Read audio block header */ + fread(&header, 1, sizeof(header), file); + + /* Read SAD blocks, clamping the maximum size for safety */ + if (header.length > (int)sizeof(block)) + header.length = (int)sizeof(block); + fread(&block, header.length, 1, file); + + fclose(file); + + /* Calculate the number of SAD blocks */ + num_audio_blocks = header.length / SAD_BLOCK_SIZE; + + for (i = 0; i < num_audio_blocks; i++) { + /* Only consider LPCM blocks */ + if ((sad[0] >> 3) != EDID_FORMAT_LPCM) + continue; + + channel_count = (sad[0] & 0x7) + 1; + if (channel_count > max_channels) + max_channels = channel_count; + + /* Advance to next block */ + sad += 3; + } + + return max_channels; +} diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h new file mode 100644 index 000000000..9b97648ec --- /dev/null +++ b/hal/msm8974/platform.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef QCOM_AUDIO_PLATFORM_H +#define QCOM_AUDIO_PLATFORM_H + +/* + * Below are the devices for which is back end is same, SLIMBUS_0_RX. + * All these devices are handled by the internal HW codec. We can + * enable any one of these devices at any time + */ +#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \ + (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \ + AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE) + +/* Sound devices specific to the platform + * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound + * devices to enable corresponding mixer paths + */ +enum { + SND_DEVICE_NONE = 0, + + /* Playback devices */ + SND_DEVICE_MIN, + SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN, + SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN, + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_REVERSE, + SND_DEVICE_OUT_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_VOICE_HANDSET, + SND_DEVICE_OUT_VOICE_SPEAKER, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_HDMI, + SND_DEVICE_OUT_SPEAKER_AND_HDMI, + SND_DEVICE_OUT_BT_SCO, + SND_DEVICE_OUT_VOICE_HANDSET_TMUS, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_END, + + /* + * Note: IN_BEGIN should be same as OUT_END because total number of devices + * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices. + */ + /* Capture devices */ + SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END, + SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN, + SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_HANDSET_MIC_AEC, + SND_DEVICE_IN_SPEAKER_MIC_AEC, + SND_DEVICE_IN_HEADSET_MIC_AEC, + SND_DEVICE_IN_VOICE_SPEAKER_MIC, + SND_DEVICE_IN_VOICE_HEADSET_MIC, + SND_DEVICE_IN_HDMI_MIC, + SND_DEVICE_IN_BT_SCO_MIC, + SND_DEVICE_IN_CAMCORDER_MIC, + SND_DEVICE_IN_VOICE_DMIC_EF, + SND_DEVICE_IN_VOICE_DMIC_BS, + SND_DEVICE_IN_VOICE_DMIC_EF_TMUS, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS, + SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, + SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, + SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, + SND_DEVICE_IN_VOICE_REC_MIC, + SND_DEVICE_IN_VOICE_REC_DMIC_EF, + SND_DEVICE_IN_VOICE_REC_DMIC_BS, + SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE, + SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE, + SND_DEVICE_IN_END, + + SND_DEVICE_MAX = SND_DEVICE_IN_END, + +}; + +#define MIXER_CARD 0 +#define SOUND_CARD 0 + +#define DEFAULT_OUTPUT_SAMPLING_RATE 48000 + +/* + * tinyAlsa library interprets period size as number of frames + * one frame = channel_count * sizeof (pcm sample) + * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes + * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes + * We should take care of returning proper size when AudioFlinger queries for + * the buffer size of an input/output stream + */ +#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1024 +#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8 +#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 256 +#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 + +#define HDMI_MULTI_PERIOD_SIZE 336 +#define HDMI_MULTI_PERIOD_COUNT 8 +#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 +#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2) + +#define AUDIO_CAPTURE_PERIOD_SIZE 512 +#define AUDIO_CAPTURE_PERIOD_COUNT 16 + +#endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal/platform_api.h b/hal/platform_api.h new file mode 100644 index 000000000..837fce969 --- /dev/null +++ b/hal/platform_api.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef QCOM_AUDIO_PLATFORM_API_H +#define QCOM_AUDIO_PLATFORM_API_H + +void *platform_init(struct audio_device *adev); +void platform_deinit(void *platform); +const char *platform_get_snd_device_name(snd_device_t snd_device); +void platform_add_backend_name(char *mixer_path, snd_device_t snd_device); +int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type); +int platform_send_audio_calibration(void *platform, snd_device_t snd_device); +int platform_switch_voice_call_device_pre(void *platform); +int platform_switch_voice_call_device_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device); +int platform_start_voice_call(void *platform); +int platform_stop_voice_call(void *platform); +int platform_set_voice_volume(void *platform, int volume); +int platform_set_mic_mute(void *platform, bool state); +snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices); +snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device); +int platform_set_hdmi_channels(void *platform, int channel_count); +int platform_edid_get_max_channels(void); + +#endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From 33d330678f797b8796f72114bad42957b9ca204f Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Tue, 11 Jun 2013 14:40:01 -0700 Subject: [PATCH 012/298] audio/hal: Set playback buffer size to integral multiple of msec - Set the deep-buffer and low-latency output buffer sizes to integral multiple of msec. This reduces the variations in the writes. - Compute the input buffer size based on sample rate. Use 20msec buffers in capture path. Bug: 9283911, 9106434 Change-Id: Icbcb653f7f0fd3293dd4b514a54ac91d8311b308 --- hal/audio_hw.c | 23 +++++++++++------------ hal/msm8960/platform.h | 2 +- hal/msm8974/platform.h | 8 ++++---- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index b73c95e02..78f38a29b 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -73,7 +73,6 @@ struct pcm_config pcm_config_hdmi_multi = { struct pcm_config pcm_config_audio_capture = { .channels = 2, - .period_size = AUDIO_CAPTURE_PERIOD_SIZE, .period_count = AUDIO_CAPTURE_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, }; @@ -817,19 +816,19 @@ static size_t get_input_buffer_size(uint32_t sample_rate, { size_t size = 0; - if (check_input_parameters(sample_rate, format, channel_count) != 0) return 0; + if (check_input_parameters(sample_rate, format, channel_count) != 0) + return 0; - if (sample_rate == 8000 || sample_rate == 16000 || sample_rate == 32000) { - size = (sample_rate * 20) / 1000; - } else if (sample_rate == 11025 || sample_rate == 12000) { - size = 256; - } else if (sample_rate == 22050 || sample_rate == 24000) { - size = 512; - } else if (sample_rate == 44100 || sample_rate == 48000) { - size = 1024; - } + size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000; + /* ToDo: should use frame_size computed based on the format and + channel_count here. */ + size *= sizeof(short) * channel_count; + + /* make sure the size is multiple of 64 */ + size += 0x3f; + size &= ~0x3f; - return size * sizeof(short) * channel_count; + return size; } static uint32_t out_get_sample_rate(const struct audio_stream *stream) diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h index e77f939c6..4bc500329 100644 --- a/hal/msm8960/platform.h +++ b/hal/msm8960/platform.h @@ -111,7 +111,7 @@ enum { #define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 #define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2) -#define AUDIO_CAPTURE_PERIOD_SIZE 320 +#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20 #define AUDIO_CAPTURE_PERIOD_COUNT 2 #endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 9b97648ec..f843fa8dd 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -102,9 +102,9 @@ enum { * We should take care of returning proper size when AudioFlinger queries for * the buffer size of an input/output stream */ -#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1024 +#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 #define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8 -#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 256 +#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 #define HDMI_MULTI_PERIOD_SIZE 336 @@ -112,7 +112,7 @@ enum { #define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 #define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2) -#define AUDIO_CAPTURE_PERIOD_SIZE 512 -#define AUDIO_CAPTURE_PERIOD_COUNT 16 +#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20 +#define AUDIO_CAPTURE_PERIOD_COUNT 2 #endif // QCOM_AUDIO_PLATFORM_H -- GitLab From 1b9f4b3708d1ed1204bdb1dec370ad2e9db7a779 Mon Sep 17 00:00:00 2001 From: sangwoo Date: Fri, 21 Jun 2013 18:22:55 -0700 Subject: [PATCH 013/298] audio HAL: Add retry to get mixer in adev_open If the sound card is not created in kernel before audio hal initialized by audio flinger, the mixer open would be failed. This is timing issue. So retry routine is need. Change-Id: Icff3cd53763bfc483725849874fe27ff4de28890 --- hal/audio_hw.c | 16 ---------------- hal/msm8960/platform.c | 14 ++++++++++++++ hal/msm8974/platform.c | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 78f38a29b..a0b65e04c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -36,8 +36,6 @@ #include "platform_api.h" #include -#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" - struct pcm_config pcm_config_deep_buffer = { .channels = 2, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, @@ -1715,20 +1713,6 @@ static int adev_open(const hw_module_t *module, const char *name, adev = calloc(1, sizeof(struct audio_device)); - adev->mixer = mixer_open(MIXER_CARD); - if (!adev->mixer) { - ALOGE("Unable to open the mixer, aborting."); - return -ENOSYS; - } - - adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); - if (!adev->audio_route) { - free(adev); - ALOGE("%s: Failed to init audio route controls, aborting.", __func__); - *device = NULL; - return -EINVAL; - } - adev->device.common.tag = HARDWARE_DEVICE_TAG; adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; adev->device.common.module = (struct hw_module_t *)module; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 7052d68e3..0c6871a08 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -37,6 +37,7 @@ * This is the sysfs path for the HDMI audio data block */ #define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" +#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" /* * This file will have a maximum of 38 bytes: @@ -248,6 +249,19 @@ void *platform_init(struct audio_device *adev) char value[PROPERTY_VALUE_MAX]; struct platform_data *my_data; + adev->mixer = mixer_open(MIXER_CARD); + + if (!adev->mixer) { + ALOGE("Unable to open the mixer, aborting."); + return NULL; + } + + adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); + if (!adev->audio_route) { + ALOGE("%s: Failed to init audio route controls, aborting.", __func__); + return NULL; + } + my_data = calloc(1, sizeof(struct platform_data)); my_data->adev = adev; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index d563288fc..0b04e9e91 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -36,6 +36,7 @@ * This is the sysfs path for the HDMI audio data block */ #define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" +#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" /* * This file will have a maximum of 38 bytes: @@ -50,6 +51,10 @@ /* EDID format ID for LPCM audio */ #define EDID_FORMAT_LPCM 1 +/* Retry for delay in FW loading*/ +#define RETRY_NUMBER 10 +#define RETRY_US 500000 + struct audio_block_header { int reserved; @@ -224,6 +229,26 @@ void *platform_init(struct audio_device *adev) { char value[PROPERTY_VALUE_MAX]; struct platform_data *my_data; + int retry_num = 0; + + adev->mixer = mixer_open(MIXER_CARD); + + while (!adev->mixer && retry_num < RETRY_NUMBER) { + usleep(RETRY_US); + adev->mixer = mixer_open(MIXER_CARD); + retry_num++; + } + + if (!adev->mixer) { + ALOGE("Unable to open the mixer, aborting."); + return NULL; + } + + adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); + if (!adev->audio_route) { + ALOGE("%s: Failed to init audio route controls, aborting.", __func__); + return NULL; + } my_data = calloc(1, sizeof(struct platform_data)); -- GitLab From 994a693158202488516c48c22534ae2035b5c8fa Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 17 Jul 2013 11:51:42 -0700 Subject: [PATCH 014/298] audio: reduce audio HAL log spam. Change-Id: I73a7ee40a32ccd4e6a85e49d08a6610351fedab7 --- hal/audio_hw.c | 78 +++++++++++++++++++++--------------------- hal/msm8960/platform.c | 2 +- hal/msm8974/platform.c | 2 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index a0b65e04c..dc683d6c5 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -126,7 +126,7 @@ static int enable_audio_route(struct audio_device *adev, strcpy(mixer_path, use_case_table[usecase->id]); platform_add_backend_name(mixer_path, snd_device); - ALOGD("%s: apply mixer path: %s", __func__, mixer_path); + ALOGV("%s: apply mixer path: %s", __func__, mixer_path); audio_route_apply_path(adev->audio_route, mixer_path); if (update_mixer) audio_route_update_mixer(adev->audio_route); @@ -152,7 +152,7 @@ static int disable_audio_route(struct audio_device *adev, snd_device = usecase->out_snd_device; strcpy(mixer_path, use_case_table[usecase->id]); platform_add_backend_name(mixer_path, snd_device); - ALOGD("%s: reset mixer path: %s", __func__, mixer_path); + ALOGV("%s: reset mixer path: %s", __func__, mixer_path); audio_route_reset_path(adev->audio_route, mixer_path); if (update_mixer) audio_route_update_mixer(adev->audio_route); @@ -173,7 +173,7 @@ static int enable_snd_device(struct audio_device *adev, adev->snd_dev_ref_cnt[snd_device]++; if (adev->snd_dev_ref_cnt[snd_device] > 1) { - ALOGD("%s: snd_device(%d: %s) is already active", + ALOGV("%s: snd_device(%d: %s) is already active", __func__, snd_device, platform_get_snd_device_name(snd_device)); return 0; } @@ -183,7 +183,7 @@ static int enable_snd_device(struct audio_device *adev, return -EINVAL; } - ALOGD("%s: snd_device(%d: %s)", __func__, + ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, platform_get_snd_device_name(snd_device)); audio_route_apply_path(adev->audio_route, platform_get_snd_device_name(snd_device)); if (update_mixer) @@ -207,7 +207,7 @@ static int disable_snd_device(struct audio_device *adev, } adev->snd_dev_ref_cnt[snd_device]--; if (adev->snd_dev_ref_cnt[snd_device] == 0) { - ALOGD("%s: snd_device(%d: %s)", __func__, + ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, platform_get_snd_device_name(snd_device)); audio_route_reset_path(adev->audio_route, platform_get_snd_device_name(snd_device)); if (update_mixer) @@ -463,7 +463,7 @@ static int select_devices(struct audio_device *adev, return 0; } - ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__, + ALOGV("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__, out_snd_device, platform_get_snd_device_name(out_snd_device), in_snd_device, platform_get_snd_device_name(in_snd_device)); @@ -522,7 +522,7 @@ static int stop_input_stream(struct stream_in *in) adev->active_input = NULL; - ALOGD("%s: enter: usecase(%d: %s)", __func__, + ALOGV("%s: enter: usecase(%d: %s)", __func__, in->usecase, use_case_table[in->usecase]); uc_info = get_usecase_from_list(adev, in->usecase); if (uc_info == NULL) { @@ -540,7 +540,7 @@ static int stop_input_stream(struct stream_in *in) list_remove(&uc_info->list); free(uc_info); - ALOGD("%s: exit: status(%d)", __func__, ret); + ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -551,7 +551,7 @@ int start_input_stream(struct stream_in *in) struct audio_usecase *uc_info; struct audio_device *adev = in->dev; - ALOGD("%s: enter: usecase(%d)", __func__, in->usecase); + ALOGV("%s: enter: usecase(%d)", __func__, in->usecase); in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); if (in->pcm_device_id < 0) { ALOGE("%s: Could not find PCM device id for the usecase(%d)", @@ -583,7 +583,7 @@ int start_input_stream(struct stream_in *in) ret = -EIO; goto error_open; } - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return ret; error_open: @@ -602,7 +602,7 @@ static int stop_output_stream(struct stream_out *out) struct audio_usecase *uc_info; struct audio_device *adev = out->dev; - ALOGD("%s: enter: usecase(%d: %s)", __func__, + ALOGV("%s: enter: usecase(%d: %s)", __func__, out->usecase, use_case_table[out->usecase]); uc_info = get_usecase_from_list(adev, out->usecase); if (uc_info == NULL) { @@ -620,7 +620,7 @@ static int stop_output_stream(struct stream_out *out) list_remove(&uc_info->list); free(uc_info); - ALOGD("%s: exit: status(%d)", __func__, ret); + ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -630,7 +630,7 @@ int start_output_stream(struct stream_out *out) struct audio_usecase *uc_info; struct audio_device *adev = out->dev; - ALOGD("%s: enter: usecase(%d: %s) devices(%#x)", + ALOGV("%s: enter: usecase(%d: %s) devices(%#x)", __func__, out->usecase, use_case_table[out->usecase], out->devices); out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); if (out->pcm_device_id < 0) { @@ -663,7 +663,7 @@ int start_output_stream(struct stream_out *out) ret = -EIO; goto error_pcm_open; } - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return 0; error_pcm_open: stop_output_stream(out); @@ -676,7 +676,7 @@ static int stop_voice_call(struct audio_device *adev) int i, ret = 0; struct audio_usecase *uc_info; - ALOGD("%s: enter", __func__); + ALOGV("%s: enter", __func__); adev->in_call = false; ret = platform_stop_voice_call(adev->platform); @@ -708,7 +708,7 @@ static int stop_voice_call(struct audio_device *adev) list_remove(&uc_info->list); free(uc_info); - ALOGD("%s: exit: status(%d)", __func__, ret); + ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -718,7 +718,7 @@ static int start_voice_call(struct audio_device *adev) struct audio_usecase *uc_info; int pcm_dev_rx_id, pcm_dev_tx_id; - ALOGD("%s: enter", __func__); + ALOGV("%s: enter", __func__); uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); uc_info->id = USECASE_VOICE_CALL; @@ -869,7 +869,7 @@ static int out_standby(struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; - ALOGD("%s: enter: usecase(%d: %s)", __func__, + ALOGV("%s: enter: usecase(%d: %s)", __func__, out->usecase, use_case_table[out->usecase]); pthread_mutex_lock(&out->lock); @@ -884,7 +884,7 @@ static int out_standby(struct audio_stream *stream) pthread_mutex_unlock(&adev->lock); } pthread_mutex_unlock(&out->lock); - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return 0; } @@ -904,7 +904,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int ret, val = 0; bool select_new_device = false; - ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", + ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s", __func__, out->usecase, use_case_table[out->usecase], kvpairs); parms = str_parms_create_str(kvpairs); ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); @@ -967,7 +967,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&out->lock); } str_parms_destroy(parms); - ALOGD("%s: exit: code(%d)", __func__, ret); + ALOGV("%s: exit: code(%d)", __func__, ret); return ret; } @@ -981,7 +981,7 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k size_t i, j; int ret; bool first = true; - ALOGD("%s: enter: keys - %s", __func__, keys); + ALOGV("%s: enter: keys - %s", __func__, keys); ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value)); if (ret >= 0) { value[0] = '\0'; @@ -1006,7 +1006,7 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k } str_parms_destroy(query); str_parms_destroy(reply); - ALOGD("%s: exit: returns - %s", __func__, str); + ALOGV("%s: exit: returns - %s", __func__, str); return str; } @@ -1132,7 +1132,7 @@ static int in_standby(struct audio_stream *stream) struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int status = 0; - ALOGD("%s: enter", __func__); + ALOGV("%s: enter", __func__); pthread_mutex_lock(&in->lock); if (!in->standby) { in->standby = true; @@ -1145,7 +1145,7 @@ static int in_standby(struct audio_stream *stream) pthread_mutex_unlock(&adev->lock); } pthread_mutex_unlock(&in->lock); - ALOGD("%s: exit: status(%d)", __func__, status); + ALOGV("%s: exit: status(%d)", __func__, status); return status; } @@ -1163,7 +1163,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) char value[32]; int ret, val = 0; - ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs); + ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs); parms = str_parms_create_str(kvpairs); ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); @@ -1193,7 +1193,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&in->lock); str_parms_destroy(parms); - ALOGD("%s: exit: status(%d)", __func__, ret); + ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -1284,14 +1284,14 @@ static int add_remove_audio_effect(const struct audio_stream *stream, static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { - ALOGD("%s: effect %p", __func__, effect); + ALOGV("%s: effect %p", __func__, effect); return add_remove_audio_effect(stream, effect, true); } static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { - ALOGD("%s: effect %p", __func__, effect); + ALOGV("%s: effect %p", __func__, effect); return add_remove_audio_effect(stream, effect, false); } @@ -1306,7 +1306,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, struct stream_out *out; int i, ret; - ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", + ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", __func__, config->sample_rate, config->channel_mask, devices, flags); *stream_out = NULL; out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); @@ -1399,7 +1399,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); *stream_out = &out->stream; - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return 0; error_open: @@ -1412,10 +1412,10 @@ error_open: static void adev_close_output_stream(struct audio_hw_device *dev, struct audio_stream_out *stream) { - ALOGD("%s: enter", __func__); + ALOGV("%s: enter", __func__); out_standby(&stream->common); free(stream); - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); } static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) @@ -1427,7 +1427,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) int val; int ret; - ALOGD("%s: enter: %s", __func__, kvpairs); + ALOGV("%s: enter: %s", __func__, kvpairs); parms = str_parms_create_str(kvpairs); ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); @@ -1509,7 +1509,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) } str_parms_destroy(parms); - ALOGD("%s: exit with code(%d)", __func__, ret); + ALOGV("%s: exit with code(%d)", __func__, ret); return ret; } @@ -1625,7 +1625,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, int ret, buffer_size, frame_size; int channel_count = popcount(config->channel_mask); - ALOGD("%s: enter", __func__); + ALOGV("%s: enter", __func__); *stream_in = NULL; if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) return -EINVAL; @@ -1667,7 +1667,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->config.period_size = buffer_size / frame_size; *stream_in = &in->stream; - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return 0; err_open: @@ -1679,7 +1679,7 @@ err_open: static void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) { - ALOGD("%s", __func__); + ALOGV("%s", __func__); in_standby(&stream->common); free(stream); @@ -1764,7 +1764,7 @@ static int adev_open(const hw_module_t *module, const char *name, } *device = &adev->device.common; - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return 0; } diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 0c6871a08..c1c122de8 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -406,7 +406,7 @@ int platform_send_audio_calibration(void *platform, snd_device_t snd_device) return -EINVAL; } if (my_data->acdb_send_audio_cal) { - ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", + ("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", __func__, snd_device, acdb_dev_id); if (snd_device >= SND_DEVICE_OUT_BEGIN && snd_device < SND_DEVICE_OUT_END) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 0b04e9e91..49daf1728 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -356,7 +356,7 @@ int platform_send_audio_calibration(void *platform, snd_device_t snd_device) return -EINVAL; } if (my_data->acdb_send_audio_cal) { - ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", + ("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", __func__, snd_device, acdb_dev_id); if (snd_device >= SND_DEVICE_OUT_BEGIN && snd_device < SND_DEVICE_OUT_END) -- GitLab From c69476f6abbd7f82c2df8cf51ba3f4fed6eb75fe Mon Sep 17 00:00:00 2001 From: sangwoo Date: Fri, 26 Jul 2013 16:57:26 -0700 Subject: [PATCH 015/298] audio: Change TMUS Voice call acdb id The acdb id is changed in Handset_cal.acdb file. So, it needs to match with acdb file Change-Id: Idb044426ad21fd5bc0a14a75c0e1ea4df8bbe6bb --- hal/msm8974/platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 49daf1728..d479768aa 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -151,7 +151,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_HDMI] = 18, [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, [SND_DEVICE_OUT_BT_SCO] = 22, - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81, + [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88, [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, @@ -169,7 +169,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_CAMCORDER_MIC] = 61, [SND_DEVICE_IN_VOICE_DMIC_EF] = 41, [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91, + [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 89, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, -- GitLab From 53b2cf0c72aa18a5848919e2309731af652e84f9 Mon Sep 17 00:00:00 2001 From: sangwoo Date: Thu, 25 Jul 2013 19:18:44 -0700 Subject: [PATCH 016/298] audio: change mute/volume controls for using soft control api Volume and Mute controls are changed to use specific session and soft control api. So, HAL also changed to use new api. bug: 10023401 Change-Id: I686d8495293242097817d870477f59ed154a6b31 Signed-off-by: hyunsub.na Signed-off-by: Sungmin Choi Signed-off-by: sangwoo --- hal/msm8974/platform.c | 54 ++++++++++++++++++++++++++++++++++++++---- hal/msm8974/platform.h | 7 ++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 49daf1728..da1686124 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -55,6 +55,11 @@ #define RETRY_NUMBER 10 #define RETRY_US 500000 +#define MAX_VOL_INDEX 5 +#define MIN_VOL_INDEX 0 +#define percent_to_index(val, min, max) \ + ((val) * ((max) - (min)) * 0.01 + (min) + .5) + struct audio_block_header { int reserved; @@ -209,6 +214,24 @@ bool is_operator_tmus() return is_tmus; } +static int set_volume_values(int type, int volume, int* values) +{ + values[0] = volume; + values[1] = ALL_SESSION_VSID; + + switch(type) { + case VOLUME_SET: + values[2] = DEFAULT_VOLUME_RAMP_DURATION_MS; + break; + case MUTE_SET: + values[2] = DEFAULT_MUTE_RAMP_DURATION; + break; + default: + return -EINVAL; + } + return 0; +} + static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -411,12 +434,14 @@ int platform_set_voice_volume(void *platform, int volume) struct platform_data *my_data = (struct platform_data *)platform; struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; - const char *mixer_ctl_name = "Voice Rx Volume"; + const char *mixer_ctl_name = "Voice Rx Gain"; + int values[VOLUME_CTL_PARAM_NUM]; + int ret = 0; // Voice volume levels are mapped to adsp volume levels as follows. // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 // But this values don't changed in kernel. So, below change is need. - volume = volume / 20; + volume = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { @@ -424,8 +449,16 @@ int platform_set_voice_volume(void *platform, int volume) __func__, mixer_ctl_name); return -EINVAL; } - ALOGV("Setting voice volume: %d", volume); - mixer_ctl_set_value(ctl, 0, volume); + ret = set_volume_values(VOLUME_SET, volume, values); + if (ret < 0) { + ALOGV("%s: failed setting volume by incorrect type", __func__); + return -EINVAL; + } + ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int)); + if (ret < 0) { + ALOGV("%s: failed set mixer ctl by %d", __func__, ret); + return -EINVAL; + } return 0; } @@ -436,6 +469,8 @@ int platform_set_mic_mute(void *platform, bool state) struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Tx Mute"; + int values[VOLUME_CTL_PARAM_NUM]; + int ret = 0; if (adev->mode == AUDIO_MODE_IN_CALL) { ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); @@ -445,7 +480,16 @@ int platform_set_mic_mute(void *platform, bool state) return -EINVAL; } ALOGV("Setting mic mute: %d", state); - mixer_ctl_set_value(ctl, 0, state); + ret = set_volume_values(MUTE_SET, state, values); + if (ret < 0) { + ALOGV("%s: failed setting mute by incorrect type", __func__); + return -EINVAL; + } + ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int)); + if (ret < 0) { + ALOGV("%s: failed set mixer ctl by %d", __func__, ret); + return -EINVAL; + } } return 0; diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index f843fa8dd..a6b3c31c7 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -94,6 +94,13 @@ enum { #define DEFAULT_OUTPUT_SAMPLING_RATE 48000 +#define ALL_SESSION_VSID 0xFFFFFFFF +#define DEFAULT_MUTE_RAMP_DURATION 500 +#define DEFAULT_VOLUME_RAMP_DURATION_MS 20 +#define VOLUME_SET 0 +#define MUTE_SET 1 +#define VOLUME_CTL_PARAM_NUM 3 + /* * tinyAlsa library interprets period size as number of frames * one frame = channel_count * sizeof (pcm sample) -- GitLab From 72cd4efa0628af6f6f0941a901a5715ec8ce0802 Mon Sep 17 00:00:00 2001 From: sangwoo Date: Thu, 25 Jul 2013 19:18:44 -0700 Subject: [PATCH 017/298] audio: change mute/volume controls for using soft control api Volume and Mute controls are changed to use specific session and soft control api. So, HAL also changed to use new api. bug: 10023401 Change-Id: I686d8495293242097817d870477f59ed154a6b31 Signed-off-by: hyunsub.na Signed-off-by: Sungmin Choi Signed-off-by: sangwoo --- hal/msm8974/platform.c | 54 ++++++++++++++++++++++++++++++++++++++---- hal/msm8974/platform.h | 7 ++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 49daf1728..da1686124 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -55,6 +55,11 @@ #define RETRY_NUMBER 10 #define RETRY_US 500000 +#define MAX_VOL_INDEX 5 +#define MIN_VOL_INDEX 0 +#define percent_to_index(val, min, max) \ + ((val) * ((max) - (min)) * 0.01 + (min) + .5) + struct audio_block_header { int reserved; @@ -209,6 +214,24 @@ bool is_operator_tmus() return is_tmus; } +static int set_volume_values(int type, int volume, int* values) +{ + values[0] = volume; + values[1] = ALL_SESSION_VSID; + + switch(type) { + case VOLUME_SET: + values[2] = DEFAULT_VOLUME_RAMP_DURATION_MS; + break; + case MUTE_SET: + values[2] = DEFAULT_MUTE_RAMP_DURATION; + break; + default: + return -EINVAL; + } + return 0; +} + static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -411,12 +434,14 @@ int platform_set_voice_volume(void *platform, int volume) struct platform_data *my_data = (struct platform_data *)platform; struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; - const char *mixer_ctl_name = "Voice Rx Volume"; + const char *mixer_ctl_name = "Voice Rx Gain"; + int values[VOLUME_CTL_PARAM_NUM]; + int ret = 0; // Voice volume levels are mapped to adsp volume levels as follows. // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 // But this values don't changed in kernel. So, below change is need. - volume = volume / 20; + volume = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { @@ -424,8 +449,16 @@ int platform_set_voice_volume(void *platform, int volume) __func__, mixer_ctl_name); return -EINVAL; } - ALOGV("Setting voice volume: %d", volume); - mixer_ctl_set_value(ctl, 0, volume); + ret = set_volume_values(VOLUME_SET, volume, values); + if (ret < 0) { + ALOGV("%s: failed setting volume by incorrect type", __func__); + return -EINVAL; + } + ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int)); + if (ret < 0) { + ALOGV("%s: failed set mixer ctl by %d", __func__, ret); + return -EINVAL; + } return 0; } @@ -436,6 +469,8 @@ int platform_set_mic_mute(void *platform, bool state) struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Tx Mute"; + int values[VOLUME_CTL_PARAM_NUM]; + int ret = 0; if (adev->mode == AUDIO_MODE_IN_CALL) { ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); @@ -445,7 +480,16 @@ int platform_set_mic_mute(void *platform, bool state) return -EINVAL; } ALOGV("Setting mic mute: %d", state); - mixer_ctl_set_value(ctl, 0, state); + ret = set_volume_values(MUTE_SET, state, values); + if (ret < 0) { + ALOGV("%s: failed setting mute by incorrect type", __func__); + return -EINVAL; + } + ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int)); + if (ret < 0) { + ALOGV("%s: failed set mixer ctl by %d", __func__, ret); + return -EINVAL; + } } return 0; diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index f843fa8dd..a6b3c31c7 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -94,6 +94,13 @@ enum { #define DEFAULT_OUTPUT_SAMPLING_RATE 48000 +#define ALL_SESSION_VSID 0xFFFFFFFF +#define DEFAULT_MUTE_RAMP_DURATION 500 +#define DEFAULT_VOLUME_RAMP_DURATION_MS 20 +#define VOLUME_SET 0 +#define MUTE_SET 1 +#define VOLUME_CTL_PARAM_NUM 3 + /* * tinyAlsa library interprets period size as number of frames * one frame = channel_count * sizeof (pcm sample) -- GitLab From 47cd4cbdb19543338d5c887e3d7bcd2513c5c3ad Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 19 Jul 2013 11:58:50 -0700 Subject: [PATCH 018/298] hal: Fix EDID information - Get EDID audio block info from a mixer control instead of a file. - Fix a bug where the current sad is not updated in the for loop. Bug: 9430906 Change-Id: I750e307ce1064eeb98d09ea8534a375252630841 --- hal/audio_hw.c | 4 ++-- hal/msm8960/platform.c | 2 +- hal/msm8974/platform.c | 47 +++++++++++++++++++++++------------------- hal/platform_api.h | 2 +- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index dc683d6c5..6c89e7bf8 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -356,7 +356,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, static int read_hdmi_channel_masks(struct stream_out *out) { int ret = 0; - int channels = platform_edid_get_max_channels(); + int channels = platform_edid_get_max_channels(out->dev->platform); switch (channels) { /* @@ -1318,6 +1318,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; out->flags = flags; out->devices = devices; + out->dev = adev; /* Init use case and pcm_config */ if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && @@ -1390,7 +1391,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_render_position = out_get_render_position; out->stream.get_next_write_timestamp = out_get_next_write_timestamp; - out->dev = adev; out->standby = 1; /* out->muted = false; by calloc() */ diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index c1c122de8..e533f3387 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -835,7 +835,7 @@ int platform_set_hdmi_channels(void *platform, int channel_count) return 0; } -int platform_edid_get_max_channels(void) +int platform_edid_get_max_channels(void *platform) { FILE *file; struct audio_block_header header; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1cb668eaa..8560f9d1f 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -26,18 +26,14 @@ #include #include "platform.h" +#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define LIB_ACDB_LOADER "libacdbloader.so" +#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" #define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ #define DUALMIC_CONFIG_ENDFIRE 1 #define DUALMIC_CONFIG_BROADSIDE 2 -/* - * This is the sysfs path for the HDMI audio data block - */ -#define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" -#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" - /* * This file will have a maximum of 38 bytes: * @@ -776,40 +772,49 @@ int platform_set_hdmi_channels(void *platform, int channel_count) return 0; } -int platform_edid_get_max_channels(void) +int platform_edid_get_max_channels(void *platform) { - FILE *file; - struct audio_block_header header; + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE]; char *sad = block; int num_audio_blocks; int channel_count; int max_channels = 0; - int i; + int i, ret, count; - file = fopen(AUDIO_DATA_BLOCK_PATH, "rb"); - if (file == NULL) { - ALOGE("Unable to open '%s'", AUDIO_DATA_BLOCK_PATH); + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, AUDIO_DATA_BLOCK_MIXER_CTL); return 0; } - /* Read audio block header */ - fread(&header, 1, sizeof(header), file); + mixer_ctl_update(ctl); + + count = mixer_ctl_get_num_values(ctl); /* Read SAD blocks, clamping the maximum size for safety */ - if (header.length > (int)sizeof(block)) - header.length = (int)sizeof(block); - fread(&block, header.length, 1, file); + if (count > (int)sizeof(block)) + count = (int)sizeof(block); - fclose(file); + ret = mixer_ctl_get_array(ctl, block, count); + if (ret != 0) { + ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__); + return 0; + } /* Calculate the number of SAD blocks */ - num_audio_blocks = header.length / SAD_BLOCK_SIZE; + num_audio_blocks = count / SAD_BLOCK_SIZE; for (i = 0; i < num_audio_blocks; i++) { /* Only consider LPCM blocks */ - if ((sad[0] >> 3) != EDID_FORMAT_LPCM) + if ((sad[0] >> 3) != EDID_FORMAT_LPCM) { + sad += 3; continue; + } channel_count = (sad[0] & 0x7) + 1; if (channel_count > max_channels) diff --git a/hal/platform_api.h b/hal/platform_api.h index 837fce969..2362a5b3f 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -34,6 +34,6 @@ int platform_set_mic_mute(void *platform, bool state); snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices); snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device); int platform_set_hdmi_channels(void *platform, int channel_count); -int platform_edid_get_max_channels(void); +int platform_edid_get_max_channels(void *platform); #endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From 83841b9f2bcb53bd05dc48ff3304543db1be797e Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 19 Jul 2013 11:58:50 -0700 Subject: [PATCH 019/298] hal: Fix EDID information - Get EDID audio block info from a mixer control instead of a file. - Fix a bug where the current sad is not updated in the for loop. Bug: 9430906 Change-Id: I750e307ce1064eeb98d09ea8534a375252630841 --- hal/audio_hw.c | 4 ++-- hal/msm8960/platform.c | 2 +- hal/msm8974/platform.c | 47 +++++++++++++++++++++++------------------- hal/platform_api.h | 2 +- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index dc683d6c5..6c89e7bf8 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -356,7 +356,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, static int read_hdmi_channel_masks(struct stream_out *out) { int ret = 0; - int channels = platform_edid_get_max_channels(); + int channels = platform_edid_get_max_channels(out->dev->platform); switch (channels) { /* @@ -1318,6 +1318,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; out->flags = flags; out->devices = devices; + out->dev = adev; /* Init use case and pcm_config */ if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && @@ -1390,7 +1391,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_render_position = out_get_render_position; out->stream.get_next_write_timestamp = out_get_next_write_timestamp; - out->dev = adev; out->standby = 1; /* out->muted = false; by calloc() */ diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index c1c122de8..e533f3387 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -835,7 +835,7 @@ int platform_set_hdmi_channels(void *platform, int channel_count) return 0; } -int platform_edid_get_max_channels(void) +int platform_edid_get_max_channels(void *platform) { FILE *file; struct audio_block_header header; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1cb668eaa..8560f9d1f 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -26,18 +26,14 @@ #include #include "platform.h" +#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define LIB_ACDB_LOADER "libacdbloader.so" +#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" #define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ #define DUALMIC_CONFIG_ENDFIRE 1 #define DUALMIC_CONFIG_BROADSIDE 2 -/* - * This is the sysfs path for the HDMI audio data block - */ -#define AUDIO_DATA_BLOCK_PATH "/sys/class/graphics/fb1/audio_data_block" -#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" - /* * This file will have a maximum of 38 bytes: * @@ -776,40 +772,49 @@ int platform_set_hdmi_channels(void *platform, int channel_count) return 0; } -int platform_edid_get_max_channels(void) +int platform_edid_get_max_channels(void *platform) { - FILE *file; - struct audio_block_header header; + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE]; char *sad = block; int num_audio_blocks; int channel_count; int max_channels = 0; - int i; + int i, ret, count; - file = fopen(AUDIO_DATA_BLOCK_PATH, "rb"); - if (file == NULL) { - ALOGE("Unable to open '%s'", AUDIO_DATA_BLOCK_PATH); + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, AUDIO_DATA_BLOCK_MIXER_CTL); return 0; } - /* Read audio block header */ - fread(&header, 1, sizeof(header), file); + mixer_ctl_update(ctl); + + count = mixer_ctl_get_num_values(ctl); /* Read SAD blocks, clamping the maximum size for safety */ - if (header.length > (int)sizeof(block)) - header.length = (int)sizeof(block); - fread(&block, header.length, 1, file); + if (count > (int)sizeof(block)) + count = (int)sizeof(block); - fclose(file); + ret = mixer_ctl_get_array(ctl, block, count); + if (ret != 0) { + ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__); + return 0; + } /* Calculate the number of SAD blocks */ - num_audio_blocks = header.length / SAD_BLOCK_SIZE; + num_audio_blocks = count / SAD_BLOCK_SIZE; for (i = 0; i < num_audio_blocks; i++) { /* Only consider LPCM blocks */ - if ((sad[0] >> 3) != EDID_FORMAT_LPCM) + if ((sad[0] >> 3) != EDID_FORMAT_LPCM) { + sad += 3; continue; + } channel_count = (sad[0] & 0x7) + 1; if (channel_count > max_channels) diff --git a/hal/platform_api.h b/hal/platform_api.h index 837fce969..2362a5b3f 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -34,6 +34,6 @@ int platform_set_mic_mute(void *platform, bool state); snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices); snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device); int platform_set_hdmi_channels(void *platform, int channel_count); -int platform_edid_get_max_channels(void); +int platform_edid_get_max_channels(void *platform); #endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From bc677243eb84cad20cdedd9909d44f71308620c3 Mon Sep 17 00:00:00 2001 From: sangwoo Date: Thu, 8 Aug 2013 16:53:43 +0900 Subject: [PATCH 020/298] audio: change debug message level for debugging For debugging, path changing debug message and out_set_paramters debug message need. Change-Id: Ibd203aea957f84381c631184a4c9303ec069dad5 --- hal/audio_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 6c89e7bf8..cafe0d8be 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -463,7 +463,7 @@ static int select_devices(struct audio_device *adev, return 0; } - ALOGV("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__, + ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__, out_snd_device, platform_get_snd_device_name(out_snd_device), in_snd_device, platform_get_snd_device_name(in_snd_device)); @@ -904,7 +904,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int ret, val = 0; bool select_new_device = false; - ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s", + ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", __func__, out->usecase, use_case_table[out->usecase], kvpairs); parms = str_parms_create_str(kvpairs); ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); -- GitLab From 1e5f35378d14987df8f8641c2da6438999763536 Mon Sep 17 00:00:00 2001 From: Devin Kim Date: Fri, 9 Aug 2013 07:48:29 -0700 Subject: [PATCH 021/298] audio: fix logging After separate platform specific code, device table is set to each platform specific code. But, this debug message didn't changed correctly. Change-Id: I4607907e182cf57525847aba1e189c6539c9a3be Signed-off-by: sangwoo Signed-off-by: Devin Kim --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index cafe0d8be..5e966d92d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -314,7 +314,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, usecase->in_snd_device != snd_device) { ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", __func__, use_case_table[usecase->id], - device_table[usecase->in_snd_device]); + platform_get_snd_device_name(usecase->in_snd_device)); disable_audio_route(adev, usecase, false); switch_device[usecase->id] = true; num_uc_to_switch++; -- GitLab From be3335ab71f097449546112d9ae77f43aa967f47 Mon Sep 17 00:00:00 2001 From: Ajay Dudani Date: Mon, 19 Aug 2013 18:47:21 -0700 Subject: [PATCH 022/298] hal: Add support for msm8226 platform msm8226 uses common code base as msm8974. Change-Id: Ibea589637c7a9464ba274156ab43820c82124bd3 --- hal/Android.mk | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index 9e3c89779..7c71b9753 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -6,9 +6,15 @@ include $(CLEAR_VARS) LOCAL_ARM_MODE := arm +AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) +ifneq ($(filter msm8974 msm8226,$(TARGET_BOARD_PLATFORM)),) + # B-family platform uses msm8974 code base + AUDIO_PLATFORM = msm8974 +endif + LOCAL_SRC_FILES := \ audio_hw.c \ - $(TARGET_BOARD_PLATFORM)/platform.c + $(AUDIO_PLATFORM)/platform.c LOCAL_SHARED_LIBRARIES := \ liblog \ @@ -22,9 +28,9 @@ LOCAL_C_INCLUDES += \ external/tinyalsa/include \ $(call include-path-for, audio-route) \ $(call include-path-for, audio-effects) \ - $(LOCAL_PATH)/$(TARGET_BOARD_PLATFORM) + $(LOCAL_PATH)/$(AUDIO_PLATFORM) -LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) +LOCAL_MODULE := audio.primary.$(AUDIO_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -- GitLab From 4e02e5575f2eb440632a60fb8bed0a44ddae83af Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 17 Jul 2013 15:22:04 -0700 Subject: [PATCH 023/298] hal: Add support for Tunnel mode audio playback - Initial implementation to support audio playback in tunnel mode. Change-Id: I4ffa660bd9beb855fdfe6a7572d8f6b7eade7bd9 --- hal/Android.mk | 2 + hal/audio_hw.c | 454 ++++++++++++++++++++++++++++++++++++++--- hal/audio_hw.h | 38 +++- hal/msm8974/platform.c | 1 + 4 files changed, 469 insertions(+), 26 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index 7c71b9753..b5949daec 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -20,12 +20,14 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ libtinyalsa \ + libtinycompress \ libaudioroute \ libdl LOCAL_C_INCLUDES += \ external/tinyalsa/include \ + external/tinycompress/include \ $(call include-path-for, audio-route) \ $(call include-path-for, audio-effects) \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 5e966d92d..73d9a3b0f 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -16,7 +16,12 @@ #define LOG_TAG "audio_hw_primary" /*#define LOG_NDEBUG 0*/ -#define LOG_NDDEBUG 0 +/*#define VERY_VERY_VERBOSE_LOGGING*/ +#ifdef VERY_VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif #include #include @@ -24,18 +29,31 @@ #include #include #include +#include +#include #include #include #include +#include +#include #include +#include #include #include #include "audio_hw.h" #include "platform_api.h" #include +#include "sound/compress_params.h" + +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) +#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 +/* ToDo: Check and update a proper value in msec */ +#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 +#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 + struct pcm_config pcm_config_deep_buffer = { .channels = 2, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, @@ -90,6 +108,7 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", [USECASE_VOICE_CALL] = "voice-call", + [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", }; @@ -106,6 +125,32 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), }; +static bool is_supported_format(audio_format_t format) +{ + if (format == AUDIO_FORMAT_MP3 /*|| + format == AUDIO_FORMAT_AAC */) + return true; + + return false; +} + +static int get_snd_codec_id(audio_format_t format) +{ + int id = 0; + + switch (format) { + case AUDIO_FORMAT_MP3: + id = SND_AUDIOCODEC_MP3; + break; + case AUDIO_FORMAT_AAC: + id = SND_AUDIOCODEC_AAC; + break; + default: + ALOGE("%s: Unsupported audio format", __func__); + } + + return id; +} static int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, @@ -596,6 +641,143 @@ error_config: return ret; } +/* must be called with out->lock locked */ +static int send_offload_cmd_l(struct stream_out* out, int command) +{ + struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd)); + + ALOGVV("%s %d", __func__, command); + + cmd->cmd = command; + list_add_tail(&out->offload_cmd_list, &cmd->node); + pthread_cond_signal(&out->offload_cond); + return 0; +} + +/* must be called iwth out->lock locked */ +static void stop_compressed_output_l(struct stream_out *out) +{ + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + if (out->compr != NULL) { + compress_stop(out->compr); + while (out->offload_thread_blocked) { + pthread_cond_wait(&out->cond, &out->lock); + } + } +} + +static void *offload_thread_loop(void *context) +{ + struct stream_out *out = (struct stream_out *) context; + struct listnode *item; + + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); + set_sched_policy(0, SP_FOREGROUND); + prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0); + + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + for (;;) { + struct offload_cmd *cmd = NULL; + stream_callback_event_t event; + bool send_callback = false; + + ALOGVV("%s offload_cmd_list %d out->offload_state %d", + __func__, list_empty(&out->offload_cmd_list), + out->offload_state); + if (list_empty(&out->offload_cmd_list)) { + ALOGV("%s SLEEPING", __func__); + pthread_cond_wait(&out->offload_cond, &out->lock); + ALOGV("%s RUNNING", __func__); + continue; + } + + item = list_head(&out->offload_cmd_list); + cmd = node_to_item(item, struct offload_cmd, node); + list_remove(item); + + ALOGVV("%s STATE %d CMD %d out->compr %p", + __func__, out->offload_state, cmd->cmd, out->compr); + + if (cmd->cmd == OFFLOAD_CMD_EXIT) { + free(cmd); + break; + } + + if (out->compr == NULL) { + ALOGE("%s: Compress handle is NULL", __func__); + pthread_cond_signal(&out->cond); + continue; + } + out->offload_thread_blocked = true; + pthread_mutex_unlock(&out->lock); + send_callback = false; + switch(cmd->cmd) { + case OFFLOAD_CMD_WAIT_FOR_BUFFER: + compress_wait(out->compr, -1); + send_callback = true; + event = STREAM_CBK_EVENT_WRITE_READY; + break; + case OFFLOAD_CMD_PARTIAL_DRAIN: + compress_drain(out->compr); +//FIXME compress_partial_drain(out->compr); + send_callback = true; + event = STREAM_CBK_EVENT_DRAIN_READY; + break; + case OFFLOAD_CMD_DRAIN: + compress_drain(out->compr); + send_callback = true; + event = STREAM_CBK_EVENT_DRAIN_READY; + break; + default: + ALOGE("%s unknown command received: %d", __func__, cmd->cmd); + break; + } + pthread_mutex_lock(&out->lock); + out->offload_thread_blocked = false; + pthread_cond_signal(&out->cond); + if (send_callback) + out->offload_callback(event, NULL, out->offload_cookie); + free(cmd); + } + + pthread_cond_signal(&out->cond); + while (!list_empty(&out->offload_cmd_list)) { + item = list_head(&out->offload_cmd_list); + list_remove(item); + free(node_to_item(item, struct offload_cmd, node)); + } + pthread_mutex_unlock(&out->lock); + + return NULL; +} + +static int create_offload_callback_thread(struct stream_out *out) +{ + pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL); + list_init(&out->offload_cmd_list); + pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL, + offload_thread_loop, out); + return 0; +} + +static int destroy_offload_callback_thread(struct stream_out *out) +{ + pthread_mutex_lock(&out->lock); + stop_compressed_output_l(out); + send_offload_cmd_l(out, OFFLOAD_CMD_EXIT); + + pthread_mutex_unlock(&out->lock); + pthread_join(out->offload_thread, (void **) NULL); + pthread_cond_destroy(&out->offload_cond); + + return 0; +} + static int stop_output_stream(struct stream_out *out) { int i, ret = 0; @@ -654,18 +836,33 @@ int start_output_stream(struct stream_out *out) ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", __func__, 0, out->pcm_device_id); - out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, - PCM_OUT, &out->config); - if (out->pcm && !pcm_is_ready(out->pcm)) { - ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); - pcm_close(out->pcm); + if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { + out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, + PCM_OUT, &out->config); + if (out->pcm && !pcm_is_ready(out->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); + pcm_close(out->pcm); + out->pcm = NULL; + ret = -EIO; + goto error_open; + } + } else { out->pcm = NULL; - ret = -EIO; - goto error_pcm_open; + out->compr = compress_open(SOUND_CARD, out->pcm_device_id, + COMPRESS_IN, &out->compr_config); + if (out->compr && !is_compress_ready(out->compr)) { + ALOGE("%s: %s", __func__, compress_get_error(out->compr)); + compress_close(out->compr); + out->compr = NULL; + ret = -EIO; + goto error_open; + } + if (out->offload_callback) + compress_nonblock(out->compr, out->non_blocking); } ALOGV("%s: exit", __func__); return 0; -error_pcm_open: +error_open: stop_output_stream(out); error_config: return ret; @@ -833,7 +1030,7 @@ static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; - return out->config.rate; + return out->sample_rate; } static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) @@ -845,6 +1042,10 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + return out->compr_config.fragment_size; + } + return out->config.period_size * audio_stream_frame_size(stream); } @@ -857,7 +1058,9 @@ static uint32_t out_get_channels(const struct audio_stream *stream) static audio_format_t out_get_format(const struct audio_stream *stream) { - return AUDIO_FORMAT_PCM_16_BIT; + struct stream_out *out = (struct stream_out *)stream; + + return out->format; } static int out_set_format(struct audio_stream *stream, audio_format_t format) @@ -869,15 +1072,24 @@ static int out_standby(struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; + ALOGV("%s: enter: usecase(%d: %s)", __func__, out->usecase, use_case_table[out->usecase]); - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->lock); if (!out->standby) { out->standby = true; - if (out->pcm) { - pcm_close(out->pcm); - out->pcm = NULL; + if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->pcm) { + pcm_close(out->pcm); + out->pcm = NULL; + } + } else { + stop_compressed_output_l(out); + if (out->compr != NULL) { + compress_close(out->compr); + out->compr = NULL; + } } pthread_mutex_lock(&adev->lock); stop_output_stream(out); @@ -1014,18 +1226,40 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream) { struct stream_out *out = (struct stream_out *)stream; - return (out->config.period_count * out->config.period_size * 1000) / (out->config.rate); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; + + return (out->config.period_count * out->config.period_size * 1000) / + (out->config.rate); } static int out_set_volume(struct audio_stream_out *stream, float left, float right) { struct stream_out *out = (struct stream_out *)stream; + int volume[2]; + if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) { /* only take left channel into account: the API is for stereo anyway */ out->muted = (left == 0.0f); return 0; + } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + const char *mixer_ctl_name = "Compress Playback Volume"; + struct audio_device *adev = out->dev; + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX); + volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX); + mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0])); + return 0; } + return -ENOSYS; } @@ -1034,7 +1268,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; - int i, ret = -1; + size_t ret = 0; pthread_mutex_lock(&out->lock); if (out->standby) { @@ -1042,17 +1276,32 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, pthread_mutex_lock(&adev->lock); ret = start_output_stream(out); pthread_mutex_unlock(&adev->lock); + /* ToDo: If use case is compress offload should return 0 */ if (ret != 0) { out->standby = true; goto exit; } } - if (out->pcm) { - if (out->muted) - memset((void *)buffer, 0, bytes); - //ALOGV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); - ret = pcm_write(out->pcm, (void *)buffer, bytes); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + ret = compress_write(out->compr, buffer, bytes); + if (ret < bytes) { + send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); + } + if (!out->playback_started) { + compress_start(out->compr); + out->playback_started = 1; + out->offload_state = OFFLOAD_STATE_PLAYING; + } + pthread_mutex_unlock(&out->lock); + return ret; + } else { + if (out->pcm) { + if (out->muted) + memset((void *)buffer, 0, bytes); + ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); + ret = pcm_write(out->pcm, (void *)buffer, bytes); + } } exit: @@ -1071,7 +1320,20 @@ exit: static int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) { - return -EINVAL; + struct stream_out *out = (struct stream_out *)stream; + *dsp_frames = 0; + if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { + pthread_mutex_lock(&out->lock); + if (out->compr != NULL) { + compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %d sample_rate %d", + __func__, *dsp_frames, out->sample_rate); + } + pthread_mutex_unlock(&out->lock); + return 0; + } else + return -EINVAL; } static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) @@ -1090,6 +1352,81 @@ static int out_get_next_write_timestamp(const struct audio_stream_out *stream, return -EINVAL; } +static int out_set_callback(struct audio_stream_out *stream, + stream_callback_t callback, void *cookie) +{ + struct stream_out *out = (struct stream_out *)stream; + + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + out->offload_callback = callback; + out->offload_cookie = cookie; + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int out_pause(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) { + status = compress_pause(out->compr); + out->offload_state = OFFLOAD_STATE_PAUSED; + } + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_resume(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + status = 0; + pthread_mutex_lock(&out->lock); + if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) { + status = compress_resume(out->compr); + out->offload_state = OFFLOAD_STATE_PLAYING; + } + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type ) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + if (type == AUDIO_DRAIN_EARLY_NOTIFY) + status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN); + else + status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN); + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_flush(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + stop_compressed_output_l(out); + pthread_mutex_unlock(&out->lock); + return 0; + } + return -ENOSYS; +} + /** audio_stream_in implementation **/ static uint32_t in_get_sample_rate(const struct audio_stream *stream) { @@ -1314,11 +1651,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (devices == AUDIO_DEVICE_NONE) devices = AUDIO_DEVICE_OUT_SPEAKER; - out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; - out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; out->flags = flags; out->devices = devices; out->dev = adev; + out->format = config->format; + out->sample_rate = config->sample_rate; + out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; /* Init use case and pcm_config */ if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && @@ -1339,6 +1678,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1; out->channel_mask = config->channel_mask; + out->sample_rate = config->sample_rate; out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH; out->config = pcm_config_hdmi_multi; out->config.rate = config->sample_rate; @@ -1348,9 +1688,59 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; out->config = pcm_config_deep_buffer; + out->sample_rate = out->config.rate; + } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || + config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { + ALOGE("%s: Unsupported Offload information", __func__); + ret = -EINVAL; + goto error_open; + } + if (!is_supported_format(config->offload_info.format)) { + ALOGE("%s: Unsupported audio format", __func__); + ret = -EINVAL; + goto error_open; + } + + out->compr_config.codec = (struct snd_codec *) + calloc(1, sizeof(struct snd_codec)); + + out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; + if (config->offload_info.channel_mask) + out->channel_mask = config->offload_info.channel_mask; + else if (config->channel_mask) + out->channel_mask = config->channel_mask; + out->format = config->offload_info.format; + out->sample_rate = config->offload_info.sample_rate; + + out->stream.set_callback = out_set_callback; + out->stream.pause = out_pause; + out->stream.resume = out_resume; + out->stream.drain = out_drain; + out->stream.flush = out_flush; + + out->compr_config.codec->id = + get_snd_codec_id(config->offload_info.format); + out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; + out->compr_config.codec->sample_rate = + compress_get_alsa_rate(config->offload_info.sample_rate); + out->compr_config.codec->bit_rate = + config->offload_info.bit_rate; + out->compr_config.codec->ch_in = + popcount(config->channel_mask); + out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + + if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) + out->non_blocking = 1; + create_offload_callback_thread(out); + ALOGV("%s: offloaded output offload_info version %04x bit rate %d", + __func__, config->offload_info.version, + config->offload_info.bit_rate); } else { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; + out->sample_rate = out->config.rate; } if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { @@ -1394,6 +1784,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->standby = 1; /* out->muted = false; by calloc() */ + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + config->format = out->stream.common.get_format(&out->stream.common); config->channel_mask = out->stream.common.get_channels(&out->stream.common); config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); @@ -1412,8 +1805,19 @@ error_open: static void adev_close_output_stream(struct audio_hw_device *dev, struct audio_stream_out *stream) { + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + ALOGV("%s: enter", __func__); out_standby(&stream->common); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + destroy_offload_callback_thread(out); + + if (out->compr_config.codec != NULL) + free(out->compr_config.codec); + } + pthread_cond_destroy(&out->cond); + pthread_mutex_destroy(&out->lock); free(stream); ALOGV("%s: exit", __func__); } diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 5702f373f..b61bcd40f 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -21,6 +21,7 @@ #include #include +#include #include @@ -49,13 +50,13 @@ typedef enum { USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0, USECASE_AUDIO_PLAYBACK_LOW_LATENCY, USECASE_AUDIO_PLAYBACK_MULTI_CH, + USECASE_AUDIO_PLAYBACK_OFFLOAD, /* Capture usecases */ USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_LOW_LATENCY, USECASE_VOICE_CALL, - AUDIO_USECASE_MAX } audio_usecase_t; @@ -70,14 +71,38 @@ typedef enum { * the buffer size of an input/output stream */ +enum { + OFFLOAD_CMD_EXIT, /* exit compress offload thread loop*/ + OFFLOAD_CMD_DRAIN, /* send a full drain request to DSP */ + OFFLOAD_CMD_PARTIAL_DRAIN, /* send a partial drain request to DSP */ + OFFLOAD_CMD_WAIT_FOR_BUFFER, /* wait for buffer released by DSP */ +}; + +enum { + OFFLOAD_STATE_IDLE, + OFFLOAD_STATE_PLAYING, + OFFLOAD_STATE_PAUSED, +}; + +struct offload_cmd { + struct listnode node; + int cmd; + int data[]; +}; + struct stream_out { struct audio_stream_out stream; pthread_mutex_t lock; /* see note below on mutex acquisition order */ + pthread_cond_t cond; struct pcm_config config; + struct compr_config compr_config; struct pcm *pcm; + struct compress *compr; int standby; int pcm_device_id; + unsigned int sample_rate; audio_channel_mask_t channel_mask; + audio_format_t format; audio_devices_t devices; audio_output_flags_t flags; audio_usecase_t usecase; @@ -85,6 +110,17 @@ struct stream_out { audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1]; bool muted; + int non_blocking; + int playback_started; + int offload_state; + pthread_cond_t offload_cond; + pthread_t offload_thread; + struct listnode offload_cmd_list; + bool offload_thread_blocked; + + stream_callback_t offload_callback; + void *offload_cookie; + struct audio_device *dev; }; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 8560f9d1f..2ea80956c 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -86,6 +86,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0}, [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15}, [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1}, + [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9}, [USECASE_AUDIO_RECORD] = {0, 0}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15}, [USECASE_VOICE_CALL] = {2, 2}, -- GitLab From 6e89524079e9c3a1037c57a99854820d88c9380b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 5 Sep 2013 16:10:57 -0700 Subject: [PATCH 024/298] hal: force stop after drain. Force playback state to IDLE and send compress_stop() when drain completes to force reset driver and DSP pointers. This ensures that even if last write was partial, next write will be on a 32 byte boundary. Also do not wait for write completion if compress_write() returns an error. Bug 8174410. Change-Id: If144981c6396b24515d45b32a75ab61872a35ea2 --- hal/audio_hw.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 73d9a3b0f..852ddf680 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -740,8 +740,11 @@ static void *offload_thread_loop(void *context) pthread_mutex_lock(&out->lock); out->offload_thread_blocked = false; pthread_cond_signal(&out->cond); - if (send_callback) + if (send_callback) { + if (event == STREAM_CBK_EVENT_DRAIN_READY) + stop_compressed_output_l(out); out->offload_callback(event, NULL, out->offload_cookie); + } free(cmd); } @@ -1268,7 +1271,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; - size_t ret = 0; + ssize_t ret = 0; pthread_mutex_lock(&out->lock); if (out->standby) { @@ -1285,7 +1288,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { ret = compress_write(out->compr, buffer, bytes); - if (ret < bytes) { + ALOGVV("%s: writing buffer (%d bytes) to pcm device returned %d", __func__, bytes, ret); + if (ret >= 0 && ret < (ssize_t)bytes) { send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); } if (!out->playback_started) { -- GitLab From 2ccd7babcde54a8073945dec69660cb60e66a931 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 10 Sep 2013 09:04:31 -0700 Subject: [PATCH 025/298] Implement HAL API get_presentation_position This does _not_ address bug 10551158 (to include DSP buffering) Change-Id: Ifbc5ca21c46eced3f93a891200c763a062625dd9 --- hal/audio_hw.c | 35 +++++++++++++++++++++++++++++++++-- hal/audio_hw.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 852ddf680..404f17c8f 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -841,7 +841,7 @@ int start_output_stream(struct stream_out *out) __func__, 0, out->pcm_device_id); if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, - PCM_OUT, &out->config); + PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm && !pcm_is_ready(out->pcm)) { ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); pcm_close(out->pcm); @@ -946,7 +946,7 @@ static int start_voice_call(struct audio_device *adev) __func__, SOUND_CARD, pcm_dev_rx_id); adev->voice_call_rx = pcm_open(SOUND_CARD, pcm_dev_rx_id, - PCM_OUT, &pcm_config_voice_call); + PCM_OUT | PCM_MONOTONIC, &pcm_config_voice_call); if (adev->voice_call_rx && !pcm_is_ready(adev->voice_call_rx)) { ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_rx)); ret = -EIO; @@ -1305,6 +1305,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, memset((void *)buffer, 0, bytes); ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); ret = pcm_write(out->pcm, (void *)buffer, bytes); + if (ret == 0) + out->written += bytes / (out->config.channels * sizeof(short)); } } @@ -1356,6 +1358,33 @@ static int out_get_next_write_timestamp(const struct audio_stream_out *stream, return -EINVAL; } +static int out_get_presentation_position(const struct audio_stream_out *stream, + uint64_t *frames, struct timespec *timestamp) +{ + struct stream_out *out = (struct stream_out *)stream; + int ret = -1; + + pthread_mutex_lock(&out->lock); + + if (out->pcm) { + size_t avail; + if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { + size_t kernel_buffer_size = out->config.period_size * out->config.period_count; + // FIXME This calculation is incorrect if there is buffering after app processor + int64_t signed_frames = out->written - kernel_buffer_size + avail; + // It would be unusual for this value to be negative, but check just in case ... + if (signed_frames >= 0) { + *frames = signed_frames; + ret = 0; + } + } + } + + pthread_mutex_unlock(&out->lock); + + return ret; +} + static int out_set_callback(struct audio_stream_out *stream, stream_callback_t callback, void *cookie) { @@ -1784,9 +1813,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.write = out_write; out->stream.get_render_position = out_get_render_position; out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + out->stream.get_presentation_position = out_get_presentation_position; out->standby = 1; /* out->muted = false; by calloc() */ + /* out->written = 0; by calloc() */ pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index b61bcd40f..03f276fac 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -109,6 +109,7 @@ struct stream_out { /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */ audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1]; bool muted; + uint64_t written; /* total frames written, not cleared when entering standby */ int non_blocking; int playback_started; -- GitLab From 5191a856311c5bd5a1b48810032ccdbc35a7fdc7 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Wed, 11 Sep 2013 14:19:36 -0700 Subject: [PATCH 026/298] audio: set cached volume before starting voice call Apply cached voice volume before starting voice call. Change-Id: I6a86d5f104b6a19c13bffbdeafa7a7f325d5ad3b Bug: 10516515 --- hal/audio_hw.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 404f17c8f..2ad5c8831 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -125,6 +125,8 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), }; +static int set_voice_volume_l(struct audio_device *adev, float volume); + static bool is_supported_format(audio_format_t format) { if (format == AUDIO_FORMAT_MP3 /*|| @@ -963,6 +965,10 @@ static int start_voice_call(struct audio_device *adev) ret = -EIO; goto error_start_voice; } + + /* set cached volume */ + set_voice_volume_l(adev, adev->voice_volume); + pcm_start(adev->voice_call_rx); pcm_start(adev->voice_call_tx); @@ -971,7 +977,6 @@ static int start_voice_call(struct audio_device *adev) ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); goto error_start_voice; } - adev->in_call = true; return 0; @@ -1963,13 +1968,11 @@ static int adev_init_check(const struct audio_hw_device *dev) return 0; } -static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +/* always called with adev lock held */ +static int set_voice_volume_l(struct audio_device *adev, float volume) { - struct audio_device *adev = (struct audio_device *)dev; int vol, err = 0; - pthread_mutex_lock(&adev->lock); - adev->voice_volume = volume; if (adev->mode == AUDIO_MODE_IN_CALL) { if (volume < 0.0) { volume = 0.0; @@ -1986,10 +1989,21 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) err = platform_set_voice_volume(adev->platform, vol); } - pthread_mutex_unlock(&adev->lock); return err; } +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + int ret; + struct audio_device *adev = (struct audio_device *)dev; + pthread_mutex_lock(&adev->lock); + /* cache volume */ + adev->voice_volume = volume; + ret = set_voice_volume_l(adev, adev->voice_volume); + pthread_mutex_unlock(&adev->lock); + return ret; +} + static int adev_set_master_volume(struct audio_hw_device *dev, float volume) { return -ENOSYS; -- GitLab From 4d20e58c4389ae81ba9b3a1fe7357c281aad1b9e Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Wed, 11 Sep 2013 14:19:36 -0700 Subject: [PATCH 027/298] audio: set cached volume before starting voice call Apply cached voice volume before starting voice call. Change-Id: I6a86d5f104b6a19c13bffbdeafa7a7f325d5ad3b Bug: 10516515 --- hal/audio_hw.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 404f17c8f..2ad5c8831 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -125,6 +125,8 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), }; +static int set_voice_volume_l(struct audio_device *adev, float volume); + static bool is_supported_format(audio_format_t format) { if (format == AUDIO_FORMAT_MP3 /*|| @@ -963,6 +965,10 @@ static int start_voice_call(struct audio_device *adev) ret = -EIO; goto error_start_voice; } + + /* set cached volume */ + set_voice_volume_l(adev, adev->voice_volume); + pcm_start(adev->voice_call_rx); pcm_start(adev->voice_call_tx); @@ -971,7 +977,6 @@ static int start_voice_call(struct audio_device *adev) ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); goto error_start_voice; } - adev->in_call = true; return 0; @@ -1963,13 +1968,11 @@ static int adev_init_check(const struct audio_hw_device *dev) return 0; } -static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +/* always called with adev lock held */ +static int set_voice_volume_l(struct audio_device *adev, float volume) { - struct audio_device *adev = (struct audio_device *)dev; int vol, err = 0; - pthread_mutex_lock(&adev->lock); - adev->voice_volume = volume; if (adev->mode == AUDIO_MODE_IN_CALL) { if (volume < 0.0) { volume = 0.0; @@ -1986,10 +1989,21 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) err = platform_set_voice_volume(adev->platform, vol); } - pthread_mutex_unlock(&adev->lock); return err; } +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + int ret; + struct audio_device *adev = (struct audio_device *)dev; + pthread_mutex_lock(&adev->lock); + /* cache volume */ + adev->voice_volume = volume; + ret = set_voice_volume_l(adev, adev->voice_volume); + pthread_mutex_unlock(&adev->lock); + return ret; +} + static int adev_set_master_volume(struct audio_hw_device *dev, float volume) { return -ENOSYS; -- GitLab From 86e1713c4eb1378823c1f544f0fea2339c08f393 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 12 Sep 2013 17:49:30 -0700 Subject: [PATCH 028/298] audio: enable AAC offload Bug: 8174410. Change-Id: I343a35b90a2b21ea7954856ac7f73b9f5a07e0f2 --- hal/audio_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 404f17c8f..24cfaf9d0 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -127,8 +127,8 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = { static bool is_supported_format(audio_format_t format) { - if (format == AUDIO_FORMAT_MP3 /*|| - format == AUDIO_FORMAT_AAC */) + if (format == AUDIO_FORMAT_MP3 || + format == AUDIO_FORMAT_AAC) return true; return false; -- GitLab From 352f27bea3ea82b64234485de7a0f87a1991ab06 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 26 Jul 2013 00:00:15 -0700 Subject: [PATCH 029/298] audio: compress offload enhancements 1) Parse and set encoder metadata (delay, padding) 2) Call compress_next_track to allow partial drain 3) Do not flush output on returning succesfully from partial drain Change-Id: I0fa1a2c968a5590dff9b6c58bd52bb111dcf3e9b Bug: 8174410 --- hal/audio_hw.c | 58 +++++++++++++++++++++++++++++++++++++++++++++----- hal/audio_hw.h | 2 ++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 9f554fa3b..4f92ea3ab 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -661,6 +661,7 @@ static void stop_compressed_output_l(struct stream_out *out) { out->offload_state = OFFLOAD_STATE_IDLE; out->playback_started = 0; + out->send_new_metadata = 1; if (out->compr != NULL) { compress_stop(out->compr); while (out->offload_thread_blocked) { @@ -725,8 +726,8 @@ static void *offload_thread_loop(void *context) event = STREAM_CBK_EVENT_WRITE_READY; break; case OFFLOAD_CMD_PARTIAL_DRAIN: - compress_drain(out->compr); -//FIXME compress_partial_drain(out->compr); + compress_next_track(out->compr); + compress_partial_drain(out->compr); send_callback = true; event = STREAM_CBK_EVENT_DRAIN_READY; break; @@ -743,8 +744,6 @@ static void *offload_thread_loop(void *context) out->offload_thread_blocked = false; pthread_cond_signal(&out->cond); if (send_callback) { - if (event == STREAM_CBK_EVENT_DRAIN_READY) - stop_compressed_output_l(out); out->offload_callback(event, NULL, out->offload_cookie); } free(cmd); @@ -1094,6 +1093,8 @@ static int out_standby(struct audio_stream *stream) } } else { stop_compressed_output_l(out); + out->gapless_mdata.encoder_delay = 0; + out->gapless_mdata.encoder_padding = 0; if (out->compr != NULL) { compress_close(out->compr); out->compr = NULL; @@ -1113,6 +1114,39 @@ static int out_dump(const struct audio_stream *stream, int fd) return 0; } +static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms) +{ + int ret = 0; + char value[32]; + struct compr_gapless_mdata tmp_mdata; + + if (!out || !parms) { + return -EINVAL; + } + + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value)); + if (ret >= 0) { + tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? + } else { + return -EINVAL; + } + + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); + if (ret >= 0) { + tmp_mdata.encoder_padding = atoi(value); + } else { + return -EINVAL; + } + + out->gapless_mdata = tmp_mdata; + out->send_new_metadata = 1; + ALOGV("%s new encoder delay %u and padding %u", __func__, + out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); + + return 0; +} + + static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { struct stream_out *out = (struct stream_out *)stream; @@ -1186,6 +1220,11 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&out->lock); } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + parse_compress_metadata(out, parms); + } + str_parms_destroy(parms); ALOGV("%s: exit: code(%d)", __func__, ret); return ret; @@ -1292,8 +1331,15 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, } if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); + if (out->send_new_metadata) { + ALOGVV("send new gapless metadata"); + compress_set_gapless_metadata(out->compr, &out->gapless_mdata); + out->send_new_metadata = 0; + } + ret = compress_write(out->compr, buffer, bytes); - ALOGVV("%s: writing buffer (%d bytes) to pcm device returned %d", __func__, bytes, ret); + ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); if (ret >= 0 && ret < (ssize_t)bytes) { send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); } @@ -1771,6 +1817,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; + + out->send_new_metadata = 1; create_offload_callback_thread(out); ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 03f276fac..2c7fffd82 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -121,6 +121,8 @@ struct stream_out { stream_callback_t offload_callback; void *offload_cookie; + struct compr_gapless_mdata gapless_mdata; + int send_new_metadata; struct audio_device *dev; }; -- GitLab From c4aef75c2c5a0d49cac941d22235ac0b9e435ca0 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 12 Sep 2013 17:45:53 -0700 Subject: [PATCH 030/298] add offloaded audio visualizer Add library for visualizer effect used when audio decompression is offloaded to QCOM audio DSP. The implementation reads PCM back from the proxy port in the audio DSP. The audio HAL dynamically loads the effect library if present and indicates offloaded output activity. The PCM capture is only active when an offloaded output is active and at least one effect is enabled on this output. Bug: 8174410. Change-Id: Ic78de932f9116e246494f9171c1cc7c3e35a0ea1 --- Android.mk | 1 + hal/audio_hw.c | 25 + hal/audio_hw.h | 7 + visualizer/Android.mk | 36 + visualizer/MODULE_LICENSE_APACHE2 | 0 visualizer/NOTICE | 190 +++++ visualizer/offload_visualizer.c | 1121 +++++++++++++++++++++++++++++ 7 files changed, 1380 insertions(+) create mode 100644 visualizer/Android.mk create mode 100644 visualizer/MODULE_LICENSE_APACHE2 create mode 100644 visualizer/NOTICE create mode 100644 visualizer/offload_visualizer.c diff --git a/Android.mk b/Android.mk index 1c5c5b3db..1228876a3 100644 --- a/Android.mk +++ b/Android.mk @@ -7,6 +7,7 @@ include $(MY_LOCAL_PATH)/legacy/Android.mk else include $(MY_LOCAL_PATH)/hal/Android.mk include $(MY_LOCAL_PATH)/voice_processing/Android.mk +include $(MY_LOCAL_PATH)/visualizer/Android.mk endif endif diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 4f92ea3ab..c2997c66e 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -797,6 +798,10 @@ static int stop_output_stream(struct stream_out *out) return -EINVAL; } + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD && + adev->visualizer_stop_output != NULL) + adev->visualizer_stop_output(out->handle); + /* 1. Get and set stream specific mixer controls */ disable_audio_route(adev, uc_info, true); @@ -863,6 +868,9 @@ int start_output_stream(struct stream_out *out) } if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); + + if (adev->visualizer_start_output != NULL) + adev->visualizer_start_output(out->handle); } ALOGV("%s: exit", __func__); return 0; @@ -1742,6 +1750,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->sample_rate = config->sample_rate; out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; + out->handle = handle; /* Init use case and pcm_config */ if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && @@ -2263,6 +2272,22 @@ static int adev_open(const hw_module_t *module, const char *name, *device = NULL; return -EINVAL; } + + if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) { + adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW); + if (adev->visualizer_lib == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH); + adev->visualizer_start_output = + (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib, + "visualizer_hal_start_output"); + adev->visualizer_stop_output = + (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib, + "visualizer_hal_stop_output"); + } + } + *device = &adev->device.common; ALOGV("%s: exit", __func__); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 2c7fffd82..717c0a6cd 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -25,6 +25,8 @@ #include +#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so" + /* Flags used to initialize acdb_settings variable that goes to ACDB library */ #define DMIC_FLAG 0x00000002 #define TTY_MODE_OFF 0x00000010 @@ -110,6 +112,7 @@ struct stream_out { audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1]; bool muted; uint64_t written; /* total frames written, not cleared when entering standby */ + audio_io_handle_t handle; int non_blocking; int playback_started; @@ -187,6 +190,10 @@ struct audio_device { bool speaker_lr_swap; void *platform; + + void *visualizer_lib; + int (*visualizer_start_output)(audio_io_handle_t); + int (*visualizer_stop_output)(audio_io_handle_t); }; /* diff --git a/visualizer/Android.mk b/visualizer/Android.mk new file mode 100644 index 000000000..3c92044da --- /dev/null +++ b/visualizer/Android.mk @@ -0,0 +1,36 @@ +# Copyright 2013 The Android Open Source Project +# +# 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + offload_visualizer.c + +LOCAL_CFLAGS+= -O2 -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libtinyalsa + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx +LOCAL_MODULE:= libqcomvisualizer + +LOCAL_C_INCLUDES := \ + external/tinyalsa/include \ + $(call include-path-for, audio-effects) + +include $(BUILD_SHARED_LIBRARY) diff --git a/visualizer/MODULE_LICENSE_APACHE2 b/visualizer/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000..e69de29bb diff --git a/visualizer/NOTICE b/visualizer/NOTICE new file mode 100644 index 000000000..ad6ed94fe --- /dev/null +++ b/visualizer/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2013, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c new file mode 100644 index 000000000..75ce4a5cd --- /dev/null +++ b/visualizer/offload_visualizer.c @@ -0,0 +1,1121 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "offload_visualizer" +/*#define LOG_NDEBUG 0*/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +enum { + EFFECT_STATE_UNINITIALIZED, + EFFECT_STATE_INITIALIZED, + EFFECT_STATE_ACTIVE, +}; + +typedef struct effect_context_s effect_context_t; + +/* effect specific operations. Only the init() and process() operations must be defined. + * Others are optional. + */ +typedef struct effect_ops_s { + int (*init)(effect_context_t *context); + int (*release)(effect_context_t *context); + int (*reset)(effect_context_t *context); + int (*enable)(effect_context_t *context); + int (*disable)(effect_context_t *context); + int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out); + int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size); + int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size); + int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData); +} effect_ops_t; + +struct effect_context_s { + const struct effect_interface_s *itfe; + struct listnode effects_list_node; /* node in created_effects_list */ + struct listnode output_node; /* node in output_context_t.effects_list */ + effect_config_t config; + const effect_descriptor_t *desc; + audio_io_handle_t out_handle; /* io handle of the output the effect is attached to */ + uint32_t state; + bool offload_enabled; /* when offload is enabled we process VISUALIZER_CMD_CAPTURE command. + Otherwise non offloaded visualizer has already processed the command + and we must not overwrite the reply. */ + effect_ops_t ops; +}; + +typedef struct output_context_s { + struct listnode outputs_list_node; /* node in active_outputs_list */ + audio_io_handle_t handle; /* io handle */ + struct listnode effects_list; /* list of effects attached to this output */ +} output_context_t; + + +/* maximum time since last capture buffer update before resetting capture buffer. This means + that the framework has stopped playing audio and we must start returning silence */ +#define MAX_STALL_TIME_MS 1000 + +#define CAPTURE_BUF_SIZE 65536 /* "64k should be enough for everyone" */ + + +typedef struct visualizer_context_s { + effect_context_t common; + + uint32_t capture_idx; + uint32_t capture_size; + uint32_t scaling_mode; + uint32_t last_capture_idx; + uint32_t latency; + struct timespec buffer_update_time; + uint8_t capture_buf[CAPTURE_BUF_SIZE]; +} visualizer_context_t; + + +extern const struct effect_interface_s effect_interface; + +/* Offload visualizer UUID: 7a8044a0-1a71-11e3-a184-0002a5d5c51b */ +const effect_descriptor_t visualizer_descriptor = { + {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0x7a8044a0, 0x1a71, 0x11e3, 0xa184, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL ), + 0, /* TODO */ + 1, + "QCOM MSM offload visualizer", + "The Android Open Source Project", +}; + +const effect_descriptor_t *descriptors[] = { + &visualizer_descriptor, + NULL, +}; + + +pthread_once_t once = PTHREAD_ONCE_INIT; +int init_status; + +/* list of created effects. Updated by visualizer_hal_start_output() + * and visualizer_hal_stop_output() */ +struct listnode created_effects_list; +/* list of active output streams. Updated by visualizer_hal_start_output() + * and visualizer_hal_stop_output() */ +struct listnode active_outputs_list; + +/* thread capturing PCM from Proxy port and calling the process function on each enabled effect + * attached to an active output stream */ +pthread_t capture_thread; +/* lock must be held when modifying or accessing created_effects_list or active_outputs_list */ +pthread_mutex_t lock; +/* thread_lock must be held when starting or stopping the capture thread. + * Locking order: thread_lock -> lock */ +pthread_mutex_t thread_lock; +/* cond is signaled when an output is started or stopped or an effect is enabled or disable: the + * capture thread will reevaluate the capture and effect rocess conditions. */ +pthread_cond_t cond; +/* true when requesting the capture thread to exit */ +bool exit_thread; +/* 0 if the capture thread was created successfully */ +int thread_status; + + +#define DSP_OUTPUT_LATENCY_MS 0 /* Fudge factor for latency after capture point in audio DSP */ + +/* Retry for delay for mixer open */ +#define RETRY_NUMBER 10 +#define RETRY_US 500000 + +#define MIXER_CARD 0 +#define SOUND_CARD 0 +#define CAPTURE_DEVICE 8 + +/* Proxy port supports only MMAP read and those fixed parameters*/ +#define AUDIO_CAPTURE_CHANNEL_COUNT 2 +#define AUDIO_CAPTURE_SMP_RATE 48000 +#define AUDIO_CAPTURE_PERIOD_SIZE (768) +#define AUDIO_CAPTURE_PERIOD_COUNT 32 + +struct pcm_config pcm_config_capture = { + .channels = AUDIO_CAPTURE_CHANNEL_COUNT, + .rate = AUDIO_CAPTURE_SMP_RATE, + .period_size = AUDIO_CAPTURE_PERIOD_SIZE, + .period_count = AUDIO_CAPTURE_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = AUDIO_CAPTURE_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = AUDIO_CAPTURE_PERIOD_SIZE / 4, +}; + + +/* + * Local functions + */ + +static void init_once() { + list_init(&created_effects_list); + list_init(&active_outputs_list); + + pthread_mutex_init(&lock, NULL); + pthread_mutex_init(&thread_lock, NULL); + pthread_cond_init(&cond, NULL); + exit_thread = false; + thread_status = -1; + + init_status = 0; +} + +int lib_init() { + pthread_once(&once, init_once); + return init_status; +} + +bool effect_exists(effect_context_t *context) { + struct listnode *node; + + list_for_each(node, &created_effects_list) { + effect_context_t *fx_ctxt = node_to_item(node, + effect_context_t, + effects_list_node); + if (fx_ctxt == context) { + return true; + } + } + return false; +} + +output_context_t *get_output(audio_io_handle_t output) { + struct listnode *node; + + list_for_each(node, &active_outputs_list) { + output_context_t *out_ctxt = node_to_item(node, + output_context_t, + outputs_list_node); + if (out_ctxt->handle == output) { + return out_ctxt; + } + } + return NULL; +} + +void add_effect_to_output(output_context_t * output, effect_context_t *context) { + struct listnode *fx_node; + + list_for_each(fx_node, &output->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt == context) + return; + } + list_add_tail(&output->effects_list, &context->output_node); +} + +void remove_effect_from_output(output_context_t * output, effect_context_t *context) { + struct listnode *fx_node; + + list_for_each(fx_node, &output->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt == context) { + list_remove(&context->output_node); + return; + } + } +} + +bool effects_enabled() { + struct listnode *out_node; + + list_for_each(out_node, &active_outputs_list) { + struct listnode *fx_node; + output_context_t *out_ctxt = node_to_item(out_node, + output_context_t, + outputs_list_node); + + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt->state == EFFECT_STATE_ACTIVE) + return true; + } + } + return false; +} + +int configure_proxy_capture(struct mixer *mixer, int value) { + const char *proxy_ctl_name = "AFE_PCM_RX Audio Mixer MultiMedia4"; + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(mixer, proxy_ctl_name); + if (ctl == NULL) { + ALOGW("%s: could not get %s ctl", __func__, proxy_ctl_name); + return -EINVAL; + } + if (mixer_ctl_set_value(ctl, 0, value) != 0) + ALOGW("%s: error setting value %d on %s ", __func__, value, proxy_ctl_name); + + return 0; +} + + +void *capture_thread_loop(void *arg) +{ + int16_t data[AUDIO_CAPTURE_PERIOD_SIZE * AUDIO_CAPTURE_CHANNEL_COUNT * sizeof(int16_t)]; + audio_buffer_t buf; + buf.frameCount = AUDIO_CAPTURE_PERIOD_SIZE; + buf.s16 = data; + bool capture_enabled = false; + struct mixer *mixer; + struct pcm *pcm = NULL; + int ret; + int retry_num = 0; + + ALOGD("thread enter"); + + prctl(PR_SET_NAME, (unsigned long)"visualizer capture", 0, 0, 0); + + pthread_mutex_lock(&lock); + + mixer = mixer_open(MIXER_CARD); + while (mixer == NULL && retry_num < RETRY_NUMBER) { + usleep(RETRY_US); + mixer = mixer_open(MIXER_CARD); + retry_num++; + } + if (mixer == NULL) { + pthread_mutex_unlock(&lock); + return NULL; + } + + for (;;) { + if (exit_thread) { + break; + } + if (effects_enabled()) { + if (!capture_enabled) { + ret = configure_proxy_capture(mixer, 1); + if (ret == 0) { + pcm = pcm_open(SOUND_CARD, CAPTURE_DEVICE, + PCM_IN|PCM_MMAP|PCM_NOIRQ, &pcm_config_capture); + if (pcm && !pcm_is_ready(pcm)) { + ALOGW("%s: %s", __func__, pcm_get_error(pcm)); + pcm_close(pcm); + pcm = NULL; + configure_proxy_capture(mixer, 0); + } else { + capture_enabled = true; + ALOGD("%s: capture ENABLED", __func__); + } + } + } + } else { + if (capture_enabled) { + if (pcm != NULL) + pcm_close(pcm); + configure_proxy_capture(mixer, 0); + ALOGD("%s: capture DISABLED", __func__); + capture_enabled = false; + } + pthread_cond_wait(&cond, &lock); + } + if (!capture_enabled) + continue; + + pthread_mutex_unlock(&lock); + ret = pcm_mmap_read(pcm, data, sizeof(data)); + pthread_mutex_lock(&lock); + + if (ret == 0) { + struct listnode *out_node; + + list_for_each(out_node, &active_outputs_list) { + output_context_t *out_ctxt = node_to_item(out_node, + output_context_t, + outputs_list_node); + struct listnode *fx_node; + + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + fx_ctxt->ops.process(fx_ctxt, &buf, &buf); + } + } + } else { + ALOGW("%s: read status %d %s", __func__, ret, pcm_get_error(pcm)); + } + } + + if (capture_enabled) { + if (pcm != NULL) + pcm_close(pcm); + configure_proxy_capture(mixer, 0); + } + mixer_close(mixer); + pthread_mutex_unlock(&lock); + + ALOGD("thread exit"); + + return NULL; +} + +/* + * Interface from audio HAL + */ + +__attribute__ ((visibility ("default"))) +int visualizer_hal_start_output(audio_io_handle_t output) { + int ret; + struct listnode *node; + + ALOGV("%s", __func__); + + if (lib_init() != 0) + return init_status; + + pthread_mutex_lock(&thread_lock); + pthread_mutex_lock(&lock); + if (get_output(output) != NULL) { + ALOGW("%s output already started", __func__); + ret = -ENOSYS; + goto exit; + } + + output_context_t *out_ctxt = (output_context_t *)malloc(sizeof(output_context_t)); + out_ctxt->handle = output; + list_init(&out_ctxt->effects_list); + + list_for_each(node, &created_effects_list) { + effect_context_t *fx_ctxt = node_to_item(node, + effect_context_t, + effects_list_node); + if (fx_ctxt->out_handle == output) { + list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node); + } + } + if (list_empty(&active_outputs_list)) { + exit_thread = false; + thread_status = pthread_create(&capture_thread, (const pthread_attr_t *) NULL, + capture_thread_loop, NULL); + } + list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node); + pthread_cond_signal(&cond); + +exit: + pthread_mutex_unlock(&lock); + pthread_mutex_unlock(&thread_lock); + return ret; +} + +__attribute__ ((visibility ("default"))) +int visualizer_hal_stop_output(audio_io_handle_t output) { + int ret; + struct listnode *node; + output_context_t *out_ctxt; + + ALOGV("%s", __func__); + + if (lib_init() != 0) + return init_status; + + pthread_mutex_lock(&thread_lock); + pthread_mutex_lock(&lock); + + out_ctxt = get_output(output); + if (out_ctxt == NULL) { + ALOGW("%s output not started", __func__); + ret = -ENOSYS; + goto exit; + } + + list_remove(&out_ctxt->outputs_list_node); + pthread_cond_signal(&cond); + + if (list_empty(&active_outputs_list)) { + if (thread_status == 0) { + exit_thread = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + pthread_join(capture_thread, (void **) NULL); + pthread_mutex_lock(&lock); + thread_status = -1; + } + } + + free(out_ctxt); + +exit: + pthread_mutex_unlock(&lock); + pthread_mutex_unlock(&thread_lock); + return ret; +} + + +/* + * Effect operations + */ + +int set_config(effect_context_t *context, effect_config_t *config) +{ + if (config->inputCfg.samplingRate != config->outputCfg.samplingRate) return -EINVAL; + if (config->inputCfg.channels != config->outputCfg.channels) return -EINVAL; + if (config->inputCfg.format != config->outputCfg.format) return -EINVAL; + if (config->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL; + if (config->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE && + config->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL; + if (config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; + + context->config = *config; + + if (context->ops.reset) + context->ops.reset(context); + + return 0; +} + +void get_config(effect_context_t *context, effect_config_t *config) +{ + *config = context->config; +} + + +/* + * Visualizer operations + */ + +int visualizer_reset(effect_context_t *context) +{ + visualizer_context_t * visu_ctxt = (visualizer_context_t *)context; + + visu_ctxt->capture_idx = 0; + visu_ctxt->last_capture_idx = 0; + visu_ctxt->buffer_update_time.tv_sec = 0; + visu_ctxt->latency = DSP_OUTPUT_LATENCY_MS; + memset(visu_ctxt->capture_buf, 0x80, CAPTURE_BUF_SIZE); + return 0; +} + +int visualizer_init(effect_context_t *context) +{ + visualizer_context_t * visu_ctxt = (visualizer_context_t *)context; + + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + visu_ctxt->capture_size = VISUALIZER_CAPTURE_SIZE_MAX; + visu_ctxt->scaling_mode = VISUALIZER_SCALING_MODE_NORMALIZED; + + set_config(context, &context->config); + + return 0; +} + +int visualizer_get_parameter(effect_context_t *context, effect_param_t *p, uint32_t *size) +{ + visualizer_context_t *visu_ctxt = (visualizer_context_t *)context; + + p->status = 0; + *size = sizeof(effect_param_t) + sizeof(uint32_t); + if (p->psize != sizeof(uint32_t)) { + p->status = -EINVAL; + return 0; + } + switch (*(uint32_t *)p->data) { + case VISUALIZER_PARAM_CAPTURE_SIZE: + ALOGV("%s get capture_size = %d", __func__, visu_ctxt->capture_size); + *((uint32_t *)p->data + 1) = visu_ctxt->capture_size; + p->vsize = sizeof(uint32_t); + *size += sizeof(uint32_t); + break; + case VISUALIZER_PARAM_SCALING_MODE: + ALOGV("%s get scaling_mode = %d", __func__, visu_ctxt->scaling_mode); + *((uint32_t *)p->data + 1) = visu_ctxt->scaling_mode; + p->vsize = sizeof(uint32_t); + *size += sizeof(uint32_t); + break; + default: + p->status = -EINVAL; + } + return 0; +} + +int visualizer_set_parameter(effect_context_t *context, effect_param_t *p, uint32_t size) +{ + visualizer_context_t *visu_ctxt = (visualizer_context_t *)context; + + if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) + return -EINVAL; + + switch (*(uint32_t *)p->data) { + case VISUALIZER_PARAM_CAPTURE_SIZE: + visu_ctxt->capture_size = *((uint32_t *)p->data + 1); + ALOGV("%s set capture_size = %d", __func__, visu_ctxt->capture_size); + break; + case VISUALIZER_PARAM_SCALING_MODE: + visu_ctxt->scaling_mode = *((uint32_t *)p->data + 1); + ALOGV("%s set scaling_mode = %d", __func__, visu_ctxt->scaling_mode); + break; + case VISUALIZER_PARAM_LATENCY: + /* Ignore latency as we capture at DSP output + * visu_ctxt->latency = *((uint32_t *)p->data + 1); */ + ALOGV("%s set latency = %d", __func__, visu_ctxt->latency); + break; + default: + return -EINVAL; + } + return 0; +} + +/* Real process function called from capture thread. Called with lock held */ +int visualizer_process(effect_context_t *context, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer) +{ + visualizer_context_t *visu_ctxt = (visualizer_context_t *)context; + + if (!effect_exists(context)) + return -EINVAL; + + if (inBuffer == NULL || inBuffer->raw == NULL || + outBuffer == NULL || outBuffer->raw == NULL || + inBuffer->frameCount != outBuffer->frameCount || + inBuffer->frameCount == 0) { + return -EINVAL; + } + + /* all code below assumes stereo 16 bit PCM output and input */ + int32_t shift; + + if (visu_ctxt->scaling_mode == VISUALIZER_SCALING_MODE_NORMALIZED) { + /* derive capture scaling factor from peak value in current buffer + * this gives more interesting captures for display. */ + shift = 32; + int len = inBuffer->frameCount * 2; + int i; + for (i = 0; i < len; i++) { + int32_t smp = inBuffer->s16[i]; + if (smp < 0) smp = -smp - 1; /* take care to keep the max negative in range */ + int32_t clz = __builtin_clz(smp); + if (shift > clz) shift = clz; + } + /* A maximum amplitude signal will have 17 leading zeros, which we want to + * translate to a shift of 8 (for converting 16 bit to 8 bit) */ + shift = 25 - shift; + /* Never scale by less than 8 to avoid returning unaltered PCM signal. */ + if (shift < 3) { + shift = 3; + } + /* add one to combine the division by 2 needed after summing + * left and right channels below */ + shift++; + } else { + assert(visu_ctxt->scaling_mode == VISUALIZER_SCALING_MODE_AS_PLAYED); + shift = 9; + } + + uint32_t capt_idx; + uint32_t in_idx; + uint8_t *buf = visu_ctxt->capture_buf; + for (in_idx = 0, capt_idx = visu_ctxt->capture_idx; + in_idx < inBuffer->frameCount; + in_idx++, capt_idx++) { + if (capt_idx >= CAPTURE_BUF_SIZE) { + /* wrap around */ + capt_idx = 0; + } + int32_t smp = inBuffer->s16[2 * in_idx] + inBuffer->s16[2 * in_idx + 1]; + smp = smp >> shift; + buf[capt_idx] = ((uint8_t)smp)^0x80; + } + + /* XXX the following two should really be atomic, though it probably doesn't + * matter much for visualization purposes */ + visu_ctxt->capture_idx = capt_idx; + /* update last buffer update time stamp */ + if (clock_gettime(CLOCK_MONOTONIC, &visu_ctxt->buffer_update_time) < 0) { + visu_ctxt->buffer_update_time.tv_sec = 0; + } + + if (context->state != EFFECT_STATE_ACTIVE) { + ALOGV("%s DONE inactive", __func__); + return -ENODATA; + } + + return 0; +} + +int visualizer_command(effect_context_t * context, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData) +{ + visualizer_context_t * visu_ctxt = (visualizer_context_t *)context; + + switch (cmdCode) { + case VISUALIZER_CMD_CAPTURE: + if (pReplyData == NULL || *replySize != visu_ctxt->capture_size) { + ALOGV("%s VISUALIZER_CMD_CAPTURE error *replySize %d context->capture_size %d", + __func__, *replySize, visu_ctxt->capture_size); + return -EINVAL; + } + + if (!context->offload_enabled) + break; + + if (context->state == EFFECT_STATE_ACTIVE) { + int32_t latency_ms = visu_ctxt->latency; + uint32_t delta_ms = 0; + if (visu_ctxt->buffer_update_time.tv_sec != 0) { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + time_t secs = ts.tv_sec - visu_ctxt->buffer_update_time.tv_sec; + long nsec = ts.tv_nsec - visu_ctxt->buffer_update_time.tv_nsec; + if (nsec < 0) { + --secs; + nsec += 1000000000; + } + delta_ms = secs * 1000 + nsec / 1000000; + latency_ms -= delta_ms; + if (latency_ms < 0) + latency_ms = 0; + } + } + uint32_t delta_smp = context->config.inputCfg.samplingRate * latency_ms / 1000; + + int32_t capture_point = visu_ctxt->capture_idx - visu_ctxt->capture_size - delta_smp; + int32_t capture_size = visu_ctxt->capture_size; + if (capture_point < 0) { + int32_t size = -capture_point; + if (size > capture_size) + size = capture_size; + + memcpy(pReplyData, + visu_ctxt->capture_buf + CAPTURE_BUF_SIZE + capture_point, + size); + pReplyData = (void *)((size_t)pReplyData + size); + capture_size -= size; + capture_point = 0; + } + memcpy(pReplyData, + visu_ctxt->capture_buf + capture_point, + capture_size); + + + /* if audio framework has stopped playing audio although the effect is still + * active we must clear the capture buffer to return silence */ + if ((visu_ctxt->last_capture_idx == visu_ctxt->capture_idx) && + (visu_ctxt->buffer_update_time.tv_sec != 0)) { + if (delta_ms > MAX_STALL_TIME_MS) { + ALOGV("%s capture going to idle", __func__); + visu_ctxt->buffer_update_time.tv_sec = 0; + memset(pReplyData, 0x80, visu_ctxt->capture_size); + } + } + visu_ctxt->last_capture_idx = visu_ctxt->capture_idx; + } else { + memset(pReplyData, 0x80, visu_ctxt->capture_size); + } + break; + + default: + ALOGW("%s invalid command %d", __func__, cmdCode); + return -EINVAL; + } + return 0; +} + + +/* + * Effect Library Interface Implementation + */ + +int effect_lib_create(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle) { + int ret; + int i; + + if (lib_init() != 0) + return init_status; + + if (pHandle == NULL || uuid == NULL) + return -EINVAL; + + for (i = 0; descriptors[i] != NULL; i++) { + if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) + break; + } + + if (descriptors[i] == NULL) + return -EINVAL; + + effect_context_t *context; + if (memcmp(uuid, &visualizer_descriptor.uuid, sizeof(effect_uuid_t)) == 0) { + visualizer_context_t *visu_ctxt = (visualizer_context_t *)calloc(1, + sizeof(visualizer_context_t)); + context = (effect_context_t *)visu_ctxt; + context->ops.init = visualizer_init; + context->ops.reset = visualizer_reset; + context->ops.process = visualizer_process; + context->ops.set_parameter = visualizer_set_parameter; + context->ops.get_parameter = visualizer_get_parameter; + context->ops.command = visualizer_command; + } else { + return -EINVAL; + } + + context->itfe = &effect_interface; + context->state = EFFECT_STATE_UNINITIALIZED; + context->out_handle = (audio_io_handle_t)ioId; + context->desc = &visualizer_descriptor; + + ret = context->ops.init(context); + if (ret < 0) { + ALOGW("%s init failed", __func__); + free(context); + return ret; + } + + context->state = EFFECT_STATE_INITIALIZED; + + pthread_mutex_lock(&lock); + list_add_tail(&created_effects_list, &context->effects_list_node); + output_context_t *out_ctxt = get_output(ioId); + if (out_ctxt != NULL) + add_effect_to_output(out_ctxt, context); + pthread_mutex_unlock(&lock); + + *pHandle = (effect_handle_t)context; + + ALOGV("%s created context %p", __func__, context); + + return 0; + +} + +int effect_lib_release(effect_handle_t handle) { + effect_context_t *context = (effect_context_t *)handle; + int status; + + if (lib_init() != 0) + return init_status; + + ALOGV("%s context %p", __func__, handle); + pthread_mutex_lock(&lock); + status = -EINVAL; + if (effect_exists(context)) { + output_context_t *out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + remove_effect_from_output(out_ctxt, context); + list_remove(&context->effects_list_node); + if (context->ops.release) + context->ops.release(context); + free(context); + status = 0; + } + pthread_mutex_unlock(&lock); + + return status; +} + +int effect_lib_get_descriptor(const effect_uuid_t *uuid, + effect_descriptor_t *descriptor) { + int i; + + if (lib_init() != 0) + return init_status; + + if (descriptor == NULL || uuid == NULL) { + ALOGV("%s called with NULL pointer", __func__); + return -EINVAL; + } + + for (i = 0; descriptors[i] != NULL; i++) { + if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) { + *descriptor = *descriptors[i]; + return 0; + } + } + + return -EINVAL; +} + +/* + * Effect Control Interface Implementation + */ + + /* Stub function for effect interface: never called for offloaded effects */ +int effect_process(effect_handle_t self, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer) +{ + effect_context_t * context = (effect_context_t *)self; + int status = 0; + + ALOGW("%s Called ?????", __func__); + + pthread_mutex_lock(&lock); + if (!effect_exists(context)) { + status = -EINVAL; + goto exit; + } + + if (context->state != EFFECT_STATE_ACTIVE) { + status = -EINVAL; + goto exit; + } + +exit: + pthread_mutex_unlock(&lock); + return status; +} + +int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData) +{ + + effect_context_t * context = (effect_context_t *)self; + int retsize; + int status = 0; + + pthread_mutex_lock(&lock); + + if (!effect_exists(context)) { + status = -EINVAL; + goto exit; + } + + if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) { + status = -EINVAL; + goto exit; + } + +// ALOGV_IF(cmdCode != VISUALIZER_CMD_CAPTURE, +// "%s command %d cmdSize %d", __func__, cmdCode, cmdSize); + + switch (cmdCode) { + case EFFECT_CMD_INIT: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->ops.init) + *(int *) pReplyData = context->ops.init(context); + else + *(int *) pReplyData = 0; + break; + case EFFECT_CMD_SET_CONFIG: + if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) + || pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData); + break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + status = -EINVAL; + goto exit; + } + if (!context->offload_enabled) { + status = -EINVAL; + goto exit; + } + + get_config(context, (effect_config_t *)pReplyData); + break; + case EFFECT_CMD_RESET: + if (context->ops.reset) + context->ops.reset(context); + break; + case EFFECT_CMD_ENABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->state != EFFECT_STATE_INITIALIZED) { + status = -ENOSYS; + goto exit; + } + context->state = EFFECT_STATE_ACTIVE; + if (context->ops.enable) + context->ops.enable(context); + pthread_cond_signal(&cond); + ALOGV("%s EFFECT_CMD_ENABLE", __func__); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_DISABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->state != EFFECT_STATE_ACTIVE) { + status = -ENOSYS; + goto exit; + } + context->state = EFFECT_STATE_INITIALIZED; + if (context->ops.disable) + context->ops.disable(context); + pthread_cond_signal(&cond); + ALOGV("%s EFFECT_CMD_DISABLE", __func__); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_GET_PARAM: { + if (pCmdData == NULL || + cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || + pReplyData == NULL || + *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) { + status = -EINVAL; + goto exit; + } + if (!context->offload_enabled) { + status = -EINVAL; + goto exit; + } + memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t)); + effect_param_t *p = (effect_param_t *)pReplyData; + if (context->ops.get_parameter) + context->ops.get_parameter(context, p, replySize); + } break; + case EFFECT_CMD_SET_PARAM: { + if (pCmdData == NULL || + cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) || + pReplyData == NULL || *replySize != sizeof(int32_t)) { + status = -EINVAL; + goto exit; + } + *(int32_t *)pReplyData = 0; + effect_param_t *p = (effect_param_t *)pCmdData; + if (context->ops.set_parameter) + *(int32_t *)pReplyData = context->ops.set_parameter(context, p, *replySize); + + } break; + case EFFECT_CMD_SET_DEVICE: + case EFFECT_CMD_SET_VOLUME: + case EFFECT_CMD_SET_AUDIO_MODE: + break; + + case EFFECT_CMD_OFFLOAD: { + output_context_t *out_ctxt; + + if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL + || pReplyData == NULL || *replySize != sizeof(int)) { + ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__); + status = -EINVAL; + break; + } + + effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData; + + ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", + __func__, offload_param->isOffload, offload_param->ioHandle); + + *(int *)pReplyData = 0; + + context->offload_enabled = offload_param->isOffload; + if (context->out_handle == offload_param->ioHandle) + break; + + out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + remove_effect_from_output(out_ctxt, context); + out_ctxt = get_output(offload_param->ioHandle); + if (out_ctxt != NULL) + add_effect_to_output(out_ctxt, context); + + context->out_handle = offload_param->ioHandle; + + } break; + + + default: + if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command) + status = context->ops.command(context, cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + else { + ALOGW("%s invalid command %d", __func__, cmdCode); + status = -EINVAL; + } + break; + } + +exit: + pthread_mutex_unlock(&lock); + +// ALOGV_IF(cmdCode != VISUALIZER_CMD_CAPTURE,"%s DONE", __func__); + return status; +} + +/* Effect Control Interface Implementation: get_descriptor */ +int effect_get_descriptor(effect_handle_t self, + effect_descriptor_t *descriptor) +{ + effect_context_t *context = (effect_context_t *)self; + + if (!effect_exists(context)) + return -EINVAL; + + if (descriptor == NULL) + return -EINVAL; + + *descriptor = *context->desc; + + return 0; +} + +/* effect_handle_t interface implementation for visualizer effect */ +const struct effect_interface_s effect_interface = { + effect_process, + effect_command, + effect_get_descriptor, + NULL, +}; + +__attribute__ ((visibility ("default"))) +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Visualizer Library", + implementor : "The Android Open Source Project", + create_effect : effect_lib_create, + release_effect : effect_lib_release, + get_descriptor : effect_lib_get_descriptor, +}; -- GitLab From b891db5473ab23a0cbc52d566a97c3d3529f8ddd Mon Sep 17 00:00:00 2001 From: "sangwon.jeon" Date: Sat, 14 Sep 2013 17:39:15 +0900 Subject: [PATCH 031/298] audio : add new TMUS MCC and MNC list Add new TMUS MCC and MNC to use TMUS audio tuning data Bug: 10751789 Change-Id: I1082cda69f50e722164cb5066eeef0273943a93c --- hal/msm8974/platform.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 2ea80956c..cd7150cdd 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -200,6 +200,19 @@ static void check_operator() case 310490: case 310260: case 310026: + /* Add new TMUS MNC(800, 660, 580, 310, 270, 250, 240, 230, 220, 210, 200, 160) */ + case 310800: + case 310660: + case 310580: + case 310310: + case 310270: + case 310250: + case 310240: + case 310230: + case 310220: + case 310210: + case 310200: + case 310160: is_tmus = true; break; } -- GitLab From 8d8f4d50ebc4caa2c886fcb2ab8cf4729ec84878 Mon Sep 17 00:00:00 2001 From: "sangwon.jeon" Date: Sat, 14 Sep 2013 17:39:15 +0900 Subject: [PATCH 032/298] audio : add new TMUS MCC and MNC list Add new TMUS MCC and MNC to use TMUS audio tuning data Bug: 10751789 Change-Id: I1082cda69f50e722164cb5066eeef0273943a93c --- hal/msm8974/platform.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 2ea80956c..cd7150cdd 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -200,6 +200,19 @@ static void check_operator() case 310490: case 310260: case 310026: + /* Add new TMUS MNC(800, 660, 580, 310, 270, 250, 240, 230, 220, 210, 200, 160) */ + case 310800: + case 310660: + case 310580: + case 310310: + case 310270: + case 310250: + case 310240: + case 310230: + case 310220: + case 310210: + case 310200: + case 310160: is_tmus = true; break; } -- GitLab From ed0b99ceb452a371e9f7707e7beef5002e9418c9 Mon Sep 17 00:00:00 2001 From: "sangwon.jeon" Date: Sat, 14 Sep 2013 17:39:15 +0900 Subject: [PATCH 033/298] audio : add new TMUS MCC and MNC list Add new TMUS MCC and MNC to use TMUS audio tuning data Bug: 10751789 Change-Id: I1082cda69f50e722164cb5066eeef0273943a93c --- hal/msm8974/platform.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 2ea80956c..cd7150cdd 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -200,6 +200,19 @@ static void check_operator() case 310490: case 310260: case 310026: + /* Add new TMUS MNC(800, 660, 580, 310, 270, 250, 240, 230, 220, 210, 200, 160) */ + case 310800: + case 310660: + case 310580: + case 310310: + case 310270: + case 310250: + case 310240: + case 310230: + case 310220: + case 310210: + case 310200: + case 310160: is_tmus = true; break; } -- GitLab From 949a089132db31b652d937a949f7bd425f2e42f9 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 20 Sep 2013 09:20:13 -0700 Subject: [PATCH 034/298] implement get_presentation_position() for offloaded outputs Bug: 9587132. Change-Id: Idf40259b59552c29671830f30ccca3bef6ef0edd --- hal/audio_hw.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c2997c66e..76533c666 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1422,19 +1422,33 @@ static int out_get_presentation_position(const struct audio_stream_out *stream, { struct stream_out *out = (struct stream_out *)stream; int ret = -1; + unsigned long dsp_frames; pthread_mutex_lock(&out->lock); - if (out->pcm) { - size_t avail; - if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { - size_t kernel_buffer_size = out->config.period_size * out->config.period_count; - // FIXME This calculation is incorrect if there is buffering after app processor - int64_t signed_frames = out->written - kernel_buffer_size + avail; - // It would be unusual for this value to be negative, but check just in case ... - if (signed_frames >= 0) { - *frames = signed_frames; - ret = 0; + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->compr != NULL) { + compress_get_tstamp(out->compr, &dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %ld sample_rate %d", + __func__, dsp_frames, out->sample_rate); + *frames = dsp_frames; + ret = 0; + /* this is the best we can do */ + clock_gettime(CLOCK_MONOTONIC, timestamp); + } + } else { + if (out->pcm) { + size_t avail; + if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { + size_t kernel_buffer_size = out->config.period_size * out->config.period_count; + // FIXME This calculation is incorrect if there is buffering after app processor + int64_t signed_frames = out->written - kernel_buffer_size + avail; + // It would be unusual for this value to be negative, but check just in case ... + if (signed_frames >= 0) { + *frames = signed_frames; + ret = 0; + } } } } -- GitLab From 7ff216f80f6e53235b4239c6fb7da9b0d5127738 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Wed, 11 Sep 2013 19:51:41 -0700 Subject: [PATCH 035/298] audio: Presentation time enhancements 1) Add API to query platform render latency. This API is only valid for deep-buffer and low-latency streams. 2) Adjust frames rendered for deep-buffer and low-latency streams with the platform render latency 3) Use tinycompress APIs to query presentation time in case of offload streams. Bug: 10551158 Change-Id: If94e0994bfc0b757f29aa4b48be6fc63dc17bca0 --- hal/audio_hw.c | 6 +++++- hal/msm8960/platform.c | 16 ++++++++++++++++ hal/msm8974/platform.c | 16 ++++++++++++++++ hal/platform_api.h | 3 +++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 76533c666..c89d88ead 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1442,8 +1442,12 @@ static int out_get_presentation_position(const struct audio_stream_out *stream, size_t avail; if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { size_t kernel_buffer_size = out->config.period_size * out->config.period_count; - // FIXME This calculation is incorrect if there is buffering after app processor int64_t signed_frames = out->written - kernel_buffer_size + avail; + // This adjustment accounts for buffering after app processor. + // It is based on estimated DSP latency per use case, rather than exact. + signed_frames -= + (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL); + // It would be unusual for this value to be negative, but check just in case ... if (signed_frames >= 0) { *frames = signed_frames; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index e533f3387..b200e2746 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -200,6 +200,9 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, }; +#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) +#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) + static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; static bool is_tmus = false; @@ -880,3 +883,16 @@ int platform_edid_get_max_channels(void *platform) return max_channels; } + +/* Delay in Us */ +int64_t platform_render_latency(audio_usecase_t usecase) +{ + switch (usecase) { + case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: + return DEEP_BUFFER_PLATFORM_DELAY; + case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: + return LOW_LATENCY_PLATFORM_DELAY; + default: + return 0; + } +} diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index cd7150cdd..b5d568f51 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -185,6 +185,9 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, }; +#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) +#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) + static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; static bool is_tmus = false; @@ -840,3 +843,16 @@ int platform_edid_get_max_channels(void *platform) return max_channels; } + +/* Delay in Us */ +int64_t platform_render_latency(audio_usecase_t usecase) +{ + switch (usecase) { + case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: + return DEEP_BUFFER_PLATFORM_DELAY; + case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: + return LOW_LATENCY_PLATFORM_DELAY; + default: + return 0; + } +} diff --git a/hal/platform_api.h b/hal/platform_api.h index 2362a5b3f..afd2ee413 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -36,4 +36,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d int platform_set_hdmi_channels(void *platform, int channel_count); int platform_edid_get_max_channels(void *platform); +/* returns the latency for a usecase in Us */ +int64_t platform_render_latency(audio_usecase_t usecase); + #endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From a6c11c11e2e7aee28b544674f1158b7b057c0c52 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 24 Sep 2013 15:08:56 -0700 Subject: [PATCH 036/298] Level measurement in offloaded visualizer Add Peak and RMS measurement capabilities in the "offloaded" version of the visualizer effect. Bug 8413913 Change-Id: I09a88f4cc791db6c68f0769dc23ced0d3aac955c --- visualizer/offload_visualizer.c | 152 ++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 16 deletions(-) diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c index 75ce4a5cd..eb43558d9 100644 --- a/visualizer/offload_visualizer.c +++ b/visualizer/offload_visualizer.c @@ -17,6 +17,7 @@ #define LOG_TAG "offload_visualizer" /*#define LOG_NDEBUG 0*/ #include +#include #include #include #include @@ -80,6 +81,16 @@ typedef struct output_context_s { #define CAPTURE_BUF_SIZE 65536 /* "64k should be enough for everyone" */ +#define DISCARD_MEASUREMENTS_TIME_MS 2000 /* discard measurements older than this number of ms */ + +/* maximum number of buffers for which we keep track of the measurements */ +#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 /* note: buffer index is stored in uint8_t */ + +typedef struct buffer_stats_s { + bool is_valid; + uint16_t peak_u16; /* the positive peak of the absolute value of the samples in a buffer */ + float rms_squared; /* the average square of the samples in a buffer */ +} buffer_stats_t; typedef struct visualizer_context_s { effect_context_t common; @@ -91,6 +102,12 @@ typedef struct visualizer_context_s { uint32_t latency; struct timespec buffer_update_time; uint8_t capture_buf[CAPTURE_BUF_SIZE]; + /* for measurements */ + uint8_t channel_count; /* to avoid recomputing it every time a buffer is processed */ + uint32_t meas_mode; + uint8_t meas_wndw_size_in_buffers; + uint8_t meas_buffer_idx; + buffer_stats_t past_meas[MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS]; } visualizer_context_t; @@ -507,6 +524,23 @@ void get_config(effect_context_t *context, effect_config_t *config) * Visualizer operations */ +uint32_t visualizer_get_delta_time_ms_from_updated_time(visualizer_context_t* visu_ctxt) { + uint32_t delta_ms = 0; + if (visu_ctxt->buffer_update_time.tv_sec != 0) { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + time_t secs = ts.tv_sec - visu_ctxt->buffer_update_time.tv_sec; + long nsec = ts.tv_nsec - visu_ctxt->buffer_update_time.tv_nsec; + if (nsec < 0) { + --secs; + nsec += 1000000000; + } + delta_ms = secs * 1000 + nsec / 1000000; + } + } + return delta_ms; +} + int visualizer_reset(effect_context_t *context) { visualizer_context_t * visu_ctxt = (visualizer_context_t *)context; @@ -521,6 +555,8 @@ int visualizer_reset(effect_context_t *context) int visualizer_init(effect_context_t *context) { + int32_t i; + visualizer_context_t * visu_ctxt = (visualizer_context_t *)context; context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; @@ -543,6 +579,17 @@ int visualizer_init(effect_context_t *context) visu_ctxt->capture_size = VISUALIZER_CAPTURE_SIZE_MAX; visu_ctxt->scaling_mode = VISUALIZER_SCALING_MODE_NORMALIZED; + // measurement initialization + visu_ctxt->channel_count = popcount(context->config.inputCfg.channels); + visu_ctxt->meas_mode = MEASUREMENT_MODE_NONE; + visu_ctxt->meas_wndw_size_in_buffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS; + visu_ctxt->meas_buffer_idx = 0; + for (i=0 ; imeas_wndw_size_in_buffers ; i++) { + visu_ctxt->past_meas[i].is_valid = false; + visu_ctxt->past_meas[i].peak_u16 = 0; + visu_ctxt->past_meas[i].rms_squared = 0; + } + set_config(context, &context->config); return 0; @@ -571,6 +618,12 @@ int visualizer_get_parameter(effect_context_t *context, effect_param_t *p, uint3 p->vsize = sizeof(uint32_t); *size += sizeof(uint32_t); break; + case VISUALIZER_PARAM_MEASUREMENT_MODE: + ALOGV("%s get meas_mode = %d", __func__, visu_ctxt->meas_mode); + *((uint32_t *)p->data + 1) = visu_ctxt->meas_mode; + p->vsize = sizeof(uint32_t); + *size += sizeof(uint32_t); + break; default: p->status = -EINVAL; } @@ -598,6 +651,10 @@ int visualizer_set_parameter(effect_context_t *context, effect_param_t *p, uint3 * visu_ctxt->latency = *((uint32_t *)p->data + 1); */ ALOGV("%s set latency = %d", __func__, visu_ctxt->latency); break; + case VISUALIZER_PARAM_MEASUREMENT_MODE: + visu_ctxt->meas_mode = *((uint32_t *)p->data + 1); + ALOGV("%s set meas_mode = %d", __func__, visu_ctxt->meas_mode); + break; default: return -EINVAL; } @@ -621,6 +678,30 @@ int visualizer_process(effect_context_t *context, return -EINVAL; } + // perform measurements if needed + if (visu_ctxt->meas_mode & MEASUREMENT_MODE_PEAK_RMS) { + // find the peak and RMS squared for the new buffer + uint32_t inIdx; + int16_t max_sample = 0; + float rms_squared_acc = 0; + for (inIdx = 0 ; inIdx < inBuffer->frameCount * visu_ctxt->channel_count ; inIdx++) { + if (inBuffer->s16[inIdx] > max_sample) { + max_sample = inBuffer->s16[inIdx]; + } else if (-inBuffer->s16[inIdx] > max_sample) { + max_sample = -inBuffer->s16[inIdx]; + } + rms_squared_acc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]); + } + // store the measurement + visu_ctxt->past_meas[visu_ctxt->meas_buffer_idx].peak_u16 = (uint16_t)max_sample; + visu_ctxt->past_meas[visu_ctxt->meas_buffer_idx].rms_squared = + rms_squared_acc / (inBuffer->frameCount * visu_ctxt->channel_count); + visu_ctxt->past_meas[visu_ctxt->meas_buffer_idx].is_valid = true; + if (++visu_ctxt->meas_buffer_idx >= visu_ctxt->meas_wndw_size_in_buffers) { + visu_ctxt->meas_buffer_idx = 0; + } + } + /* all code below assumes stereo 16 bit PCM output and input */ int32_t shift; @@ -700,23 +781,12 @@ int visualizer_command(effect_context_t * context, uint32_t cmdCode, uint32_t cm if (context->state == EFFECT_STATE_ACTIVE) { int32_t latency_ms = visu_ctxt->latency; - uint32_t delta_ms = 0; - if (visu_ctxt->buffer_update_time.tv_sec != 0) { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - time_t secs = ts.tv_sec - visu_ctxt->buffer_update_time.tv_sec; - long nsec = ts.tv_nsec - visu_ctxt->buffer_update_time.tv_nsec; - if (nsec < 0) { - --secs; - nsec += 1000000000; - } - delta_ms = secs * 1000 + nsec / 1000000; - latency_ms -= delta_ms; - if (latency_ms < 0) - latency_ms = 0; - } + const uint32_t delta_ms = visualizer_get_delta_time_ms_from_updated_time(visu_ctxt); + latency_ms -= delta_ms; + if (latency_ms < 0) { + latency_ms = 0; } - uint32_t delta_smp = context->config.inputCfg.samplingRate * latency_ms / 1000; + const uint32_t delta_smp = context->config.inputCfg.samplingRate * latency_ms / 1000; int32_t capture_point = visu_ctxt->capture_idx - visu_ctxt->capture_size - delta_smp; int32_t capture_size = visu_ctxt->capture_size; @@ -753,6 +823,56 @@ int visualizer_command(effect_context_t * context, uint32_t cmdCode, uint32_t cm } break; + case VISUALIZER_CMD_MEASURE: { + uint16_t peak_u16 = 0; + float sum_rms_squared = 0.0f; + uint8_t nb_valid_meas = 0; + /* reset measurements if last measurement was too long ago (which implies stored + * measurements aren't relevant anymore and shouldn't bias the new one) */ + const int32_t delay_ms = visualizer_get_delta_time_ms_from_updated_time(visu_ctxt); + if (delay_ms > DISCARD_MEASUREMENTS_TIME_MS) { + uint32_t i; + ALOGV("Discarding measurements, last measurement is %dms old", delay_ms); + for (i=0 ; imeas_wndw_size_in_buffers ; i++) { + visu_ctxt->past_meas[i].is_valid = false; + visu_ctxt->past_meas[i].peak_u16 = 0; + visu_ctxt->past_meas[i].rms_squared = 0; + } + visu_ctxt->meas_buffer_idx = 0; + } else { + /* only use actual measurements, otherwise the first RMS measure happening before + * MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially + * low */ + uint32_t i; + for (i=0 ; i < visu_ctxt->meas_wndw_size_in_buffers ; i++) { + if (visu_ctxt->past_meas[i].is_valid) { + if (visu_ctxt->past_meas[i].peak_u16 > peak_u16) { + peak_u16 = visu_ctxt->past_meas[i].peak_u16; + } + sum_rms_squared += visu_ctxt->past_meas[i].rms_squared; + nb_valid_meas++; + } + } + } + float rms = nb_valid_meas == 0 ? 0.0f : sqrtf(sum_rms_squared / nb_valid_meas); + int32_t* p_int_reply_data = (int32_t*)pReplyData; + /* convert from I16 sample values to mB and write results */ + if (rms < 0.000016f) { + p_int_reply_data[MEASUREMENT_IDX_RMS] = -9600; //-96dB + } else { + p_int_reply_data[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f)); + } + if (peak_u16 == 0) { + p_int_reply_data[MEASUREMENT_IDX_PEAK] = -9600; //-96dB + } else { + p_int_reply_data[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peak_u16 / 32767.0f)); + } + ALOGV("VISUALIZER_CMD_MEASURE peak=%d (%dmB), rms=%.1f (%dmB)", + peak_u16, p_int_reply_data[MEASUREMENT_IDX_PEAK], + rms, p_int_reply_data[MEASUREMENT_IDX_RMS]); + } + break; + default: ALOGW("%s invalid command %d", __func__, cmdCode); return -EINVAL; -- GitLab From 7f24504d395380420bb4143bdec3e701aef428aa Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 30 Sep 2013 19:22:50 -0700 Subject: [PATCH 037/298] audio: fix output flag test in open_output_stream If flag AUDIO_OUTPUT_FLAG_DIRECT is set, we should only try to open a multi channel HDMI PCM output if flag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD is not set. Bug: 8174410. Change-Id: I63fe6cabca590e70c077dea13c86c6948700e606 --- hal/audio_hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c89d88ead..0786b3f69 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1772,6 +1772,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, /* Init use case and pcm_config */ if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && + !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { pthread_mutex_lock(&adev->lock); ret = read_hdmi_channel_masks(out); -- GitLab From ed9c56ad071e5d0fb09ac7f310dc83a4553c1ad7 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 2 Oct 2013 09:56:18 -0700 Subject: [PATCH 038/298] hal: Fix for Tx Mute issue when a new call accepted while in call - While in a voice call, if an incoming call is accepted, Tx path is muted on some specific networks. - If there is an incoming call, Telephony sets the mode to RINGTONE, and the condition check in audio HAL leads to voice call tear down. When the call is accepted, the mode is set back to IN_CALL and voice call path is re-enabled but the voice drivers will be operating with default settings as there is no notification from Modem side in this case. For modem, there is no change in the call state i.e. just switched from caller 1 to caller2. - Fix the issue by ensuring that the voice call is teared down only if mode is set to NORMAL while call is progress. Bug: 10733490 Change-Id: I2f205bb055807bb8d25f81e2907f78cd98bb77ad --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c89d88ead..c5e44aa23 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1220,7 +1220,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } } - if ((adev->mode != AUDIO_MODE_IN_CALL) && adev->in_call && + if ((adev->mode == AUDIO_MODE_NORMAL) && adev->in_call && (out == adev->primary_output)) { stop_voice_call(adev); } -- GitLab From 8e5a4f60401350f697eebf14c7cdb063a6fef8e8 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Mon, 7 Oct 2013 15:23:41 -0700 Subject: [PATCH 039/298] Hal: Initial commit for B-family targets - Remove broadside dual-mic config specific code which is not supported anymore. - change output device for voice calls. Voice calls should enable side tone,use voice handset device which enables side tone during voice calls. - Add Fluence quad MIC support for voice calls in speaker mode. - Correct the audio hal library name to reflect the target name. - Compile the msm8974 platform code for all b-family targets. - Fix the low latency number accordingly for msm8610 in platform code Change-Id: I8f16ac8eef8ef4bec1295bf73208ebaf90303603 --- Android.mk | 2 +- hal/Android.mk | 7 ++- hal/audio_hw.h | 1 + hal/msm8960/platform.c | 108 +++++++++++++++-------------------- hal/msm8960/platform.h | 21 ++++--- hal/msm8974/platform.c | 127 ++++++++++++++++++----------------------- hal/msm8974/platform.h | 31 +++++++--- 7 files changed, 144 insertions(+), 153 deletions(-) diff --git a/Android.mk b/Android.mk index 1c5c5b3db..03929fcbd 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,4 @@ -ifneq ($(filter msm8960 msm8226 msm8x26 msm8974 msm8x74,$(TARGET_BOARD_PLATFORM)),) +ifneq ($(filter msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74,$(TARGET_BOARD_PLATFORM)),) MY_LOCAL_PATH := $(call my-dir) diff --git a/hal/Android.mk b/hal/Android.mk index 7c71b9753..71e6d5ae8 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -7,9 +7,12 @@ include $(CLEAR_VARS) LOCAL_ARM_MODE := arm AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) -ifneq ($(filter msm8974 msm8226,$(TARGET_BOARD_PLATFORM)),) +ifneq ($(filter msm8974 msm8226 msm8610,$(TARGET_BOARD_PLATFORM)),) # B-family platform uses msm8974 code base AUDIO_PLATFORM = msm8974 +ifneq ($(filter msm8610,$(TARGET_BOARD_PLATFORM)),) + LOCAL_CFLAGS := -DPLATFORM_MSM8610 +endif endif LOCAL_SRC_FILES := \ @@ -30,7 +33,7 @@ LOCAL_C_INCLUDES += \ $(call include-path-for, audio-effects) \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) -LOCAL_MODULE := audio.primary.$(AUDIO_PLATFORM) +LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 5702f373f..ecb624545 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -26,6 +26,7 @@ /* Flags used to initialize acdb_settings variable that goes to ACDB library */ #define DMIC_FLAG 0x00000002 +#define QMIC_FLAG 0x00000004 #define TTY_MODE_OFF 0x00000010 #define TTY_MODE_FULL 0x00000020 #define TTY_MODE_VCO 0x00000040 diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index e533f3387..a24ca83e4 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -29,10 +29,6 @@ #define LIB_ACDB_LOADER "libacdbloader.so" #define LIB_CSD_CLIENT "libcsd-client.so" -#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ -#define DUALMIC_CONFIG_ENDFIRE 1 -#define DUALMIC_CONFIG_BROADSIDE 2 - /* * This is the sysfs path for the HDMI audio data block */ @@ -80,6 +76,7 @@ struct platform_data { bool fluence_in_spkr_mode; bool fluence_in_voice_call; bool fluence_in_voice_rec; + int fluence_type; int dualmic_config; void *acdb_handle; @@ -140,19 +137,15 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", - [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef", - [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs", - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus", - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef", - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs", + [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", + [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", - [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef", - [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs", - [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence", - [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence", + [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef", + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ @@ -184,20 +177,16 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_HDMI_MIC] = 4, [SND_DEVICE_IN_BT_SCO_MIC] = 21, [SND_DEVICE_IN_CAMCORDER_MIC] = 61, - [SND_DEVICE_IN_VOICE_DMIC_EF] = 6, - [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91, - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 13, - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, + [SND_DEVICE_IN_VOICE_DMIC] = 6, + [SND_DEVICE_IN_VOICE_DMIC_TMUS] = 91, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 13, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_REC_MIC] = 62, /* TODO: Update with proper acdb ids */ - [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6, - [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, + [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, }; static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; @@ -265,33 +254,33 @@ void *platform_init(struct audio_device *adev) my_data = calloc(1, sizeof(struct platform_data)); my_data->adev = adev; - my_data->dualmic_config = DUALMIC_CONFIG_NONE; my_data->fluence_in_spkr_mode = false; my_data->fluence_in_voice_call = false; my_data->fluence_in_voice_rec = false; + my_data->fluence_type = FLUENCE_NONE; - property_get("persist.audio.dualmic.config",value,""); - if (!strcmp("broadside", value)) { - my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE; - adev->acdb_settings |= DMIC_FLAG; - } else if (!strcmp("endfire", value)) { - my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE; - adev->acdb_settings |= DMIC_FLAG; + property_get("ro.qc.sdk.audio.fluencetype", value, ""); + if (!strncmp("fluencepro", value, sizeof("fluencepro"))) { + my_data->fluence_type = FLUENCE_QUAD_MIC; + } else if (!strncmp("fluence", value, sizeof("fluence"))) { + my_data->fluence_type = FLUENCE_DUAL_MIC; + } else { + my_data->fluence_type = FLUENCE_NONE; } - if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) { + if (my_data->fluence_type != FLUENCE_NONE) { property_get("persist.audio.fluence.voicecall",value,""); - if (!strcmp("true", value)) { + if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_voice_call = true; } property_get("persist.audio.fluence.voicerec",value,""); - if (!strcmp("true", value)) { + if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_voice_rec = true; } property_get("persist.audio.fluence.speaker",value,""); - if (!strcmp("true", value)) { + if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_spkr_mode = true; } } @@ -683,30 +672,31 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } if (out_device & AUDIO_DEVICE_OUT_EARPIECE || out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { - if (my_data->fluence_in_voice_call == false) { + if (my_data->fluence_type == FLUENCE_NONE || + my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else { - if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - if (is_operator_tmus()) - snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS; - else - snd_device = SND_DEVICE_IN_VOICE_DMIC_EF; - } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) - snd_device = SND_DEVICE_IN_VOICE_DMIC_BS; + if (is_operator_tmus()) + snd_device = SND_DEVICE_IN_VOICE_DMIC_TMUS; else - snd_device = SND_DEVICE_IN_HANDSET_MIC; + snd_device = SND_DEVICE_IN_VOICE_DMIC; + adev->acdb_settings |= DMIC_FLAG; } } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { snd_device = SND_DEVICE_IN_BT_SCO_MIC ; } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { - if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && - my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF; - } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && - my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS; + if (my_data->fluence_type != FLUENCE_NONE && + my_data->fluence_in_voice_call && + my_data->fluence_in_spkr_mode) { + if(my_data->fluence_type == FLUENCE_DUAL_MIC) { + adev->acdb_settings |= DMIC_FLAG; + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC; + } else { + adev->acdb_settings |= QMIC_FLAG; + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC; + } } else { snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; } @@ -718,21 +708,15 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF; - else if (my_data->fluence_in_voice_rec) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE; - } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS; - else if (my_data->fluence_in_voice_rec) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE; - } + if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC; + else if (my_data->fluence_in_voice_rec) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE; - if (snd_device == SND_DEVICE_NONE) { + if (snd_device == SND_DEVICE_NONE) snd_device = SND_DEVICE_IN_VOICE_REC_MIC; - } + else + adev->acdb_settings |= DMIC_FLAG; } } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { if (out_device & AUDIO_DEVICE_OUT_SPEAKER) diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h index 4bc500329..f09b9b124 100644 --- a/hal/msm8960/platform.h +++ b/hal/msm8960/platform.h @@ -17,6 +17,12 @@ #ifndef QCOM_AUDIO_PLATFORM_H #define QCOM_AUDIO_PLATFORM_H +enum { + FLUENCE_NONE, + FLUENCE_DUAL_MIC, + FLUENCE_QUAD_MIC +}; + /* * Below are the devices for which is back end is same, SLIMBUS_0_RX. * All these devices are handled by the internal HW codec. We can @@ -69,19 +75,16 @@ enum { SND_DEVICE_IN_HDMI_MIC, SND_DEVICE_IN_BT_SCO_MIC, SND_DEVICE_IN_CAMCORDER_MIC, - SND_DEVICE_IN_VOICE_DMIC_EF, - SND_DEVICE_IN_VOICE_DMIC_BS, - SND_DEVICE_IN_VOICE_DMIC_EF_TMUS, - SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF, - SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS, + SND_DEVICE_IN_VOICE_DMIC, + SND_DEVICE_IN_VOICE_DMIC_TMUS, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC, + SND_DEVICE_IN_VOICE_SPEAKER_QMIC, SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, SND_DEVICE_IN_VOICE_REC_MIC, - SND_DEVICE_IN_VOICE_REC_DMIC_EF, - SND_DEVICE_IN_VOICE_REC_DMIC_BS, - SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE, - SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE, + SND_DEVICE_IN_VOICE_REC_DMIC, + SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, SND_DEVICE_IN_END, SND_DEVICE_MAX = SND_DEVICE_IN_END, diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 8560f9d1f..3d13c7df9 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -30,10 +30,6 @@ #define LIB_ACDB_LOADER "libacdbloader.so" #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" -#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */ -#define DUALMIC_CONFIG_ENDFIRE 1 -#define DUALMIC_CONFIG_BROADSIDE 2 - /* * This file will have a maximum of 38 bytes: * @@ -73,7 +69,7 @@ struct platform_data { bool fluence_in_spkr_mode; bool fluence_in_voice_call; bool fluence_in_voice_rec; - int dualmic_config; + int fluence_type; void *acdb_handle; acdb_init_t acdb_init; @@ -83,12 +79,16 @@ struct platform_data { }; static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { - [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0}, - [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15}, - [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1}, - [USECASE_AUDIO_RECORD] = {0, 0}, - [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15}, - [USECASE_VOICE_CALL] = {2, 2}, + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE, + DEEP_BUFFER_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, + LOWLATENCY_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTI_CHANNEL_PCM_DEVICE, + MULTI_CHANNEL_PCM_DEVICE}, + [USECASE_AUDIO_RECORD] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE}, + [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, + LOWLATENCY_PCM_DEVICE}, + [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, }; /* Array to store sound devices */ @@ -123,19 +123,15 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", - [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef", - [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs", - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus", - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef", - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs", + [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", + [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", - [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef", - [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs", - [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence", - [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence", + [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef", + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ @@ -168,20 +164,16 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_HDMI_MIC] = 4, [SND_DEVICE_IN_BT_SCO_MIC] = 21, [SND_DEVICE_IN_CAMCORDER_MIC] = 61, - [SND_DEVICE_IN_VOICE_DMIC_EF] = 41, - [SND_DEVICE_IN_VOICE_DMIC_BS] = 5, - [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 89, - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43, - [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12, + [SND_DEVICE_IN_VOICE_DMIC] = 41, + [SND_DEVICE_IN_VOICE_DMIC_TMUS] = 89, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_REC_MIC] = 62, /* TODO: Update with proper acdb ids */ - [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6, - [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5, + [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, }; static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; @@ -272,33 +264,33 @@ void *platform_init(struct audio_device *adev) my_data = calloc(1, sizeof(struct platform_data)); my_data->adev = adev; - my_data->dualmic_config = DUALMIC_CONFIG_NONE; my_data->fluence_in_spkr_mode = false; my_data->fluence_in_voice_call = false; my_data->fluence_in_voice_rec = false; + my_data->fluence_type = FLUENCE_NONE; - property_get("persist.audio.dualmic.config",value,""); - if (!strcmp("broadside", value)) { - my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE; - adev->acdb_settings |= DMIC_FLAG; - } else if (!strcmp("endfire", value)) { - my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE; - adev->acdb_settings |= DMIC_FLAG; + property_get("ro.qc.sdk.audio.fluencetype", value, ""); + if (!strncmp("fluencepro", value, sizeof("fluencepro"))) { + my_data->fluence_type = FLUENCE_QUAD_MIC; + } else if (!strncmp("fluence", value, sizeof("fluence"))) { + my_data->fluence_type = FLUENCE_DUAL_MIC; + } else { + my_data->fluence_type = FLUENCE_NONE; } - if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) { + if (my_data->fluence_type != FLUENCE_NONE) { property_get("persist.audio.fluence.voicecall",value,""); - if (!strcmp("true", value)) { + if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_voice_call = true; } property_get("persist.audio.fluence.voicerec",value,""); - if (!strcmp("true", value)) { + if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_voice_rec = true; } property_get("persist.audio.fluence.speaker",value,""); - if (!strcmp("true", value)) { + if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_spkr_mode = true; } } @@ -524,7 +516,7 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi if (is_operator_tmus()) snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; else - snd_device = SND_DEVICE_OUT_HANDSET; + snd_device = SND_DEVICE_OUT_VOICE_HANDSET; } if (snd_device != SND_DEVICE_NONE) { goto exit; @@ -620,30 +612,31 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } if (out_device & AUDIO_DEVICE_OUT_EARPIECE || out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { - if (my_data->fluence_in_voice_call == false) { + if (my_data->fluence_type == FLUENCE_NONE || + my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else { - if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - if (is_operator_tmus()) - snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS; - else - snd_device = SND_DEVICE_IN_VOICE_DMIC_EF; - } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) - snd_device = SND_DEVICE_IN_VOICE_DMIC_BS; + if (is_operator_tmus()) + snd_device = SND_DEVICE_IN_VOICE_DMIC_TMUS; else - snd_device = SND_DEVICE_IN_HANDSET_MIC; + snd_device = SND_DEVICE_IN_VOICE_DMIC; + adev->acdb_settings |= DMIC_FLAG; } } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { snd_device = SND_DEVICE_IN_BT_SCO_MIC ; } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { - if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && - my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF; - } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode && - my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS; + if (my_data->fluence_type != FLUENCE_NONE && + my_data->fluence_in_voice_call && + my_data->fluence_in_spkr_mode) { + if(my_data->fluence_type == FLUENCE_DUAL_MIC) { + adev->acdb_settings |= DMIC_FLAG; + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC; + } else { + adev->acdb_settings |= QMIC_FLAG; + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC; + } } else { snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; } @@ -655,21 +648,15 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF; - else if (my_data->fluence_in_voice_rec) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE; - } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS; - else if (my_data->fluence_in_voice_rec) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE; - } + if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC; + else if (my_data->fluence_in_voice_rec) + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE; - if (snd_device == SND_DEVICE_NONE) { + if (snd_device == SND_DEVICE_NONE) snd_device = SND_DEVICE_IN_VOICE_REC_MIC; - } + else + adev->acdb_settings |= DMIC_FLAG; } } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { if (out_device & AUDIO_DEVICE_OUT_SPEAKER) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index a6b3c31c7..26d4a9f34 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -17,6 +17,12 @@ #ifndef QCOM_AUDIO_PLATFORM_H #define QCOM_AUDIO_PLATFORM_H +enum { + FLUENCE_NONE, + FLUENCE_DUAL_MIC, + FLUENCE_QUAD_MIC +}; + /* * Below are the devices for which is back end is same, SLIMBUS_0_RX. * All these devices are handled by the internal HW codec. We can @@ -70,19 +76,16 @@ enum { SND_DEVICE_IN_HDMI_MIC, SND_DEVICE_IN_BT_SCO_MIC, SND_DEVICE_IN_CAMCORDER_MIC, - SND_DEVICE_IN_VOICE_DMIC_EF, - SND_DEVICE_IN_VOICE_DMIC_BS, - SND_DEVICE_IN_VOICE_DMIC_EF_TMUS, - SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF, - SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS, + SND_DEVICE_IN_VOICE_DMIC, + SND_DEVICE_IN_VOICE_DMIC_TMUS, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC, + SND_DEVICE_IN_VOICE_SPEAKER_QMIC, SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, SND_DEVICE_IN_VOICE_REC_MIC, - SND_DEVICE_IN_VOICE_REC_DMIC_EF, - SND_DEVICE_IN_VOICE_REC_DMIC_BS, - SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE, - SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE, + SND_DEVICE_IN_VOICE_REC_DMIC, + SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, SND_DEVICE_IN_END, SND_DEVICE_MAX = SND_DEVICE_IN_END, @@ -122,4 +125,14 @@ enum { #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20 #define AUDIO_CAPTURE_PERIOD_COUNT 2 +#define DEEP_BUFFER_PCM_DEVICE 0 +#define MULTI_CHANNEL_PCM_DEVICE 1 +#define VOICE_CALL_PCM_DEVICE 2 + +#ifdef PLATFORM_MSM8610 +#define LOWLATENCY_PCM_DEVICE 12 +#else +#define LOWLATENCY_PCM_DEVICE 15 +#endif + #endif // QCOM_AUDIO_PLATFORM_H -- GitLab From 486032d2729247bb57c839c858d87d2b8269d6aa Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Thu, 26 Sep 2013 17:22:07 -0700 Subject: [PATCH 040/298] audio: audio encoder/decoder enhancement - Enable decoder test app for AAC, AMR, AMRWB, and MP3 formats. - Enable encoder for AMRWB, AAC, EVRC, and QCELP formats. Change-Id: I0c75dcc4fb02044f127270a64d3578d62bf6eeda --- Android.mk | 1 + mm-audio/Android.mk | 1 + mm-audio/Makefile | 10 + mm-audio/Makefile.am | 5 + mm-audio/adec-aac/Android.mk | 1 + mm-audio/adec-aac/Makefile | 6 + mm-audio/adec-aac/Makefile.am | 1 + mm-audio/adec-aac/sw/Android.mk | 58 + mm-audio/adec-aac/sw/test/omx_aac_dec_test.c | 1302 +++++ mm-audio/adec-amr/Android.mk | 1 + mm-audio/adec-amr/sw/Android.mk | 59 + mm-audio/adec-amr/sw/test/omx_amr_dec_test.c | 1297 +++++ mm-audio/adec-amrwb/Android.mk | 1 + mm-audio/adec-amrwb/sw/Android.mk | 58 + .../adec-amrwb/sw/test/omx_amrwb_dec_test.c | 1283 +++++ mm-audio/adec-mp3/Android.mk | 1 + mm-audio/adec-mp3/Makefile | 6 + mm-audio/adec-mp3/Makefile.am | 1 + mm-audio/adec-mp3/sw/Android.mk | 59 + mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c | 2159 +++++++ mm-audio/aenc-aac/Android.mk | 23 + mm-audio/aenc-aac/Makefile | 6 + mm-audio/aenc-aac/Makefile.am | 1 + mm-audio/aenc-aac/qdsp6/Android.mk | 76 + mm-audio/aenc-aac/qdsp6/Makefile | 81 + mm-audio/aenc-aac/qdsp6/Makefile.am | 30 + mm-audio/aenc-aac/qdsp6/inc/Map.h | 244 + mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h | 120 + mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h | 624 ++ mm-audio/aenc-aac/qdsp6/src/aenc_svr.c | 206 + mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp | 5016 +++++++++++++++++ .../aenc-aac/qdsp6/test/omx_aac_enc_test.c | 1289 +++++ mm-audio/aenc-amrnb/Android.mk | 23 + mm-audio/aenc-amrnb/Makefile | 6 + mm-audio/aenc-amrnb/qdsp6/Android.mk | 76 + mm-audio/aenc-amrnb/qdsp6/Makefile | 81 + mm-audio/aenc-amrnb/qdsp6/inc/Map.h | 244 + mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h | 120 + mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h | 538 ++ mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c | 205 + .../aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp | 4531 +++++++++++++++ .../aenc-amrnb/qdsp6/test/omx_amr_enc_test.c | 1051 ++++ mm-audio/aenc-evrc/Android.mk | 23 + mm-audio/aenc-evrc/Makefile | 6 + mm-audio/aenc-evrc/qdsp6/Android.mk | 75 + mm-audio/aenc-evrc/qdsp6/Makefile | 81 + mm-audio/aenc-evrc/qdsp6/inc/Map.h | 244 + mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h | 122 + mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h | 539 ++ mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c | 205 + .../aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp | 4530 +++++++++++++++ .../aenc-evrc/qdsp6/test/omx_evrc_enc_test.c | 1094 ++++ mm-audio/aenc-qcelp13/Android.mk | 23 + mm-audio/aenc-qcelp13/Makefile | 6 + mm-audio/aenc-qcelp13/qdsp6/Android.mk | 78 + mm-audio/aenc-qcelp13/qdsp6/Makefile | 81 + mm-audio/aenc-qcelp13/qdsp6/inc/Map.h | 244 + mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h | 120 + .../aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h | 539 ++ mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c | 208 + .../qdsp6/src/omx_qcelp13_aenc.cpp | 4531 +++++++++++++++ .../qdsp6/test/omx_qcelp13_enc_test.c | 1097 ++++ mm-audio/autogen.sh | 10 + mm-audio/configure.ac | 44 + 64 files changed, 34801 insertions(+) create mode 100644 mm-audio/Android.mk create mode 100644 mm-audio/Makefile create mode 100644 mm-audio/Makefile.am create mode 100644 mm-audio/adec-aac/Android.mk create mode 100644 mm-audio/adec-aac/Makefile create mode 100644 mm-audio/adec-aac/Makefile.am create mode 100644 mm-audio/adec-aac/sw/Android.mk create mode 100644 mm-audio/adec-aac/sw/test/omx_aac_dec_test.c create mode 100644 mm-audio/adec-amr/Android.mk create mode 100644 mm-audio/adec-amr/sw/Android.mk create mode 100644 mm-audio/adec-amr/sw/test/omx_amr_dec_test.c create mode 100644 mm-audio/adec-amrwb/Android.mk create mode 100644 mm-audio/adec-amrwb/sw/Android.mk create mode 100644 mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c create mode 100644 mm-audio/adec-mp3/Android.mk create mode 100644 mm-audio/adec-mp3/Makefile create mode 100644 mm-audio/adec-mp3/Makefile.am create mode 100644 mm-audio/adec-mp3/sw/Android.mk create mode 100644 mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c create mode 100644 mm-audio/aenc-aac/Android.mk create mode 100644 mm-audio/aenc-aac/Makefile create mode 100644 mm-audio/aenc-aac/Makefile.am create mode 100644 mm-audio/aenc-aac/qdsp6/Android.mk create mode 100644 mm-audio/aenc-aac/qdsp6/Makefile create mode 100644 mm-audio/aenc-aac/qdsp6/Makefile.am create mode 100644 mm-audio/aenc-aac/qdsp6/inc/Map.h create mode 100644 mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h create mode 100644 mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h create mode 100644 mm-audio/aenc-aac/qdsp6/src/aenc_svr.c create mode 100644 mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp create mode 100644 mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c create mode 100644 mm-audio/aenc-amrnb/Android.mk create mode 100644 mm-audio/aenc-amrnb/Makefile create mode 100644 mm-audio/aenc-amrnb/qdsp6/Android.mk create mode 100644 mm-audio/aenc-amrnb/qdsp6/Makefile create mode 100644 mm-audio/aenc-amrnb/qdsp6/inc/Map.h create mode 100644 mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h create mode 100644 mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h create mode 100644 mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c create mode 100644 mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp create mode 100644 mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c create mode 100644 mm-audio/aenc-evrc/Android.mk create mode 100644 mm-audio/aenc-evrc/Makefile create mode 100644 mm-audio/aenc-evrc/qdsp6/Android.mk create mode 100644 mm-audio/aenc-evrc/qdsp6/Makefile create mode 100644 mm-audio/aenc-evrc/qdsp6/inc/Map.h create mode 100644 mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h create mode 100644 mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h create mode 100644 mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c create mode 100644 mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp create mode 100644 mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c create mode 100644 mm-audio/aenc-qcelp13/Android.mk create mode 100644 mm-audio/aenc-qcelp13/Makefile create mode 100644 mm-audio/aenc-qcelp13/qdsp6/Android.mk create mode 100644 mm-audio/aenc-qcelp13/qdsp6/Makefile create mode 100644 mm-audio/aenc-qcelp13/qdsp6/inc/Map.h create mode 100644 mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h create mode 100644 mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h create mode 100644 mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c create mode 100644 mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp create mode 100644 mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c create mode 100644 mm-audio/autogen.sh create mode 100644 mm-audio/configure.ac diff --git a/Android.mk b/Android.mk index 1c5c5b3db..c3d6aae51 100644 --- a/Android.mk +++ b/Android.mk @@ -7,6 +7,7 @@ include $(MY_LOCAL_PATH)/legacy/Android.mk else include $(MY_LOCAL_PATH)/hal/Android.mk include $(MY_LOCAL_PATH)/voice_processing/Android.mk +include $(MY_LOCAL_PATH)/mm-audio/Android.mk endif endif diff --git a/mm-audio/Android.mk b/mm-audio/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/mm-audio/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/mm-audio/Makefile b/mm-audio/Makefile new file mode 100644 index 000000000..2be93e922 --- /dev/null +++ b/mm-audio/Makefile @@ -0,0 +1,10 @@ +all: + @echo "invoking omxaudio make" + $(MAKE) -C adec-mp3 + $(MAKE) -C adec-aac + $(MAKE) -C aenc-aac + +install: + $(MAKE) -C adec-mp3 install + $(MAKE) -C adec-aac install + $(MAKE) -C aenc-aac install diff --git a/mm-audio/Makefile.am b/mm-audio/Makefile.am new file mode 100644 index 000000000..e423acbb9 --- /dev/null +++ b/mm-audio/Makefile.am @@ -0,0 +1,5 @@ +# Makefile.am - Automake script for mm-omxaudio +# +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = adec-aac adec-mp3 aenc-aac diff --git a/mm-audio/adec-aac/Android.mk b/mm-audio/adec-aac/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/mm-audio/adec-aac/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/mm-audio/adec-aac/Makefile b/mm-audio/adec-aac/Makefile new file mode 100644 index 000000000..169fdc6df --- /dev/null +++ b/mm-audio/adec-aac/Makefile @@ -0,0 +1,6 @@ +all: + @echo "invoking adec-aac make" + $(MAKE) -C qdsp6 + +install: + $(MAKE) -C qdsp6 install diff --git a/mm-audio/adec-aac/Makefile.am b/mm-audio/adec-aac/Makefile.am new file mode 100644 index 000000000..24c1af26d --- /dev/null +++ b/mm-audio/adec-aac/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qdsp6 diff --git a/mm-audio/adec-aac/sw/Android.mk b/mm-audio/adec-aac/sw/Android.mk new file mode 100644 index 000000000..12a91b1ef --- /dev/null +++ b/mm-audio/adec-aac/sw/Android.mk @@ -0,0 +1,58 @@ +ifneq ($(BUILD_TINY_ANDROID),true) +ifneq ($(BUILD_WITHOUT_PV),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxAacDec-def := -g -O3 +libOmxAacDec-def += -DQC_MODIFIED +libOmxAacDec-def += -D_ANDROID_ +libOmxAacDec-def += -D_ENABLE_QC_MSG_LOG_ +libOmxAacDec-def += -DVERBOSE +libOmxAacDec-def += -D_DEBUG + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +libOmxAacDec-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-adec-omxaac-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +mm-aac-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +mm-aac-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +mm-aac-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \ + $(PV_TOP)/codecs_v2/omx/omx_common/include \ + $(PV_TOP)/extern_libs_v2/khronos/openmax/include \ + $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \ + $(PV_TOP)/codecs_v2/omx/omx_aac/include \ + $(PV_TOP)/codecs_v2/audio/aac/dec/include \ + +LOCAL_MODULE := sw-adec-omxaac-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAacDec-def) +LOCAL_C_INCLUDES := $(mm-aac-dec-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libopencore_common +LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary +LOCAL_SHARED_LIBRARIES += libomx_aacdec_sharedlibrary +LOCAL_SHARED_LIBRARIES += libaudioalsa + +LOCAL_SRC_FILES := test/omx_aac_dec_test.c + +include $(BUILD_EXECUTABLE) +endif + +endif #BUILD_WITHOUT_PV +endif #BUILD_TINY_ANDROID + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c b/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c new file mode 100644 index 000000000..e591cdda6 --- /dev/null +++ b/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c @@ -0,0 +1,1302 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" + + +#ifdef AUDIOV2 +#include "control.h" +#endif +#include "pthread.h" +#include + +#include +#include +#include +#define SAMPLE_RATE 16000 +#define STEREO 2 +uint32_t samplerate = 16000; +uint32_t channels = 2; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t filewrite = 0; +uint32_t configbufsize = 0; +uint32_t sbr_ps_enabled = 0; //if 0, then both not enabled. if 1 only sbr enabled, if 2 both enabled. +#define DEBUG_PRINT printf +uint32_t flushinprogress = 0; +uint32_t bsac = 0; +int start_done = 0; + +#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/ + + int m_pcmdrv_fd; + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +pthread_mutex_t lock; +pthread_cond_t cond; +pthread_mutex_t elock; +pthread_cond_t econd; +pthread_mutex_t lock1; +pthread_mutexattr_t lock1_attr; +pthread_cond_t fcond; +pthread_mutex_t etb_lock; +pthread_mutex_t etb_lock1; +pthread_cond_t etb_cond; +pthread_mutexattr_t etb_lock_attr; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; +OMX_AUDIO_PARAM_AACPROFILETYPE aacparam; +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; +OMX_PORT_PARAM_TYPE portParam; +OMX_ERRORTYPE error; +int bReconfigureOutputPort = 0; + + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +static int bFileclose = 0; + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +static unsigned totaldatalen = 0; +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +volatile int etb_event_is_done = 0; +int ebd_cnt; +int bOutputEosReached = 0; +int bInputEosReached = 0; +int bEosOnInputBuf = 0; +int bEosOnOutputBuf = 0; +static int etb_done = 0; +#ifdef AUDIOV2 +unsigned short session_id; +unsigned short session_id_hpcm; +int device_id; +int control = 0; +const char *device="speaker_stereo_rx"; +int devmgr_fd; +#endif +int bFlushing = false; +int bPause = false; +const char *in_filename; +const char out_filename[512]; + + +OMX_U8* pBuffer_tmp = NULL; + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* aac_dec_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Decoder(char*); +int Play_Decoder(); +void process_portreconfig(); +OMX_STRING aud_comp; + +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *aac_dec_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +static void write_devctlcmd(int fd, const void *buf, int param); + +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock1); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock1); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock1); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock1); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock1); +} + + + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + + int bufCnt=0; + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + + switch(eEvent) { + case OMX_EventCmdComplete: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventCmdComplete \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("Recieved DISABLE Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("******************************************\n"); + } + else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved ENABLE Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("*********************************************\n"); + } + else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved FLUSH Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("*********************************************\n"); + } + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventError \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("\n OMX_ErrorInvalidState \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(aac_dec_handle, 0, pInputBufHdrs[bufCnt]); + } + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(aac_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Deinitialized \n"); + DEBUG_PRINT("*********************************************\n"); + exit(0); + } + else if(OMX_ErrorComponentSuspended == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Received Suspend Event \n"); + DEBUG_PRINT("*********************************************\n"); + } + break; + + + case OMX_EventPortSettingsChanged: + bReconfigureOutputPort = 1; + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + DEBUG_PRINT("*********************************************\n"); + event_complete(); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("\n *********************************************\n"); + DEBUG_PRINT("\n OMX_EventBufferFlag \n"); + DEBUG_PRINT("\n *********************************************\n"); + + bOutputEosReached = true; + + event_complete(); + break; + + case OMX_EventComponentResumed: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Received Suspend Event \n"); + DEBUG_PRINT("*********************************************\n"); + break; + + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + unsigned int i=0; + int bytes_writen = 0; + static int count = 0; + static int copy_done = 0; + static int length_filled = 0; + static int spill_length = 0; + static int pcm_buf_size = 4800; + static unsigned int pcm_buf_count = 2; + struct msm_audio_config drv_pcm_config; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(flushinprogress == 1) + { + DEBUG_PRINT(" FillBufferDone: flush is in progress so hold the buffers\n"); + return OMX_ErrorNone; + } + if(count == 0 && pcmplayback) + { + DEBUG_PRINT(" open pcm device \n"); + m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR); + if (m_pcmdrv_fd < 0) + { + DEBUG_PRINT("Cannot open audio device\n"); + return -1; + } + else + { + DEBUG_PRINT("Open pcm device successfull\n"); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + drv_pcm_config.sample_rate = samplerate; //SAMPLE_RATE; //m_adec_param.nSampleRate; + drv_pcm_config.channel_count = channels; /* 1-> mono 2-> stereo*/ + ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + pcm_buf_size = drv_pcm_config.buffer_size; + pcm_buf_count = drv_pcm_config.buffer_count; +#ifdef AUDIOV2 + ioctl(m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &session_id_hpcm); + DEBUG_PRINT("session id 0x%x \n", session_id_hpcm); + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id_hpcm); + } + else + { + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + device_id = 2; + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + if (msm_route_stream(1, session_id_hpcm,device_id, 1)) + { + DEBUG_PRINT("could not set stream routing\n"); + return -1; + } + } +#endif + } + pBuffer_tmp= (OMX_U8*)malloc(pcm_buf_count*sizeof(OMX_U8)*pcm_buf_size); + if (pBuffer_tmp == NULL) + { + return -1; + } + else + { + memset(pBuffer_tmp, 0, pcm_buf_count*pcm_buf_size); + } + } + DEBUG_PRINT(" FillBufferDone #%d size %lu\n", count++,pBuffer->nFilledLen); + if(bEosOnOutputBuf) + return OMX_ErrorNone; + if(filewrite == 1) + { + bytes_writen = + fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,outputBufferFile); + DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen); + totaldatalen += bytes_writen ; + } + +#ifdef PCM_PLAYBACK + if(pcmplayback && pBuffer->nFilledLen) + { + if(start_done == 0) + { + if((length_filled+pBuffer->nFilledLen)>=(pcm_buf_count*pcm_buf_size)) + { + spill_length = (pBuffer->nFilledLen-(pcm_buf_count*pcm_buf_size)+length_filled); + memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, ((pcm_buf_count*pcm_buf_size)-length_filled)); + + length_filled = (pcm_buf_count*pcm_buf_size); + copy_done = 1; + } + else + { + memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, pBuffer->nFilledLen); + length_filled +=pBuffer->nFilledLen; + } + if (copy_done == 1) + { + for (i=0; ipBuffer+((pBuffer->nFilledLen)-spill_length), spill_length) != spill_length) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return -1; + } + } + + copy_done = 0; + start_done = 1; + + } + } + else + { + if (write(m_pcmdrv_fd, pBuffer->pBuffer, pBuffer->nFilledLen ) != + (ssize_t)pBuffer->nFilledLen) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return OMX_ErrorNone; + } + } + DEBUG_PRINT(" FillBufferDone: writing data to pcm device for play succesfull \n"); + } +#endif // PCM_PLAYBACK + + + if(pBuffer->nFlags != OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT(" FBD calling FTB"); + OMX_FillThisBuffer(hComponent,pBuffer); + } + else + { + DEBUG_PRINT(" FBD EOS REACHED...........\n"); + bEosOnOutputBuf = true; + + } + return OMX_ErrorNone; + +} + + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + DEBUG_PRINT("\nFunction %s cnt[%d], used_ip_buf_cnt[%d]\n", __FUNCTION__, ebd_cnt,used_ip_buf_cnt); + DEBUG_PRINT("\nFunction %s %p %lu\n", __FUNCTION__, pBuffer,pBuffer->nFilledLen); + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock); + } + + + if(bEosOnInputBuf) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + }else if (bFlushing == true) { + DEBUG_PRINT("omx_aac_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (used_ip_buf_cnt == 0) { + //fseek(inputBufferFile, 0, 0); + bFlushing = false; + } else { + DEBUG_PRINT("omx_aac_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + return OMX_ErrorNone; + } + } + + if((readBytes = Read_Buffer(pBuffer)) > 0) { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else{ + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + //bInputEosReached = true; + bEosOnInputBuf = true; + pBuffer->nFilledLen = 0; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) { + + /* Flush */ + + + if (sig_id == SIGUSR1) { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(aac_dec_handle, OMX_CommandFlush, OMX_ALL, NULL); + } else if (sig_id == SIGUSR2) { + if (bPause == true) { + DEBUG_PRINT("%s resume playback\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } else { + DEBUG_PRINT("%s pause playback\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + struct sigaction sa; + + + struct wav_header hdr; + int bytes_writen = 0; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + pthread_mutexattr_init(&lock1_attr); + pthread_mutex_init(&lock1, &lock1_attr); + + if (argc >= 6) { + in_filename = argv[1]; + samplerate = atoi(argv[2]); + channels = atoi(argv[3]); + pcmplayback = atoi(argv[4]); + filewrite = atoi(argv[5]); + strlcpy((char *)out_filename,argv[1],sizeof((char *)out_filename)); + strlcat((char *)out_filename,".wav",sizeof((char *)out_filename)); + } else { + + DEBUG_PRINT(" invalid format: \n"); + DEBUG_PRINT("ex: ./sw-adec-omxaac-test AACINPUTFILE SAMPFREQ CHANNEL PCMPLAYBACK FILEWRITE\n"); + DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + return 0; + } + + aud_comp = "OMX.PV.aacdec"; + + if(Init_Decoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + if(Play_Decoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + + printf("before wait_for_event\n"); + if(bReconfigureOutputPort) + { + wait_for_event(); + } + if(bOutputEosReached) { + + /******************************************************************/ + #ifdef PCM_PLAYBACK + if(pcmplayback == 1) + { + sleep(1); + ioctl(m_pcmdrv_fd, AUDIO_STOP, 0); + +#ifdef AUDIOV2 + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id_hpcm); + } + else + { + if (msm_route_stream(1, session_id_hpcm, device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + } + } +#endif + if(m_pcmdrv_fd >= 0) { + close(m_pcmdrv_fd); + m_pcmdrv_fd = -1; + DEBUG_PRINT(" PCM device closed succesfully \n"); + } + else + { + DEBUG_PRINT(" PCM device close failure \n"); + } + } + #endif // PCM_PLAYBACK + + if(filewrite == 1) + { + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = channels;//2; + hdr.sample_rate = samplerate; //SAMPLE_RATE; //44100; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",totaldatalen); + hdr.data_sz = totaldatalen; + hdr.riff_sz = totaldatalen + 8 + 16 + 8; + fseek(outputBufferFile, 0L , SEEK_SET); + bytes_writen = fwrite(&hdr,1,sizeof(hdr),outputBufferFile); + if (bytes_writen <= 0) { + DEBUG_PRINT("Invalid Wav header write failed\n"); + } + bFileclose = 1; + fclose(outputBufferFile); + } + /************************************************************************************/ + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + DEBUG_PRINT("\nMoving the decoder to loaded state \n"); + OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(aac_dec_handle, 0, pInputBufHdrs[bufCnt]); + } + + DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(aac_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + ebd_cnt=0; + wait_for_event(); + ebd_cnt=0; + bOutputEosReached = false; + bInputEosReached = false; + bEosOnInputBuf = 0; + bEosOnOutputBuf = 0; + result = OMX_FreeHandle(aac_dec_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + aac_dec_handle = NULL; +#ifdef AUDIOV2 + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id); + close(devmgr_fd); + } + else + { + if (msm_route_stream(1,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + } +#endif + /* Deinit OpenMAX */ + + OMX_Deinit(); + + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + pthread_cond_destroy(&etb_cond); + pthread_mutex_destroy(&etb_lock); + pthread_mutex_destroy(&etb_lock1); + etb_done = 0; + bReconfigureOutputPort = 0; + if (pBuffer_tmp) + { + free(pBuffer_tmp); + pBuffer_tmp =NULL; + } + + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + return 0; +} + +int Init_Decoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + typedef OMX_U8* OMX_U8_PTR; + char *role ="audio_decoder.aac"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Aac_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total); + + + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&aac_dec_handle), + (OMX_STRING)audio_component, NULL, &call_back); + if (FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component); + return -1; + } + else + { + DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(portParam); + omxresult = OMX_GetParameter(aac_dec_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&portParam); + + if(FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to get Port Param\n"); + return -1; + } + else + { + DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts); + DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n", + portParam.nStartPortNumber); + } + return 0; +} + +int Play_Decoder() +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file()) { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + + /* Configuration of Input Port definition */ + + /* Query the decoder input min buf requirements */ + CONFIG_VERSION_SIZE(inputportFmt); + + /* Port for which the Client needs to obtain info */ + inputportFmt.nPortIndex = portParam.nStartPortNumber; + + OMX_GetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt); + DEBUG_PRINT ("\nDec: Input Buffer Count %lu\n", inputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nDec: Input Buffer Size %lu\n", inputportFmt.nBufferSize); + + if(OMX_DirInput != inputportFmt.eDir) { + DEBUG_PRINT ("\nDec: Expect Input Port\n"); + return -1; + } + + inputportFmt.nBufferCountActual = inputportFmt.nBufferCountMin + 5; + OMX_SetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt); + OMX_GetExtensionIndex(aac_dec_handle,"OMX.Qualcomm.index.audio.sessionId",&index); + OMX_GetParameter(aac_dec_handle,index,&streaminfoparam); +#ifdef AUDIOV2 + session_id = streaminfoparam.sessionId; + devmgr_fd = open("/data/omx_devmgr", O_WRONLY); + if(devmgr_fd >= 0) + { + control = 0; + write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id); + } + else + { + /*control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + device_id = 2; + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + + if (msm_route_stream(1,session_id,device_id, 1)) + { + perror("could not set stream routing\n"); + return -1; + } + */ + } +#endif + /* Configuration of Ouput Port definition */ + + /* Query the decoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nDec: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nDec: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) { + DEBUG_PRINT ("\nDec: Expect Output Port\n"); + return -1; + } + + outputportFmt.nBufferCountActual = outputportFmt.nBufferCountMin + 3; + OMX_SetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt); + + CONFIG_VERSION_SIZE(aacparam); + aacparam.nPortIndex = 0; + aacparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/ + aacparam.nBitRate = samplerate; //SAMPLE_RATE; + aacparam.nSampleRate = samplerate; //SAMPLE_RATE; + aacparam.eChannelMode = OMX_AUDIO_ChannelModeStereo; + if (sbr_ps_enabled == 0 ) + aacparam.eAACProfile = OMX_AUDIO_AACObjectLC; + else if (sbr_ps_enabled == 1 ) + aacparam.eAACProfile = OMX_AUDIO_AACObjectHE; + else if (sbr_ps_enabled == 2 ) + aacparam.eAACProfile = OMX_AUDIO_AACObjectHE_PS; + aacparam.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP2ADTS; + OMX_SetParameter(aac_dec_handle,OMX_IndexParamAudioAac,&aacparam); + + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n"); + OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + + input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(aac_dec_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + + output_buf_cnt = outputportFmt.nBufferCountActual; // outputportFmt.nBufferCountMin ; + + /* Allocate buffer on decoder's O/Pp port */ + error = Allocate_Buffer(aac_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n"); + OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags = 0; + ret = OMX_FillThisBuffer(aac_dec_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) { + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + //bInputEosReached = true; + bEosOnInputBuf = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + ret = OMX_EmptyThisBuffer(aac_dec_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock); + if(etb_done) + { + DEBUG_PRINT("Component is waiting for EBD to be released.\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock); + while(1) + { + wait_for_event(); + if(bOutputEosReached) + { + bReconfigureOutputPort = 0; + printf("bOutputEosReached breaking\n"); + break; + } + else + { + if(bReconfigureOutputPort) + process_portreconfig(); + } + } + return 0; +} + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_dec_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + /* To remove warning for unused variable to keep prototype same */ + (void)avc_dec_handle; + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(aac_dec_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + int bytes_read=0; + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT("\n Length : %lu, buffer address : %p\n", pBufHdr->nAllocLen, pBufHdr->pBuffer); + if(bsac && configbufsize) + { + bytes_read = fread(pBufHdr->pBuffer, 1, configbufsize, inputBufferFile); + configbufsize = 0; + bsac = 0; + } + else + { + bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile); + } + pBufHdr->nFilledLen = bytes_read; + if(bytes_read == 0) + { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read is Non zero=%d\n",bytes_read); + } + return bytes_read;; +} + + +static int open_audio_file () +{ + int error_code = 0; + struct wav_header hdr; + int header_len = 0; + memset(&hdr,0,sizeof(hdr)); + + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = channels;//2; + hdr.sample_rate = samplerate; //SAMPLE_RATE; //44100; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("Inside %s filename=%s -->%s\n", __FUNCTION__, in_filename,out_filename); + inputBufferFile = fopen (in_filename, "rb"); + DEBUG_PRINT("\n FILE DESCRIPTOR : %p\n", inputBufferFile ); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + } + + if(filewrite == 1) + { + DEBUG_PRINT("output file is opened\n"); + outputBufferFile = fopen(out_filename,"wb"); + if (outputBufferFile == NULL) { + DEBUG_PRINT("\no/p file %s could NOT be opened\n", + out_filename); + error_code = -1; + return error_code; + } + header_len = fwrite(&hdr,1,sizeof(hdr),outputBufferFile); + if (header_len <= 0) { + DEBUG_PRINT("Invalid Wav header \n"); + } + DEBUG_PRINT(" Length og wav header is %d \n",header_len ); + } + return error_code; +} + +void process_portreconfig ( ) +{ + int bufCnt,i=0; + OMX_ERRORTYPE ret; + struct msm_audio_config drv_pcm_config; + //wait_for_event(); + DEBUG_PRINT("************************************"); + DEBUG_PRINT("RECIEVED EVENT PORT SETTINGS CHANGED EVENT\n"); + DEBUG_PRINT("******************************************\n"); + + // wait for port settings changed event + DEBUG_PRINT("************************************"); + DEBUG_PRINT("NOW SENDING FLUSH CMD\n"); + DEBUG_PRINT("******************************************\n"); + flushinprogress = 1; + OMX_SendCommand(aac_dec_handle, OMX_CommandFlush, 1, 0); + + wait_for_event(); + DEBUG_PRINT("************************************"); + DEBUG_PRINT("RECIEVED FLUSH EVENT CMPL\n"); + DEBUG_PRINT("******************************************\n"); + + // Send DISABLE command + OMX_SendCommand(aac_dec_handle, OMX_CommandPortDisable, 1, 0); + + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("FREEING BUFFERS output_buf_cnt=%d\n",output_buf_cnt); + DEBUG_PRINT("******************************************\n"); + // Free output Buffer + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(aac_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + + // wait for Disable event to come back + wait_for_event(); + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("DISABLE EVENT RECD\n"); + DEBUG_PRINT("******************************************\n"); + + // Send Enable command + OMX_SendCommand(aac_dec_handle, OMX_CommandPortEnable, 1, 0); + flushinprogress = 0; + // AllocateBuffers + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("ALLOC BUFFER AFTER PORT REENABLE"); + DEBUG_PRINT("******************************************\n"); + /* Allocate buffer on decoder's o/p port */ + error = Allocate_Buffer(aac_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error output_buf_cnt=%d\n",output_buf_cnt); + //return -1; + } + else + { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success output_buf_cnt=%d\n",output_buf_cnt); + } + + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("ENABLE EVENTiHANDLER RECD\n"); + DEBUG_PRINT("******************************************\n"); + // wait for enable event to come back + wait_for_event(); + DEBUG_PRINT(" Calling stop on pcm driver...\n"); + if(pcmplayback && start_done) + { + while (fsync(m_pcmdrv_fd) < 0) { + printf(" fsync failed\n"); + sleep(1); + } + ioctl(m_pcmdrv_fd, AUDIO_STOP, 0); + ioctl(m_pcmdrv_fd, AUDIO_FLUSH, 0); + sleep(3); + DEBUG_PRINT("AUDIO_STOP\n"); + OMX_GetParameter(aac_dec_handle,OMX_IndexParamAudioAac,&aacparam); + drv_pcm_config.sample_rate = aacparam.nSampleRate; + drv_pcm_config.channel_count = aacparam.nChannels; + printf("sample =%lu channel = %lu\n",aacparam.nSampleRate,aacparam.nChannels); + ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + start_done = 0; + bReconfigureOutputPort = 0; + } + + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("FTB after PORT RENABLE\n"); + DEBUG_PRINT("******************************************\n"); + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + //pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(aac_dec_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } +} + +static void write_devctlcmd(int fd, const void *buf, int param){ + int nbytes, nbytesWritten; + char cmdstr[128]; + snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param); + nbytes = strlen(cmdstr); + nbytesWritten = write(fd, cmdstr, nbytes); + + if(nbytes != nbytesWritten) + printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr); +} + diff --git a/mm-audio/adec-amr/Android.mk b/mm-audio/adec-amr/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/mm-audio/adec-amr/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/mm-audio/adec-amr/sw/Android.mk b/mm-audio/adec-amr/sw/Android.mk new file mode 100644 index 000000000..ffa9789d6 --- /dev/null +++ b/mm-audio/adec-amr/sw/Android.mk @@ -0,0 +1,59 @@ +ifneq ($(BUILD_TINY_ANDROID),true) +ifneq ($(BUILD_WITHOUT_PV),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxAmrDec-def := -g -O3 +libOmxAmrDec-def += -DQC_MODIFIED +libOmxAmrDec-def += -D_ANDROID_ +libOmxAmrDec-def += -D_ENABLE_QC_MSG_LOG_ +libOmxAmrDec-def += -DVERBOSE +libOmxAmrDec-def += -D_DEBUG +libOmxAmrDec-def += -DAUDIOV2 + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +libOmxAmrDec-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-adec-omxamr-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +mm-amr-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \ + $(PV_TOP)/codecs_v2/omx/omx_common/include \ + $(PV_TOP)/extern_libs_v2/khronos/openmax/include \ + $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \ + $(PV_TOP)/codecs_v2/omx/omx_amr/include \ + $(PV_TOP)/codecs_v2/audio/amr/dec/include \ + +LOCAL_MODULE := sw-adec-omxamr-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAmrDec-def) +LOCAL_C_INCLUDES := $(mm-amr-dec-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libopencore_common +LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary +LOCAL_SHARED_LIBRARIES += libomx_amrdec_sharedlibrary +LOCAL_SHARED_LIBRARIES += libaudioalsa + +LOCAL_SRC_FILES := test/omx_amr_dec_test.c + +include $(BUILD_EXECUTABLE) +endif + +endif #BUILD_WITHOUT_PV +endif #BUILD_TINY_ANDROID + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c b/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c new file mode 100644 index 000000000..2ce789636 --- /dev/null +++ b/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c @@ -0,0 +1,1297 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SAMPLE_RATE 8000 +#define STEREO 2 +uint32_t samplerate = 8000; +uint32_t channels = 1; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t filewrite = 0; +#ifdef _DEBUG + +#define DEBUG_PRINT(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \ + printf(args) + +#define DEBUG_PRINT_ERROR(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \ + printf(args) + +#else + +#define DEBUG_PRINT +#define DEBUG_PRINT_ERROR + +#endif + +#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/ +int m_pcmdrv_fd; + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +/* From WmfDecBytesPerFrame in dec_input_format_tab.cpp */ +const int sizes[] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0 }; + +pthread_mutex_t lock; +pthread_mutex_t lock1; +pthread_mutexattr_t lock1_attr; +pthread_mutex_t etb_lock1; +pthread_mutex_t etb_lock; +pthread_cond_t etb_cond; + +pthread_cond_t cond; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; +OMX_AUDIO_PARAM_AMRTYPE amrparam; +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; +OMX_PORT_PARAM_TYPE portParam; +OMX_ERRORTYPE error; +OMX_U8* pBuffer_tmp = NULL; + + +/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */ + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +static int bFileclose = 0; + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +static unsigned totaldatalen = 0; + +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +int ebd_cnt; +int bOutputEosReached = 0; +int bInputEosReached = 0; +int bEosOnInputBuf = 0; +int bEosOnOutputBuf = 0; +#ifdef AUDIOV2 +unsigned short session_id; +unsigned short session_id_hpcm; +int device_id; +int control = 0; +//const char *device="handset_rx"; +const char *device="speaker_stereo_rx"; +int devmgr_fd; +#endif +static int etb_done = 0; +static int etb_event_is_done = 0; + +OMX_AUDIO_AMRFRAMEFORMATTYPE frameFormat = 0; +int bFlushing = false; +int bPause = false; +const char *in_filename; +const char out_filename[512]; +int chunksize =0; + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* amr_dec_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Decoder(OMX_STRING audio_component); +int Play_Decoder(); + +OMX_STRING aud_comp; + +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *amr_dec_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +static void write_devctlcmd(int fd, const void *buf, int param); + +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock); +} + + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + int bufCnt=0; + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + + switch(eEvent) + { + case OMX_EventCmdComplete: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventCmdComplete \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("Recieved DISABLE Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("******************************************\n"); + } + else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved ENABLE Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("*********************************************\n"); + } + else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved FLUSH Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("*********************************************\n"); + } + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventError \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("\n OMX_ErrorInvalidState \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(amr_dec_handle, 0, pInputBufHdrs[bufCnt]); + } + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(amr_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Deinitialized \n"); + DEBUG_PRINT("*********************************************\n"); + exit(0); + } + else if(OMX_ErrorComponentSuspended == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Received Suspend Event \n"); + DEBUG_PRINT("*********************************************\n"); + } + break; + + case OMX_EventPortSettingsChanged: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + DEBUG_PRINT("*********************************************\n"); + event_complete(); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_Bufferflag \n"); + DEBUG_PRINT("*********************************************\n"); + bOutputEosReached = true; + event_complete(); + break; + case OMX_EventComponentResumed: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Received Suspend Event \n"); + DEBUG_PRINT("*********************************************\n"); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + unsigned int i=0; + int bytes_writen = 0; + static int count = 0; + static int copy_done = 0; + static int start_done = 0; + static int length_filled = 0; + static int spill_length = 0; + static int pcm_buf_size = 4800; + static unsigned int pcm_buf_count = 2; + struct msm_audio_config drv_pcm_config; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(count == 0 && pcmplayback) + { + DEBUG_PRINT(" open pcm device \n"); + m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR); + if (m_pcmdrv_fd < 0) + { + DEBUG_PRINT("Cannot open audio device\n"); + return -1; + } + else + { + DEBUG_PRINT("Open pcm device successfull\n"); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + drv_pcm_config.sample_rate = samplerate; //SAMPLE_RATE; //m_adec_param.nSampleRate; + drv_pcm_config.channel_count = channels; /* 1-> mono 2-> stereo*/ + ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + pcm_buf_size = drv_pcm_config.buffer_size; + pcm_buf_count = drv_pcm_config.buffer_count; +#ifdef AUDIOV2 + ioctl(m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &session_id_hpcm); + DEBUG_PRINT("session id 0x%4x \n", session_id_hpcm); + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id_hpcm); + } + else + { + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + + if (msm_route_stream(1, session_id_hpcm,device_id, 1)) + { + DEBUG_PRINT("could not set stream routing\n"); + return -1; + } + } +#endif + } + pBuffer_tmp= (OMX_U8*)malloc(pcm_buf_count*sizeof(OMX_U8)*pcm_buf_size); + if (pBuffer_tmp == NULL) + { + return -1; + } + else + { + memset(pBuffer_tmp, 0, pcm_buf_count*pcm_buf_size); + } + } + DEBUG_PRINT(" FillBufferDone #%d size %lu\n", count++,pBuffer->nFilledLen); + + if(bEosOnOutputBuf) + { + return OMX_ErrorNone; + } + + if(filewrite == 1) + { + bytes_writen = + fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,outputBufferFile); + DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen); + totaldatalen += bytes_writen ; + } + +#ifdef PCM_PLAYBACK + if(pcmplayback && pBuffer->nFilledLen) + { + if(start_done == 0) + { + if((length_filled+pBuffer->nFilledLen)>=(pcm_buf_count*pcm_buf_size)) + { + spill_length = (pBuffer->nFilledLen-(pcm_buf_count*pcm_buf_size)+length_filled); + memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, ((pcm_buf_count*pcm_buf_size)-length_filled)); + length_filled = (pcm_buf_count*pcm_buf_size); + copy_done = 1; + } + else + { + memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, pBuffer->nFilledLen); + length_filled +=pBuffer->nFilledLen; + } + if (copy_done == 1) + { + for (i=0; ipBuffer+((pBuffer->nFilledLen)-spill_length), spill_length) != spill_length) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return -1; + } + } + if (pBuffer_tmp) + { + free(pBuffer_tmp); + pBuffer_tmp =NULL; + } + copy_done = 0; + start_done = 1; + } + } + else + { + if (write(m_pcmdrv_fd, pBuffer->pBuffer, pBuffer->nFilledLen ) != + (ssize_t)pBuffer->nFilledLen) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return OMX_ErrorNone; + } + } + + DEBUG_PRINT(" FillBufferDone: writing data to pcm device for play succesfull \n"); + } +#endif // PCM_PLAYBACK + + + if(pBuffer->nFlags != OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT(" FBD calling FTB"); + OMX_FillThisBuffer(hComponent,pBuffer); + } + else + { + DEBUG_PRINT(" FBD EOS REACHED...........\n"); + bEosOnOutputBuf = true; + return OMX_ErrorNone; + } + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + DEBUG_PRINT("\nFunction %s cnt[%d]\n", __FUNCTION__, ebd_cnt); + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock1); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock1); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock1); + } + if(bEosOnInputBuf) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + } + else if (true == bFlushing) + { + DEBUG_PRINT("omx_amr_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (0 == used_ip_buf_cnt) + { + //fseek(inputBufferFile, 0, 0); + bFlushing = false; + } + else + { + DEBUG_PRINT("omx_amr_adec_test: more buffer to come back\n"); + return OMX_ErrorNone; + } + } + if((readBytes = Read_Buffer(pBuffer)) > 0) + { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + DEBUG_PRINT("pBuffer->nFilledLen = %d,used_ip_buf_cnt:%d\n", readBytes,used_ip_buf_cnt); + timeStampLfile += timestampInterval; + pBuffer->nTimeStamp = timeStampLfile; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else + { + DEBUG_PRINT("OMX_BUFFERFLAG_EOS\n"); + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + bEosOnInputBuf = true; + pBuffer->nFilledLen = 0; + timeStampLfile += timestampInterval; + pBuffer->nTimeStamp = timeStampLfile; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) { + + /* Flush */ + if (sig_id == SIGUSR1) { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(amr_dec_handle, OMX_CommandFlush, OMX_ALL, NULL); + } else if (sig_id == SIGUSR2) { + if (bPause == true) { + DEBUG_PRINT("%s resume playback\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } else { + DEBUG_PRINT("%s pause playback\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + struct sigaction sa; + + + struct wav_header hdr; + int bytes_writen = 0; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + + pthread_mutexattr_init(&lock1_attr); + pthread_mutex_init(&lock1, &lock1_attr); + + if (argc >= 7) + { + in_filename = argv[1]; + DEBUG_PRINT("argv[1]- file name = %s\n", argv[1]); + samplerate = atoi(argv[2]); + DEBUG_PRINT("argv[2]- sample rate = %d\n", samplerate); + channels = atoi(argv[3]); + DEBUG_PRINT("argv[3]- channels = %d\n", channels); + pcmplayback = atoi(argv[4]); + DEBUG_PRINT("argv[4]- PCM play y/n = %d\n", pcmplayback); + filewrite = atoi(argv[5]); + frameFormat = atoi(argv[6]); + DEBUG_PRINT("argv[7]- frameFormat = %d\n", frameFormat); + strlcpy((char *)out_filename,argv[1],sizeof((char *)out_filename)); + strlcat((char *)out_filename,".wav",sizeof((char *)out_filename)); + + } + else + { + DEBUG_PRINT("invalid format: ex: "); + DEBUG_PRINT("ex: ./sw-adec-omxamr-test AMRINPUTFILE SAMPFREQ CHANNEL\n"); + DEBUG_PRINT("PCMPLAYBACK FILEWRITE FRAMEFORMAT\n"); + DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT("FRAMEFORMAT = 1 (IF1 format) \n"); + DEBUG_PRINT("FRAMEFORMAT = 2 (IF2 format) \n"); + DEBUG_PRINT("FRAMEFORMAT = 3 (FSF format) \n"); + DEBUG_PRINT("FRAMEFORMAT = 4 (RTP format) \n"); + + return 0; + } + aud_comp = "OMX.PV.amrdec"; + + DEBUG_PRINT(" OMX test app : aud_comp = %s\n",aud_comp); + + if(Init_Decoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + if(Play_Decoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + wait_for_event(); + + DEBUG_PRINT("\nAfter wait event .....\n"); + if(bOutputEosReached) + { +#ifdef PCM_PLAYBACK + if(1 == pcmplayback) + { + sleep(1); + ioctl(m_pcmdrv_fd, AUDIO_STOP, 0); +#ifdef AUDIOV2 + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id_hpcm); + } + else + { + if (msm_route_stream(1, session_id_hpcm, device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + } + } +#endif + if(m_pcmdrv_fd >= 0) + { + close(m_pcmdrv_fd); + m_pcmdrv_fd = -1; + DEBUG_PRINT(" PCM device closed succesfully \n"); + } + else + { + DEBUG_PRINT(" PCM device close failure \n"); + } + } +#endif // PCM_PLAYBACK + + if(1 == filewrite) + { + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = channels;//2; + hdr.sample_rate = samplerate; //SAMPLE_RATE; //44100; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",totaldatalen); + hdr.data_sz = totaldatalen; + hdr.riff_sz = totaldatalen + 8 + 16 + 8; + fseek(outputBufferFile, 0L , SEEK_SET); + bytes_writen = fwrite(&hdr,1,sizeof(hdr),outputBufferFile); + if (bytes_writen <= 0) + { + DEBUG_PRINT("Invalid Wav header write failed\n"); + } + bFileclose = 1; + fclose(outputBufferFile); + } + /************************************************************************************/ + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + + DEBUG_PRINT("\nMoving the decoder to loaded state \n"); + OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(amr_dec_handle, 0, pInputBufHdrs[bufCnt]); + } + + DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(amr_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + + ebd_cnt=0; + wait_for_event(); + ebd_cnt=0; + result = OMX_FreeHandle(amr_dec_handle); + if (result != OMX_ErrorNone) + { + DEBUG_PRINT("\nOMX_FreeHandle error. Error code: %d\n", result); + } +#ifdef AUDIOV2 + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id); + close(devmgr_fd); + } + else + { + if (msm_route_stream(1,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + } +#endif + + /* Deinit OpenMAX */ + OMX_Deinit(); + fclose(inputBufferFile); + timeStampLfile = 0; + amr_dec_handle = NULL; + bInputEosReached = false; + bOutputEosReached = false; + bEosOnInputBuf = 0; + bEosOnOutputBuf = 0; + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + pthread_mutexattr_destroy(&lock1_attr); + pthread_mutex_destroy(&lock1); + pthread_mutex_destroy(&etb_lock1); + pthread_cond_destroy(&etb_cond); + pthread_mutex_destroy(&etb_lock); + etb_done = 0; + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + + DEBUG_PRINT("\nClosing Session\n"); + return 0; +} + +int Init_Decoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0,total1 = 0; + unsigned int i = 0; + OMX_U8** audCompNames; + typedef OMX_U8* OMX_U8_PTR; + OMX_STRING role ="audio_decoder.amrnb"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + DEBUG_PRINT("Inside Play_Decoder - samplerate = %d\n", samplerate); + DEBUG_PRINT("Inside Play_Decoder - channels = %d\n", channels); + DEBUG_PRINT("Inside Play_Decoder - pcmplayback = %d\n", pcmplayback); + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + char* audiocomponent ="OMX.PV.amrdec"; + int componentfound = false; + /* Query for audio decoders*/ + DEBUG_PRINT("Amr_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT("\nTotal components of role=%s :%lu", role, total); + + if(total) + { + DEBUG_PRINT("Total number of components = %lu\n", total); + /* Allocate memory for pointers to component name */ + audCompNames = (OMX_U8**)malloc((sizeof(OMX_U8))*total); + + if(NULL == audCompNames) + { + return -1; + } + + for (i = 0; i < total; ++i) + { + audCompNames[i] = + (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_MAX_STRINGNAME_SIZE); + if(NULL == audCompNames[i] ) + { + while (i > 0) + { + free(audCompNames[--i]); + } + free(audCompNames); + return -1; + } + memset(&audCompNames[i],0,sizeof(audCompNames[i])); + } + total1 = total; + DEBUG_PRINT("Before calling OMX_GetComponentsOfRole()\n"); + OMX_GetComponentsOfRole(role, &total, audCompNames); + DEBUG_PRINT("\nComponents of Role:%s\n", role); + for (i = 0; i < total; ++i) + { + if(i= 0) + { + control = 0; + write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id); + } +#endif + /* Query the decoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(amr_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nDec: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nDec: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) { + DEBUG_PRINT ("\nDec: Expect Output Port\n"); + return -1; + } + // Modified to Set the Actual Buffer Count for output port + outputportFmt.nBufferCountActual = outputportFmt.nBufferCountMin + 1; + OMX_SetParameter(amr_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt); + + CONFIG_VERSION_SIZE(amrparam); + + OMX_GetParameter(amr_dec_handle,OMX_IndexParamAudioAmr,&amrparam); + amrparam.nPortIndex = 0; + amrparam.nChannels = 1; //2 ; /* 1-> mono 2-> stereo*/ + amrparam.nBitRate = 8000; //SAMPLE_RATE; + amrparam.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; //default mode + if (frameFormat == 1) + { + amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatIF1; + } + else if (frameFormat == 2) + { + amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatIF2; + } + else if (frameFormat == 3) + { + amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; + } + else if (frameFormat == 4) + { + amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatRTPPayload; + } + OMX_SetParameter(amr_dec_handle,OMX_IndexParamAudioAmr,&amrparam); + + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n"); + OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + + input_buf_cnt = inputportFmt.nBufferCountMin + 3; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(amr_dec_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + + output_buf_cnt = outputportFmt.nBufferCountMin + 1 ; + + /* Allocate buffer on decoder's O/Pp port */ + error = Allocate_Buffer(amr_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n"); + OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(amr_dec_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) { + + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + bInputEosReached = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + timeStampLfile += timestampInterval; + pInputBufHdrs[i]->nTimeStamp = timeStampLfile; + ret = OMX_EmptyThisBuffer(amr_dec_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock1); + if(etb_done) + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("Component is waiting for EBD to be releases, BC signal\n"); + DEBUG_PRINT("\n****************************\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock1); + + return 0; +} + + + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_dec_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + + /* To remove warning for unused variable to keep prototype same */ + (void)avc_dec_handle; + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(amr_dec_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + + + + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + + int bytes_read=0; + static int totalbytes_read =0; + + DEBUG_PRINT ("\nInside Read_Buffer\n"); + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + + DEBUG_PRINT("AllocLen:%lu\n", pBufHdr->nAllocLen); + + bytes_read = fread(pBufHdr->pBuffer,1,pBufHdr->nAllocLen ,inputBufferFile); + + totalbytes_read += bytes_read; + DEBUG_PRINT ("bytes_read = %d\n",bytes_read); + DEBUG_PRINT ("totalbytes_read = %d\n",totalbytes_read); + pBufHdr->nFilledLen = bytes_read; + if( bytes_read <= 0) + { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read is Non zero\n"); + } + return bytes_read; +} + +static int open_audio_file () +{ + int error_code = 0; + struct wav_header hdr; + int header_len = 0; + memset(&hdr,0,sizeof(hdr)); + + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = channels; + hdr.sample_rate = samplerate; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); + inputBufferFile = fopen (in_filename, "rb"); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + return error_code; + } + DEBUG_PRINT("Setting the file pointer to the beginging of the byte"); + fseek(inputBufferFile, 0, SEEK_SET); + + if(filewrite == 1) + { + DEBUG_PRINT("output file is opened\n"); + + outputBufferFile = fopen(out_filename,"wb"); + if (outputBufferFile == NULL) + { + DEBUG_PRINT("\no/p file %s could NOT be opened\n", + out_filename); + error_code = -1; + return error_code; + } + + header_len = fwrite(&hdr,1,sizeof(hdr),outputBufferFile); + if (header_len <= 0) + { + DEBUG_PRINT("Invalid Wav header \n"); + } + DEBUG_PRINT(" Length og wav header is %d \n",header_len ); + } + return error_code; +} + +static void write_devctlcmd(int fd, const void *buf, int param){ + int nbytes, nbytesWritten; + char cmdstr[128]; + snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param); + nbytes = strlen(cmdstr); + nbytesWritten = write(fd, cmdstr, nbytes); + + if(nbytes != nbytesWritten) + printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr); +} + + + diff --git a/mm-audio/adec-amrwb/Android.mk b/mm-audio/adec-amrwb/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/mm-audio/adec-amrwb/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/mm-audio/adec-amrwb/sw/Android.mk b/mm-audio/adec-amrwb/sw/Android.mk new file mode 100644 index 000000000..5de1d9d3b --- /dev/null +++ b/mm-audio/adec-amrwb/sw/Android.mk @@ -0,0 +1,58 @@ +ifneq ($(BUILD_TINY_ANDROID),true) +ifneq ($(BUILD_WITHOUT_PV),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxAmrDec-def := -g -O3 +libOmxAmrDec-def += -DQC_MODIFIED +libOmxAmrDec-def += -D_ANDROID_ +libOmxAmrDec-def += -D_ENABLE_QC_MSG_LOG_ +libOmxAmrDec-def += -DVERBOSE +libOmxAmrDec-def += -D_DEBUG +libOmxAmrDec-def += -DAUDIOV2 + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +libOmxAmrDec-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the apps-test (sw-adec-omxamr-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +mm-amr-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \ + $(PV_TOP)/codecs_v2/omx/omx_common/include \ + $(PV_TOP)/extern_libs_v2/khronos/openmax/include \ + $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \ + $(PV_TOP)/codecs_v2/omx/omx_amr/include \ + $(PV_TOP)/codecs_v2/audio/amr/dec/include \ + +LOCAL_MODULE := sw-adec-omxamrwb-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAmrDec-def) +LOCAL_C_INCLUDES := $(mm-amr-dec-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libopencore_common +LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary +LOCAL_SHARED_LIBRARIES += libomx_amrdec_sharedlibrary +LOCAL_SHARED_LIBRARIES += libaudioalsa +LOCAL_SRC_FILES := test/omx_amrwb_dec_test.c + +include $(BUILD_EXECUTABLE) +endif + +endif #BUILD_WITHOUT_PV +endif #BUILD_TINY_ANDROID + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c b/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c new file mode 100644 index 000000000..5e9d7489d --- /dev/null +++ b/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c @@ -0,0 +1,1283 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef AUDIOV2 +#include "control.h" +#endif + +#ifdef AUDIOV2 +unsigned short session_id; +unsigned short session_id_hpcm; +int device_id; +int control = 0; +const char *device="handset_rx"; +int devmgr_fd; +#endif + +#include + +#define SAMPLE_RATE 8000 +#define STEREO 2 +uint32_t samplerate = 8000; +uint32_t channels = 1; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t filewrite = 0; + +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; + +int sf = 0; +int ch = 0; +int format = 0; + +#ifdef _DEBUG + +#define DEBUG_PRINT(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \ + printf(args) + +#define DEBUG_PRINT_ERROR(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \ + printf(args) + +#else + +#define DEBUG_PRINT +#define DEBUG_PRINT_ERROR + +#endif + + +#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/ + +int m_pcmdrv_fd; + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +pthread_mutex_t lock; +pthread_mutex_t lock1; +pthread_mutexattr_t lock1_attr; +pthread_mutex_t etb_lock1; +pthread_mutex_t etb_lock; +pthread_cond_t etb_cond; + +pthread_cond_t cond; +pthread_mutex_t elock; +pthread_cond_t econd; +pthread_cond_t fcond; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; + +OMX_AUDIO_PARAM_AMRTYPE amrparam; +QOMX_AUDIO_PARAM_AMRWBPLUSTYPE amrwbPlusparam; + +OMX_PORT_PARAM_TYPE portParam; +OMX_ERRORTYPE error; +OMX_U8* pBuffer_tmp = NULL; + +/* AMRWB specific macros */ + +//AMR-WB Number of channels +#define AMRWB_CHANNELS 1 + +//AMR-WB Sampling rate +#define AMRWB_SAMPLE_RATE 16000 + +//AMR-WB File Header size +#define AMRWB_FILE_HEADER_SIZE 9 + +/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */ + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +static int bFileclose = 0; + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +static unsigned totaldatalen = 0; + +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +int ebd_cnt; +int bOutputEosReached = 0; +int bInputEosReached = 0; +int bEosOnInputBuf = 0; +int bEosOnOutputBuf = 0; +static int etb_done = 0; +static int etb_event_is_done = 0; + +int bFlushing = false; +int bPause = false; +const char *in_filename; + + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* amrwb_dec_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Decoder(OMX_STRING audio_component); +int Play_Decoder(); + +OMX_STRING aud_comp; + +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *amrwb_dec_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static void write_devctlcmd(int fd, const void *buf, int param); + +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock); +} + + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + int bufCnt = 0; + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + + switch(eEvent) + { + case OMX_EventCmdComplete: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventCmdComplete \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("Recieved DISABLE Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("******************************************\n"); + } + else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved ENABLE Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("*********************************************\n"); + } + else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved FLUSH Event Command Complete[%lu]\n",nData2); + DEBUG_PRINT("*********************************************\n"); + } + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventError \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("\n OMX_ErrorInvalidState \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(amrwb_dec_handle, 0, pInputBufHdrs[bufCnt]); + } + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(amrwb_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Deinitialized \n"); + DEBUG_PRINT("*********************************************\n"); + exit(0); + } + break; + + case OMX_EventPortSettingsChanged: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + DEBUG_PRINT("*********************************************\n"); + event_complete(); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_Bufferflag \n"); + DEBUG_PRINT("*********************************************\n"); + bOutputEosReached = true; + event_complete(); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + unsigned int i=0; + int bytes_writen = 0; + static int count = 0; + static int copy_done = 0; + static int start_done = 0; + static int length_filled = 0; + static int spill_length = 0; + static int pcm_buf_size = 4800; + static unsigned int pcm_buf_count = 2; + struct msm_audio_config drv_pcm_config; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(count == 0 && pcmplayback) + { + DEBUG_PRINT(" open pcm device \n"); + m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR); + if (m_pcmdrv_fd < 0) + { + DEBUG_PRINT("Cannot open audio device\n"); + return -1; + } + else + { + DEBUG_PRINT("Open pcm device successfull\n"); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + drv_pcm_config.sample_rate = sf;//SAMPLE_RATE; //m_adec_param.nSampleRate; + drv_pcm_config.channel_count = ch;//channels; /* 1-> mono 2-> stereo*/ + ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + pcm_buf_size = drv_pcm_config.buffer_size; + pcm_buf_count = drv_pcm_config.buffer_count; +#ifdef AUDIOV2 + ioctl(m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &session_id_hpcm); + DEBUG_PRINT("session id 0x%4x \n", session_id_hpcm); + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id_hpcm); + } + else + { + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + if (msm_route_stream(1, session_id_hpcm,device_id, 1)) + { + DEBUG_PRINT("could not set stream routing\n"); + return -1; + } + } +#endif + } + pBuffer_tmp= (OMX_U8*)malloc(pcm_buf_count*sizeof(OMX_U8)*pcm_buf_size); + if (pBuffer_tmp == NULL) + { + return -1; + } + else + { + memset(pBuffer_tmp, 0, pcm_buf_count*pcm_buf_size); + } + } + DEBUG_PRINT(" FillBufferDone #%d size %lu\n", count++,pBuffer->nFilledLen); + + if(bEosOnOutputBuf) + return OMX_ErrorNone; + + if(filewrite == 1) + { + bytes_writen = + fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,outputBufferFile); + DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen); + totaldatalen += bytes_writen ; + } + +#ifdef PCM_PLAYBACK + if(pcmplayback && pBuffer->nFilledLen) + { + if(start_done == 0) + { + if((length_filled+pBuffer->nFilledLen)>=(pcm_buf_count*pcm_buf_size)) + { + spill_length = (pBuffer->nFilledLen-(pcm_buf_count*pcm_buf_size)+length_filled); + memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, ((pcm_buf_count*pcm_buf_size)-length_filled)); + length_filled = (pcm_buf_count*pcm_buf_size); + copy_done = 1; + } + else + { + memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, pBuffer->nFilledLen); + length_filled +=pBuffer->nFilledLen; + } + if (copy_done == 1) + { + for (i=0; ipBuffer+((pBuffer->nFilledLen)-spill_length), spill_length) != spill_length) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return -1; + } + } + if (pBuffer_tmp) + { + free(pBuffer_tmp); + pBuffer_tmp =NULL; + } + copy_done = 0; + start_done = 1; + } + } + else + { + if (write(m_pcmdrv_fd, pBuffer->pBuffer, pBuffer->nFilledLen ) != + (ssize_t)pBuffer->nFilledLen) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return OMX_ErrorNone; + } + } + + DEBUG_PRINT(" FillBufferDone: writing data to pcm device for play succesfull \n"); + } +#endif // PCM_PLAYBACK + + + if(pBuffer->nFlags != OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT(" FBD calling FTB"); + OMX_FillThisBuffer(hComponent,pBuffer); + } + else + { + DEBUG_PRINT(" FBD EOS REACHED...........\n"); + bEosOnOutputBuf = true; + return OMX_ErrorNone; + } + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + DEBUG_PRINT("\nFunction %s cnt[%d]\n", __FUNCTION__, ebd_cnt); + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock1); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock1); + DEBUG_PRINT("EBD: Before etb_wait_for_event.....\n"); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock1); + } + if(bEosOnInputBuf) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + } + else if (true == bFlushing) + { + DEBUG_PRINT("omx_amrwb_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (0 == used_ip_buf_cnt) + { + bFlushing = false; + } + else + { + DEBUG_PRINT("omx_amr_adec_test: more buffer to come back\n"); + return OMX_ErrorNone; + } + } + if((readBytes = Read_Buffer(pBuffer)) > 0) + { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + timeStampLfile += timestampInterval; + pBuffer->nTimeStamp = timeStampLfile; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else + { + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + bEosOnInputBuf = true; + pBuffer->nFilledLen = 0; + timeStampLfile += timestampInterval; + pBuffer->nTimeStamp = timeStampLfile; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) +{ + if (sig_id == SIGUSR1) + { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(amrwb_dec_handle, OMX_CommandFlush, OMX_ALL, NULL); + } + else if (sig_id == SIGUSR2) + { + if (bPause == true) + { + DEBUG_PRINT("%s resume playback\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } + else + { + DEBUG_PRINT("%s pause playback\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + struct sigaction sa; + struct wav_header hdr; + int bytes_writen = 0; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + + pthread_mutexattr_init(&lock1_attr); + pthread_mutex_init(&lock1, &lock1_attr); + + if (argc == 6) + { + in_filename = argv[1]; + DEBUG_PRINT("argv[1]- file name = %s\n", argv[1]); + pcmplayback = atoi(argv[2]); + DEBUG_PRINT("argv[2]- PCM play y/n = %d\n", pcmplayback); + filewrite = atoi(argv[3]); + sf = atoi(argv[4]); + ch = atoi(argv[5]); + } + else + { + DEBUG_PRINT("\ninvalid format\n"); + DEBUG_PRINT("ex: ./sw-adec-omxamrwb-test AMRINPUTFILE PCMPLAYBACK"); + DEBUG_PRINT("FILEWRITE SAMP-FREQ CHANNELS\n"); + DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "SAMPLING FREQUENCY:\n"); + DEBUG_PRINT( "CHANNELS = 1 (MONO)\n"); + DEBUG_PRINT( "CHANNELS = 2 (STEREO)\n"); + return 0; + } + + aud_comp = "OMX.PV.amrdec"; + + DEBUG_PRINT(" OMX test app : aud_comp = %s\n",aud_comp); + + if(Init_Decoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + if(Play_Decoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + wait_for_event(); + + if(bOutputEosReached) + { +#ifdef PCM_PLAYBACK + if(1 == pcmplayback) + { + sleep(1); + ioctl(m_pcmdrv_fd, AUDIO_STOP, 0); + +#ifdef AUDIOV2 + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id_hpcm); + } + else + { + if (msm_route_stream(1, session_id_hpcm, device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + } + } +#endif + if(m_pcmdrv_fd >= 0) + { + close(m_pcmdrv_fd); + m_pcmdrv_fd = -1; + DEBUG_PRINT(" PCM device closed succesfully \n"); + } + else + { + DEBUG_PRINT(" PCM device close failure \n"); + } + } +#endif // PCM_PLAYBACK + + if(1 == filewrite) + { + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = AMRWB_CHANNELS; + hdr.sample_rate = AMRWB_SAMPLE_RATE; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",totaldatalen); + hdr.data_sz = totaldatalen; + hdr.riff_sz = totaldatalen + 8 + 16 + 8; + fseek(outputBufferFile, 0L , SEEK_SET); + bytes_writen = fwrite(&hdr,1,sizeof(hdr),outputBufferFile); + if (bytes_writen <= 0) + { + DEBUG_PRINT("Invalid Wav header write failed\n"); + } + bFileclose = 1; + fclose(outputBufferFile); + } + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + + DEBUG_PRINT("\nMoving the decoder to loaded state \n"); + OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(amrwb_dec_handle, 0, pInputBufHdrs[bufCnt]); + } + + DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(amrwb_dec_handle, 1, pOutputBufHdrs[bufCnt]); + } + + ebd_cnt=0; + wait_for_event(); + ebd_cnt=0; + + result = OMX_FreeHandle(amrwb_dec_handle); + if (result != OMX_ErrorNone) + { + DEBUG_PRINT("\nOMX_FreeHandle error. Error code: %d\n", result); + } +#ifdef AUDIOV2 + if(devmgr_fd >= 0) + { + write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id); + close(devmgr_fd); + } + else + { + if (msm_route_stream(1,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + } +#endif + /* Deinit OpenMAX */ + OMX_Deinit(); + fclose(inputBufferFile); + timeStampLfile = 0; + amrwb_dec_handle = NULL; + bInputEosReached = false; + bOutputEosReached = false; + bEosOnInputBuf = 0; + bEosOnOutputBuf = 0; + pthread_cond_destroy(&cond); + pthread_cond_destroy(&etb_cond); + pthread_mutex_destroy(&lock); + pthread_mutexattr_destroy(&lock1_attr); + pthread_mutex_destroy(&lock1); + pthread_mutex_destroy(&etb_lock); + pthread_mutex_destroy(&etb_lock1); + etb_done = 0; + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + return 0; +} + +//int Init_Decoder() +int Init_Decoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + OMX_U8** audCompNames; + typedef OMX_U8* OMX_U8_PTR; + unsigned int i = 0; + OMX_STRING role ="audio_decoder.amrwb"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + DEBUG_PRINT(" Play_Decoder - pcmplayback = %d\n", pcmplayback); + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) + { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else + { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Amrwb_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT("\nTotal components of role=%s :%lu\n", role, total); + + if(total) + { + DEBUG_PRINT("Total number of components = %lu\n", total); + /* Allocate memory for pointers to component name */ + audCompNames = (OMX_U8**)malloc((sizeof(OMX_U8))*total); + + if(NULL == audCompNames) + { + return -1; + } + + for (i = 0; i < total; ++i) + { + audCompNames[i] = + (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_MAX_STRINGNAME_SIZE); + if(NULL == audCompNames[i] ) + { + while (i > 0) + { + free(audCompNames[--i]); + } + free(audCompNames); + return -1; + } + } + DEBUG_PRINT("Before calling OMX_GetComponentsOfRole()\n"); + OMX_GetComponentsOfRole(role, &total, audCompNames); + DEBUG_PRINT("\nComponents of Role:%s\n", role); + } + else + { + DEBUG_PRINT("No components found with Role:%s", role); + } + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&amrwb_dec_handle), + (OMX_STRING)audio_component, NULL, &call_back); + if (FAILED(omxresult)) + { + DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component); + for (i = 0; i < total; ++i) + free(audCompNames[i]); + free(audCompNames); + return -1; + } + else + { + DEBUG_PRINT("\nComponent is in LOADED state\n"); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(portParam); + omxresult = OMX_GetParameter(amrwb_dec_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&portParam); + + if(FAILED(omxresult)) + { + DEBUG_PRINT("\nFailed to get Port Param\n"); + for (i = 0; i < total; ++i) + free(audCompNames[i]); + free(audCompNames); + return -1; + } + else + { + DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts); + DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n", + portParam.nStartPortNumber); + } + for (i = 0; i < total; ++i) + free(audCompNames[i]); + free(audCompNames); + return 0; +} + +int Play_Decoder() +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file()) + { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + /* Query the decoder input min buf requirements */ + CONFIG_VERSION_SIZE(inputportFmt); + + /* Port for which the Client needs to obtain info */ + inputportFmt.nPortIndex = portParam.nStartPortNumber; + + OMX_GetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt); + DEBUG_PRINT ("\nDec: Input Buffer Count %lu\n", inputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nDec: Input Buffer Size %lu\n", inputportFmt.nBufferSize); + + if(OMX_DirInput != inputportFmt.eDir) + { + DEBUG_PRINT ("\nDec: Expect Input Port\n"); + return -1; + } +// Modified to Set the Actual Buffer Count for input port + inputportFmt.nBufferCountActual = inputportFmt.nBufferCountMin + 3; + OMX_SetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt); + + /* Query the decoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nDec: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nDec: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) + { + DEBUG_PRINT ("\nDec: Expect Output Port\n"); + return -1; + } + // Modified to Set the Actual Buffer Count for output port + outputportFmt.nBufferCountActual = outputportFmt.nBufferCountMin + 1; + OMX_SetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt); + + CONFIG_VERSION_SIZE(amrparam); + OMX_GetExtensionIndex(amrwb_dec_handle,"OMX.Qualcomm.index.audio.sessionId",&index); + OMX_GetParameter(amrwb_dec_handle,index,&streaminfoparam); +#ifdef AUDIOV2 + session_id = streaminfoparam.sessionId; + devmgr_fd = open("/data/omx_devmgr", O_WRONLY); + if(devmgr_fd >= 0) + { + control = 0; + write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id); + } + else + { + /* + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + + if (msm_route_stream(1,session_id,device_id, 1)) + { + perror("could not set stream routing\n"); + return -1; + } + */ + } +#endif + + OMX_GetParameter(amrwb_dec_handle,OMX_IndexParamAudioAmr,&amrparam); + amrparam.nPortIndex = 0; + amrparam.nChannels = ch; + amrparam.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0; //default + amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; + OMX_SetParameter(amrwb_dec_handle,OMX_IndexParamAudioAmr,&amrparam); + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n"); + OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + + input_buf_cnt = inputportFmt.nBufferCountMin + 3; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(amrwb_dec_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone) + { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else + { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + + + output_buf_cnt = outputportFmt.nBufferCountMin + 1; + + /* Allocate buffer on decoder's O/Pp port */ + error = Allocate_Buffer(amrwb_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone) + { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else + { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n"); + OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + for(i=0; i < output_buf_cnt; i++) + { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(amrwb_dec_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) + { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else + { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) + { + + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + bInputEosReached = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + timeStampLfile += timestampInterval; + pInputBufHdrs[i]->nTimeStamp = timeStampLfile; + ret = OMX_EmptyThisBuffer(amrwb_dec_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock1); + if(etb_done) + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("Component is waiting for EBD to be releases, BC signal\n"); + DEBUG_PRINT("\n****************************\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock1); + + return 0; +} + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_dec_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + + /* To remove warning for unused variable to keep prototype same */ + (void)avc_dec_handle; + + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) + { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(amrwb_dec_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + + int bytes_read=0; + static int totalbytes_read =0; + + DEBUG_PRINT ("\nInside Read_Buffer nAllocLen:%lu\n", pBufHdr->nAllocLen); + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + bytes_read = fread(pBufHdr->pBuffer, + 1, pBufHdr->nAllocLen, inputBufferFile); + pBufHdr->nFilledLen = bytes_read; + totalbytes_read += bytes_read; + + DEBUG_PRINT ("\bytes_read = %d\n",bytes_read); + DEBUG_PRINT ("\totalbytes_read = %d\n",totalbytes_read); + if( bytes_read <= 0) + { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read is Non zero\n"); + } + return bytes_read; +} + +static int open_audio_file () +{ + int error_code = 0; + const char *outfilename = "Audio_amrwb.wav"; + struct wav_header hdr; + int header_len = 0; + + memset(&hdr,0,sizeof(hdr)); + + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = AMRWB_CHANNELS; + hdr.sample_rate = AMRWB_SAMPLE_RATE; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); + inputBufferFile = fopen (in_filename, "rb"); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + } + + if(filewrite == 1) + { + DEBUG_PRINT("output file is opened\n"); + outputBufferFile = fopen(outfilename,"wb"); + if (outputBufferFile == NULL) + { + DEBUG_PRINT("\no/p file %s could NOT be opened\n", + outfilename); + error_code = -1; + return error_code; + } + + header_len = fwrite(&hdr,1,sizeof(hdr),outputBufferFile); + + if (header_len <= 0) + { + DEBUG_PRINT("Invalid Wav header \n"); + } + DEBUG_PRINT(" Length og wav header is %d \n",header_len ); + } + return error_code; +} + +static void write_devctlcmd(int fd, const void *buf, int param){ + int nbytes, nbytesWritten; + char cmdstr[128]; + snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param); + nbytes = strlen(cmdstr); + nbytesWritten = write(fd, cmdstr, nbytes); + + if(nbytes != nbytesWritten) + printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr); +} + diff --git a/mm-audio/adec-mp3/Android.mk b/mm-audio/adec-mp3/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/mm-audio/adec-mp3/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/mm-audio/adec-mp3/Makefile b/mm-audio/adec-mp3/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/mm-audio/adec-mp3/Makefile @@ -0,0 +1,6 @@ +all: + @echo "invoking omxaudio make" + $(MAKE) -C qdsp6 + +install: + $(MAKE) -C qdsp6 install diff --git a/mm-audio/adec-mp3/Makefile.am b/mm-audio/adec-mp3/Makefile.am new file mode 100644 index 000000000..24c1af26d --- /dev/null +++ b/mm-audio/adec-mp3/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qdsp6 diff --git a/mm-audio/adec-mp3/sw/Android.mk b/mm-audio/adec-mp3/sw/Android.mk new file mode 100644 index 000000000..3773a889f --- /dev/null +++ b/mm-audio/adec-mp3/sw/Android.mk @@ -0,0 +1,59 @@ +ifneq ($(BUILD_TINY_ANDROID),true) +ifneq ($(BUILD_WITHOUT_PV),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxMp3Dec-def := -g -O3 +libOmxMp3Dec-def += -DQC_MODIFIED +libOmxMp3Dec-def += -D_ANDROID_ +libOmxMp3Dec-def += -D_ENABLE_QC_MSG_LOG_ +libOmxMp3Dec-def += -DVERBOSE +libOmxMp3Dec-def += -D_DEBUG +libOmxMp3Dec-def += -DAUDIOV2 + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +libOmxMp3Dec-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-adec-omxmp3-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true) +mm-mp3-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +mm-mp3-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +mm-mp3-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \ + $(PV_TOP)/codecs_v2/omx/omx_common/include \ + $(PV_TOP)/extern_libs_v2/khronos/openmax/include \ + $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \ + $(PV_TOP)/codecs_v2/omx/omx_mp3/include \ + $(PV_TOP)/codecs_v2/audio/mp3/dec/include \ + +LOCAL_MODULE := sw-adec-omxmp3-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxMp3Dec-def) +LOCAL_C_INCLUDES := $(mm-mp3-dec-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libopencore_common +LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary +LOCAL_SHARED_LIBRARIES += libomx_mp3dec_sharedlibrary +LOCAL_SHARED_LIBRARIES += libaudioalsa + +LOCAL_SRC_FILES := test/omx_mp3_dec_test.c + +include $(BUILD_EXECUTABLE) +endif + +endif #BUILD_WITHOUT_PV +endif #BUILD_TINY_ANDROID + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c b/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c new file mode 100644 index 000000000..31931d759 --- /dev/null +++ b/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c @@ -0,0 +1,2159 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif +#include "pthread.h" +#include +#include +#include +#include +#include +#include +#include + +#define USE_BUFFER_CASE 1 +#define HOST_PCM_DEVICE 0 +#define PCM_DEC_DEVICE 1 + +OMX_U32 mp3_frequency_index[3][4] = { + {11025,0,22050,44100}, + {12000,0,24000,48000}, + {8000,0,16000,32000} +}; + +int is_multi_inst = 0; + +#define DEBUG_PRINT printf +#define DEBUG_PRINT_ERROR printf +#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/ + +#ifdef PCM_PLAYBACK + +struct mp3_header +{ + OMX_U8 sync; + OMX_U8 version; + uint8_t Layer; + OMX_U8 protection; + OMX_U32 bitrate; + OMX_U32 sampling_rate; + OMX_U8 padding; + OMX_U8 private_bit; + OMX_U8 channel_mode; +}; + + +#define DEFAULT_SAMPLING_RATE 44100 +#define DEFAULT_CHANNEL_MODE 2 + +#endif // PCM_PLAYBACK + + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +OMX_ERRORTYPE parse_mp3_frameheader(OMX_BUFFERHEADERTYPE* buffer, + struct mp3_header *header); + +unsigned int extract_id3_header_size(OMX_U8* buffer); + +/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */ + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +typedef struct hpcm +{ + int pipe_in; + int pipe_out; +}hpcm; + +typedef enum msg +{ + CTRL = 0, + DATA = 1 +}MSG; + +typedef struct hpcm_info +{ + MSG msg_type; + int fd; + OMX_COMPONENTTYPE *hComponent; + OMX_BUFFERHEADERTYPE *bufHdr; +}hpcm_info; + +struct adec_appdata +{ + uint32_t pcmplayback; + uint32_t tunnel; + uint32_t filewrite; + uint32_t flushinprogress; + uint32_t buffer_option; + uint32_t pcm_device_type; + pthread_mutex_t lock; + pthread_cond_t cond; + pthread_mutex_t elock; + pthread_cond_t econd; + pthread_cond_t fcond; + FILE * inputBufferFile; + FILE * outputBufferFile; + OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; + OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; + OMX_AUDIO_PARAM_MP3TYPE mp3param; + QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; + OMX_PORT_PARAM_TYPE portParam; + OMX_ERRORTYPE error; + int input_buf_cnt; + int output_buf_cnt; + int used_ip_buf_cnt; + int event_is_done; + int ebd_event_is_done; + int fbd_event_is_done; + int ebd_cnt; + int bOutputEosReached ; + int bInputEosReached ; + int bFlushing; + int bPause; + #ifdef AUDIOV2 + unsigned short session_id; + unsigned short session_id_hpcm; + int device_id ; + int control ; + char device[44]; + int devmgr_fd; + #endif + const char *in_filename; + unsigned totaldatalen; + OMX_STRING aud_comp; + OMX_COMPONENTTYPE* mp3_dec_handle; + OMX_BUFFERHEADERTYPE **pInputBufHdrs ; + OMX_BUFFERHEADERTYPE **pOutputBufHdrs; + int m_pcmdrv_fd; + int num_pcm_buffers; + pthread_mutex_t pcm_buf_lock; + pthread_t m_pcmdrv_evt_thread_id; + const char *out_filename; + int bReconfigureOutputPort; + int bEosOnInputBuf; + int bEosOnOutputBuf; + int bParseHeader; + struct mp3_header mp3Header; + OMX_U8* pBuffer_tmp; + int count; + int copy_done; + int start_done; + unsigned int length_filled; + int spill_length; + unsigned int pcm_buf_size; + unsigned int pcm_buf_count; + int first_buffer; + hpcm mp3_hpcm; +}; + +struct adec_appdata adec_mp3_inst1; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; + + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Decoder(struct adec_appdata* adec_appdata); +int Play_Decoder(struct adec_appdata* adec_appdata); +void process_portreconfig(struct adec_appdata* adec_appdata); +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (struct adec_appdata* adec_appdata); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr,FILE * inputBufferFile); +static OMX_ERRORTYPE Use_Buffer ( struct adec_appdata* adec_appdata, + OMX_U32 nPortIndex ); + +static OMX_ERRORTYPE Free_Buffer ( struct adec_appdata* adec_appdata, + OMX_U32 nPortIndex, + OMX_BUFFERHEADERTYPE *bufHdr + ); + +static OMX_ERRORTYPE Allocate_Buffer ( struct adec_appdata* adec_appdata, + OMX_U32 nPortIndex ); + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +void write_devctlcmd(int fd, const void *buf, int param); + +void adec_appdata_init(struct adec_appdata* adec_appdata) +{ + adec_appdata->totaldatalen = 0; + adec_appdata->input_buf_cnt = 0; + adec_appdata->output_buf_cnt = 0; + adec_appdata->used_ip_buf_cnt = 0; + adec_appdata->event_is_done = 0; + adec_appdata->ebd_event_is_done = 0; + adec_appdata->fbd_event_is_done = 0; + adec_appdata->ebd_cnt = 0; + adec_appdata->bOutputEosReached = 0; + adec_appdata->bInputEosReached = 0; + adec_appdata->bFlushing = false; + adec_appdata->bPause= false; + adec_appdata->pcmplayback = 0; + adec_appdata->tunnel = 0; + adec_appdata->filewrite = 0; + adec_appdata->flushinprogress = 0; + adec_appdata->buffer_option = 0; + adec_appdata->pcm_device_type = HOST_PCM_DEVICE; + adec_appdata->bReconfigureOutputPort = 0; + adec_appdata->bEosOnInputBuf = 0; + adec_appdata->bEosOnOutputBuf = 0; + adec_appdata->bParseHeader = 0; + adec_appdata->mp3_dec_handle = NULL; + adec_appdata->pInputBufHdrs = NULL; + adec_appdata->pOutputBufHdrs = NULL; + adec_appdata->pBuffer_tmp = NULL; + adec_appdata->count = 0; + adec_appdata->copy_done = 0; + adec_appdata->start_done = 0; + adec_appdata->length_filled = 0; + adec_appdata->spill_length = 0; + adec_appdata->pcm_buf_size = 4800; + adec_appdata->pcm_buf_count = 2; + adec_appdata->first_buffer = 1; + adec_appdata->mp3Header.sync = 0; + adec_appdata->mp3Header.version = 0; + adec_appdata->mp3Header.Layer = 0; + adec_appdata->mp3Header.protection = 0; + adec_appdata->mp3Header.bitrate = 0; + adec_appdata->mp3Header.sampling_rate = 0; + adec_appdata->mp3Header.padding = 0; + adec_appdata->mp3Header.private_bit = 0; + adec_appdata->mp3Header.channel_mode = 0; + adec_appdata->m_pcmdrv_fd = -1; + adec_appdata->num_pcm_buffers = 0; + adec_appdata->inputBufferFile = NULL; + adec_appdata->outputBufferFile = NULL; + adec_appdata->error = 0; +} + +void wait_for_event(struct adec_appdata * adec_appdata) +{ + pthread_mutex_lock(&adec_appdata->lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, adec_appdata->event_is_done); + while (adec_appdata->event_is_done == 0) { + pthread_cond_wait(&adec_appdata->cond, &adec_appdata->lock); + } + adec_appdata->event_is_done = 0; + pthread_mutex_unlock(&adec_appdata->lock); +} + +void event_complete(struct adec_appdata * adec_appdata) +{ + pthread_mutex_lock(&adec_appdata->lock); + if (adec_appdata->event_is_done == 0) { + adec_appdata->event_is_done = 1; + pthread_cond_broadcast(&adec_appdata->cond); + } + pthread_mutex_unlock(&adec_appdata->lock); +} + +void *process_hpcm_drv_events( void* data) +{ + struct adec_appdata *adec_data = (struct adec_appdata *)data; + hpcm_info ftb; + + int n=0; + hpcm_info p; + DEBUG_PRINT("%s adec_data=%p pipe_in=%d pipe_out=%d\n",__FUNCTION__, + adec_data, + adec_data->mp3_hpcm.pipe_in, + adec_data->mp3_hpcm.pipe_out); + while(1) + { + DEBUG_PRINT("\n Waiting for next FBD from OMX.....\n"); + n = read(adec_data->mp3_hpcm.pipe_in,&p,sizeof(struct hpcm_info)); + if(n <= 0){ + DEBUG_PRINT("*********************\n"); + DEBUG_PRINT("KILLING HPCM THREAD...\n"); + DEBUG_PRINT("***********************\n"); + return (void*) -1; + } + if(p.msg_type == CTRL) + { + event_complete(adec_data); + DEBUG_PRINT("DATA EMPTY\n"); + } + else + { + DEBUG_PRINT("***********************\n"); + DEBUG_PRINT("\n%s-->pipe_in=%d pipe_out=%d n=%d\n",__FUNCTION__, + adec_data->mp3_hpcm.pipe_in, + adec_data->mp3_hpcm.pipe_out,n); + DEBUG_PRINT("***********************\n"); + ftb.hComponent = p.hComponent; + ftb.bufHdr = p.bufHdr; + + if ( write(adec_data->m_pcmdrv_fd, ftb.bufHdr->pBuffer, ftb.bufHdr->nFilledLen ) != + (ssize_t)(ftb.bufHdr->nFilledLen) ) + { + DEBUG_PRINT_ERROR("%s: Write data to PCM failed\n",__FUNCTION__); + } + DEBUG_PRINT("drvfd=%d bufHdr[%p] buffer[%p] len[%lu] hComponent[%p] bOutputEos=%d\n", + adec_data->m_pcmdrv_fd, + ftb.bufHdr,ftb.bufHdr->pBuffer, + ftb.bufHdr->nFilledLen, + ftb.hComponent,adec_data->bOutputEosReached); + if(!(adec_data->bOutputEosReached)) + OMX_FillThisBuffer(ftb.hComponent,ftb.bufHdr); + } + } + return 0; +} + +/* Thread for handling the events from PCM_DEC driver */ +void* process_pcm_drv_events( void* data) +{ + struct adec_appdata *adec_data = (struct adec_appdata *)data; + OMX_BUFFERHEADERTYPE *bufHdr = NULL; + struct msm_audio_event tcxo_event; + int rc = 0, buf_count = 0; + + if(data == NULL) + { + DEBUG_PRINT("\n PPDE: data is NULL\n"); + return (void*)(-1); + } + + while(1) + { + DEBUG_PRINT("\nPPDE:Calling ioctl AUDIO_GET_EVENT ...\n"); + rc = ioctl(adec_data->m_pcmdrv_fd, AUDIO_GET_EVENT, &tcxo_event); + if((rc == -1) && (errno == ENODEV )) + { + DEBUG_PRINT("\nPPDE:Exiting with rc %d and error %d", rc, errno); + return (void*)(-1); + } + DEBUG_PRINT("\nPPDE:Event Type[%d]", tcxo_event.event_type); + + switch(tcxo_event.event_type) + { + case AUDIO_EVENT_WRITE_DONE: + { + bufHdr = (OMX_BUFFERHEADERTYPE*)tcxo_event.event_payload. + aio_buf.private_data; + + if(bufHdr) + { + buf_count++; + DEBUG_PRINT("\nPPDE:PCMDEC-ASYNC_WRITE DONE for bufHdr[%p], \ + buf_count = %d\n", bufHdr, buf_count); + + pthread_mutex_lock(&adec_data->pcm_buf_lock); + adec_data->num_pcm_buffers--; + pthread_mutex_unlock(&adec_data->pcm_buf_lock); + + if(adec_data->bOutputEosReached == true) + { + if(adec_data->num_pcm_buffers == 0) + { + DEBUG_PRINT("\nPPDE: Output EOS reached in PCMDEC\n"); + DEBUG_PRINT("\nPPDE::: OUTPUT EOS REACHED....\n"); + event_complete(adec_data); + return 0; + } + else + { + DEBUG_PRINT("\nWaiting for PCM to play remaining \ + %d buffers ...\n", adec_data->num_pcm_buffers); + } + } + else + { + DEBUG_PRINT("\nPPDE calling FTB"); + OMX_FillThisBuffer(adec_data->mp3_dec_handle, bufHdr); + } + } + else + { + DEBUG_PRINT("\nPPDE: Invalid bufHdr[%p] in WRITE_DONE\n", + bufHdr); + } + } + break; + + default: + DEBUG_PRINT("PPDE: Received Invalid Event"); + break; + } + } + return 0; +} + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + //DEBUG_PRINT("Function %s \n command %d Event complete %d", __FUNCTION__,(OMX_COMMANDTYPE)nData1,nData2); + int bufCnt=0; + struct adec_appdata* adec_appdata; + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pEventData; + + if(NULL != pAppData) + adec_appdata = (struct adec_appdata*) pAppData; + else + return OMX_ErrorBadParameter; + switch(eEvent) { + case OMX_EventCmdComplete: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventCmdComplete \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1) { + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("Recieved DISABLE Event Command Complete[%d]\n",(signed)nData2); + DEBUG_PRINT("******************************************\n"); + } + else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1) { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved ENABLE Event Command Complete[%d]\n",(signed)nData2); + DEBUG_PRINT("*********************************************\n"); + } + else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("Recieved FLUSH Event Command Complete[%d]\n",(signed)nData2); + DEBUG_PRINT("*********************************************\n"); + } + event_complete(adec_appdata); + break; + + case OMX_EventError: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventError \n"); + DEBUG_PRINT("*********************************************\n"); + if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("\n OMX_ErrorInvalidState \n"); + for(bufCnt=0; bufCnt < adec_appdata->input_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(adec_appdata->mp3_dec_handle, 0, adec_appdata->pInputBufHdrs[bufCnt]); + } + if(adec_appdata->tunnel == 0) + { + for(bufCnt=0; bufCnt < adec_appdata->output_buf_cnt; ++bufCnt) + { + OMX_FreeBuffer(adec_appdata->mp3_dec_handle, 1, adec_appdata->pOutputBufHdrs[bufCnt]); + } + } + + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Deinitialized \n"); + DEBUG_PRINT("*********************************************\n"); + exit(0); + } + else if(OMX_ErrorComponentSuspended == (OMX_ERRORTYPE)nData1) + { + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Received Suspend Event \n"); + DEBUG_PRINT("*********************************************\n"); + } + break; + + case OMX_EventPortSettingsChanged: + if(adec_appdata->tunnel == 0) + { + adec_appdata->bReconfigureOutputPort = 1; + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + DEBUG_PRINT("*********************************************\n"); + event_complete(adec_appdata); + } + break; + + case OMX_EventBufferFlag: + DEBUG_PRINT("\n *********************************************\n"); + DEBUG_PRINT("\n OMX_EventBufferFlag \n"); + DEBUG_PRINT("\n *********************************************\n"); + adec_appdata->bOutputEosReached = true; + if((!adec_appdata->pcmplayback && adec_appdata->filewrite) + || (adec_appdata->pcmplayback && + (adec_appdata->pcm_device_type == HOST_PCM_DEVICE || + (adec_appdata->pcm_device_type == PCM_DEC_DEVICE + && !adec_appdata->num_pcm_buffers)))) + { + event_complete(adec_appdata); + } + break; + case OMX_EventComponentResumed: + DEBUG_PRINT("*********************************************\n"); + DEBUG_PRINT("\n Component Received Resume Event \n"); + DEBUG_PRINT("*********************************************\n"); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + struct msm_audio_aio_buf audio_aio_buf; + unsigned int i=0; + int bytes_writen = 0; + struct msm_audio_config drv_pcm_config; + struct adec_appdata* adec_appdata; + + if(NULL != pAppData) + adec_appdata = (struct adec_appdata*) pAppData; + else + return OMX_ErrorBadParameter; + + if (adec_appdata->flushinprogress == 1 ) + { + DEBUG_PRINT(" FillBufferDone: flush is in progress so hold the buffers\n"); + return OMX_ErrorNone; + } + if ( (adec_appdata->count == 0) && + (adec_appdata->pcm_device_type == HOST_PCM_DEVICE) && + (adec_appdata->pcmplayback)) + { + DEBUG_PRINT(" open pcm device \n"); + adec_appdata->m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR); + if ( adec_appdata->m_pcmdrv_fd < 0 ) + { + DEBUG_PRINT("Cannot open audio device\n"); + return -1; + } + else + { + DEBUG_PRINT("Open pcm device successfull\n"); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + drv_pcm_config.sample_rate = adec_appdata->mp3Header.sampling_rate; + drv_pcm_config.channel_count = adec_appdata->mp3Header.channel_mode; + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("Configure Driver for PCM playback \n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count); + DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size); + adec_appdata->pcm_buf_size = drv_pcm_config.buffer_size; + adec_appdata->pcm_buf_count = drv_pcm_config.buffer_count; +#ifdef AUDIOV2 + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &adec_appdata->session_id_hpcm); + DEBUG_PRINT("session id 0x%4x \n", adec_appdata->session_id_hpcm); + if(adec_appdata->devmgr_fd >= 0) + { + write_devctlcmd(adec_appdata->devmgr_fd, "-cmd=register_session_rx -sid=", adec_appdata->session_id_hpcm); + } + else + { + adec_appdata->control = msm_mixer_open("/dev/snd/controlC0", 0); + if (adec_appdata->control < 0) + printf("ERROR opening the device\n"); + adec_appdata->device_id = msm_get_device(adec_appdata->device); + DEBUG_PRINT ("\ndevice_id = %d\n", adec_appdata->device_id); + DEBUG_PRINT("\nsessionid = %d\n", adec_appdata->session_id); + if (msm_en_device(adec_appdata->device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + if (msm_route_stream(1, adec_appdata->session_id_hpcm, adec_appdata->device_id, 1)) + { + DEBUG_PRINT("could not set stream routing\n"); + return -1; + } + } +#endif + } + adec_appdata->pBuffer_tmp= (OMX_U8*)malloc(adec_appdata->pcm_buf_count*sizeof(OMX_U8)*adec_appdata->pcm_buf_size); + if ( adec_appdata->pBuffer_tmp == NULL ) + { + return -1; + } + else + { + memset(adec_appdata->pBuffer_tmp, 0, adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size); + } + } + DEBUG_PRINT(" FillBufferDone #%d size %u\n", adec_appdata->count++,(unsigned)(pBuffer->nFilledLen)); + + if ( adec_appdata->bEosOnOutputBuf ) + { + return OMX_ErrorNone; + } + + if ( (adec_appdata->tunnel == 0) && (adec_appdata->filewrite == 1) ) + { + bytes_writen = + fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,adec_appdata->outputBufferFile); + DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen); + adec_appdata->totaldatalen += bytes_writen ; + } + +#ifdef PCM_PLAYBACK + if ( adec_appdata->pcmplayback && pBuffer->nFilledLen ) + { + if(adec_appdata->pcm_device_type == HOST_PCM_DEVICE) + { + if ( adec_appdata->start_done == 0 ) + { + if ( (adec_appdata->length_filled+ pBuffer->nFilledLen)>=(adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size) ) + { + adec_appdata->spill_length = (pBuffer->nFilledLen-(adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size)+adec_appdata->length_filled); + memcpy (adec_appdata->pBuffer_tmp+adec_appdata->length_filled, pBuffer->pBuffer, + ((adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size)-adec_appdata->length_filled)); + adec_appdata->length_filled = (adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size); + adec_appdata->copy_done = 1; + } + else + { + memcpy (adec_appdata->pBuffer_tmp+adec_appdata->length_filled, pBuffer->pBuffer, pBuffer->nFilledLen); + adec_appdata->length_filled +=pBuffer->nFilledLen; + } + if (adec_appdata->copy_done == 1 ) + { + for ( i=0; ipcm_buf_count; i++ ) + { + if ( write(adec_appdata->m_pcmdrv_fd,adec_appdata->pBuffer_tmp+i*adec_appdata->pcm_buf_size, adec_appdata->pcm_buf_size ) + != (ssize_t)(adec_appdata->pcm_buf_size) ) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return -1; + } + + } + DEBUG_PRINT("AUDIO_START called for PCM \n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_START, 0); + if (adec_appdata->spill_length != 0 ) + { + if ( write(adec_appdata->m_pcmdrv_fd, pBuffer->pBuffer+((pBuffer->nFilledLen)-adec_appdata->spill_length),adec_appdata->spill_length) + != adec_appdata->spill_length ) + { + DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n"); + return -1; + } + } + + + + + adec_appdata->copy_done = 0; + adec_appdata->start_done = 1; + } + if((adec_appdata->pcmplayback && (adec_appdata->pcm_device_type == HOST_PCM_DEVICE)) || + (!adec_appdata->pcmplayback && adec_appdata->filewrite)) + { + DEBUG_PRINT(" FBD calling FTB"); + OMX_FillThisBuffer(hComponent,pBuffer); + } + } + else + { + unsigned int len=0; + hpcm_info ftb; + ftb.msg_type = DATA; + ftb.hComponent = hComponent; + ftb.bufHdr = pBuffer; + len= write(adec_appdata->mp3_hpcm.pipe_out,&ftb,sizeof(hpcm_info)); + DEBUG_PRINT(" FillBufferDone: writing data to hpcm thread len=%d\n",len); + + } + + } + + /* Write o/p data in Async manner to PCM Dec Driver */ + if(adec_appdata->pcm_device_type == PCM_DEC_DEVICE) + { + if(adec_appdata->count == 1) + { + DEBUG_PRINT("FillBufferDone: PCM AUDIO_START\n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_START, 0); + } + + audio_aio_buf.buf_len = pBuffer->nAllocLen; + audio_aio_buf.data_len = pBuffer->nFilledLen; + audio_aio_buf.buf_addr = pBuffer->pBuffer; + audio_aio_buf.private_data = pBuffer; + + DEBUG_PRINT("FBD:Calling PCMDEC ASYNC_WRITE for bufhdr[%p]\n", pBuffer); + + if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_ASYNC_WRITE, &audio_aio_buf)) + { + DEBUG_PRINT("\nERROR in PCMDEC ASYNC WRITE call\n"); + return OMX_ErrorHardware; + } + + pthread_mutex_lock(&adec_appdata->pcm_buf_lock); + adec_appdata->num_pcm_buffers++; + DEBUG_PRINT("FBD: Bufcnt with PCMDEC = %d\n", adec_appdata->num_pcm_buffers); + pthread_mutex_unlock(&adec_appdata->pcm_buf_lock); + + DEBUG_PRINT("FBD: PCMDEC ASYNC_WRITE call is succesfull\n"); + } + } + else if(adec_appdata->pcmplayback && !pBuffer->nFilledLen) + { + DEBUG_PRINT(" FBD calling FTB...special case"); + OMX_FillThisBuffer(hComponent,pBuffer); + + } + else if(!(adec_appdata->pcmplayback) && (adec_appdata->filewrite)) + { + DEBUG_PRINT(" FBD calling FTB"); + OMX_FillThisBuffer(hComponent,pBuffer); + + } +#endif // PCM_PLAYBACK + + if(pBuffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT("FBD EOS REACHED...........\n"); + adec_appdata->bEosOnOutputBuf = true; + } + + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + struct adec_appdata* adec_appdata; + + if(NULL != pAppData) + adec_appdata = (struct adec_appdata*) pAppData; + else + return OMX_ErrorBadParameter; + DEBUG_PRINT("\nFunction %s cnt[%d]\n", __FUNCTION__,adec_appdata->ebd_cnt); + adec_appdata->ebd_cnt++; + adec_appdata->used_ip_buf_cnt--; + if(adec_appdata->bEosOnInputBuf) { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT(" TBD:::De Init the open max here....!!!\n"); + DEBUG_PRINT("*********************************************\n"); + + return OMX_ErrorNone; + } + else if (adec_appdata->bFlushing == true) { + if (adec_appdata->used_ip_buf_cnt == 0) { + fseek(adec_appdata->inputBufferFile, 0, 0); + adec_appdata->bFlushing = false; + } + else { + DEBUG_PRINT("omx_mp3_adec_test: more buffer to come back\n"); + return OMX_ErrorNone; + } + } + if((readBytes = Read_Buffer(pBuffer,adec_appdata->inputBufferFile)) > 0) { + pBuffer->nFilledLen = readBytes; + adec_appdata->used_ip_buf_cnt++; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else { + DEBUG_PRINT("\n readBytes = %d\n", readBytes); + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + adec_appdata->bEosOnInputBuf = true; + adec_appdata->used_ip_buf_cnt++; + pBuffer->nFilledLen = 0; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + + +void signal_handler(int sig_id) +{ + /* Flush */ + + if (sig_id == SIGUSR1) { + DEBUG_PRINT("SIGUSR1 Invoked\n"); + if(!is_multi_inst) + { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + adec_mp3_inst1.bFlushing = true; + OMX_SendCommand(adec_mp3_inst1.mp3_dec_handle, OMX_CommandFlush, OMX_ALL, NULL); + } + } + else if (sig_id == SIGUSR2) { + DEBUG_PRINT("SIGUSR2 Invoked\n"); + if(!is_multi_inst) + { + if (adec_mp3_inst1.bPause == true) { + DEBUG_PRINT("%s resume playback\n", __FUNCTION__); + adec_mp3_inst1.bPause = false; + OMX_SendCommand(adec_mp3_inst1.mp3_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } + else { + DEBUG_PRINT("%s pause playback\n", __FUNCTION__); + adec_mp3_inst1.bPause = true; + OMX_SendCommand(adec_mp3_inst1.mp3_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } + } +} + + +void* thread_function(void* data) +{ + struct adec_appdata *adec_mp3_inst = (struct adec_appdata *)data; + struct wav_header hdr; + int bufCnt=0; + OMX_ERRORTYPE result; + int bytes_writen = 0; + +#ifdef AUDIOV2 +strlcpy(adec_mp3_inst1.device,"speaker_stereo_rx", + sizeof(adec_mp3_inst1.device)); +adec_mp3_inst1.control=0; +#endif + + if(Init_Decoder(adec_mp3_inst)!= 0x00) { + DEBUG_PRINT("Decoder Init failed\n"); + return (void*)(-1); + } + + if(Play_Decoder(adec_mp3_inst) != 0x00) { + DEBUG_PRINT("Play_Decoder failed\n"); + return (void*) (-1); + } + + // Wait till EOS is reached... + if(adec_mp3_inst->bReconfigureOutputPort) + { + wait_for_event(adec_mp3_inst); + } + + DEBUG_PRINT(" bOutputEosReached = %d bInputEosReached = %d \n", + adec_mp3_inst->bOutputEosReached, adec_mp3_inst->bInputEosReached); + if(adec_mp3_inst->bOutputEosReached) { + + #ifdef PCM_PLAYBACK + if(adec_mp3_inst->pcmplayback == 1) { + sleep(1); + if(adec_mp3_inst->pcm_device_type == PCM_DEC_DEVICE) + { + fsync(adec_mp3_inst->m_pcmdrv_fd); + } + + + if(adec_mp3_inst->pcm_device_type == PCM_DEC_DEVICE) + { + DEBUG_PRINT("\n Calling ABORT_GET_EVENT for PCMDEC driver\n"); + if(0 > ioctl(adec_mp3_inst->m_pcmdrv_fd, AUDIO_ABORT_GET_EVENT, NULL)) + { + DEBUG_PRINT("\n Error in ioctl AUDIO_ABORT_GET_EVENT\n"); + } + + DEBUG_PRINT("\n Waiting for PCMDrv Event Thread complete\n"); + pthread_join(adec_mp3_inst->m_pcmdrv_evt_thread_id, NULL); + } + else + { + DEBUG_PRINT("*******************************\n"); + DEBUG_PRINT("\n HPCMDrv Event Thread complete %d %d\n", + adec_mp3_inst->mp3_hpcm.pipe_in, + adec_mp3_inst->mp3_hpcm.pipe_out); + close(adec_mp3_inst->mp3_hpcm.pipe_in); + close(adec_mp3_inst->mp3_hpcm.pipe_out); + adec_mp3_inst->mp3_hpcm.pipe_in=-1; + adec_mp3_inst->mp3_hpcm.pipe_out=-1; + pthread_join(adec_mp3_inst->m_pcmdrv_evt_thread_id, NULL); + DEBUG_PRINT("*******************************\n"); + } + ioctl(adec_mp3_inst->m_pcmdrv_fd, AUDIO_STOP, 0); +#ifdef AUDIOV2 + if(adec_mp3_inst->devmgr_fd >= 0) + { + write_devctlcmd(adec_mp3_inst->devmgr_fd, "-cmd=unregister_session_rx -sid=", adec_mp3_inst->session_id_hpcm); + } + else + { + if (msm_route_stream(1, adec_mp3_inst->session_id_hpcm, adec_mp3_inst->device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + } + } +#endif + if(adec_mp3_inst->m_pcmdrv_fd >= 0) { + close(adec_mp3_inst->m_pcmdrv_fd); + adec_mp3_inst->m_pcmdrv_fd = -1; + DEBUG_PRINT(" PCM device closed succesfully \n"); + } + else { + DEBUG_PRINT(" PCM device close failure \n"); + } + } + #endif // PCM_PLAYBACK + + if((adec_mp3_inst->tunnel == 0) && (adec_mp3_inst->filewrite == 1)) { + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = adec_mp3_inst->mp3Header.channel_mode; + hdr.sample_rate = adec_mp3_inst->mp3Header.sampling_rate; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",adec_mp3_inst->totaldatalen); + hdr.data_sz = adec_mp3_inst->totaldatalen; + hdr.riff_sz = adec_mp3_inst->totaldatalen + 8 + 16 + 8; + fseek(adec_mp3_inst->outputBufferFile, 0L , SEEK_SET); + bytes_writen = fwrite(&hdr,1,sizeof(hdr),adec_mp3_inst->outputBufferFile); + if (bytes_writen <= 0) { + DEBUG_PRINT("Invalid Wav header write failed\n"); + } + fclose(adec_mp3_inst->outputBufferFile); + } + /************************************************************************************/ + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(adec_mp3_inst->mp3_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(adec_mp3_inst); + + DEBUG_PRINT("\nMoving the decoder to loaded state \n"); + OMX_SendCommand(adec_mp3_inst->mp3_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < adec_mp3_inst->input_buf_cnt; ++bufCnt) { + Free_Buffer(adec_mp3_inst, 0, adec_mp3_inst->pInputBufHdrs[bufCnt]); + } + + free(adec_mp3_inst->pInputBufHdrs); + adec_mp3_inst->pInputBufHdrs = NULL; + + if(adec_mp3_inst->tunnel == 0) { + DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < adec_mp3_inst->output_buf_cnt; ++bufCnt) { + Free_Buffer(adec_mp3_inst, 1, adec_mp3_inst->pOutputBufHdrs[bufCnt]); + } + free(adec_mp3_inst->pOutputBufHdrs); + adec_mp3_inst->pOutputBufHdrs = NULL; + } + + DEBUG_PRINT("*******************************************\n"); + wait_for_event(adec_mp3_inst); + adec_mp3_inst->ebd_cnt=0; + adec_mp3_inst->bOutputEosReached = false; + adec_mp3_inst->bInputEosReached = false; + adec_mp3_inst->bEosOnInputBuf = 0; + adec_mp3_inst->bEosOnOutputBuf = 0; + adec_mp3_inst->bReconfigureOutputPort = 0; + if (adec_mp3_inst->pBuffer_tmp ) + { + free(adec_mp3_inst->pBuffer_tmp); + adec_mp3_inst->pBuffer_tmp =NULL; + } + result = OMX_FreeHandle(adec_mp3_inst->mp3_dec_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("\nOMX_FreeHandle error. Error code: %d\n", result); + } + else DEBUG_PRINT("OMX_FreeHandle success...\n"); + + adec_mp3_inst->mp3_dec_handle = NULL; +#ifdef AUDIOV2 + if(adec_mp3_inst->devmgr_fd >= 0) + { + write_devctlcmd(adec_mp3_inst->devmgr_fd, "-cmd=unregister_session_rx -sid=", adec_mp3_inst->session_id); + close(adec_mp3_inst->devmgr_fd); + } + else + { + if (msm_route_stream(1, adec_mp3_inst->session_id, adec_mp3_inst->device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return (void *)-1; + } + if (msm_en_device(adec_mp3_inst->device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return (void *)-1; + } + msm_mixer_close(); + } +#endif + pthread_cond_destroy(&adec_mp3_inst->cond); + pthread_mutex_destroy(&adec_mp3_inst->lock); + + if(adec_mp3_inst->pcmplayback && + adec_mp3_inst->pcm_device_type == PCM_DEC_DEVICE) + { + pthread_mutex_destroy(&adec_mp3_inst->pcm_buf_lock); + } + } + return 0; +} + +int main(int argc, char **argv) +{ + struct sigaction sa; + pthread_t thread1_id; + int thread1_ret=0; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + if(argc == 7) + { + adec_appdata_init(&adec_mp3_inst1); + pthread_cond_init(&adec_mp3_inst1.cond, 0); + pthread_mutex_init(&adec_mp3_inst1.lock, 0); + adec_mp3_inst1.in_filename = argv[1]; + adec_mp3_inst1.bParseHeader = atoi(argv[2]); + adec_mp3_inst1.pcmplayback = atoi(argv[3]); + adec_mp3_inst1.filewrite = atoi(argv[4]); + adec_mp3_inst1.out_filename = argv[5]; + adec_mp3_inst1.buffer_option = atoi(argv[6]); + + //adec_mp3_inst1.out_filename = (char*)malloc(sizeof("audio.wav")); + //strncpy(adec_mp3_inst1.out_filename,"audio.wav",strlen("audio.wav")); + if(adec_mp3_inst1.tunnel == 0) + adec_mp3_inst1.aud_comp = "OMX.PV.mp3dec"; + + if(adec_mp3_inst1.pcmplayback && + adec_mp3_inst1.pcm_device_type == PCM_DEC_DEVICE) + { + pthread_mutex_init(&adec_mp3_inst1.pcm_buf_lock, 0); + } + DEBUG_PRINT(" OMX test app : aud_comp instance = %s\n",adec_mp3_inst1.aud_comp); + + } + else + { + DEBUG_PRINT( "invalid format: \n"); + DEBUG_PRINT( "ex: ./sw-adec-omxmp3-test MP3INPUTFILE ParseHeader PCMPLAYBACK \n"); + DEBUG_PRINT( "FILEWRITE OUTFILENAME BUFFEROPTION PCMDEVICETYPE\n"); + DEBUG_PRINT( "ParseHeader= 1 (Parses MP3 Header) \n"); + DEBUG_PRINT( "ParseHeader= 0 (Uses Default Sampling rate and channel) \n"); + DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n"); + DEBUG_PRINT( "BUFFER OPTION = 0 (AllocateBuffer case)\n"); + DEBUG_PRINT( "BUFFER OPTION = 1 (UseBuffer case)\n"); + return 0; + } + + if(adec_mp3_inst1.tunnel == 0) + adec_mp3_inst1.aud_comp = "OMX.PV.mp3dec"; + + DEBUG_PRINT(" OMX test app : aud_comp instance 1= %s\n",adec_mp3_inst1.aud_comp); + pthread_create (&thread1_id, NULL, &thread_function, &adec_mp3_inst1); + pthread_join(thread1_id,(void**) &thread1_ret); + if(0 == thread1_ret) + DEBUG_PRINT(" Thread 1 ended successfully\n"); + + /* Deinit OpenMAX */ + OMX_Deinit(); + + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + return 0; +} + + +int Init_Decoder(struct adec_appdata* adec_appdata) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + typedef OMX_U8* OMX_U8_PTR; + char *role ="audio_decoder.mp3"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Mp3_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT("\nTotal components of role = %s :%u \n", role ,(unsigned)total); + + DEBUG_PRINT("\nComponent before GEThandle %s \n", adec_appdata->aud_comp); + + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&adec_appdata->mp3_dec_handle), + (OMX_STRING)adec_appdata->aud_comp, adec_appdata, &call_back); + + if (FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to Load the component:%s\n", adec_appdata->aud_comp); + return -1; + } + else { + DEBUG_PRINT("\nComponent %s is in LOADED state with handle: %p\n", adec_appdata->aud_comp,adec_appdata->mp3_dec_handle); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(adec_appdata->portParam); + omxresult = OMX_GetParameter(adec_appdata->mp3_dec_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&(adec_appdata->portParam)); + + if(FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to get Port Param\n"); + return -1; + } + else { + DEBUG_PRINT("\nportParam.nPorts:%u\n", (unsigned)(adec_appdata->portParam.nPorts)); + DEBUG_PRINT("\nportParam.nStartPortNumber:%u\n", + (unsigned)(adec_appdata->portParam.nStartPortNumber)); + } + return 0; +} + +int Play_Decoder(struct adec_appdata* adec_appdata) +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + #ifdef PCM_PLAYBACK + struct msm_audio_config drv_pcm_config; + #endif // PCM_PLAYBACK + + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file(adec_appdata)) { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + /* Query the decoder input min buf requirements */ + CONFIG_VERSION_SIZE(adec_appdata->inputportFmt); + + /* Port for which the Client needs to obtain info */ + adec_appdata->inputportFmt.nPortIndex = adec_appdata->portParam.nStartPortNumber; + + OMX_GetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->inputportFmt); + DEBUG_PRINT ("\nDec: Input Buffer Count %u\n",(unsigned) (adec_appdata->inputportFmt.nBufferCountMin)); + DEBUG_PRINT ("\nDec: Input Buffer Size %u\n", (unsigned) (adec_appdata->inputportFmt.nBufferSize)); + + if(OMX_DirInput != adec_appdata->inputportFmt.eDir) { + DEBUG_PRINT ("\nDec: Expect Input Port\n"); + return -1; + } + + adec_appdata->inputportFmt.nBufferCountActual = adec_appdata->inputportFmt.nBufferCountMin + 5; + OMX_SetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->inputportFmt); + OMX_GetExtensionIndex(adec_appdata->mp3_dec_handle,"OMX.Qualcomm.index.audio.sessionid",&index); + OMX_GetParameter(adec_appdata->mp3_dec_handle,index,&adec_appdata->streaminfoparam); +#ifdef AUDIOV2 + adec_appdata->session_id = adec_appdata->streaminfoparam.sessionId; + adec_appdata->devmgr_fd = open("/data/omx_devmgr", O_WRONLY); + if(adec_appdata->devmgr_fd >= 0) + { + adec_appdata->control = 0; + write_devctlcmd(adec_appdata->devmgr_fd, "-cmd=register_session_rx -sid=", adec_appdata->session_id); + } +#endif + if(adec_appdata->tunnel == 0) { + /* Query the decoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(adec_appdata->outputportFmt); + /* Port for which the Client needs to obtain info */ + adec_appdata->outputportFmt.nPortIndex = adec_appdata->portParam.nStartPortNumber + 1; + + OMX_GetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->outputportFmt); + DEBUG_PRINT ("\nDec: Output Buffer Count %u\n",(unsigned)( adec_appdata->outputportFmt.nBufferCountMin)); + DEBUG_PRINT ("\nDec: Output Buffer Size %u\n",(unsigned)( adec_appdata->outputportFmt.nBufferSize)); + + if(OMX_DirOutput != adec_appdata->outputportFmt.eDir) { + DEBUG_PRINT ("\nDec: Expect Output Port\n"); + return -1; + } + adec_appdata->outputportFmt.nBufferCountActual = adec_appdata->outputportFmt.nBufferCountMin + 3; + OMX_SetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->outputportFmt); + } + + CONFIG_VERSION_SIZE(adec_appdata->mp3param); + + DEBUG_PRINT(" adec_appdata->pcm_device_type = %d\n", adec_appdata->pcm_device_type); + #ifdef PCM_PLAYBACK + if(adec_appdata->pcmplayback && adec_appdata->pcm_device_type == PCM_DEC_DEVICE) + { + DEBUG_PRINT(" open pcm dec device \n"); + adec_appdata->m_pcmdrv_fd = open("/dev/msm_pcm_dec", O_WRONLY | O_NONBLOCK); + if (adec_appdata->m_pcmdrv_fd < 0) + { + DEBUG_PRINT("Play_Decoder: cannot open pcm_dec device"); + return -1; + } + DEBUG_PRINT(" Play_Decoder: open pcm device successfull\n"); + + /* Create the Event Thread for PCM Dec driver */ + if (pthread_create(&adec_appdata->m_pcmdrv_evt_thread_id, 0, process_pcm_drv_events, + adec_appdata) < 0) + { + DEBUG_PRINT("\n Event Thread creation for PCM Dec driver FAILED\n"); + return -1; + } + } + else + { + int fds[2]; + if (pipe(fds)) { + DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__); + } + adec_appdata->mp3_hpcm.pipe_in=fds[0]; + adec_appdata->mp3_hpcm.pipe_out=fds[1]; + DEBUG_PRINT("********************************\n"); + DEBUG_PRINT("HPCM PIPES %d %d\n",fds[0],fds[1]); + DEBUG_PRINT("********************************\n"); + + if (pthread_create(&adec_appdata->m_pcmdrv_evt_thread_id, 0, process_hpcm_drv_events, + adec_appdata) < 0) + { + DEBUG_PRINT_ERROR("\n Event Thread creation for PCM Dec driver FAILED\n"); + return -1; + } + } + #endif // PCM_PLAYBACK + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n"); + OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + + adec_appdata->input_buf_cnt = adec_appdata->inputportFmt.nBufferCountActual; //inputportFmt.nBufferCountMin + 5; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + + if(adec_appdata->buffer_option == USE_BUFFER_CASE) + { + /* Use buffer on decoder's I/P port */ + adec_appdata->error = Use_Buffer(adec_appdata, + adec_appdata->inputportFmt.nPortIndex); + if (adec_appdata->error != OMX_ErrorNone) + { + DEBUG_PRINT ("\nOMX_UseBuffer Input buffer error\n"); + return -1; + } + else + { + DEBUG_PRINT ("\nOMX_UseBuffer Input buffer success\n"); + } + } + else + { + /* Allocate buffer on decoder's i/p port */ + adec_appdata->error = Allocate_Buffer(adec_appdata, + adec_appdata->inputportFmt.nPortIndex); + if (adec_appdata->error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + } + + if(adec_appdata->tunnel == 0) { + adec_appdata->output_buf_cnt = adec_appdata->outputportFmt.nBufferCountActual ; + + if(adec_appdata->buffer_option == USE_BUFFER_CASE) + { + /* Use buffer on decoder's O/P port */ + adec_appdata->error = Use_Buffer(adec_appdata, + adec_appdata->outputportFmt.nPortIndex); + if (adec_appdata->error != OMX_ErrorNone) + { + DEBUG_PRINT ("\nOMX_UseBuffer Output buffer error\n"); + return -1; + } + else + { + DEBUG_PRINT ("\nOMX_UseBuffer Output buffer success\n"); + } + } + else + { + /* Allocate buffer on decoder's O/Pp port */ + adec_appdata->error = Allocate_Buffer(adec_appdata, + adec_appdata->outputportFmt.nPortIndex); + if (adec_appdata->error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + } + } + + wait_for_event(adec_appdata); + + DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n"); + OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(adec_appdata); + + if((adec_appdata->tunnel == 0)) + { + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + + for(i=0; i < adec_appdata->output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + adec_appdata->pOutputBufHdrs[i]->nOutputPortIndex = 1; + adec_appdata->pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(adec_appdata->mp3_dec_handle, adec_appdata->pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + } + + + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < adec_appdata->input_buf_cnt;i++) { + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + adec_appdata->pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(adec_appdata->pInputBufHdrs[i],adec_appdata->inputBufferFile); + if(Size <=0 ) { + DEBUG_PRINT("\n readBytes = %d\n", Size); + DEBUG_PRINT("NO DATA READ\n"); + adec_appdata->bEosOnInputBuf = true; + Size = 0; + adec_appdata->pInputBufHdrs[i]->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT("Play_decoder::EOS or Error while reading file\n"); + } + adec_appdata->pInputBufHdrs[i]->nFilledLen = Size; + adec_appdata->pInputBufHdrs[i]->nInputPortIndex = 0; + adec_appdata->used_ip_buf_cnt++; + + if(adec_appdata->first_buffer) + { + adec_appdata->first_buffer = 0; + ret = parse_mp3_frameheader(adec_appdata->pInputBufHdrs[i],&adec_appdata->mp3Header); + if(ret != OMX_ErrorNone) + { + DEBUG_PRINT("parse_mp3_frameheader return failure\n"); + adec_appdata->mp3Header.sampling_rate = DEFAULT_SAMPLING_RATE; + adec_appdata->mp3Header.channel_mode = DEFAULT_CHANNEL_MODE; + } + + /* Get the Output port PCM configuration details */ + adec_appdata->mp3param.nPortIndex = 0; + adec_appdata->mp3param.nSampleRate = adec_appdata->mp3Header.sampling_rate; + adec_appdata->mp3param.nChannels = adec_appdata->mp3Header.channel_mode; + adec_appdata->mp3param.nBitRate = 0; + adec_appdata->mp3param.eChannelMode = OMX_AUDIO_ChannelModeStereo; + adec_appdata->mp3param.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3; + + if(!adec_appdata->bParseHeader) + { + adec_appdata->mp3param.nSampleRate = DEFAULT_SAMPLING_RATE; + adec_appdata->mp3param.nChannels = DEFAULT_CHANNEL_MODE; + } + + OMX_SetParameter(adec_appdata->mp3_dec_handle, OMX_IndexParamAudioMp3, + (OMX_PTR)&adec_appdata->mp3param); + + if(adec_appdata->pcmplayback && + adec_appdata->pcm_device_type == PCM_DEC_DEVICE) + { + DEBUG_PRINT("configure Driver for PCM playback \n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config); + drv_pcm_config.sample_rate = adec_appdata->mp3Header.sampling_rate; + drv_pcm_config.channel_count = adec_appdata->mp3Header.channel_mode; + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + } + } + + ret = OMX_EmptyThisBuffer(adec_appdata->mp3_dec_handle, adec_appdata->pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + } + + /* Waiting for EOS or PortSettingsChange*/ + while(1) + { + wait_for_event(adec_appdata); + if(adec_appdata->bOutputEosReached) + { + adec_appdata->bReconfigureOutputPort = 0; + printf("bOutputEosReached breaking\n"); + break; + } + else + { + if(adec_appdata->tunnel == 0 && adec_appdata->bReconfigureOutputPort) + process_portreconfig(adec_appdata); + } + } + + return 0; +} + +unsigned int extract_id3_header_size(OMX_U8* buffer) +{ + unsigned int size = 0; + OMX_U8* pTemp = NULL; + + if(!buffer) + { + return 0; + } + + pTemp = buffer+6; + size = ((pTemp[0]&0x7F) << 21); + size |= ((pTemp[1]&0x7F) << 14); + size |= ((pTemp[2]&0x7F) << 7); + size |= ((pTemp[3]&0x7F)); + + return (size+10); +} + +OMX_ERRORTYPE parse_mp3_frameheader(OMX_BUFFERHEADERTYPE* buffer, + struct mp3_header *header) +{ + OMX_U8* temp_pBuf1 = NULL; + unsigned int i = 0; + unsigned int id3_size = 0; + OMX_U8 temp; + + + for(i=0;i<10;i++) + DEBUG_PRINT ("\n buffer[%d] = 0x%x",i,buffer->pBuffer[i]); + if ( buffer->nFilledLen == 0 ) + { + DEBUG_PRINT ("\n Length is zero hence no point in processing \n"); + return OMX_ErrorNone; + } + + temp_pBuf1 = buffer->pBuffer; + + i = 0; + while (inFilledLen) + { + if((i < buffer->nFilledLen-2) && (temp_pBuf1[0] == 0x49) && + (temp_pBuf1[1] == 0x44) && (temp_pBuf1[2] == 0x33)) + { + if(i < buffer->nFilledLen-10) + { + id3_size = extract_id3_header_size(temp_pBuf1); + DEBUG_PRINT("\n ID3 tag size = %u\n", id3_size); + } + else + { + DEBUG_PRINT("\nFull ID3 tag header not available\n"); + return OMX_ErrorMax; + } + + if(id3_size && i < buffer->nFilledLen-id3_size) + { + i += id3_size; + temp_pBuf1 += id3_size; + + DEBUG_PRINT("\n Skipping valid ID3 tag\n"); + break; + } + else + { + DEBUG_PRINT("\n ID3 Tag size 0 or exceeds 1st buffer\n"); + return OMX_ErrorMax; + } + } + else if(*temp_pBuf1 == 0xFF ) + { + break; + } + + i++; + temp_pBuf1++; + } + + if ( i==buffer->nFilledLen ) + return OMX_ErrorMax; + + temp = temp_pBuf1[0]; + header->sync = temp & 0xFF; + if ( header->sync == 0xFF ) + { + temp = temp_pBuf1[1]; + header->sync = temp & 0xC0; + if ( header->sync != 0xC0 ) + { + DEBUG_PRINT("parse_mp3_frameheader failure"); + return OMX_ErrorMax; + } + } + else + { + DEBUG_PRINT("parse_mp3_frameheader failure"); + return OMX_ErrorMax; + } + temp = temp_pBuf1[1]; + header->version = (temp & 0x18)>>3; + header->Layer = (temp & 0x06)>>1; + temp = temp_pBuf1[2]; + header->sampling_rate = (temp & 0x0C)>>2; + temp = temp_pBuf1[3]; + header->channel_mode = (temp & 0xC0)>>6; + + DEBUG_PRINT("Channel Mode: %u, Sampling rate: %u and header version: %u from the header\n", + (unsigned)(header->channel_mode),(unsigned) (header->sampling_rate),(unsigned)( header->version)); + // Stereo, Joint Stereo,Dual Mono) + if ( (header->channel_mode == 0)||(header->channel_mode == 1)||(header->channel_mode == 2) ) + { + header->channel_mode = 2; // stereo + } + else if ( header->channel_mode == 3 ) + { + header->channel_mode = 1; // for all other cases configuring as mono TBD + } + else + { + header->channel_mode = 2; // if the channel is not recog. making the channel by default to Stereo. + DEBUG_PRINT("Defauting the channel mode to Stereo"); + } + header->sampling_rate = mp3_frequency_index[header->sampling_rate][header->version]; + DEBUG_PRINT(" frequency = %u, channels = %u\n",(unsigned)(header->sampling_rate),(unsigned)(header->channel_mode)); + return OMX_ErrorNone; +} + + +static OMX_ERRORTYPE Allocate_Buffer ( struct adec_appdata* adec_appdata, + OMX_U32 nPortIndex ) +{ + OMX_BUFFERHEADERTYPE ***pBufHdrs = NULL; + OMX_BUFFERHEADERTYPE *bufHdr = NULL; + struct msm_audio_pmem_info pmem_info; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + long bufCntMin = 0; + long bufSize = 0; + + if(!adec_appdata || !adec_appdata->mp3_dec_handle) + { + DEBUG_PRINT("\nAllocate_Buffer:Invalid i/p parameter\n"); + return OMX_ErrorBadParameter; + } + + if(nPortIndex == 0) + { + pBufHdrs = &adec_appdata->pInputBufHdrs; + bufCntMin = adec_appdata->input_buf_cnt; + bufSize = adec_appdata->inputportFmt.nBufferSize; + } + else if(nPortIndex == 1) + { + pBufHdrs = &adec_appdata->pOutputBufHdrs; + bufCntMin = adec_appdata->output_buf_cnt; + bufSize = adec_appdata->outputportFmt.nBufferSize; + } + else + { + DEBUG_PRINT("\nAllocate_Buffer:Invalid PortIndex\n"); + return OMX_ErrorBadPortIndex; + } + + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + if(*pBufHdrs == NULL) + { + DEBUG_PRINT ("\nAllocate_Buffer: *pBufHdrs allocation failed!\n"); + return OMX_ErrorInsufficientResources; + } + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(adec_appdata->mp3_dec_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + + if(error != OMX_ErrorNone) + { + DEBUG_PRINT("\nOMX_AllocateBuffer ERROR\n"); + break; + } + +#ifdef PCM_PLAYBACK + if(adec_appdata->pcmplayback == 1 && adec_appdata->pcm_device_type == PCM_DEC_DEVICE) + { + if(nPortIndex == 1) + { + bufHdr = (*pBufHdrs)[bufCnt]; + + if(bufHdr) + { + pmem_info.fd = (int)bufHdr->pOutputPortPrivate; + pmem_info.vaddr = bufHdr->pBuffer; + + DEBUG_PRINT ("\n PCMDEC REGISTER_PMEM fd = %d, vaddr = %x", + pmem_info.fd,(unsigned) (pmem_info.vaddr)); + if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_REGISTER_PMEM, &pmem_info)) + { + DEBUG_PRINT("\n Error in ioctl AUDIO_REGISTER_PMEM\n"); + error = OMX_ErrorHardware; + break; + } + } + else + { + DEBUG_PRINT("\nbufHdr is NULL, couldnt REGISTER PMEM\n"); + error = OMX_ErrorUndefined; + break; + } + } + } +#endif + + } + + if(error != OMX_ErrorNone && bufCnt < bufCntMin) + { + while(bufCnt) + { + bufCnt--; + bufHdr = (*pBufHdrs)[bufCnt]; + Free_Buffer(adec_appdata, nPortIndex, bufHdr); + } + free(*pBufHdrs); + *pBufHdrs = NULL; + } + + return error; +} + +static OMX_ERRORTYPE Use_Buffer ( struct adec_appdata* adec_appdata, + OMX_U32 nPortIndex ) +{ + OMX_BUFFERHEADERTYPE ***pBufHdrs = NULL; + OMX_BUFFERHEADERTYPE *bufHdr = NULL; + OMX_U8 *buffer = NULL; + struct msm_audio_pmem_info pmem_info; + OMX_ERRORTYPE error = OMX_ErrorNone; + long bufCnt = 0; + long bufCntMin = 0; + long bufSize = 0; + int pmem_fd = -1; + + if(!adec_appdata || !adec_appdata->mp3_dec_handle) + { + DEBUG_PRINT("\nUse_Buffer:Invalid i/p parameter\n"); + return OMX_ErrorBadParameter; + } + + if(nPortIndex == 0) + { + pBufHdrs = &adec_appdata->pInputBufHdrs; + bufCntMin = adec_appdata->input_buf_cnt; + bufSize = adec_appdata->inputportFmt.nBufferSize; + } + else if(nPortIndex == 1) + { + pBufHdrs = &adec_appdata->pOutputBufHdrs; + bufCntMin = adec_appdata->output_buf_cnt; + bufSize = adec_appdata->outputportFmt.nBufferSize; + } + else + { + DEBUG_PRINT("\nUse_Buffer:Invalid PortIndex\n"); + return OMX_ErrorBadPortIndex; + } + + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + *pBufHdrs = (OMX_BUFFERHEADERTYPE **)calloc + (sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin, 1); + + if(*pBufHdrs == NULL) + { + DEBUG_PRINT ("\nUse_Buffer: *pBufHdrs allocation failed!\n"); + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT("\nUse_Buffer::*pBufHdrs = %p", *pBufHdrs); + for(bufCnt = 0; bufCnt < bufCntMin; ++bufCnt) + { + pmem_fd = open("/dev/pmem_adsp", O_RDWR); + + if (pmem_fd < 0) + { + DEBUG_PRINT ("\n pmem_adsp open failed"); + error = OMX_ErrorInsufficientResources; + break; + } + + DEBUG_PRINT("\nUse_Buffer:: For Buffer %ld, pmem_fd = %d \n", bufCnt, + pmem_fd); + + /* Map the PMEM file descriptor into current process address space */ + buffer = (OMX_U8*) mmap( NULL, + bufSize, + PROT_READ | PROT_WRITE, + MAP_SHARED, + pmem_fd, + 0 + ); + + if(MAP_FAILED == buffer) + { + DEBUG_PRINT ("\n mmap() failed"); + buffer = NULL; + close(pmem_fd); + error = OMX_ErrorInsufficientResources; + break; + } + + DEBUG_PRINT("\n Use_Buffer::Client Buf = %p", buffer); + DEBUG_PRINT("\n OMX_UseBuffer No %ld \n", bufCnt); + error = OMX_UseBuffer( adec_appdata->mp3_dec_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, (void*)pmem_fd, bufSize, buffer + ); + DEBUG_PRINT("\nUse_Buffer::Buf ret = %p", (*pBufHdrs)[bufCnt]); + + if(error != OMX_ErrorNone) + { + DEBUG_PRINT("\nOMX_AllocateBuffer ERROR\n"); + munmap(buffer, bufSize); + buffer = NULL; + close(pmem_fd); + break; + } + +#ifdef PCM_PLAYBACK + if(adec_appdata->pcmplayback == 1 && adec_appdata->pcm_device_type == PCM_DEC_DEVICE) + { + if(nPortIndex == 1) + { + bufHdr = (*pBufHdrs)[bufCnt]; + if(bufHdr) + { + pmem_info.fd = pmem_fd; + pmem_info.vaddr = buffer; + DEBUG_PRINT ("\n PCMDEC REGISTER_PMEM fd = %d, vaddr = %x", + pmem_info.fd, (unsigned)(pmem_info.vaddr)); + if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_REGISTER_PMEM, &pmem_info)) + { + DEBUG_PRINT("\n Error in ioctl AUDIO_REGISTER_PMEM\n"); + error = OMX_ErrorHardware; + break; + } + } + else + { + DEBUG_PRINT("\nbufHdr is NULL, couldnt REGISTER PMEM\n"); + error = OMX_ErrorUndefined; + break; + } + } + } +#endif + + } + + if(error != OMX_ErrorNone && bufCnt != bufCntMin) + { + while(bufCnt) + { + bufCnt--; + bufHdr = (*pBufHdrs)[bufCnt]; + Free_Buffer(adec_appdata, nPortIndex, bufHdr); + } + free(*pBufHdrs); + *pBufHdrs = NULL; + } + + return error; +} + +static OMX_ERRORTYPE Free_Buffer ( struct adec_appdata* adec_appdata, + OMX_U32 nPortIndex, + OMX_BUFFERHEADERTYPE *bufHdr + ) +{ + struct msm_audio_pmem_info audio_pmem_buf; + OMX_ERRORTYPE error = OMX_ErrorNone; + int pmem_fd = -1; + + if(!adec_appdata || !adec_appdata->mp3_dec_handle || !bufHdr + || (nPortIndex > 1)) + { + DEBUG_PRINT("\nFree_Buffer:Invalid i/p parameters\n"); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT("\nFree_Buffer::bufHdr = %p", bufHdr); + if(adec_appdata->buffer_option == USE_BUFFER_CASE) + { + pmem_fd = (int)bufHdr->pAppPrivate; + } + else + { + if(nPortIndex == 1) + { + pmem_fd = (int)bufHdr->pOutputPortPrivate; + } + } + +#ifdef PCM_PLAYBACK + if(adec_appdata->pcmplayback && adec_appdata->pcm_device_type == PCM_DEC_DEVICE) + { + if(nPortIndex == 1 && pmem_fd > 0) + { + audio_pmem_buf.fd = pmem_fd; + audio_pmem_buf.vaddr = bufHdr->pBuffer; + DEBUG_PRINT ("\n PCMDEC DEREGISTER_PMEM fd = %d, vaddr = %x", + audio_pmem_buf.fd,(unsigned)( audio_pmem_buf.vaddr)); + if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_DEREGISTER_PMEM, &audio_pmem_buf)) + { + DEBUG_PRINT("\n Error in ioctl AUDIO_DEREGISTER_PMEM\n"); + error = OMX_ErrorHardware; + } + } + } +#endif + + if(adec_appdata->buffer_option == USE_BUFFER_CASE) + { + if (bufHdr->pBuffer && + (EINVAL == munmap (bufHdr->pBuffer, bufHdr->nAllocLen))) + { + DEBUG_PRINT ("\n Error in Unmapping the buffer %p", + bufHdr); + } + bufHdr->pBuffer = NULL; + close(pmem_fd); + DEBUG_PRINT("FREED CLIENT BUFHDR[%p], pmem_fd[%d]", bufHdr, pmem_fd); + } + return(OMX_FreeBuffer(adec_appdata->mp3_dec_handle, nPortIndex, bufHdr)); +} + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr,FILE* inputBufferFile) +{ + int bytes_read=0; + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + + bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile); + DEBUG_PRINT ("\nBytes read :%d\n",bytes_read); + pBufHdr->nFilledLen = bytes_read; + if(bytes_read == 0) { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read is Non zero\n"); + } + + return bytes_read;; +} + +static int open_audio_file (struct adec_appdata* adec_appdata) +{ + int error_code = 0; + struct wav_header hdr; + int header_len = 0; + memset(&hdr,0,sizeof(hdr)); + + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = 2; // Will be updated in the end + hdr.sample_rate = 44100; // Will be updated in the end + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, adec_appdata->in_filename); + adec_appdata->inputBufferFile = fopen (adec_appdata->in_filename, "rb"); + if (adec_appdata->inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + adec_appdata->in_filename); + error_code = -1; + } + + if((adec_appdata->tunnel == 0) && (adec_appdata->filewrite == 1)) { + DEBUG_PRINT("output file is opened\n"); + adec_appdata->outputBufferFile = fopen(adec_appdata->out_filename,"wb"); + if (adec_appdata->outputBufferFile == NULL) { + DEBUG_PRINT("\no/p file %s could NOT be opened\n", + adec_appdata->out_filename); + error_code = -1; + return error_code; + } + + header_len = fwrite(&hdr,1,sizeof(hdr),adec_appdata->outputBufferFile); + + if (header_len <= 0) { + DEBUG_PRINT("Invalid Wav header \n"); + } + DEBUG_PRINT(" Length og wav header is %d \n",header_len ); + } + return error_code; +} + +void process_portreconfig(struct adec_appdata* adec_appdata) +{ + int bufCnt,i=0; + OMX_ERRORTYPE ret; + struct msm_audio_config drv_pcm_config; + + unsigned int len=0; + hpcm_info ftb; + ftb.msg_type = CTRL; + ftb.hComponent = NULL; + ftb.bufHdr = NULL; + + DEBUG_PRINT("************************************"); + DEBUG_PRINT("RECIEVED EVENT PORT SETTINGS CHANGED EVENT\n"); + DEBUG_PRINT("******************************************\n"); + if(adec_appdata->start_done) + sleep(1); + len= write(adec_appdata->mp3_hpcm.pipe_out,&ftb,sizeof(hpcm_info)); + wait_for_event(adec_appdata); + DEBUG_PRINT("*PORT SETTINGS CHANGED: FLUSHCOMMAND TO COMPONENT*******\n"); + adec_appdata->flushinprogress = 1; + OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandFlush, 1, NULL); + wait_for_event(adec_appdata); // output port + + // Send DISABLE command + OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandPortDisable, 1, 0); + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("FREEING BUFFERS output_buf_cnt=%d\n",adec_appdata->output_buf_cnt); + DEBUG_PRINT("******************************************\n"); + + // Free output Buffer + for(bufCnt=0; bufCnt < adec_appdata->output_buf_cnt; ++bufCnt) { + Free_Buffer(adec_appdata, 1, adec_appdata->pOutputBufHdrs[bufCnt]); + } + + free(adec_appdata->pOutputBufHdrs); + adec_appdata->pOutputBufHdrs = NULL; + // wait for Disable event to come back + wait_for_event(adec_appdata); + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("DISABLE EVENT RECD\n"); + DEBUG_PRINT("******************************************\n"); + + // Send Enable command + OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandPortEnable, 1, 0); + + adec_appdata->flushinprogress = 0; + + // AllocateBuffers + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("ALLOC BUFFER AFTER PORT REENABLE"); + DEBUG_PRINT("******************************************\n"); + + if(adec_appdata->buffer_option == USE_BUFFER_CASE) + { + + /* Use buffer on decoder's o/p port */ + adec_appdata->error = Use_Buffer(adec_appdata, + adec_appdata->outputportFmt.nPortIndex); + if (adec_appdata->error != OMX_ErrorNone) + { + DEBUG_PRINT ("\nOMX_UseBuffer Output buffer error\n"); + return; + } + else + { + DEBUG_PRINT ("\nOMX_UseBuffer Output buffer success\n"); + } + } + else + { + /* Allocate buffer on decoder's o/p port */ + adec_appdata->error = Allocate_Buffer(adec_appdata, + adec_appdata->outputportFmt.nPortIndex); + if (adec_appdata->error != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error output_buf_cnt=%d\n",adec_appdata->output_buf_cnt); + return; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success output_buf_cnt=%d\n",adec_appdata->output_buf_cnt); + } + } + + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("ENABLE EVENTiHANDLER RECD\n"); + DEBUG_PRINT("******************************************\n"); + // wait for enable event to come back + wait_for_event(adec_appdata); + if(adec_appdata->pcmplayback && adec_appdata->pcm_device_type == HOST_PCM_DEVICE + && adec_appdata->start_done) + + { + DEBUG_PRINT(" Calling fsync on pcm driver...\n"); + while (fsync(adec_appdata->m_pcmdrv_fd) < 0) { + printf(" fsync failed\n"); + sleep(1); + } + DEBUG_PRINT(" Calling stop on pcm driver...\n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_STOP, 0); + DEBUG_PRINT(" Calling flush on pcm driver...\n"); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_FLUSH, 0); + sleep(3); + OMX_GetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamAudioMp3,&adec_appdata->mp3param); + drv_pcm_config.sample_rate = adec_appdata->mp3param.nSampleRate; + drv_pcm_config.channel_count =adec_appdata-> mp3param.nChannels; + printf("sample =%lu channel = %lu\n",adec_appdata->mp3param.nSampleRate,adec_appdata->mp3param.nChannels); + ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config); + + + DEBUG_PRINT("Configure Driver for PCM playback \n"); + adec_appdata->start_done = 0; + adec_appdata->bReconfigureOutputPort = 0; + } + DEBUG_PRINT("******************************************\n"); + DEBUG_PRINT("FTB after PORT RENABLE\n"); + DEBUG_PRINT("******************************************\n"); + for(i=0; i < adec_appdata->output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + adec_appdata->pOutputBufHdrs[i]->nOutputPortIndex = 1; + adec_appdata->pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(adec_appdata->mp3_dec_handle, adec_appdata->pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } +} + +void write_devctlcmd(int fd, const void *buf, int param){ + int nbytes, nbytesWritten; + char cmdstr[128]; + snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param); + nbytes = strlen(cmdstr); + nbytesWritten = write(fd, cmdstr, nbytes); + + if(nbytes != nbytesWritten) + printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr); +} + + diff --git a/mm-audio/aenc-aac/Android.mk b/mm-audio/aenc-aac/Android.mk new file mode 100644 index 000000000..b81257259 --- /dev/null +++ b/mm-audio/aenc-aac/Android.mk @@ -0,0 +1,23 @@ +ifeq ($(TARGET_ARCH),arm) + + +AENC_AAC_PATH:= $(call my-dir) + +ifeq ($(call is-board-platform,msm8660),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8960),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8974),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8226),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8610),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif + + +endif diff --git a/mm-audio/aenc-aac/Makefile b/mm-audio/aenc-aac/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/mm-audio/aenc-aac/Makefile @@ -0,0 +1,6 @@ +all: + @echo "invoking omxaudio make" + $(MAKE) -C qdsp6 + +install: + $(MAKE) -C qdsp6 install diff --git a/mm-audio/aenc-aac/Makefile.am b/mm-audio/aenc-aac/Makefile.am new file mode 100644 index 000000000..24c1af26d --- /dev/null +++ b/mm-audio/aenc-aac/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qdsp6 diff --git a/mm-audio/aenc-aac/qdsp6/Android.mk b/mm-audio/aenc-aac/qdsp6/Android.mk new file mode 100644 index 000000000..e339f5d09 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/Android.mk @@ -0,0 +1,76 @@ +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxAacEnc-def := -g -O3 +libOmxAacEnc-def += -DQC_MODIFIED +libOmxAacEnc-def += -D_ANDROID_ +libOmxAacEnc-def += -D_ENABLE_QC_MSG_LOG_ +libOmxAacEnc-def += -DVERBOSE +libOmxAacEnc-def += -D_DEBUG +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +libOmxAacEnc-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxAacEnc) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +libOmxAacEnc-inc := $(LOCAL_PATH)/inc +libOmxAacEnc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore + +LOCAL_MODULE := libOmxAacEnc +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAacEnc-def) +LOCAL_C_INCLUDES := $(libOmxAacEnc-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libutils liblog + +LOCAL_SRC_FILES := src/aenc_svr.c +LOCAL_SRC_FILES += src/omx_aac_aenc.cpp + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +include $(BUILD_SHARED_LIBRARY) + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-aenc-omxaac-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +mm-aac-enc-test-inc := $(LOCAL_PATH)/inc +mm-aac-enc-test-inc += $(LOCAL_PATH)/test +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +mm-aac-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +endif +mm-aac-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore + +LOCAL_MODULE := mm-aenc-omxaac-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAacEnc-def) +LOCAL_C_INCLUDES := $(mm-aac-enc-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libmm-omxcore +LOCAL_SHARED_LIBRARIES += libOmxAacEnc +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +LOCAL_SHARED_LIBRARIES += libaudioalsa +endif +LOCAL_SRC_FILES := test/omx_aac_enc_test.c + +include $(BUILD_EXECUTABLE) + +endif + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- + diff --git a/mm-audio/aenc-aac/qdsp6/Makefile b/mm-audio/aenc-aac/qdsp6/Makefile new file mode 100644 index 000000000..5421d45b9 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/Makefile @@ -0,0 +1,81 @@ +# --------------------------------------------------------------------------------- +# MM-AUDIO-OSS-8K-AENC-AAC +# --------------------------------------------------------------------------------- + +# cross-compiler flags +CFLAGS += -Wall +CFLAGS += -Wundef +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wno-trigraphs + +# cross-compile flags specific to shared objects +CFLAGS_SO += -fpic + +# required pre-processor flags +CPPFLAGS := -D__packed__= +CPPFLAGS += -DIMAGE_APPS_PROC +CPPFLAGS += -DFEATURE_Q_SINGLE_LINK +CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR +CPPFLAGS += -DFEATURE_LINUX +CPPFLAGS += -DFEATURE_NATIVELINUX +CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS + +CPPFLAGS += -g +CPPFALGS += -D_DEBUG +CPPFLAGS += -Iinc + +# linker flags +LDFLAGS += -L$(SYSROOT)/usr/lib + +# linker flags for shared objects +LDFLAGS_SO := -shared + +# defintions +LIBMAJOR := $(basename $(basename $(LIBVER))) +LIBINSTALLDIR := $(DESTDIR)usr/lib +INCINSTALLDIR := $(DESTDIR)usr/include +BININSTALLDIR := $(DESTDIR)usr/bin + +# --------------------------------------------------------------------------------- +# BUILD +# --------------------------------------------------------------------------------- +all: libOmxAacEnc.so.$(LIBVER) mm-aenc-omxaac-test + +install: + echo "intalling aenc-aac in $(DESTDIR)" + if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi + if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi + if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi + install -m 555 libOmxAacEnc.so.$(LIBVER) $(LIBINSTALLDIR) + cd $(LIBINSTALLDIR) && ln -s libOmxAacEnc.so.$(LIBVER) libOmxAacEnc.so.$(LIBMAJOR) + cd $(LIBINSTALLDIR) && ln -s libOmxAacEnc.so.$(LIBMAJOR) libOmxAacEnc.so + install -m 555 mm-aenc-omxaac-test $(BININSTALLDIR) + +# --------------------------------------------------------------------------------- +# COMPILE LIBRARY +# --------------------------------------------------------------------------------- +LDLIBS := -lpthread +LDLIBS += -lstdc++ +LDLIBS += -lOmxCore + +SRCS := src/omx_aac_aenc.cpp +SRCS += src/aenc_svr.c + +libOmxAacEnc.so.$(LIBVER): $(SRCS) + $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxAacEnc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +# --------------------------------------------------------------------------------- +# COMPILE TEST APP +# --------------------------------------------------------------------------------- +TEST_LDLIBS := -lpthread +TEST_LDLIBS += -ldl +TEST_LDLIBS += -lOmxCore + +TEST_SRCS := test/omx_aac_enc_test.c + +mm-aenc-omxaac-test: libOmxAacEnc.so.$(LIBVER) $(TEST_SRCS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS) + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/aenc-aac/qdsp6/Makefile.am b/mm-audio/aenc-aac/qdsp6/Makefile.am new file mode 100644 index 000000000..5af028a0d --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/Makefile.am @@ -0,0 +1,30 @@ +# sources and intermediate files are separated + +AM_CFLAGS = -Wall +AM_CFLAGS += -Wundef +AM_CFLAGS += -Wstrict-prototypes +AM_CFLAGS += -Wno-trigraphs +AM_CFLAGS += -g -O3 + +AM_CPPFLAGS = -D__packed__= +AM_CPPFLAGS += -DIMAGE_APPS_PROC +AM_CPPFLAGS += -DFEATURE_Q_SINGLE_LINK +AM_CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR +AM_CPPFLAGS += -DFEATURE_LINUX +AM_CPPFLAGS += -DFEATURE_NATIVELINUX +AM_CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS +AM_CPPFLAGS += -D_DEBUG +AM_CPPFLAGS += -Iinc + +c_sources =src/omx_aac_aenc.cpp +c_sources +=src/aenc_svr.c + +lib_LTLIBRARIES = libOmxAacEnc.la +libOmxAacEnc_la_SOURCES = $(c_sources) +libOmxAacEnc_la_CFLAGS = $(AM_CFLAGS) -fPIC +libOmxAacEnc_la_LDLIBS = -lOmxCore -lstdc++ -lpthread +libOmxAacEnc_la_LDFLAGS = -shared -version-info $(OMXAUDIO_LIBRARY_VERSION) + +bin_PROGRAMS = mm-aenc-omxaac-test +mm_aenc_omxaac_test_SOURCES = test/omx_aac_enc_test.c +mm_aenc_omxaac_test_LDADD = -lOmxCore -ldl -lpthread libOmxAacEnc.la diff --git a/mm-audio/aenc-aac/qdsp6/inc/Map.h b/mm-audio/aenc-aac/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/inc/Map.h @@ -0,0 +1,244 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _MAP_H_ +#define _MAP_H_ + +#include +using namespace std; + +template +class Map +{ + struct node + { + T data; + T2 data2; + node* prev; + node* next; + node(T t, T2 t2,node* p, node* n) : + data(t), data2(t2), prev(p), next(n) {} + }; + node* head; + node* tail; + node* tmp; + unsigned size_of_list; + static Map *m_self; +public: + Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {} + bool empty() const { return ( !head || !tail ); } + operator bool() const { return !empty(); } + void insert(T,T2); + void show(); + int size(); + T2 find(T); // Return VALUE + T find_ele(T);// Check if the KEY is present or not + T2 begin(); //give the first ele + bool erase(T); + bool eraseall(); + bool isempty(); + ~Map() + { + while(head) + { + node* temp(head); + head=head->next; + size_of_list--; + delete temp; + } + } +}; + +template +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::insert(T data, T2 data2) +{ + tail = new node(data, data2,tail, NULL); + if( tail->prev ) + tail->prev->next = tail; + + if( empty() ) + { + head = tail; + tmp=head; + } + tmp = head; + size_of_list++; +} + +template +bool Map::erase(T d) +{ + bool found = false; + tmp = head; + node* prevnode = tmp; + node *tempnode; + + while(tmp) + { + if((head == tail) && (head->data == d)) + { + found = true; + tempnode = head; + head = tail = NULL; + delete tempnode; + break; + } + if((tmp ==head) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + tmp = tmp->next; + tmp->prev = NULL; + head = tmp; + tempnode->next = NULL; + delete tempnode; + break; + } + if((tmp == tail) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + prevnode->next = NULL; + tmp->prev = NULL; + tail = prevnode; + delete tempnode; + break; + } + if(tmp->data == d) + { + found = true; + prevnode->next = tmp->next; + tmp->next->prev = prevnode->next; + tempnode = tmp; + //tmp = tmp->next; + delete tempnode; + break; + } + prevnode = tmp; + tmp = tmp->next; + } + if(found)size_of_list--; + return found; +} + +template +bool Map::eraseall() +{ + // Be careful while using this method + // it not only removes the node but FREES(not delete) the allocated + // memory. + node *tempnode; + tmp = head; + while(head) + { + tempnode = head; + head = head->next; + tempnode->next = NULL; + if(tempnode->data) + free(tempnode->data); + if(tempnode->data2) + free(tempnode->data2); + delete tempnode; + } + tail = head = NULL; + return true; +} + + +template +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..72bfebed2 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h @@ -0,0 +1,120 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef AENC_SVR_H +#define AENC_SVR_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include + +#ifdef _ANDROID_ +#define LOG_TAG "QC_AACENC" +#endif + +#ifndef LOGE +#define LOGE ALOGE +#endif + +#ifndef LOGW +#define LOGW ALOGW +#endif + +#ifndef LOGD +#define LOGD ALOGD +#endif + +#ifndef LOGV +#define LOGV ALOGV +#endif + +#ifndef LOGI +#define LOGI ALOGI +#endif + +#define DEBUG_PRINT_ERROR LOGE +#define DEBUG_PRINT LOGI +#define DEBUG_DETAIL LOGV + +typedef void (*message_func)(void* client_data, unsigned char id); + +/** + @brief audio encoder ipc info structure + + */ +struct aac_ipc_info +{ + pthread_t thr; + int pipe_in; + int pipe_out; + int dead; + message_func process_msg_cb; + void *client_data; + char thread_name[128]; +}; + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to command server + */ +struct aac_ipc_info *omx_aac_thread_create(message_func cb, + void* client_data, + char *th_name); + +struct aac_ipc_info *omx_aac_event_thread_create(message_func cb, + void* client_data, + char *th_name); +/** + @brief This function stop command server + + @param svr handle to command server + @return none + */ +void omx_aac_thread_stop(struct aac_ipc_info *aac_ipc); + + +/** + @brief This function post message in the command server + + @param svr handle to command server + @return none + */ +void omx_aac_post_msg(struct aac_ipc_info *aac_ipc, + unsigned char id); + +#ifdef __cplusplus +} +#endif + +#endif /* AENC_SVR */ diff --git a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h new file mode 100644 index 000000000..276eaa351 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h @@ -0,0 +1,624 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _AAC_ENC_H_ +#define _AAC_ENC_H_ +/*============================================================================ + Audio Encoder + +@file omx_aac_aenc.h +This module contains the class definition for openMAX encoder component. + + + +============================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see + * all DEBUG_PRINT or LOGV messaging */ +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#include "OMX_Core.h" +#include "OMX_Audio.h" +#include "aenc_svr.h" +#include "qc_omx_component.h" +#include "Map.h" +#include +#include +#include +extern "C" { + void * get_omx_component_factory_fn(void); +} + + +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// + + + +#define OMX_SPEC_VERSION 0x00000101 +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (x >= y?x:y) + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +// + + +#define PrintFrameHdr(i,bufHdr) \ + DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\ + i,\ + (unsigned) bufHdr, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags) + + +// BitMask Management logic +#define BITS_PER_BYTE 8 +#define BITMASK_SIZE(mIndex) \ + (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE) +#define BITMASK_OFFSET(mIndex)\ + ((mIndex)/BITS_PER_BYTE) +#define BITMASK_FLAG(mIndex) \ + (1 << ((mIndex) % BITS_PER_BYTE)) +#define BITMASK_CLEAR(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex)\ + ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex)\ + (((mArray)[BITMASK_OFFSET(mIndex)] & \ + BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_NUM_INPUT_BUFFERS 2 +#define OMX_CORE_NUM_OUTPUT_BUFFERS 16 + +#define OMX_CORE_INPUT_BUFFER_SIZE 8192 +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_AENC_VOLUME_STEP 0x147 +#define OMX_AENC_MIN 0 +#define OMX_AENC_MAX 100 +#define NON_TUNNEL 1 +#define TUNNEL 0 +#define IP_PORT_BITMASK 0x02 +#define OP_PORT_BITMASK 0x01 +#define IP_OP_PORT_BITMASK 0x03 + +#define DEFAULT_SF 44100 +#define DEFAULT_CH_CFG 2 +#define DEFAULT_BITRATE 64000 +#define OMX_AAC_DEFAULT_VOL 25 +// 14 bytes for input meta data +#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14) + +#define TRUE 1 +#define FALSE 0 + + +#define NUMOFFRAMES 1 +#define MAXFRAMELENGTH 1536 +#define OMX_AAC_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT)+ MAXFRAMELENGTH + 1)\ + + 1023) & (~1023)) +//Raw Header +#define AUDAAC_MAX_MP4FF_HEADER_LENGTH 2 + +#define AUDAAC_MP4FF_OBJ_TYPE 5 +#define AUDAAC_MP4FF_FREQ_IDX 4 +#define AUDAAC_MP4FF_CH_CONFIG 4 + +//ADIF Header +#define AUDAAC_MAX_ADIF_HEADER_LENGTH 17 + +#define AAC_COPYRIGHT_PRESENT_SIZE 1 +#define AAC_ORIGINAL_COPY_SIZE 1 +#define AAC_HOME_SIZE 1 +#define AAC_BITSTREAM_TYPE_SIZE 1 +#define AAC_BITRATE_SIZE 23 +#define AAC_NUM_PFE_SIZE 4 +#define AAC_BUFFER_FULLNESS_SIZE 20 +#define AAC_ELEMENT_INSTANCE_TAG_SIZE 4 +#define AAC_NUM_FRONT_CHANNEL_ELEMENTS_SIZE 4 +#define AAC_NUM_SIDE_CHANNEL_ELEMENTS_SIZE 4 +#define AAC_NUM_BACK_CHANNEL_ELEMENTS_SIZE 4 +#define AAC_NUM_LFE_CHANNEL_ELEMENTS_SIZE 2 +#define AAC_NUM_ASSOC_DATA_ELEMENTS_SIZE 3 +#define AAC_NUM_VALID_CC_ELEMENTS_SIZE 4 +#define AAC_MONO_MIXDOWN_PRESENT_SIZE 1 +#define AAC_MONO_MIXDOWN_ELEMENT_SIZE 4 +#define AAC_STEREO_MIXDOWN_PRESENT_SIZE 1 +#define AAC_STEREO_MIXDOWN_ELEMENT_SIZE 4 +#define AAC_MATRIX_MIXDOWN_PRESENT_SIZE 1 +#define AAC_MATRIX_MIXDOWN_SIZE 3 +#define AAC_FCE_SIZE 5 +#define AAC_SCE_SIZE 5 +#define AAC_BCE_SIZE 5 +#define AAC_LFE_SIZE 4 +#define AAC_ADE_SIZE 4 +#define AAC_VCE_SIZE 5 +#define AAC_COMMENT_FIELD_BYTES_SIZE 8 +#define AAC_COMMENT_FIELD_DATA_SIZE 8 +#define AAC_SAMPLING_FREQ_INDEX_SIZE 4 +#define AAC_PROFILE_SIZE 2 + + + +//Raw Header +#define AUDAAC_MAX_RAW_HEADER_LENGTH 8 + +#define AUDAAC_RAW_OBJ_TYPE 8 +#define AUDAAC_RAW_FREQ_IDX 8 +#define AUDAAC_RAW_CH_CONFIG 8 +#define AUDAAC_RAW_SBR_PRESENT 8 +#define AUDAAC_RAW_SBR_PS_PRESENT 8 +#define AUDAAC_RAW_EXT_OBJ_TYPE 8 +#define AUDAAC_RAW_EXT_FREQ_IDX 8 +#define AUDAAC_RAW_EXT_CH_CONFIG 8 + +struct sample_rate_idx { + OMX_U32 sample_rate; + OMX_U32 sample_rate_idx; +}; +static struct sample_rate_idx sample_idx_tbl[10] = { + {8000, 0x0b}, + {11025, 0x0a}, + {12000, 0x09}, + {16000, 0x08}, + {22050, 0x07}, + {24000, 0x06}, + {32000, 0x05}, + {44100, 0x04}, + {48000, 0x03}, + {64000, 0x02}, +}; +class omx_aac_aenc; + +// OMX AAC audio encoder class +class omx_aac_aenc: public qc_omx_component +{ +public: + omx_aac_aenc(); // constructor + virtual ~omx_aac_aenc(); // destructor + + OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index); + + OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup); + + OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE * specVersion, + OMX_UUIDTYPE *componentUUID); + + OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + static void process_in_port_msg(void *client_data, + unsigned char id); + + static void process_out_port_msg(void *client_data, + unsigned char id); + + static void process_command_msg(void *client_data, + unsigned char id); + + static void process_event_cb(void *client_data, + unsigned char id); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + + bool post_command(unsigned int p1, unsigned int p2, + unsigned int id); + + // Deferred callback identifiers + enum + { + //Event Callbacks from the component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + OMX_COMPONENT_GENERATE_ETB = 0x3, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x4, + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05, + OMX_COMPONENT_GENERATE_FTB = 0x06, + OMX_COMPONENT_GENERATE_EOS = 0x07, + OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08, + OMX_COMPONENT_SUSPEND = 0x09, + OMX_COMPONENT_RESUME = 0x0a + }; +private: + + /////////////////////////////////////////////////////////// + // Type definitions + /////////////////////////////////////////////////////////// + // Bit Positions + enum flags_bit_positions + { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + + OMX_COMPONENT_MUTED =0x3, + + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7 + }; + + + typedef Map + input_buffer_map; + + typedef Map + output_buffer_map; + + enum port_indexes + { + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 + }; + + struct omx_event + { + unsigned param1; + unsigned param2; + unsigned id; + }; + + struct omx_cmd_queue + { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned m_read; + unsigned m_write; + unsigned m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned p1, unsigned p2, unsigned id); + bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id); + bool get_msg_id(unsigned *id); + bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id); + }; + + typedef struct TIMESTAMP + { + unsigned long LowPart; + unsigned long HighPart; + }__attribute__((packed)) TIMESTAMP; + + typedef struct metadata_input + { + unsigned short offsetVal; + TIMESTAMP nTimeStamp; + unsigned int nFlags; + }__attribute__((packed)) META_IN; + + typedef struct enc_meta_out + { + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; + } __attribute__ ((packed))ENC_META_OUT; + + typedef struct + { + OMX_U32 tot_in_buf_len; + OMX_U32 tot_out_buf_len; + OMX_U32 tot_pb_time; + OMX_U32 fbd_cnt; + OMX_U32 ftb_cnt; + OMX_U32 etb_cnt; + OMX_U32 ebd_cnt; + }AAC_PB_STATS; + + /////////////////////////////////////////////////////////// + // Member variables + /////////////////////////////////////////////////////////// + OMX_U8 *m_tmp_meta_buf; + OMX_U8 *m_tmp_out_meta_buf; + OMX_U8 m_flush_cnt ; + OMX_U8 m_comp_deinit; + + // the below var doesnt hold good if combo of use and alloc bufs are used + OMX_U8 m_eos_bm; + OMX_S32 m_volume;//Unit to be determined + OMX_U8 audaac_header_adif[AUDAAC_MAX_ADIF_HEADER_LENGTH]; + OMX_U8 audaac_header_mp4ff[AUDAAC_MAX_MP4FF_HEADER_LENGTH]; + OMX_U16 audaac_hdr_bit_index; + OMX_S32 sample_idx; + OMX_S32 adif_flag; + OMX_S32 mp4ff_flag; + OMX_PTR m_app_data;// Application data + int nNumInputBuf; + int nNumOutputBuf; + int m_drv_fd; // Kernel device node file handle + bool bFlushinprogress; + bool is_in_th_sleep; + bool is_out_th_sleep; + unsigned int m_flags; //encapsulate the waiting states. + OMX_U64 nTimestamp; + OMX_U64 ts; + unsigned int frameduration; + unsigned int pcm_input; //tunnel or non-tunnel + unsigned int m_inp_act_buf_count; // Num of Input Buffers + unsigned int m_out_act_buf_count; // Numb of Output Buffers + unsigned int m_inp_current_buf_count; // Num of Input Buffers + unsigned int m_out_current_buf_count; // Numb of Output Buffers + unsigned int output_buffer_size; + unsigned int input_buffer_size; + unsigned short m_session_id; + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + sem_t sem_States; + sem_t sem_read_msg; + sem_t sem_write_msg; + + volatile int m_is_event_done; + volatile int m_is_in_th_sleep; + volatile int m_is_out_th_sleep; + input_buffer_map m_input_buf_hdrs; + output_buffer_map m_output_buf_hdrs; + omx_cmd_queue m_input_q; + omx_cmd_queue m_input_ctrl_cmd_q; + omx_cmd_queue m_input_ctrl_ebd_q; + omx_cmd_queue m_command_q; + omx_cmd_queue m_output_q; + omx_cmd_queue m_output_ctrl_cmd_q; + omx_cmd_queue m_output_ctrl_fbd_q; + pthread_mutexattr_t m_outputlock_attr; + pthread_mutexattr_t m_commandlock_attr; + pthread_mutexattr_t m_lock_attr; + pthread_mutexattr_t m_state_attr; + pthread_mutexattr_t m_flush_attr; + pthread_mutexattr_t m_in_th_attr_1; + pthread_mutexattr_t m_out_th_attr_1; + pthread_mutexattr_t m_event_attr; + pthread_mutexattr_t m_in_th_attr; + pthread_mutexattr_t m_out_th_attr; + pthread_mutexattr_t out_buf_count_lock_attr; + pthread_mutexattr_t in_buf_count_lock_attr; + pthread_cond_t cond; + pthread_cond_t in_cond; + pthread_cond_t out_cond; + pthread_mutex_t m_lock; + pthread_mutex_t m_commandlock; + pthread_mutex_t m_outputlock; + // Mutexes for state change + pthread_mutex_t m_state_lock; + // Mutexes for flush acks from input and output threads + pthread_mutex_t m_flush_lock; + pthread_mutex_t m_event_lock; + pthread_mutex_t m_in_th_lock; + pthread_mutex_t m_out_th_lock; + pthread_mutex_t m_in_th_lock_1; + pthread_mutex_t m_out_th_lock_1; + pthread_mutex_t out_buf_count_lock; + pthread_mutex_t in_buf_count_lock; + + OMX_STATETYPE m_state; // OMX State + OMX_STATETYPE nState; + OMX_CALLBACKTYPE m_cb; // Application callbacks + AAC_PB_STATS m_aac_pb_stats; + struct aac_ipc_info *m_ipc_to_in_th; // for input thread + struct aac_ipc_info *m_ipc_to_out_th; // for output thread + struct aac_ipc_info *m_ipc_to_cmd_th; // for command thread + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_AUDIO_PARAM_AACPROFILETYPE m_aac_param; // Cache AAC encoder parameter + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter + OMX_PARAM_COMPONENTROLETYPE component_Role; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + + /////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////// + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + bool allocate_done(void); + + bool release_done(OMX_U32 param1); + + bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true); + + bool execute_input_omx_flush(void); + + bool execute_output_omx_flush(void); + + bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool post_input(unsigned int p1, unsigned int p2, + unsigned int id); + + bool post_output(unsigned int p1, unsigned int p2, + unsigned int id); + + void process_events(omx_aac_aenc *client_data); + + void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void wait_for_event(); + + void event_complete(); + + void in_th_goto_sleep(); + + void in_th_wakeup(); + + void out_th_goto_sleep(); + + void out_th_wakeup(); + + void flush_ack(); + void deinit_encoder(); + void audaac_rec_install_adif_header_variable (OMX_U16 byte_num, + OMX_U32 sample_index, OMX_U8 channel_config); + void audaac_rec_install_mp4ff_header_variable (OMX_U16 byte_num, + OMX_U32 sample_index,OMX_U8 channel_config); + void audaac_rec_install_bits(OMX_U8 *input, + OMX_U8 num_bits_reqd, + OMX_U32 value, + OMX_U16 *hdr_bit_index); + +}; +#endif diff --git a/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c b/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..a7c2a42b7 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c @@ -0,0 +1,206 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#include +#include +#include + +#include +#include + +#include + +/** + @brief This function processes posted messages + + Once thread is being spawned, this function is run to + start processing commands posted by client + + @param info pointer to context + + */ +void *omx_aac_msg(void *info) +{ + struct aac_ipc_info *aac_info = (struct aac_ipc_info*)info; + unsigned char id; + int n; + + DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__); + while (!aac_info->dead) + { + n = read(aac_info->pipe_in, &id, 1); + if (0 == n) break; + if (1 == n) + { + DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n", + aac_info->thread_name, + aac_info->pipe_in, + aac_info->pipe_out); + + aac_info->process_msg_cb(aac_info->client_data, id); + } + if ((n < 0) && (errno != EINTR)) break; + } + DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__); + + return 0; +} + +void *omx_aac_events(void *info) +{ + struct aac_ipc_info *aac_info = (struct aac_ipc_info*)info; + unsigned char id = 0; + + DEBUG_DETAIL("%s: message thread start\n", aac_info->thread_name); + aac_info->process_msg_cb(aac_info->client_data, id); + DEBUG_DETAIL("%s: message thread stop\n", aac_info->thread_name); + return 0; +} + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to msging thread + */ +struct aac_ipc_info *omx_aac_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct aac_ipc_info *aac_info; + + aac_info = calloc(1, sizeof(struct aac_ipc_info)); + if (!aac_info) + { + return 0; + } + + aac_info->client_data = client_data; + aac_info->process_msg_cb = cb; + strlcpy(aac_info->thread_name, th_name, sizeof(aac_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + aac_info->pipe_in = fds[0]; + aac_info->pipe_out = fds[1]; + + r = pthread_create(&aac_info->thr, 0, omx_aac_msg, aac_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", aac_info->thread_name); + return aac_info; + + +fail_thread: + close(aac_info->pipe_in); + close(aac_info->pipe_out); + +fail_pipe: + free(aac_info); + + return 0; +} + +/** + * @brief This function starts command server + * + * @param cb pointer to callback function from the client + * @param client_data reference client wants to get back + * through callback + * @return handle to msging thread + * */ +struct aac_ipc_info *omx_aac_event_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct aac_ipc_info *aac_info; + + aac_info = calloc(1, sizeof(struct aac_ipc_info)); + if (!aac_info) + { + return 0; + } + + aac_info->client_data = client_data; + aac_info->process_msg_cb = cb; + strlcpy(aac_info->thread_name, th_name, sizeof(aac_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + aac_info->pipe_in = fds[0]; + aac_info->pipe_out = fds[1]; + + r = pthread_create(&aac_info->thr, 0, omx_aac_events, aac_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", aac_info->thread_name); + return aac_info; + + +fail_thread: + close(aac_info->pipe_in); + close(aac_info->pipe_out); + +fail_pipe: + free(aac_info); + + return 0; +} + +void omx_aac_thread_stop(struct aac_ipc_info *aac_info) { + DEBUG_DETAIL("%s stop server\n", __FUNCTION__); + close(aac_info->pipe_in); + close(aac_info->pipe_out); + pthread_join(aac_info->thr,NULL); + aac_info->pipe_out = -1; + aac_info->pipe_in = -1; + DEBUG_DETAIL("%s: message thread close fds%d %d\n", aac_info->thread_name, + aac_info->pipe_in,aac_info->pipe_out); + free(aac_info); +} + +void omx_aac_post_msg(struct aac_ipc_info *aac_info, unsigned char id) { + DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id); + + write(aac_info->pipe_out, &id, 1); +} diff --git a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp new file mode 100644 index 000000000..52aa915fb --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp @@ -0,0 +1,5016 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +/*============================================================================ +@file omx_aenc_aac.c + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include "omx_aac_aenc.h" +#include + +using namespace std; + +#define SLEEP_MS 100 + +// omx_cmd_queue destructor +omx_aac_aenc::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_aac_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE); +} + +// omx cmd queue insert +bool omx_aac_aenc::omx_cmd_queue::insert_entry(unsigned p1, + unsigned p2, + unsigned id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_write = 0; + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full"); + } + return ret; +} + +bool omx_aac_aenc::omx_cmd_queue::pop_entry(unsigned *p1, + unsigned *p2, unsigned *id) +{ + bool ret = true; + if (m_size > 0) + { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_read = 0; + + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty"); + } + return ret; +} + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return(new omx_aac_aenc); +} +bool omx_aac_aenc::omx_cmd_queue::get_msg_id(unsigned *id) +{ + if(m_size > 0) + { + *id = m_q[m_read].id; + DEBUG_PRINT("get_msg_id=%d\n",*id); + } + else{ + return false; + } + return true; +} +/*============================================================================= +FUNCTION: + wait_for_event + +DESCRIPTION: + waits for a particular event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_aac_aenc::wait_for_event() +{ + int rc; + struct timespec ts; + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (SLEEP_MS/1000); + ts.tv_nsec += ((SLEEP_MS%1000) * 1000000); + rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts); + if (rc == ETIMEDOUT && !m_is_event_done) { + DEBUG_PRINT("Timed out waiting for flush"); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + } + } + m_is_event_done = 0; + pthread_mutex_unlock(&m_event_lock); +} + +/*============================================================================= +FUNCTION: + event_complete + +DESCRIPTION: + informs about the occurance of an event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_aac_aenc::event_complete() +{ + pthread_mutex_lock(&m_event_lock); + if (0 == m_is_event_done) + { + m_is_event_done = 1; + pthread_cond_signal(&cond); + } + pthread_mutex_unlock(&m_event_lock); +} + +// All this non-sense because of a single aac object +void omx_aac_aenc::in_th_goto_sleep() +{ + pthread_mutex_lock(&m_in_th_lock); + while (0 == m_is_in_th_sleep) + { + pthread_cond_wait(&in_cond, &m_in_th_lock); + } + m_is_in_th_sleep = 0; + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_aac_aenc::in_th_wakeup() +{ + pthread_mutex_lock(&m_in_th_lock); + if (0 == m_is_in_th_sleep) + { + m_is_in_th_sleep = 1; + pthread_cond_signal(&in_cond); + } + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_aac_aenc::out_th_goto_sleep() +{ + + pthread_mutex_lock(&m_out_th_lock); + while (0 == m_is_out_th_sleep) + { + pthread_cond_wait(&out_cond, &m_out_th_lock); + } + m_is_out_th_sleep = 0; + pthread_mutex_unlock(&m_out_th_lock); +} + +void omx_aac_aenc::out_th_wakeup() +{ + pthread_mutex_lock(&m_out_th_lock); + if (0 == m_is_out_th_sleep) + { + m_is_out_th_sleep = 1; + pthread_cond_signal(&out_cond); + } + pthread_mutex_unlock(&m_out_th_lock); +} +/* ====================================================================== +FUNCTION + omx_aac_aenc::omx_aac_aenc + +DESCRIPTION + Constructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_aac_aenc::omx_aac_aenc(): m_tmp_meta_buf(NULL), + m_tmp_out_meta_buf(NULL), + m_flush_cnt(255), + m_comp_deinit(0), + adif_flag(0), + mp4ff_flag(0), + m_app_data(NULL), + m_drv_fd(-1), + bFlushinprogress(0), + is_in_th_sleep(false), + is_out_th_sleep(false), + m_flags(0), + nTimestamp(0), + ts(0), + frameduration(0), + m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS), + m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS), + m_inp_current_buf_count(0), + m_out_current_buf_count(0), + output_buffer_size(OMX_AAC_OUTPUT_BUFFER_SIZE), + input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE), + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_is_event_done(0), + m_state(OMX_StateInvalid), + m_ipc_to_in_th(NULL), + m_ipc_to_out_th(NULL), + m_ipc_to_cmd_th(NULL), + nNumOutputBuf(0), + m_session_id(0) +{ + int cond_ret = 0; + component_Role.nSize = 0; + memset(&m_cmp, 0, sizeof(m_cmp)); + memset(&m_cb, 0, sizeof(m_cb)); + memset(&m_aac_pb_stats, 0, sizeof(m_aac_pb_stats)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + memset(&m_aac_param, 0, sizeof(m_aac_param)); + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + + pthread_mutexattr_init(&m_lock_attr); + pthread_mutex_init(&m_lock, &m_lock_attr); + pthread_mutexattr_init(&m_commandlock_attr); + pthread_mutex_init(&m_commandlock, &m_commandlock_attr); + + pthread_mutexattr_init(&m_outputlock_attr); + pthread_mutex_init(&m_outputlock, &m_outputlock_attr); + + pthread_mutexattr_init(&m_state_attr); + pthread_mutex_init(&m_state_lock, &m_state_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_flush_attr); + pthread_mutex_init(&m_flush_lock, &m_flush_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_in_th_attr); + pthread_mutex_init(&m_in_th_lock, &m_in_th_attr); + + pthread_mutexattr_init(&m_out_th_attr); + pthread_mutex_init(&m_out_th_lock, &m_out_th_attr); + + pthread_mutexattr_init(&m_in_th_attr_1); + pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1); + + pthread_mutexattr_init(&m_out_th_attr_1); + pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1); + + pthread_mutexattr_init(&out_buf_count_lock_attr); + pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr); + + pthread_mutexattr_init(&in_buf_count_lock_attr); + pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr); + if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to \ + initialise condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to \ + initialise condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to \ + initialise condition variable\n"); + } + + sem_init(&sem_read_msg,0, 0); + sem_init(&sem_write_msg,0, 0); + sem_init(&sem_States,0, 0); + return; +} + + +/* ====================================================================== +FUNCTION + omx_aac_aenc::~omx_aac_aenc + +DESCRIPTION + Destructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_aac_aenc::~omx_aac_aenc() +{ + DEBUG_PRINT_ERROR("AAC Object getting destroyed comp-deinit=%d\n", + m_comp_deinit); + if ( !m_comp_deinit ) + { + deinit_encoder(); + } + pthread_mutexattr_destroy(&m_lock_attr); + pthread_mutex_destroy(&m_lock); + + pthread_mutexattr_destroy(&m_commandlock_attr); + pthread_mutex_destroy(&m_commandlock); + + pthread_mutexattr_destroy(&m_outputlock_attr); + pthread_mutex_destroy(&m_outputlock); + + pthread_mutexattr_destroy(&m_state_attr); + pthread_mutex_destroy(&m_state_lock); + + pthread_mutexattr_destroy(&m_event_attr); + pthread_mutex_destroy(&m_event_lock); + + pthread_mutexattr_destroy(&m_flush_attr); + pthread_mutex_destroy(&m_flush_lock); + + pthread_mutexattr_destroy(&m_in_th_attr); + pthread_mutex_destroy(&m_in_th_lock); + + pthread_mutexattr_destroy(&m_out_th_attr); + pthread_mutex_destroy(&m_out_th_lock); + + pthread_mutexattr_destroy(&out_buf_count_lock_attr); + pthread_mutex_destroy(&out_buf_count_lock); + + pthread_mutexattr_destroy(&in_buf_count_lock_attr); + pthread_mutex_destroy(&in_buf_count_lock); + + pthread_mutexattr_destroy(&m_in_th_attr_1); + pthread_mutex_destroy(&m_in_th_lock_1); + + pthread_mutexattr_destroy(&m_out_th_attr_1); + pthread_mutex_destroy(&m_out_th_lock_1); + pthread_mutex_destroy(&out_buf_count_lock); + pthread_mutex_destroy(&in_buf_count_lock); + pthread_cond_destroy(&cond); + pthread_cond_destroy(&in_cond); + pthread_cond_destroy(&out_cond); + sem_destroy (&sem_read_msg); + sem_destroy (&sem_write_msg); + sem_destroy (&sem_States); + DEBUG_PRINT_ERROR("OMX AAC component destroyed\n"); + return; +} + +/** + @brief memory function for sending EmptyBufferDone event + back to IL client + + @param bufHdr OMX buffer header to be passed back to IL client + @return none + */ +void omx_aac_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.EmptyBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr); + bufHdr->nFilledLen = 0; + + m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr); + pthread_mutex_lock(&in_buf_count_lock); + m_aac_pb_stats.ebd_cnt++; + nNumInputBuf--; + DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\ + m_aac_pb_stats.tot_in_buf_len, + nNumInputBuf, m_aac_pb_stats.ebd_cnt); + pthread_mutex_unlock(&in_buf_count_lock); + } + + return; +} + +/*============================================================================= +FUNCTION: + flush_ack + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_aac_aenc::flush_ack() +{ + // Decrement the FLUSH ACK count and notify the waiting recepients + pthread_mutex_lock(&m_flush_lock); + --m_flush_cnt; + if (0 == m_flush_cnt) + { + event_complete(); + } + DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt); + pthread_mutex_unlock(&m_flush_lock); +} +void omx_aac_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.FillBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr); + m_aac_pb_stats.fbd_cnt++; + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf--; + DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\ + nNumOutputBuf, + m_aac_pb_stats.tot_out_buf_len, + m_aac_pb_stats.fbd_cnt); + m_aac_pb_stats.tot_out_buf_len += bufHdr->nFilledLen; + m_aac_pb_stats.tot_pb_time = bufHdr->nTimeStamp; + DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n", + m_aac_pb_stats.tot_in_buf_len, + m_aac_pb_stats.tot_out_buf_len); + pthread_mutex_unlock(&out_buf_count_lock); + m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr); + } + return; +} + +/*============================================================================= +FUNCTION: + process_out_port_msg + +DESCRIPTION: + Function for handling all commands from IL client +IL client commands are processed and callbacks are generated through +this routine Audio Command Server provides the thread context for this routine + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_aac_aenc::process_out_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; // qsize + unsigned tot_qsize = 0; + omx_aac_aenc *pThis = (omx_aac_aenc *) client_data; + OMX_STATETYPE state; + +loopback_out: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n"); + return; + } + pthread_mutex_lock(&pThis->m_outputlock); + + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + + if ( 0 == tot_qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize); + return; + } + if ( (state != OMX_StateExecuting) && !qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + + if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) ) + { + // case where no port reconfig and nothing in the flush q + DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\ + qsize,tot_qsize); + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress)) + { + DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + } + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\ + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size,state); + + + if (qsize) + { + // process FLUSH message + pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // if no FLUSH and FBD's then process FTB's + pThis->m_output_q.pop_entry(&p1,&p2,&ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pthread_mutex_unlock(&pThis->m_outputlock); + pThis->out_th_goto_sleep(); + goto loopback_out; + } + } + pthread_mutex_unlock(&pThis->m_outputlock); + + if ( qsize > 0 ) + { + id = ident; + ident = 0; + DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id ) + { + pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_FTB == id ) + { + pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_EOS == id ) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + + } + else if(id == OMX_COMPONENT_RESUME) + { + DEBUG_PRINT("RESUMED...\n"); + } + else if(id == OMX_COMPONENT_GENERATE_COMMAND) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL("Executing FLUSH command on Output port\n"); + pThis->execute_output_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n"); + } + + return; +} + +/*============================================================================= +FUNCTION: + process_command_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_aac_aenc::process_command_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + omx_aac_aenc *pThis = (omx_aac_aenc*)client_data; + pthread_mutex_lock(&pThis->m_commandlock); + + qsize = pThis->m_command_q.m_size; + DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size, + pThis->m_state); + + if (!qsize) + { + DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n"); + pthread_mutex_unlock(&pThis->m_commandlock); + return; + } else + { + pThis->m_command_q.pop_entry(&p1,&p2,&ident); + } + pthread_mutex_unlock(&pThis->m_commandlock); + + id = ident; + DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\ + pThis->m_state,ident, \ + pThis->m_command_q.m_size); + + if (OMX_COMPONENT_GENERATE_EVENT == id) + { + if (pThis->m_cb.EventHandler) + { + if (OMX_CommandStateSet == p1) + { + pthread_mutex_lock(&pThis->m_state_lock); + pThis->m_state = (OMX_STATETYPE) p2; + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_PRINT("CMD:Process->state set to %d \n", \ + pThis->m_state); + + if (pThis->m_state == OMX_StateExecuting || + pThis->m_state == OMX_StateLoaded) + { + + pthread_mutex_lock(&pThis->m_in_th_lock_1); + if (pThis->is_in_th_sleep) + { + pThis->is_in_th_sleep = false; + DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n"); + pThis->in_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + + pthread_mutex_lock(&pThis->m_out_th_lock_1); + if (pThis->is_out_th_sleep) + { + DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n"); + pThis->is_out_th_sleep = false; + pThis->out_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + } + } + if (OMX_StateInvalid == pThis->m_state) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + } else if ((signed)p2 == OMX_ErrorPortUnpopulated) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + p2, + NULL, + NULL ); + } else + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventCmdComplete, + p1, p2, NULL ); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n"); + } + } else if (OMX_COMPONENT_GENERATE_COMMAND == id) + { + pThis->send_command_proxy(&pThis->m_cmp, + (OMX_COMMANDTYPE)p1, + (OMX_U32)p2,(OMX_PTR)NULL); + } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id) + { + DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED"); + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventPortSettingsChanged, + 1, 1, NULL ); + } + else + { + DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident); + } + return; +} + +/*============================================================================= +FUNCTION: + process_in_port_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_aac_aenc::process_in_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + unsigned tot_qsize = 0; + omx_aac_aenc *pThis = (omx_aac_aenc *) client_data; + OMX_STATETYPE state; + + if (!pThis) + { + DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n"); + return; + } +loopback_in: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n"); + return; + } + // Protect the shared queue data structure + pthread_mutex_lock(&pThis->m_lock); + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + if ( 0 == tot_qsize ) + { + DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP"); + pthread_mutex_unlock(&pThis->m_lock); + return; + } + + if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_DETAIL("SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + else if ((state == OMX_StatePause)) + { + if(!(pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + + DEBUG_DETAIL("IN: SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + } + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\ + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size, state); + + + if ( qsize ) + { + // process FLUSH message + pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) && + (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident); + } else if ((qsize = pThis->m_input_q.m_size) && + (state == OMX_StateExecuting)) + { + // if no FLUSH and EBD's then process ETB's + pThis->m_input_q.pop_entry(&p1, &p2, &ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\ + state,pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pthread_mutex_unlock(&pThis->m_lock); + pThis->in_th_goto_sleep(); + goto loopback_in; + } + } + pthread_mutex_unlock(&pThis->m_lock); + + if ( qsize > 0 ) + { + id = ident; + DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id ) + { + pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } + else if(id == OMX_COMPONENT_GENERATE_EOS) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventBufferFlag, 0, 1, NULL ); + } else if ( OMX_COMPONENT_GENERATE_ETB == id ) + { + pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_COMMAND == id ) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL(" Executing FLUSH command on Input port\n"); + pThis->execute_input_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } + else + { + DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n"); + } + return; +} + +/** + @brief member function for performing component initialization + + @param role C string mandating role of this component + @return Error status + */ +OMX_ERRORTYPE omx_aac_aenc::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + m_state = OMX_StateLoaded; + + /* DSP does not give information about the bitstream + randomly assign the value right now. Query will result in + incorrect param */ + memset(&m_aac_param, 0, sizeof(m_aac_param)); + m_aac_param.nSize = sizeof(m_aac_param); + m_aac_param.nChannels = DEFAULT_CH_CFG; + m_aac_param.nSampleRate = DEFAULT_SF; + m_aac_param.nBitRate = DEFAULT_BITRATE; + m_volume = OMX_AAC_DEFAULT_VOL; /* Close to unity gain */ + memset(&m_aac_pb_stats,0,sizeof(AAC_PB_STATS)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + m_pcm_param.nSize = sizeof(m_pcm_param); + m_pcm_param.nChannels = DEFAULT_CH_CFG; + m_pcm_param.nSamplingRate = DEFAULT_SF; + + nTimestamp = 0; + ts = 0; + frameduration = 0; + nNumInputBuf = 0; + nNumOutputBuf = 0; + m_ipc_to_in_th = NULL; // Command server instance + m_ipc_to_out_th = NULL; // Client server instance + m_ipc_to_cmd_th = NULL; // command instance + m_is_out_th_sleep = 0; + m_is_in_th_sleep = 0; + is_out_th_sleep= false; + + is_in_th_sleep=false; + adif_flag = 0; + mp4ff_flag = 0; + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + m_priority_mgm.nGroupID =0; + m_priority_mgm.nGroupPriority=0; + + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified; + + DEBUG_PRINT_ERROR(" component init: role = %s\n",role); + + DEBUG_PRINT(" component init: role = %s\n",role); + component_Role.nVersion.nVersion = OMX_SPEC_VERSION; + if (!strcmp(role,"OMX.qcom.audio.encoder.aac")) + { + pcm_input = 1; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, (const char*)role, + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.aac")) + { + pcm_input = 0; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, (const char*)role, + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else + { + component_Role.nSize = sizeof("\0"); + strlcpy((char *)component_Role.cRole, (const char*)"\0", + sizeof(component_Role.cRole)); + DEBUG_PRINT_ERROR("\ncomponent_init: Component %s LOADED is invalid\n", + role); + return OMX_ErrorInsufficientResources; + } + if(pcm_input) + { + m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) * + (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN))); + + if (m_tmp_meta_buf == NULL) { + DEBUG_PRINT_ERROR("Mem alloc failed for in meta buf\n"); + return OMX_ErrorInsufficientResources; + } + } + m_tmp_out_meta_buf = + (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_AAC_OUTPUT_BUFFER_SIZE); + if ( m_tmp_out_meta_buf == NULL ) { + DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n"); + return OMX_ErrorInsufficientResources; + } + + if(0 == pcm_input) + { + m_drv_fd = open("/dev/msm_aac_in",O_RDONLY); + } + else + { + m_drv_fd = open("/dev/msm_aac_in",O_RDWR); + } + if (m_drv_fd < 0) + { + DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\ + m_drv_fd,errno); + + return OMX_ErrorInsufficientResources; + } + if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1) + { + DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n"); + } + if(pcm_input) + { + if (!m_ipc_to_in_th) + { + m_ipc_to_in_th = omx_aac_thread_create(process_in_port_msg, + this, (char *)"INPUT_THREAD"); + if (!m_ipc_to_in_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start \ + Input port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + } + + if (!m_ipc_to_cmd_th) + { + m_ipc_to_cmd_th = omx_aac_thread_create(process_command_msg, + this, (char *)"CMD_THREAD"); + if (!m_ipc_to_cmd_th) + { + DEBUG_PRINT_ERROR("ERROR!!!Failed to start " + "command message thread\n"); + return OMX_ErrorInsufficientResources; + } + } + + if (!m_ipc_to_out_th) + { + m_ipc_to_out_th = omx_aac_thread_create(process_out_port_msg, + this, (char *)"OUTPUT_THREAD"); + if (!m_ipc_to_out_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start output " + "port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + return eRet; +} + +/** + + @brief member function to retrieve version of component + + + + @param hComp handle to this component instance + @param componentName name of component + @param componentVersion pointer to memory space which stores the + version number + @param specVersion pointer to memory sapce which stores version of + openMax specification + @param componentUUID + @return Error status + */ +OMX_ERRORTYPE omx_aac_aenc::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID) +{ + if((hComp == NULL) || (componentName == NULL) || + (specVersion == NULL) || (componentUUID == NULL)) + { + componentVersion = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n"); + return OMX_ErrorInvalidState; + } + componentVersion->nVersion = OMX_SPEC_VERSION; + specVersion->nVersion = OMX_SPEC_VERSION; + return OMX_ErrorNone; +} +/** + @brief member function handles command from IL client + + This function simply queue up commands from IL client. + Commands will be processed in command server thread context later + + @param hComp handle to component instance + @param cmd type of command + @param param1 parameters associated with the command type + @param cmdData + @return Error status +*/ +OMX_ERRORTYPE omx_aac_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + int portIndex = (int)param1; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateInvalid == m_state) + { + return OMX_ErrorInvalidState; + } + if ( (cmd == OMX_CommandFlush) && (portIndex > 1) ) + { + return OMX_ErrorBadPortIndex; + } + post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); + DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n"); + DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1); + sem_wait (&sem_States); + DEBUG_PRINT("send_command : recieved state after semwait\n"); + return OMX_ErrorNone; +} + +/** + @brief member function performs actual processing of commands excluding + empty buffer call + + @param hComp handle to component + @param cmd command type + @param param1 parameter associated with the command + @param cmdData + + @return error status +*/ +OMX_ERRORTYPE omx_aac_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + // Handle only IDLE and executing + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1; + nState = eState; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_CommandStateSet == cmd) + { + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (OMX_StateLoaded == m_state) + { + if (OMX_StateIdle == eState) + { + + if (allocate_done() || + (m_inp_bEnabled == OMX_FALSE + && m_out_bEnabled == OMX_FALSE)) + { + DEBUG_PRINT("SCP-->Allocate Done Complete\n"); + } + else + { + DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + bFlag = 0; + } + + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } + + else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n"); + eRet = OMX_ErrorNone; + } + + else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + m_state = OMX_StateInvalid; + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (OMX_StateIdle == m_state) + { + if (OMX_StateLoaded == eState) + { + if (release_done(-1)) + { + if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1) + { + DEBUG_PRINT_ERROR("SCP:Idle->Loaded,ioctl \ + stop failed %d\n", errno); + } + nTimestamp=0; + ts = 0; + frameduration = 0; + DEBUG_PRINT("SCP-->Idle to Loaded\n"); + } else + { + DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + else if (OMX_StateExecuting == eState) + { + + struct msm_audio_aac_enc_config drv_aac_enc_config; + struct msm_audio_aac_config drv_aac_config; + struct msm_audio_stream_config drv_stream_config; + struct msm_audio_buf_cfg buf_cfg; + struct msm_audio_config pcm_cfg; + if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + + if(ioctl(m_drv_fd, AUDIO_GET_AAC_ENC_CONFIG, + &drv_aac_enc_config) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_AAC_ENC_CONFIG failed, \ + errno[%d]\n", errno); + } + drv_aac_enc_config.channels = m_aac_param.nChannels; + drv_aac_enc_config.sample_rate = m_aac_param.nSampleRate; + drv_aac_enc_config.bit_rate = m_aac_param.nBitRate; + DEBUG_PRINT("aac config %lu,%lu,%lu %d\n", + m_aac_param.nChannels,m_aac_param.nSampleRate, + m_aac_param.nBitRate,m_aac_param.eAACStreamFormat); + switch(m_aac_param.eAACStreamFormat) + { + + case 0: + case 1: + { + drv_aac_enc_config.stream_format = 65535; + DEBUG_PRINT("Setting AUDIO_AAC_FORMAT_ADTS\n"); + break; + } + case 4: + case 5: + case 6: + { + drv_aac_enc_config.stream_format = AUDIO_AAC_FORMAT_RAW; + DEBUG_PRINT("Setting AUDIO_AAC_FORMAT_RAW\n"); + break; + } + default: + break; + } + DEBUG_PRINT("Stream format = %d\n", + drv_aac_enc_config.stream_format); + if(ioctl(m_drv_fd, AUDIO_SET_AAC_ENC_CONFIG, + &drv_aac_enc_config) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_AAC_ENC_CONFIG failed, \ + errno[%d]\n", errno); + } + if (ioctl(m_drv_fd, AUDIO_GET_AAC_CONFIG, &drv_aac_config) + == -1) { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_AAC_CONFIG failed, \ + errno[%d]\n", errno); + } + + drv_aac_config.sbr_on_flag = 0; + drv_aac_config.sbr_ps_on_flag = 0; + /* Other members of drv_aac_config are not used, + so not setting them */ + switch(m_aac_param.eAACProfile) + { + case OMX_AUDIO_AACObjectLC: + { + DEBUG_PRINT("AAC_Profile: OMX_AUDIO_AACObjectLC\n"); + drv_aac_config.sbr_on_flag = 0; + drv_aac_config.sbr_ps_on_flag = 0; + break; + } + case OMX_AUDIO_AACObjectHE: + { + DEBUG_PRINT("AAC_Profile: OMX_AUDIO_AACObjectHE\n"); + drv_aac_config.sbr_on_flag = 1; + drv_aac_config.sbr_ps_on_flag = 0; + break; + } + case OMX_AUDIO_AACObjectHE_PS: + { + DEBUG_PRINT("AAC_Profile: OMX_AUDIO_AACObjectHE_PS\n"); + drv_aac_config.sbr_on_flag = 1; + drv_aac_config.sbr_ps_on_flag = 1; + break; + } + default: + { + DEBUG_PRINT_ERROR("Unsupported AAC Profile Type = %d\n", + m_aac_param.eAACProfile); + break; + } + } + DEBUG_PRINT("sbr_flag = %d, sbr_ps_flag = %d\n", + drv_aac_config.sbr_on_flag, + drv_aac_config.sbr_ps_on_flag); + + if (ioctl(m_drv_fd, AUDIO_SET_AAC_CONFIG, &drv_aac_config) + == -1) { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_AAC_CONFIG failed, \ + errno[%d]\n", errno); + } + + if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n", + errno); + } + buf_cfg.meta_info_enable = 1; + buf_cfg.frames_per_buf = NUMOFFRAMES; + if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n", + errno); + } + if(pcm_input) + { + if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n", + errno); + } + pcm_cfg.channel_count = m_pcm_param.nChannels; + pcm_cfg.sample_rate = m_pcm_param.nSamplingRate; + pcm_cfg.buffer_size = input_buffer_size; + pcm_cfg.buffer_count = m_inp_current_buf_count; + DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + + if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n", + errno); + } + } + if(ioctl(m_drv_fd, AUDIO_START, 0) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n", + errno); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } + DEBUG_PRINT("SCP-->Idle to Executing\n"); + nState = eState; + frameduration = (1024*1000000)/m_aac_param.nSampleRate; + } else if (eState == OMX_StateIdle) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n"); + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (OMX_StateExecuting == m_state) + { + if (OMX_StateIdle == eState) + { + DEBUG_PRINT("SCP-->Executing to Idle \n"); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + + } else if (OMX_StatePause == eState) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED PAUSE STATE\n"); + DEBUG_DETAIL("*************************\n"); + //ioctl(m_drv_fd, AUDIO_PAUSE, 0); + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n", + eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (OMX_StatePause == m_state) + { + if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) ) + { + pthread_mutex_lock(&m_out_th_lock_1); + if(is_out_th_sleep) + { + DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n"); + is_out_th_sleep = false; + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } + if ( OMX_StateExecuting == eState ) + { + nState = eState; + } else if ( OMX_StateIdle == eState ) + { + DEBUG_PRINT("SCP-->Paused to Idle \n"); + DEBUG_PRINT ("\n Internal flush issued"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + } else if ( eState == OMX_StateLoaded ) + { + DEBUG_PRINT("\n Pause --> loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n Pause --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("\n Pause --> Pause \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n Pause --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + /**************************************/ + /* Current State is WaitForResources */ + /**************************************/ + else if (m_state == OMX_StateWaitForResources) + { + if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n"); + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: \ + WaitForResources-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n", + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /****************************/ + /* Current State is Invalid */ + /****************************/ + else if (m_state == OMX_StateInvalid) + { + if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState + || OMX_StateIdle == eState || OMX_StateExecuting == eState + || OMX_StatePause == eState || OMX_StateInvalid == eState) + { + DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing" + "/Pause/Invalid/WaitForResources\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } + } else + { + DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\ + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } else if (OMX_CommandFlush == cmd) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1); + DEBUG_DETAIL("*************************\n"); + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || + param1 == OMX_CORE_OUTPUT_PORT_INDEX || + (signed)param1 == -1 ) + { + execute_omx_flush(param1); + } else + { + eRet = OMX_ErrorBadPortIndex; + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError, + OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL ); + } + } else if ( cmd == OMX_CommandPortDisable ) + { + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL ) + { + DEBUG_PRINT("SCP: Disabling Input port Indx\n"); + m_inp_bEnabled = OMX_FALSE; + if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(0) ) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_inp_bEnabled=%d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + + else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\ + " param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + // Skip the event notification + + } + + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + + DEBUG_PRINT("SCP: Disabling Output port Indx\n"); + m_out_bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(1)) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_out_bEnabled=%d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\ + "param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + // Skip the event notification + + } + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID"); + } + + } else if (cmd == OMX_CommandPortEnable) + { + bFlag = 0; + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_inp_bEnabled = OMX_TRUE; + DEBUG_PRINT("SCP: Enabling Input port Indx\n"); + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_inp_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + + } else + { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + + } + } + + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + DEBUG_PRINT("SCP: Enabling Output port Indx\n"); + m_out_bEnabled = OMX_TRUE; + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_out_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + + } + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID"); + } + + } else + { + DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd); + eRet = OMX_ErrorNotImplemented; + } + DEBUG_PRINT("posting sem_States\n"); + sem_post (&sem_States); + if (eRet == OMX_ErrorNone && bFlag) + { + post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + return eRet; +} + +/*============================================================================= +FUNCTION: + execute_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + [IN] param1 + [IN] cmd_cmpl + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_aac_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl) +{ + bool bRet = true; + + DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1); + struct timespec abs_timeout; + abs_timeout.tv_sec = 1; + abs_timeout.tv_nsec = 0; + + if ((signed)param1 == -1) + { + bFlushinprogress = true; + DEBUG_PRINT("Execute flush for both I/p O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + + // Send Flush commands to input and output threads + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + // Send Flush to the kernel so that the in and out buffers are released + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + + // sleep till the FLUSH ACK are done by both the input and + // output threads + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + + DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\ + param1,cmd_cmpl); + + // If not going to idle state, Send FLUSH complete message + // to the Client, now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n"); + } + bFlushinprogress = false; + } + else if (param1 == OMX_CORE_INPUT_PORT_INDEX) + { + DEBUG_PRINT("Execute FLUSH for I/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + //sleep till the FLUSH ACK are done by both the input and output threads + DEBUG_DETAIL("Executing FLUSH for I/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1); + + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1) + { + DEBUG_PRINT("Executing FLUSH for O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + DEBUG_DETAIL("Executing FLUSH for O/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1) + DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + // sleep till the FLUSH ACK are done by both the input + // and output threads + wait_for_event(); + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + } + DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1); + } else + { + DEBUG_PRINT("Invalid Port ID[%lu]",param1); + } + return bRet; +} + +/*============================================================================= +FUNCTION: + execute_input_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_aac_aenc::execute_input_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on input port"); + + pthread_mutex_lock(&m_lock); + do + { + qsize = m_input_q.m_size; + tot_qsize = qsize; + tot_qsize += m_input_ctrl_ebd_q.m_size; + + DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\ + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size,qsize); + if (!tot_qsize) + { + DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_lock); + break; + } + if (qsize) + { + m_input_q.pop_entry(&p1, &p2, &ident); + if ((ident == OMX_COMPONENT_GENERATE_ETB) || + (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf); + omx_buf->nFilledLen = 0; + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else if (m_input_ctrl_ebd_q.m_size) + { + m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident); + if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + omx_buf->nFilledLen = 0; + DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else + { + } + }while (tot_qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("IN-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_lock); + return true; +} + +/*============================================================================= +FUNCTION: + execute_output_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_aac_aenc::execute_output_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on output port"); + + pthread_mutex_lock(&m_outputlock); + do + { + qsize = m_output_q.m_size; + DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\ + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size,qsize); + tot_qsize = qsize; + tot_qsize += m_output_ctrl_fbd_q.m_size; + if (!tot_qsize) + { + DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_outputlock); + break; + } + if (qsize) + { + m_output_q.pop_entry(&p1,&p2,&ident); + if ( (OMX_COMPONENT_GENERATE_FTB == ident) || + (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FBD FROM FLUSH"); + } + } else if ((qsize = m_output_ctrl_fbd_q.m_size)) + { + m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident); + if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH"); + } + } + }while (qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("OUT-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_outputlock); + return true; +} + +/*============================================================================= +FUNCTION: + post_input + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_aac_aenc::post_input(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + pthread_mutex_lock(&m_lock); + + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)) + { + // insert flush message and ebd + m_input_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id)) + { + // insert ebd + m_input_ctrl_ebd_q.insert_entry(p1,p2,id); + } else + { + // ETBS in this queue + m_input_q.insert_entry(p1,p2,id); + } + + if (m_ipc_to_in_th) + { + bRet = true; + omx_aac_post_msg(m_ipc_to_in_th, id); + } + + DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\ + m_state, + id, + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size, + m_input_q.m_size); + + pthread_mutex_unlock(&m_lock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_command + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_aac_aenc::post_command(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_commandlock); + + m_command_q.insert_entry(p1,p2,id); + + if (m_ipc_to_cmd_th) + { + bRet = true; + omx_aac_post_msg(m_ipc_to_cmd_th, id); + } + + DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\ + m_state, + id, + m_command_q.m_size, + m_flags >> 3); + + pthread_mutex_unlock(&m_commandlock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_output + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_aac_aenc::post_output(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_outputlock); + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND) + || (id == OMX_COMPONENT_RESUME)) + { + // insert flush message and fbd + m_output_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) ) + { + // insert flush message and fbd + m_output_ctrl_fbd_q.insert_entry(p1,p2,id); + } else + { + m_output_q.insert_entry(p1,p2,id); + } + if ( m_ipc_to_out_th ) + { + bRet = true; + omx_aac_post_msg(m_ipc_to_out_th, id); + } + DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + m_state, + id, + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size, + m_output_q.m_size); + + pthread_mutex_unlock(&m_outputlock); + return bRet; +} +/** + @brief member function that return parameters to IL client + + @param hComp handle to component instance + @param paramIndex Parameter type + @param paramData pointer to memory space which would hold the + paramter + @return error status +*/ +OMX_ERRORTYPE omx_aac_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Param in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) + { + DEBUG_PRINT("get_parameter: paramData is NULL\n"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + DEBUG_PRINT("OMX_IndexParamPortDefinition " \ + "portDefn->nPortIndex = %lu\n", + portDefn->nPortIndex); + + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(portDefn); + portDefn->eDomain = OMX_PortDomainAudio; + + if (0 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirInput; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + portDefn->nBufferCountActual = m_inp_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS; + portDefn->nBufferSize = input_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM; + portDefn->format.audio.pNativeRender = 0; + } else if (1 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirOutput; + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + portDefn->nBufferCountActual = m_out_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS; + portDefn->nBufferSize = output_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingAAC; + portDefn->format.audio.pNativeRender = 0; + } else + { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_ERROR("Bad Port idx %d\n",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioInit\n"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n"); + portFormatType->nVersion.nVersion = OMX_SPEC_VERSION; + portFormatType->nSize = sizeof(portFormatType); + + if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex) + { + + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + portFormatType->nPortIndex) + { + DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\ + "%lu\n", portFormatType->nIndex); + + portFormatType->eEncoding = OMX_AUDIO_CodingAAC; + } else + { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n", + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioAac: + { + OMX_AUDIO_PARAM_AACPROFILETYPE *aacParam = + (OMX_AUDIO_PARAM_AACPROFILETYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioAac\n"); + if (OMX_CORE_OUTPUT_PORT_INDEX== aacParam->nPortIndex) + { + memcpy(aacParam,&m_aac_param, + sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE)); + + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioAac "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)aacParam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case QOMX_IndexParamAudioSessionId: + { + QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam = + (QOMX_AUDIO_STREAM_INFO_DATA *) paramData; + streaminfoparam->sessionId = m_session_id; + break; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam = + (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(pcmparam,&m_pcm_param,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + + DEBUG_PRINT("get_parameter: Sampling rate %lu",\ + pcmparam->nSamplingRate); + DEBUG_PRINT("get_parameter: Number of channels %lu",\ + pcmparam->nChannels); + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamComponentSuspended: + { + OMX_PARAM_SUSPENSIONTYPE *suspend = + (OMX_PARAM_SUSPENSIONTYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n", + suspend); + break; + } + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamPriorityMgmt: + { + OMX_PRIORITYMGMTTYPE *priorityMgmtType = + (OMX_PRIORITYMGMTTYPE*)paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n"); + priorityMgmtType->nSize = sizeof(priorityMgmtType); + priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmtType->nGroupID = m_priority_mgm.nGroupID; + priorityMgmtType->nGroupPriority = + m_priority_mgm.nGroupPriority; + break; + } + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + + bufferSupplierType->nSize = sizeof(bufferSupplierType); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if (OMX_CORE_INPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else + { + DEBUG_PRINT_ERROR("get_parameter:"\ + "OMX_IndexParamCompBufferSupplier eRet"\ + "%08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + componentRole->nSize = component_Role.nSize; + componentRole->nVersion = component_Role.nVersion; + strlcpy((char *)componentRole->cRole, + (const char*)component_Role.cRole, + sizeof(componentRole->cRole)); + DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n", + component_Role.nSize, + component_Role.nVersion, + component_Role.cRole); + break; + + } + default: + { + DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; + +} + +/** + @brief member function that set paramter from IL client + + @param hComp handle to component instance + @param paramIndex parameter type + @param paramData pointer to memory space which holds the paramter + @return error status + */ +OMX_ERRORTYPE omx_aac_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned int loop=0; + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("set_parameter is not in proper state\n"); + return OMX_ErrorIncorrectStateOperation; + } + if (paramData == NULL) + { + DEBUG_PRINT("param data is NULL"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamAudioAac: + { + DEBUG_PRINT("OMX_IndexParamAudioAac"); + OMX_AUDIO_PARAM_AACPROFILETYPE *aacparam + = (OMX_AUDIO_PARAM_AACPROFILETYPE *) paramData; + memcpy(&m_aac_param,aacparam, + sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE)); + + for (loop=0; loop< sizeof(sample_idx_tbl) / \ + sizeof(struct sample_rate_idx); \ + loop++) + { + if(sample_idx_tbl[loop].sample_rate == m_aac_param.nSampleRate) + { + sample_idx = sample_idx_tbl[loop].sample_rate_idx; + } + } + break; + } + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + if (((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources && + ((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == true)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == true))) + ||(((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == false)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == false)) && + (m_state != OMX_StateWaitForResources))) + { + DEBUG_PRINT("Set Parameter called in valid state\n"); + } else + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex " + "= %lu\n",portDefn->nPortIndex); + if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_INPUT_BUFFERS ) + { + m_inp_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS; + } + input_buffer_size = portDefn->nBufferSize; + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_OUTPUT_BUFFERS ) + { + m_out_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS; + } + output_buffer_size = portDefn->nBufferSize; + } else + { + DEBUG_PRINT(" set_parameter: Bad Port idx %d",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamPriorityMgmt: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n"); + + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype + = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n", + priorityMgmtype->nGroupID); + + DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n", + priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + case OMX_IndexParamAudioPortFormat: + { + + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n"); + + if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex) + { + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + portFormatType->nPortIndex) + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\ + " %lu\n", portFormatType->nIndex); + portFormatType->eEncoding = OMX_AUDIO_CodingAAC; + } else + { + DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \ + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("set_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\ + bufferSupplierType->eBufferSupplier); + + if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX + || bufferSupplierType->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) + { + DEBUG_PRINT("set_parameter:\ + OMX_IndexParamCompBufferSupplier\n"); + m_buffer_supplier.eBufferSupplier = + bufferSupplierType->eBufferSupplier; + } else + { + DEBUG_PRINT_ERROR("set_param:IndexParamCompBufferSup \ + %08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + + break; } + + case OMX_IndexParamAudioPcm: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n"); + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam + = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + + memcpy(&m_pcm_param,pcmparam,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + + DEBUG_PRINT("set_pcm_parameter: %lu %lu",\ + m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + } else + { + DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm " + "OMX_ErrorBadPortIndex %d\n", + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamSuspensionPolicy: + { + eRet = OMX_ErrorNotImplemented; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + component_Role.nSize = componentRole->nSize; + component_Role.nVersion = componentRole->nVersion; + strlcpy((char *)component_Role.cRole, + (const char*)componentRole->cRole, + sizeof(component_Role.cRole)); + break; + } + + default: + { + DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::GetConfig + +DESCRIPTION + OMX Get Config Method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *volume = + (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex) + { + volume->nSize = sizeof(volume); + volume->nVersion.nVersion = OMX_SPEC_VERSION; + volume->bLinear = OMX_TRUE; + volume->sVolume.nValue = m_volume; + volume->sVolume.nMax = OMX_AENC_MAX; + volume->sVolume.nMin = OMX_AENC_MIN; + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = + (OMX_AUDIO_CONFIG_MUTETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex) + { + mute->nSize = sizeof(mute); + mute->nVersion.nVersion = OMX_SPEC_VERSION; + mute->bMute = (BITMASK_PRESENT(&m_flags, + OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE); + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::SetConfig + +DESCRIPTION + OMX Set Config method implementation + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Set Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if ( m_state == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *vol = + (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData; + if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if ((vol->sVolume.nValue <= OMX_AENC_MAX) && + (vol->sVolume.nValue >= OMX_AENC_MIN)) + { + m_volume = vol->sVolume.nValue; + if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED)) + { + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + + } else + { + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*) + configData; + if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if (mute->bMute == OMX_TRUE) + { + BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */ + } else + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::GetExtensionIndex + +DESCRIPTION + OMX GetExtensionIndex method implementaion. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::get_extension_index( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + if((hComp == NULL) || (paramName == NULL) || (indexType == NULL)) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId", + strlen("OMX.Qualcomm.index.audio.sessionId")) == 0) + { + *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId; + DEBUG_PRINT("Extension index type - %d\n", *indexType); + + } + else + { + return OMX_ErrorBadParameter; + + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::GetState + +DESCRIPTION + Returns the state information back to the caller. + +PARAMETERS + . + +RETURN VALUE + Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + *state = m_state; + DEBUG_PRINT("Returning the state %d\n",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::ComponentTunnelRequest + +DESCRIPTION + OMX Component Tunnel Request method implementation. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::component_tunnel_request +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n"); + + if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL)) + { + port = 0; + peerPort = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::AllocateInputBuffer + +DESCRIPTION + Helper function for allocate buffer in the input pin + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::allocate_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + if(m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc((nBufSize + \ + sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1); + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + free(buf_ptr); + return OMX_ErrorBadParameter; + } + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+ + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + m_input_buf_hdrs.insert(bufHdr, NULL); + + m_inp_current_buf_count++; + DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%d \ + bytes=%lu",bufHdr, bufHdr->pBuffer,m_inp_current_buf_count, + bytes); + + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } + else + { + DEBUG_PRINT("Input buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +OMX_ERRORTYPE omx_aac_aenc::allocate_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_out_current_buf_count < m_out_act_buf_count) + { + buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr)+ + sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d "\ + "bytes=%lu",bufHdr, bufHdr->pBuffer,\ + m_out_current_buf_count, bytes); + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== +FUNCTION + omx_aac_aenc::AllocateBuffer + +DESCRIPTION + Returns zero if all the buffers released.. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::allocate_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n"); + return OMX_ErrorInvalidState; + } + // What if the client calls again. + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n", + (int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("allocate_buffer: before allocate_done \n"); + if (allocate_done()) + { + DEBUG_PRINT("allocate_buffer: after allocate_done \n"); + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("allocate_buffer: post idle transition event \n"); + } + DEBUG_PRINT("allocate_buffer: complete \n"); + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + m_out_bEnabled = OMX_TRUE; + + DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("AB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet); + return eRet; +} + +/*============================================================================= +FUNCTION: + use_buffer + +DESCRIPTION: + OMX Use Buffer method implementation. + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_aac_aenc::use_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("Checking for Output Allocate buffer Done"); + if (allocate_done()) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("UB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + } + } + DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet); + return eRet; +} +/*============================================================================= +FUNCTION: + use_input_buffer + +DESCRIPTION: + Helper function for Use buffer in the input pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_aac_aenc::use_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if(bytes < input_buffer_size) + { + /* return if i\p buffer size provided by client + is less than min i\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + if (m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \ + bytes=%lu", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + input_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_input_buf_hdrs.insert(bufHdr, NULL); + m_inp_current_buf_count++; + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Input buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/*============================================================================= +FUNCTION: + use_output_buffer + +DESCRIPTION: + Helper function for Use buffer in the output pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_aac_aenc::use_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (bytes < output_buffer_size) + { + /* return if o\p buffer size provided by client + is less than min o\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT("Inside omx_aac_aenc::use_output_buffer"); + if (m_out_current_buf_count < m_out_act_buf_count) + { + + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer); + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \ + len=%lu\n", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + output_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_aac_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_input_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_input_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_aac_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_output_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_output_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +// Free Buffer - API call +/** + @brief member function that handles free buffer command from IL client + + This function is a block-call function that handles IL client request to + freeing the buffer + + @param hComp handle to component instance + @param port id of port which holds the buffer + @param buffer buffer header + @return Error status +*/ +OMX_ERRORTYPE omx_aac_aenc::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("Free_Buffer buf %p\n", buffer); + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + DEBUG_PRINT(" free buffer while Component in Loading pending\n"); + } else if ((m_inp_bEnabled == OMX_FALSE && + port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && + port == OMX_CORE_OUTPUT_PORT_INDEX)) + { + DEBUG_PRINT("Free Buffer while port %lu disabled\n", port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) + { + DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\ + OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return eRet; + } else + { + DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\ + disabled:OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + if (m_inp_current_buf_count != 0) + { + m_inp_bPopulated = OMX_FALSE; + if (true == search_input_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer); + m_input_buf_hdrs.erase(buffer); + free(buffer); + m_inp_current_buf_count--; + } else + { + DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \ + Invalid Input buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \ + came out Invalid\n"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_done(0)) + { + DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + if (m_out_current_buf_count != 0) + { + m_out_bPopulated = OMX_FALSE; + if (true == search_output_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer); + m_output_buf_hdrs.erase(buffer); + free(buffer); + m_out_current_buf_count--; + } else + { + DEBUG_PRINT("Free_Buf:Error-->free_buffer , \ + Invalid Output buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_done(1)) + { + DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + if ((OMX_ErrorNone == eRet) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + if (release_done(-1)) + { + if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0) + DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n"); + else + DEBUG_PRINT("AUDIO STOP in free buffer passed\n"); + + DEBUG_PRINT("Free_Buf: Free buffer\n"); + + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + DEBUG_PRINT("Before OMX_StateLoaded \ + OMX_COMPONENT_GENERATE_EVENT\n"); + post_command(OMX_CommandStateSet, + OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n"); + + } + } + return eRet; +} + + +/** + @brief member function that that handles empty this buffer command + + This function meremly queue up the command and data would be consumed + in command server thread context + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_aac_aenc::empty_this_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \ + buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf)); + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT("Empty this buffer in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (!m_inp_bEnabled) + { + DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\ + "Port Status %d \n", m_inp_bEnabled); + return OMX_ErrorIncorrectStateOperation; + } + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_aac_aenc::etb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_aac_aenc::etb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + if ((m_state != OMX_StateExecuting) && + (m_state != OMX_StatePause)) + { + DEBUG_PRINT_ERROR("Invalid state\n"); + eRet = OMX_ErrorInvalidState; + } + if (OMX_ErrorNone == eRet) + { + if (search_input_bufhdr(buffer) == true) + { + post_input((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB); + } else + { + DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer); + eRet = OMX_ErrorBadParameter; + } + } + pthread_mutex_lock(&in_buf_count_lock); + nNumInputBuf++; + m_aac_pb_stats.etb_cnt++; + pthread_mutex_unlock(&in_buf_count_lock); + return eRet; +} +/** + @brief member function that writes data to kernel driver + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_aac_aenc::empty_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + META_IN meta_in; + //Pointer to the starting location of the data to be transcoded + OMX_U8 *srcStart; + //The total length of the data to be transcoded + srcStart = buffer->pBuffer; + OMX_U8 *data = NULL; + PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer); + memset(&meta_in,0,sizeof(meta_in)); + if ( search_input_bufhdr(buffer) == false ) + { + DEBUG_PRINT("ETBP: INVALID BUF HDR\n"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorBadParameter; + } + if (m_tmp_meta_buf) + { + data = m_tmp_meta_buf; + + // copy the metadata info from the BufHdr and insert to payload + meta_in.offsetVal = sizeof(META_IN); + meta_in.nTimeStamp.LowPart = + ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF); + meta_in.nTimeStamp.HighPart = + (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF); + meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS; + if(buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT("EOS OCCURED \n"); + meta_in.nFlags |= OMX_BUFFERFLAG_EOS; + } + memcpy(data,&meta_in, meta_in.offsetVal); + DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags); + } + + memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen); + write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN)); + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (OMX_StateExecuting == state) + { + DEBUG_DETAIL("In Exe state, EBD CB"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + } else + { + /* Assume empty this buffer function has already checked + validity of buffer */ + DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer); + post_input((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_BUFFER_DONE); + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_aac_aenc::fill_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + ENC_META_OUT *meta_out = NULL; + int nReadbytes = 0; + int szadifhr = 0; + int numframes = 0; + int metainfo = 0; + OMX_U8 *src = buffer->pBuffer; + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (true == search_output_bufhdr(buffer)) + { + if((m_aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatADIF) + && (adif_flag == 0)) + { + + DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd); + nReadbytes = read(m_drv_fd,m_tmp_out_meta_buf,output_buffer_size ); + DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\ + buffer->nAllocLen,m_tmp_out_meta_buf, + nReadbytes,nNumOutputBuf); + if(*m_tmp_out_meta_buf <= 0) + return OMX_ErrorBadParameter; + szadifhr = AUDAAC_MAX_ADIF_HEADER_LENGTH; + numframes = *m_tmp_out_meta_buf; + metainfo = ((sizeof(ENC_META_OUT) * numframes)+ + sizeof(unsigned char)); + audaac_rec_install_adif_header_variable(0,sample_idx, + m_aac_param.nChannels); + memcpy(buffer->pBuffer,m_tmp_out_meta_buf,metainfo); + memcpy(buffer->pBuffer + metainfo,&audaac_header_adif[0],szadifhr); + memcpy(buffer->pBuffer + metainfo + szadifhr, + m_tmp_out_meta_buf + metainfo,(nReadbytes - metainfo)); + src += sizeof(unsigned char); + meta_out = (ENC_META_OUT *)src; + meta_out->frame_size += szadifhr; + numframes--; + while(numframes > 0) + { + src += sizeof(ENC_META_OUT); + meta_out = (ENC_META_OUT *)src; + meta_out->offset_to_frame += szadifhr; + numframes--; + } + buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG; + adif_flag++; + } + else if((m_aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) + &&(mp4ff_flag == 0)) + { + DEBUG_PRINT("OMX_AUDIO_AACStreamFormatMP4FF\n"); + audaac_rec_install_mp4ff_header_variable(0,sample_idx, + m_aac_param.nChannels); + memcpy(buffer->pBuffer,&audaac_header_mp4ff[0], + AUDAAC_MAX_MP4FF_HEADER_LENGTH); + buffer->nFilledLen = AUDAAC_MAX_MP4FF_HEADER_LENGTH; + buffer->nTimeStamp = 0; + buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + mp4ff_flag++; + return OMX_ErrorNone; + + } + else + { + + DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd); + nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size ); + DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\ + buffer->nAllocLen,buffer->pBuffer, + nReadbytes,nNumOutputBuf); + if(nReadbytes <= 0) + { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorNone; + } + } + + meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char)); + buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+ + meta_out->lsw_ts); + + ts += frameduration; + buffer->nTimeStamp = ts; + nTimestamp = buffer->nTimeStamp; + buffer->nFlags |= meta_out->nflags; + buffer->nOffset = meta_out->offset_to_frame + 1; + buffer->nFilledLen = nReadbytes - buffer->nOffset + szadifhr; + DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \ + timestamp %lld\n", meta_out->nflags, + meta_out->frame_size, + meta_out->offset_to_frame, + buffer->nTimeStamp); + + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n"); + m_cb.EventHandler(&m_cmp, + m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + DEBUG_PRINT("FTBP: END OF STREAM m_eos_bm=%d\n",m_eos_bm); + } + + return OMX_ErrorNone; + } + DEBUG_PRINT("nState %d \n",nState ); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (state == OMX_StatePause) + { + DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\ + state); + post_output((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_FRAME_DONE); + } + else + { + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + DEBUG_PRINT("FTBP*******************************************\n"); + + } + + + } + else + DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n"); + + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::FillThisBuffer + +DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + + +PARAMETERS + + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::fill_this_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_aac_aenc::ftb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (m_out_bEnabled == OMX_FALSE) + { + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_aac_aenc::ftb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf++; + m_aac_pb_stats.ftb_cnt++; + DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf); + pthread_mutex_unlock(&out_buf_count_lock); + post_output((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB); + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::SetCallbacks + +DESCRIPTION + Set the callbacks. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + m_cb = *callbacks; + m_app_data = appData; + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::ComponentDeInit + +DESCRIPTION + Destroys the component and release memory allocated to the heap. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state) + { + DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n", + m_state); + } + deinit_encoder(); + + DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::deinit_encoder + +DESCRIPTION + Closes all the threads and release memory allocated to the heap. + +PARAMETERS + None. + +RETURN VALUE + None. + +========================================================================== */ +void omx_aac_aenc::deinit_encoder() +{ + DEBUG_PRINT("Component-deinit being processed\n"); + DEBUG_PRINT("********************************\n"); + DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\ + m_aac_pb_stats.tot_in_buf_len, + m_aac_pb_stats.tot_out_buf_len, + m_aac_pb_stats.tot_pb_time); + DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\ + m_aac_pb_stats.fbd_cnt,m_aac_pb_stats.ftb_cnt, + m_aac_pb_stats.etb_cnt, + m_aac_pb_stats.ebd_cnt); + memset(&m_aac_pb_stats,0,sizeof(AAC_PB_STATS)); + + if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state)) + { + DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\ + m_state); + // Get back any buffers from driver + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + // force state change to loaded so that all threads can be exited + pthread_mutex_lock(&m_state_lock); + m_state = OMX_StateLoaded; + pthread_mutex_unlock(&m_state_lock); + DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\ + m_inp_current_buf_count, + m_input_buf_hdrs.size()); + m_input_buf_hdrs.eraseall(); + DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\ + m_out_current_buf_count, + m_output_buf_hdrs.size()); + m_output_buf_hdrs.eraseall(); + + } + if(pcm_input) + { + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + if(pcm_input) + { + if (m_ipc_to_in_th != NULL) + { + omx_aac_thread_stop(m_ipc_to_in_th); + m_ipc_to_in_th = NULL; + } + } + + if (m_ipc_to_cmd_th != NULL) + { + omx_aac_thread_stop(m_ipc_to_cmd_th); + m_ipc_to_cmd_th = NULL; + } + if (m_ipc_to_out_th != NULL) + { + DEBUG_DETAIL("Inside omx_aac_thread_stop\n"); + omx_aac_thread_stop(m_ipc_to_out_th); + m_ipc_to_out_th = NULL; + } + + + if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0) + DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n"); + + if(pcm_input && m_tmp_meta_buf ) + { + free(m_tmp_meta_buf); + } + + if(m_tmp_out_meta_buf) + { + free(m_tmp_out_meta_buf); + } + nNumInputBuf = 0; + nNumOutputBuf = 0; + m_inp_current_buf_count=0; + m_out_current_buf_count=0; + m_out_act_buf_count = 0; + m_inp_act_buf_count = 0; + m_inp_bEnabled = OMX_FALSE; + m_out_bEnabled = OMX_FALSE; + m_inp_bPopulated = OMX_FALSE; + m_out_bPopulated = OMX_FALSE; + adif_flag = 0; + mp4ff_flag = 0; + ts = 0; + nTimestamp = 0; + frameduration = 0; + if ( m_drv_fd >= 0 ) + { + if(close(m_drv_fd) < 0) + DEBUG_PRINT("De-init: Driver Close Failed \n"); + m_drv_fd = -1; + } + else + { + DEBUG_PRINT_ERROR(" AAC device already closed\n"); + } + m_comp_deinit=1; + m_is_out_th_sleep = 1; + m_is_in_th_sleep = 1; + DEBUG_PRINT("************************************\n"); + DEBUG_PRINT(" DEINIT COMPLETED"); + DEBUG_PRINT("************************************\n"); + +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::UseEGLImage + +DESCRIPTION + OMX Use EGL Image method implementation . + +PARAMETERS + . + +RETURN VALUE + Not Implemented error. + +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::use_EGL_image +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n"); + + if((hComp == NULL) || (appData == NULL) || (eglImage == NULL)) + { + bufferHdr = NULL; + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_aac_aenc::ComponentRoleEnum + +DESCRIPTION + OMX Component Role Enum method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_aac_aenc::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + const char *cmp_role = "audio_encoder.aac"; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (index == 0 && role) + { + memcpy(role, cmp_role, sizeof(cmp_role)); + *(((char *) role) + sizeof(cmp_role)) = '\0'; + } else + { + eRet = OMX_ErrorNoMore; + } + return eRet; +} + + + + +/* ====================================================================== +FUNCTION + omx_aac_aenc::AllocateDone + +DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + +PARAMETERS + None. + +RETURN VALUE + true/false. + +========================================================================== */ +bool omx_aac_aenc::allocate_done(void) +{ + OMX_BOOL bRet = OMX_FALSE; + if (pcm_input==1) + { + if ((m_inp_act_buf_count == m_inp_current_buf_count) + &&(m_out_act_buf_count == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + + } + if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled ) + { + m_inp_bPopulated = OMX_TRUE; + } + + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + } else if (pcm_input==0) + { + if (m_out_act_buf_count == m_out_current_buf_count) + { + bRet=OMX_TRUE; + + } + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + + } + return bRet; +} + + +/* ====================================================================== +FUNCTION + omx_aac_aenc::ReleaseDone + +DESCRIPTION + Checks if IL client has released all the buffers. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +bool omx_aac_aenc::release_done(OMX_U32 param1) +{ + DEBUG_PRINT("Inside omx_aac_aenc::release_done"); + OMX_BOOL bRet = OMX_FALSE; + + if (param1 == OMX_ALL) + { + + if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_INPUT_PORT_INDEX ) + { + if ((0 == m_inp_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX) + { + if ((0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } + return bRet; +} + +void omx_aac_aenc::audaac_rec_install_adif_header_variable (OMX_U16 byte_num, + OMX_U32 sample_index, + OMX_U8 channel_config) +{ + OMX_U8 buf8; + OMX_U32 value; + OMX_U32 dummy = 0; + OMX_U8 num_pfe, num_fce, num_sce, num_bce; + OMX_U8 num_lfe, num_ade, num_vce, num_com; + OMX_U8 pfe_index; + OMX_U8 i; + OMX_BOOL variable_bit_rate = OMX_FALSE; + + (void)byte_num; + (void)channel_config; + num_pfe = num_sce = num_bce = + num_lfe = num_ade = num_vce = num_com = 0; + audaac_hdr_bit_index = 32; + num_fce = 1; + /* Store Header Id "ADIF" first */ + memcpy(&audaac_header_adif[0], "ADIF", sizeof(OMX_U32)); + + /* copyright_id_present field, 1 bit */ + value = 0; + audaac_rec_install_bits(audaac_header_adif, + AAC_COPYRIGHT_PRESENT_SIZE, + value, + &(audaac_hdr_bit_index)); + + if (value) { + /* Copyright present, 72 bits; skip it for now, + * just install dummy value */ + audaac_rec_install_bits(audaac_header_adif, + 72, + dummy, + &(audaac_hdr_bit_index)); + } + + /* original_copy field, 1 bit */ + value = 0; + audaac_rec_install_bits(audaac_header_adif, + AAC_ORIGINAL_COPY_SIZE, + 0, + &(audaac_hdr_bit_index)); + + /* home field, 1 bit */ + value = 0; + audaac_rec_install_bits(audaac_header_adif, + AAC_HOME_SIZE, + 0, + &(audaac_hdr_bit_index)); + + /* bitstream_type = 1, varibable bit rate, 1 bit */ + value = 0; + audaac_rec_install_bits(audaac_header_adif, + AAC_BITSTREAM_TYPE_SIZE, + value, + &(audaac_hdr_bit_index)); + + /* bit_rate field, 23 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_BITRATE_SIZE, + (OMX_U32)m_aac_param.nBitRate, + &(audaac_hdr_bit_index)); + + /* num_program_config_elements, 4 bits */ + num_pfe = 0; + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_PFE_SIZE, + (OMX_U32)num_pfe, + &(audaac_hdr_bit_index)); + + /* below is to install program_config_elements field, + * for now only one element is supported */ + for (pfe_index=0; pfe_index < num_pfe+1; pfe_index++) { + + + if (variable_bit_rate == OMX_FALSE) { + /* impossible, put dummy value for now */ + audaac_rec_install_bits(audaac_header_adif, + AAC_BUFFER_FULLNESS_SIZE, + 0, + &(audaac_hdr_bit_index)); + + } + + dummy = 0; + + /* element_instance_tag field, 4 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_ELEMENT_INSTANCE_TAG_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + /* object_type, 2 bits, AAC LC is supported */ + value = 1; + audaac_rec_install_bits(audaac_header_adif, + AAC_PROFILE_SIZE, /* object type */ + value, + &(audaac_hdr_bit_index)); + + /* sampling_frequency_index, 4 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_SAMPLING_FREQ_INDEX_SIZE, + (OMX_U32)sample_index, + &(audaac_hdr_bit_index)); + + /* num_front_channel_elements, 4 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_FRONT_CHANNEL_ELEMENTS_SIZE, + num_fce, + &(audaac_hdr_bit_index)); + + /* num_side_channel_elements, 4 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_SIDE_CHANNEL_ELEMENTS_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + /* num_back_channel_elements, 4 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_BACK_CHANNEL_ELEMENTS_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + /* num_lfe_channel_elements, 2 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_LFE_CHANNEL_ELEMENTS_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + /* num_assoc_data_elements, 3 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_ASSOC_DATA_ELEMENTS_SIZE, + num_ade, + &(audaac_hdr_bit_index)); + + /* num_valid_cc_elements, 4 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_NUM_VALID_CC_ELEMENTS_SIZE, + num_vce, + &(audaac_hdr_bit_index)); + + /* mono_mixdown_present, 1 bits */ + audaac_rec_install_bits(audaac_header_adif, + AAC_MONO_MIXDOWN_PRESENT_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + if (dummy) { + audaac_rec_install_bits(audaac_header_adif, + AAC_MONO_MIXDOWN_ELEMENT_SIZE, + dummy, + &(audaac_hdr_bit_index)); + } + + /* stereo_mixdown_present */ + audaac_rec_install_bits(audaac_header_adif, + AAC_STEREO_MIXDOWN_PRESENT_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + if (dummy) { + audaac_rec_install_bits(audaac_header_adif, + AAC_STEREO_MIXDOWN_ELEMENT_SIZE, + dummy, + &(audaac_hdr_bit_index)); + } + + /* matrix_mixdown_idx_present, 1 bit */ + audaac_rec_install_bits(audaac_header_adif, + AAC_MATRIX_MIXDOWN_PRESENT_SIZE, + dummy, + &(audaac_hdr_bit_index)); + + if (dummy) { + audaac_rec_install_bits(audaac_header_adif, + AAC_MATRIX_MIXDOWN_SIZE, + dummy, + &(audaac_hdr_bit_index)); + } + if(m_aac_param.nChannels == 2) + value = 16; + else + value = 0; + for (i=0; i> 3; + bit_index = (*hdr_bit_index) & 0x07; + + bits_avail_in_byte = 8 - bit_index; + + num_to_copy = min(bits_avail_in_byte, num_remaining); + + byte_to_copy = ((OMX_U8)((value >> (num_remaining - num_to_copy)) & 0xFF) << + (bits_avail_in_byte - num_to_copy)); + + input[byte_index] &= ((OMX_U8)(bit_mask << bits_avail_in_byte)); + input[byte_index] |= byte_to_copy; + + *hdr_bit_index += num_to_copy; + + num_remaining -= num_to_copy; + } +} +void omx_aac_aenc::audaac_rec_install_mp4ff_header_variable (OMX_U16 byte_num, + OMX_U32 sample_index, + OMX_U8 channel_config) +{ + OMX_U16 audaac_hdr_bit_index; + (void)byte_num; + audaac_header_mp4ff[0] = 0; + audaac_header_mp4ff[1] = 0; + audaac_hdr_bit_index = 0; + + /* Audio object type, 5 bit */ + audaac_rec_install_bits(audaac_header_mp4ff, + AUDAAC_MP4FF_OBJ_TYPE, + 2, + &(audaac_hdr_bit_index)); + + /* Frequency index, 4 bit */ + audaac_rec_install_bits(audaac_header_mp4ff, + AUDAAC_MP4FF_FREQ_IDX, + (OMX_U32)sample_index, + &(audaac_hdr_bit_index)); + + /* Channel config filed, 4 bit */ + audaac_rec_install_bits(audaac_header_mp4ff, + AUDAAC_MP4FF_CH_CONFIG, + channel_config, + &(audaac_hdr_bit_index)); + +} + diff --git a/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c b/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c new file mode 100644 index 000000000..c3e4b0ab8 --- /dev/null +++ b/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c @@ -0,0 +1,1289 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif +#include + +typedef unsigned char uint8; +typedef unsigned char byte; +typedef unsigned int uint32; +typedef unsigned int uint16; +#define AUDAAC_MAX_ADIF_HEADER_LENGTH 64 +/* ADTS variable frame header, frame length field */ +#define AUDAAC_ADTS_FRAME_LENGTH_SIZE 13 +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; +void audaac_rec_install_bits +( + uint8 *input, + byte num_bits_reqd, + uint32 value, + uint16 *hdr_bit_index +); + +/* maximum ADTS frame header length */ +#define AUDAAC_MAX_ADTS_HEADER_LENGTH 7 +void audaac_rec_install_adts_header_variable (uint16 byte_num); +void Release_Encoder(); + +#ifdef AUDIOV2 +unsigned short session_id; +int device_id; +int control = 0; +const char *device="handset_tx"; +#define DIR_TX 2 +#endif + +#define AACHDR_LAYER_SIZE 2 +#define AACHDR_CRC_SIZE 1 +#define AAC_PROFILE_SIZE 2 +#define AAC_SAMPLING_FREQ_INDEX_SIZE 4 +#define AAC_ORIGINAL_COPY_SIZE 1 +#define AAC_HOME_SIZE 1 + +#define MIN(A,B) (((A) < (B))?(A):(B)) + +uint8 audaac_header[AUDAAC_MAX_ADTS_HEADER_LENGTH]; +unsigned int audaac_hdr_bit_index; + + +FILE *F1 = NULL; + +uint32_t samplerate = 44100; +uint32_t channels = 2; +uint32_t bitrate = 128000; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t rectime = -1; +uint32_t format = 1; +uint32_t profile = OMX_AUDIO_AACObjectLC; +#define DEBUG_PRINT printf +unsigned to_idle_transition = 0; + +typedef enum adts_sample_index__ { + +ADTS_SAMPLE_INDEX_96000=0x0, +ADTS_SAMPLE_INDEX_88200, +ADTS_SAMPLE_INDEX_64000, +ADTS_SAMPLE_INDEX_48000, +ADTS_SAMPLE_INDEX_44100, +ADTS_SAMPLE_INDEX_32000, +ADTS_SAMPLE_INDEX_24000, +ADTS_SAMPLE_INDEX_22050, +ADTS_SAMPLE_INDEX_16000, +ADTS_SAMPLE_INDEX_12000, +ADTS_SAMPLE_INDEX_11025, +ADTS_SAMPLE_INDEX_8000, +ADTS_SAMPLE_INDEX_7350, +ADTS_SAMPLE_INDEX_MAX + +}adts_sample_index; +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +pthread_mutex_t lock; +pthread_cond_t cond; +pthread_mutex_t elock; +pthread_cond_t econd; +pthread_cond_t fcond; +pthread_mutex_t etb_lock; +pthread_mutex_t etb_lock1; +pthread_cond_t etb_cond; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; +OMX_AUDIO_PARAM_AACPROFILETYPE aacparam; +OMX_AUDIO_PARAM_PCMMODETYPE pcmparam; +OMX_PORT_PARAM_TYPE portParam; +OMX_ERRORTYPE error; + + + + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; +struct enc_meta_out{ + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; +} __attribute__ ((packed)); + +static unsigned totaldatalen = 0; +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +volatile int etb_event_is_done = 0; +int ebd_cnt; +int bInputEosReached = 0; +int bOutputEosReached = 0; +int bInputEosReached_tunnel = 0; +static int etb_done = 0; +int bFlushing = false; +int bPause = false; +const char *in_filename; +const char *out_filename; + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* aac_enc_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Encoder(char*); +int Play_Encoder(); +OMX_STRING aud_comp; +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *aac_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +static OMX_ERRORTYPE parse_pcm_header(); +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock1); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock1); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock1); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock1); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock1); +} + + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + + switch(eEvent) { + case OMX_EventCmdComplete: + DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent, + nData1,nData2); + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("\n OMX_EventError \n"); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("\n OMX_EventBufferFlag \n"); + bOutputEosReached = true; + event_complete(); + break; + case OMX_EventPortSettingsChanged: + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + size_t bytes_writen = 0; + int total_bytes_writen = 0; + unsigned int len = 0; + struct enc_meta_out *meta = NULL; + OMX_U8 *src = pBuffer->pBuffer; + unsigned int num_of_frames = 1; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT("FBD::EOS on output port\n "); + bOutputEosReached = true; + return OMX_ErrorNone; + } + if(bInputEosReached_tunnel || bOutputEosReached) + { + DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n"); + return OMX_ErrorNone; + } + if(num_of_frames != src[0]){ + + printf("Data corrupt\n"); + return OMX_ErrorNone; + } + /* Skip the first bytes */ + + + + src += sizeof(unsigned char); + meta = (struct enc_meta_out *)src; + while (num_of_frames > 0) { + meta = (struct enc_meta_out *)src; + /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n", + meta->offset_to_frame, + meta->frame_size, + meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/ + len = meta->frame_size; + + if(format == 6) + { + audaac_rec_install_adts_header_variable(len + AUDAAC_MAX_ADTS_HEADER_LENGTH); + bytes_writen = fwrite(audaac_header,1,AUDAAC_MAX_ADTS_HEADER_LENGTH,outputBufferFile); + if(bytes_writen < AUDAAC_MAX_ADTS_HEADER_LENGTH) + { + DEBUG_PRINT("error: invalid adts header length\n"); + return OMX_ErrorNone; + } + } + bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile); + if(bytes_writen < len) + { + DEBUG_PRINT("error: invalid AAC encoded data \n"); + return OMX_ErrorNone; + } + src += sizeof(struct enc_meta_out); + num_of_frames--; + total_bytes_writen += len; + } + DEBUG_PRINT(" FillBufferDone size writen to file %d\n",total_bytes_writen); + totaldatalen += total_bytes_writen ; + + DEBUG_PRINT(" FBD calling FTB\n"); + OMX_FillThisBuffer(hComponent,pBuffer); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock); + } + + + if(bInputEosReached) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + }else if (bFlushing == true) { + DEBUG_PRINT("omx_aac_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (used_ip_buf_cnt == 0) { + bFlushing = false; + } else { + DEBUG_PRINT("omx_aac_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + return OMX_ErrorNone; + } + } + + if((readBytes = Read_Buffer(pBuffer)) > 0) { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else{ + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + bInputEosReached = true; + pBuffer->nFilledLen = 0; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) { + + /* Flush */ + if (sig_id == SIGUSR1) { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(aac_enc_handle, OMX_CommandFlush, OMX_ALL, NULL); + } else if (sig_id == SIGUSR2) { + if (bPause == true) { + DEBUG_PRINT("%s resume playback\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } else { + DEBUG_PRINT("%s pause playback\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + (void) signal(SIGINT, Release_Encoder); + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + + if (argc >= 9) { + in_filename = argv[1]; + out_filename = argv[2]; + samplerate = atoi(argv[3]); + channels = atoi(argv[4]); + tunnel = atoi(argv[5]); + rectime = atoi(argv[6]); + bitrate = atoi(argv[7]); + format = atoi(argv[8]); + profile = atoi(argv[9]); + + DEBUG_PRINT("Input parameters: samplerate = %d, channels = %d, tunnel = %d," + " rectime = %d, bitrate = %d, format = %d, profile = %d\n", + samplerate, channels, tunnel, rectime, bitrate, format, profile); + + if (!((profile == 2) || (profile == 5) || (profile == 29))) { + DEBUG_PRINT("profile = %d, not supported. Supported " + "profile values are AAC_LC(2), AAC+(5), EAAC+(29)\n", profile); + return 0; + } + if (!((format == 1) || (format == 6))) { + DEBUG_PRINT("format = %d, not supported. Supported " + "formats are ADTS(1), RAW(6)\n", format); + return 0; + } + if ((channels > 2) || (channels <= 0)) { + DEBUG_PRINT("channels = %d, not supported. Supported " + "number of channels are 1 and 2\n", channels); + return 0; + } + if ((samplerate < 8000) && (samplerate > 48000)) { + DEBUG_PRINT("samplerate = %d, not supported, Supported " + "samplerates are 8000, 11025, 12000, 16000, 22050, " + "24000, 32000, 44100, 48000\n", samplerate); + return 0; + } else { + if ((profile == 5) || (profile == 29)) { + if (samplerate < 24000) { + DEBUG_PRINT("samplerate = %d, not supported for AAC+/EAAC+." + " Supported samplerates are 24000, 32000," + " 44100, 48000\n", samplerate); + return 0; + } + } + } + } else { + DEBUG_PRINT(" invalid format: \n"); + DEBUG_PRINT("ex: ./mm-aenc-omxaac INPUTFILE AAC_OUTPUTFILE SAMPFREQ CHANNEL TUNNEL RECORDTIME BITRATE FORMAT PROFILE\n"); + DEBUG_PRINT("FOR TUNNEL MOD PASS INPUT FILE AS ZERO\n"); + DEBUG_PRINT("RECORDTIME in seconds for AST Automation ...TUNNEL MODE ONLY\n"); + DEBUG_PRINT("FORMAT::ADTS(1), RAW(6)\n"); + DEBUG_PRINT("BITRATE in bits/sec \n"); + DEBUG_PRINT("PROFILE::AAC_LC(2), AAC+(5), EAAC+(29)\n"); + return 0; + } + if(tunnel == 0) + aud_comp = "OMX.qcom.audio.encoder.aac"; + else + aud_comp = "OMX.qcom.audio.encoder.tunneled.aac"; + if(Init_Encoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + fcntl(0, F_SETFL, O_NONBLOCK); + + if(Play_Encoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + if(rectime && tunnel) + { + sleep(rectime); + rectime = 0; + bInputEosReached_tunnel = 1; + DEBUG_PRINT("\EOS ON INPUT PORT\n"); + } + else + { + wait_for_event(); + } + + if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel)) + { + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + DEBUG_PRINT("\nMoving the encoder to loaded state \n"); + OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + sleep(1); + if (!tunnel) + { + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(aac_enc_handle, 0, pInputBufHdrs[bufCnt]); + } + } + + DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(aac_enc_handle, 1, pOutputBufHdrs[bufCnt]); + } + wait_for_event(); + + result = OMX_FreeHandle(aac_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + /* Deinit OpenMAX */ + if(tunnel) + { + #ifdef AUDIOV2 + if (msm_route_stream(DIR_TX,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + #endif + } + OMX_Deinit(); + ebd_cnt=0; + bOutputEosReached = false; + bInputEosReached_tunnel = false; + bInputEosReached = 0; + aac_enc_handle = NULL; + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + fclose(outputBufferFile); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...AAC ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + return 0; +} + +void Release_Encoder() +{ + static int cnt=0; + OMX_ERRORTYPE result; + + DEBUG_PRINT("END OF AAC ENCODING: EXITING PLEASE WAIT\n"); + bInputEosReached_tunnel = 1; + event_complete(); + cnt++; + if(cnt > 1) + { + /* FORCE RESET */ + aac_enc_handle = NULL; + ebd_cnt=0; + bInputEosReached_tunnel = false; + + result = OMX_FreeHandle(aac_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + + OMX_Deinit(); + + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...AAC ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + exit(0); + } +} + +int Init_Encoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + typedef OMX_U8* OMX_U8_PTR; + char *role ="audio_encoder"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Aac_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total); + + + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&aac_enc_handle), + (OMX_STRING)audio_component, NULL, &call_back); + if (FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component); + return -1; + } + else + { + DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(portParam); + omxresult = OMX_GetParameter(aac_enc_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&portParam); + + if(FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to get Port Param\n"); + return -1; + } + else + { + DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts); + DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n", + portParam.nStartPortNumber); + } + return 0; +} + +int Play_Encoder() +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file()) { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + + /* Query the encoder input min buf requirements */ + CONFIG_VERSION_SIZE(inputportFmt); + + /* Port for which the Client needs to obtain info */ + inputportFmt.nPortIndex = portParam.nStartPortNumber; + + OMX_GetParameter(aac_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt); + DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize); + + if(OMX_DirInput != inputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Input Port\n"); + return -1; + } + + pcmparam.nPortIndex = 0; + pcmparam.nChannels = channels; + pcmparam.nSamplingRate = samplerate; + OMX_SetParameter(aac_enc_handle,OMX_IndexParamAudioPcm,&pcmparam); + + + /* Query the encoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(aac_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Output Port\n"); + return -1; + } + + + CONFIG_VERSION_SIZE(aacparam); + + + aacparam.nPortIndex = 1; + aacparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/ + aacparam.nBitRate = bitrate; + aacparam.nSampleRate = samplerate; + aacparam.eChannelMode = OMX_AUDIO_ChannelModeStereo; + aacparam.eAACStreamFormat = (OMX_AUDIO_AACSTREAMFORMATTYPE)format; + aacparam.eAACProfile = (OMX_AUDIO_AACPROFILETYPE)profile; + OMX_SetParameter(aac_enc_handle,OMX_IndexParamAudioAac,&aacparam); + OMX_GetExtensionIndex(aac_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index); + OMX_GetParameter(aac_enc_handle,index,&streaminfoparam); + if(tunnel) + { + #ifdef AUDIOV2 + session_id = streaminfoparam.sessionId; + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + + if (msm_route_stream(DIR_TX,session_id,device_id, 1)) + { + perror("could not set stream routing\n"); + return -1; + } + #endif + } + DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n"); + OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + if (tunnel == 0) + { + input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(aac_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pInputBufHdrs == NULL) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + } + output_buf_cnt = outputportFmt.nBufferCountMin ; + + /* Allocate buffer on encoder's O/Pp port */ + error = Allocate_Buffer(aac_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pOutputBufHdrs == NULL) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + + if (tunnel == 1) + { + DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n"); + OMX_SendCommand(aac_enc_handle, OMX_CommandPortDisable,0,0); // disable input port + wait_for_event(); + } + + DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n"); + OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(aac_enc_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + +if(tunnel == 0) +{ + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) { + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + bInputEosReached = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + ret = OMX_EmptyThisBuffer(aac_enc_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock); + if(etb_done) +{ + DEBUG_PRINT("Component is waiting for EBD to be released.\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock); +} + + return 0; +} + + + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + /* To remove warning for unused variable to keep prototype same */ + (void)avc_enc_handle; + + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(aac_enc_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + + + + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + + int bytes_read=0; + + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + + bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile); + + pBufHdr->nFilledLen = bytes_read; + if(bytes_read == 0) + { + + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + } + + return bytes_read;; +} + + + +//In Encoder this Should Open a PCM or WAV file for input. + +static int open_audio_file () +{ + int error_code = 0; + + if (!tunnel) + { + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); + inputBufferFile = fopen (in_filename, "rb"); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + } + if(parse_pcm_header() != 0x00) + { + DEBUG_PRINT("PCM parser failed \n"); + return -1; + } + } + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename); + outputBufferFile = fopen (out_filename, "wb"); + if (outputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + out_filename); + error_code = -1; + } + return error_code; +} + + +void audaac_rec_install_bits +( + uint8 *input, + byte num_bits_reqd, + uint32 value, + uint16 *hdr_bit_index +) +{ + uint32 byte_index; + byte bit_index; + byte bits_avail_in_byte; + byte num_to_copy; + byte byte_to_copy; + + byte num_remaining = num_bits_reqd; + uint8 bit_mask; + + bit_mask = 0xFF; + + while (num_remaining) { + + byte_index = (*hdr_bit_index) >> 3; + bit_index = (*hdr_bit_index) & 0x07; + + bits_avail_in_byte = 8 - bit_index; + + num_to_copy = MIN(bits_avail_in_byte, num_remaining); + + byte_to_copy = ((uint8)((value >> (num_remaining - num_to_copy)) & 0xFF) << + (bits_avail_in_byte - num_to_copy)); + + input[byte_index] &= ((uint8)(bit_mask << bits_avail_in_byte)); + input[byte_index] |= byte_to_copy; + + *hdr_bit_index += num_to_copy; + + num_remaining -= num_to_copy; + } /* while (num_remaining) */ +} /* audaac_rec_install_bits */ + +adts_sample_index map_adts_sample_index(uint32 srate) +{ + adts_sample_index ret; + + switch(srate){ + + case 96000: + ret= ADTS_SAMPLE_INDEX_96000; + break; + case 88200: + ret= ADTS_SAMPLE_INDEX_88200; + break; + case 64000: + ret= ADTS_SAMPLE_INDEX_64000; + break; + case 48000: + ret=ADTS_SAMPLE_INDEX_48000; + break; + case 44100: + ret=ADTS_SAMPLE_INDEX_44100; + break; + case 32000: + ret=ADTS_SAMPLE_INDEX_32000; + break; + case 24000: + ret=ADTS_SAMPLE_INDEX_24000; + break; + case 22050: + ret=ADTS_SAMPLE_INDEX_22050; + break; + case 16000: + ret=ADTS_SAMPLE_INDEX_16000; + break; + case 12000: + ret=ADTS_SAMPLE_INDEX_12000; + break; + case 11025: + ret=ADTS_SAMPLE_INDEX_11025; + break; + case 8000: + ret=ADTS_SAMPLE_INDEX_8000; + break; + case 7350: + ret=ADTS_SAMPLE_INDEX_7350; + break; + default: + ret=ADTS_SAMPLE_INDEX_44100; + break; + } + return ret; +} + +void audaac_rec_install_adts_header_variable (uint16 byte_num) +{ + //uint16 bit_index=0; + + adts_sample_index srate_enum; + uint32 value; + + uint32 sample_index = samplerate; + uint8 channel_config = channels; + + /* Store Sync word first */ + audaac_header[0] = 0xFF; + audaac_header[1] = 0xF0; + + audaac_hdr_bit_index = 12; + + if ((format == OMX_AUDIO_AACStreamFormatRAW) && + ((profile == OMX_AUDIO_AACObjectHE) || + (profile == OMX_AUDIO_AACObjectHE_PS))){ + if (samplerate >= 24000) + sample_index = samplerate/2; + } + + /* ID field, 1 bit */ + value = 1; + audaac_rec_install_bits(audaac_header, + 1, + value, + &(audaac_hdr_bit_index)); + + /* Layer field, 2 bits */ + value = 0; + audaac_rec_install_bits(audaac_header, + AACHDR_LAYER_SIZE, + value, + &(audaac_hdr_bit_index)); + + /* Protection_absent field, 1 bit */ + value = 1; + audaac_rec_install_bits(audaac_header, + AACHDR_CRC_SIZE, + value, + &(audaac_hdr_bit_index)); + + /* profile_ObjectType field, 2 bit */ + value = 1; + audaac_rec_install_bits(audaac_header, + AAC_PROFILE_SIZE, + value, + &(audaac_hdr_bit_index)); + + /* sampling_frequency_index field, 4 bits */ + srate_enum = map_adts_sample_index(sample_index); + audaac_rec_install_bits(audaac_header, + AAC_SAMPLING_FREQ_INDEX_SIZE, + (uint32)srate_enum, + &(audaac_hdr_bit_index)); + + DEBUG_PRINT("%s: sample_index=%d; srate_enum = %d \n", + __FUNCTION__, sample_index, srate_enum); + + /* pravate_bit field, 1 bits */ + audaac_rec_install_bits(audaac_header, + 1, + 0, + &(audaac_hdr_bit_index)); + + /* channel_configuration field, 3 bits */ + audaac_rec_install_bits(audaac_header, + 3, + channel_config, + &(audaac_hdr_bit_index)); + + + /* original/copy field, 1 bits */ + audaac_rec_install_bits(audaac_header, + AAC_ORIGINAL_COPY_SIZE, + 0, + &(audaac_hdr_bit_index)); + + + /* home field, 1 bits */ + audaac_rec_install_bits(audaac_header, + AAC_HOME_SIZE, + 0, + &(audaac_hdr_bit_index)); + + // bit_index = audaac_hdr_bit_index; + // bit_index += 2; + + /* copyr. id. bit, 1 bits */ + audaac_rec_install_bits(audaac_header, + 1, + 0, + &(audaac_hdr_bit_index)); + + /* copyr. id. start, 1 bits */ + audaac_rec_install_bits(audaac_header, + 1, + 0, + &(audaac_hdr_bit_index)); + + /* aac_frame_length field, 13 bits */ + audaac_rec_install_bits(audaac_header, + AUDAAC_ADTS_FRAME_LENGTH_SIZE, + byte_num, + &audaac_hdr_bit_index); + + /* adts_buffer_fullness field, 11 bits */ + audaac_rec_install_bits(audaac_header, + 11, + 0x660,/*0x660 = CBR,0x7FF = VBR*/ + &audaac_hdr_bit_index); + + /* number_of_raw_data_blocks_in_frame, 2 bits */ + audaac_rec_install_bits(audaac_header, + 2, + 0, + &audaac_hdr_bit_index); + +} /* audaac_rec_install_adts_header_variable */ + +static OMX_ERRORTYPE parse_pcm_header() +{ + struct wav_header hdr; + + DEBUG_PRINT("\n***************************************************************\n"); + if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr)) + { + DEBUG_PRINT("Wav file cannot read header\n"); + return -1; + } + + if ((hdr.riff_id != ID_RIFF) || + (hdr.riff_fmt != ID_WAVE)|| + (hdr.fmt_id != ID_FMT)) + { + DEBUG_PRINT("Wav file is not a riff/wave file\n"); + return -1; + } + + if (hdr.audio_format != FORMAT_PCM) + { + DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n", + hdr.audio_format, hdr.fmt_sz); + return -1; + } + + DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate); + DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels); + DEBUG_PRINT("\n***************************************************************\n"); + + samplerate = hdr.sample_rate; + channels = hdr.num_channels; + + return OMX_ErrorNone; +} diff --git a/mm-audio/aenc-amrnb/Android.mk b/mm-audio/aenc-amrnb/Android.mk new file mode 100644 index 000000000..673c5cb36 --- /dev/null +++ b/mm-audio/aenc-amrnb/Android.mk @@ -0,0 +1,23 @@ +ifeq ($(TARGET_ARCH),arm) + + +AENC_AMR_PATH:= $(call my-dir) + +ifeq ($(call is-board-platform,msm8660),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8960),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8974),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8226),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8610),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif + + +endif diff --git a/mm-audio/aenc-amrnb/Makefile b/mm-audio/aenc-amrnb/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/mm-audio/aenc-amrnb/Makefile @@ -0,0 +1,6 @@ +all: + @echo "invoking omxaudio make" + $(MAKE) -C qdsp6 + +install: + $(MAKE) -C qdsp6 install diff --git a/mm-audio/aenc-amrnb/qdsp6/Android.mk b/mm-audio/aenc-amrnb/qdsp6/Android.mk new file mode 100644 index 000000000..b97e2e5bc --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/Android.mk @@ -0,0 +1,76 @@ +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxAmrEnc-def := -g -O3 +libOmxAmrEnc-def += -DQC_MODIFIED +libOmxAmrEnc-def += -D_ANDROID_ +libOmxAmrEnc-def += -D_ENABLE_QC_MSG_LOG_ +libOmxAmrEnc-def += -DVERBOSE +libOmxAmrEnc-def += -D_DEBUG +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +libOmxAmrEnc-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxAmrEnc) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +libOmxAmrEnc-inc := $(LOCAL_PATH)/inc +libOmxAmrEnc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore + +LOCAL_MODULE := libOmxAmrEnc +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAmrEnc-def) +LOCAL_C_INCLUDES := $(libOmxAmrEnc-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libutils liblog + +LOCAL_SRC_FILES := src/aenc_svr.c +LOCAL_SRC_FILES += src/omx_amr_aenc.cpp + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +include $(BUILD_SHARED_LIBRARY) + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-aenc-omxamr-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +mm-amr-enc-test-inc := $(LOCAL_PATH)/inc +mm-amr-enc-test-inc += $(LOCAL_PATH)/test + +mm-amr-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +mm-amr-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +endif +LOCAL_MODULE := mm-aenc-omxamr-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxAmrEnc-def) +LOCAL_C_INCLUDES := $(mm-amr-enc-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libmm-omxcore +LOCAL_SHARED_LIBRARIES += libOmxAmrEnc +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +LOCAL_SHARED_LIBRARIES += libaudioalsa +endif +LOCAL_SRC_FILES := test/omx_amr_enc_test.c + +include $(BUILD_EXECUTABLE) + +endif + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- + diff --git a/mm-audio/aenc-amrnb/qdsp6/Makefile b/mm-audio/aenc-amrnb/qdsp6/Makefile new file mode 100644 index 000000000..0abd31cff --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/Makefile @@ -0,0 +1,81 @@ +# --------------------------------------------------------------------------------- +# MM-AUDIO-OSS-8K-AENC-AMR +# --------------------------------------------------------------------------------- + +# cross-compiler flags +CFLAGS += -Wall +CFLAGS += -Wundef +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wno-trigraphs + +# cross-compile flags specific to shared objects +CFLAGS_SO += -fpic + +# required pre-processor flags +CPPFLAGS := -D__packed__= +CPPFLAGS += -DIMAGE_APPS_PROC +CPPFLAGS += -DFEATURE_Q_SINGLE_LINK +CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR +CPPFLAGS += -DFEATURE_LINUX +CPPFLAGS += -DFEATURE_NATIVELINUX +CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS + +CPPFLAGS += -g +CPPFALGS += -D_DEBUG +CPPFLAGS += -Iinc + +# linker flags +LDFLAGS += -L$(SYSROOT)/usr/lib + +# linker flags for shared objects +LDFLAGS_SO := -shared + +# defintions +LIBMAJOR := $(basename $(basename $(LIBVER))) +LIBINSTALLDIR := $(DESTDIR)usr/lib +INCINSTALLDIR := $(DESTDIR)usr/include +BININSTALLDIR := $(DESTDIR)usr/bin + +# --------------------------------------------------------------------------------- +# BUILD +# --------------------------------------------------------------------------------- +all: libOmxAmrEnc.so.$(LIBVER) mm-aenc-omxamr-test + +install: + echo "intalling aenc-amr in $(DESTDIR)" + if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi + if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi + if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi + install -m 555 libOmxAmrEnc.so.$(LIBVER) $(LIBINSTALLDIR) + cd $(LIBINSTALLDIR) && ln -s libOmxAmrEnc.so.$(LIBVER) libOmxAmrEnc.so.$(LIBMAJOR) + cd $(LIBINSTALLDIR) && ln -s libOmxAmrEnc.so.$(LIBMAJOR) libOmxAmrEnc.so + install -m 555 mm-aenc-omxamr-test $(BININSTALLDIR) + +# --------------------------------------------------------------------------------- +# COMPILE LIBRARY +# --------------------------------------------------------------------------------- +LDLIBS := -lpthread +LDLIBS += -lstdc++ +LDLIBS += -lOmxCore + +SRCS := src/omx_amr_aenc.cpp +SRCS += src/aenc_svr.c + +libOmxAmrEnc.so.$(LIBVER): $(SRCS) + $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxAmrEnc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +# --------------------------------------------------------------------------------- +# COMPILE TEST APP +# --------------------------------------------------------------------------------- +TEST_LDLIBS := -lpthread +TEST_LDLIBS += -ldl +TEST_LDLIBS += -lOmxCore + +TEST_SRCS := test/omx_amr_enc_test.c + +mm-aenc-omxamr-test: libOmxAmrEnc.so.$(LIBVER) $(TEST_SRCS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS) + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/aenc-amrnb/qdsp6/inc/Map.h b/mm-audio/aenc-amrnb/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/inc/Map.h @@ -0,0 +1,244 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _MAP_H_ +#define _MAP_H_ + +#include +using namespace std; + +template +class Map +{ + struct node + { + T data; + T2 data2; + node* prev; + node* next; + node(T t, T2 t2,node* p, node* n) : + data(t), data2(t2), prev(p), next(n) {} + }; + node* head; + node* tail; + node* tmp; + unsigned size_of_list; + static Map *m_self; +public: + Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {} + bool empty() const { return ( !head || !tail ); } + operator bool() const { return !empty(); } + void insert(T,T2); + void show(); + int size(); + T2 find(T); // Return VALUE + T find_ele(T);// Check if the KEY is present or not + T2 begin(); //give the first ele + bool erase(T); + bool eraseall(); + bool isempty(); + ~Map() + { + while(head) + { + node* temp(head); + head=head->next; + size_of_list--; + delete temp; + } + } +}; + +template +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::insert(T data, T2 data2) +{ + tail = new node(data, data2,tail, NULL); + if( tail->prev ) + tail->prev->next = tail; + + if( empty() ) + { + head = tail; + tmp=head; + } + tmp = head; + size_of_list++; +} + +template +bool Map::erase(T d) +{ + bool found = false; + tmp = head; + node* prevnode = tmp; + node *tempnode; + + while(tmp) + { + if((head == tail) && (head->data == d)) + { + found = true; + tempnode = head; + head = tail = NULL; + delete tempnode; + break; + } + if((tmp ==head) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + tmp = tmp->next; + tmp->prev = NULL; + head = tmp; + tempnode->next = NULL; + delete tempnode; + break; + } + if((tmp == tail) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + prevnode->next = NULL; + tmp->prev = NULL; + tail = prevnode; + delete tempnode; + break; + } + if(tmp->data == d) + { + found = true; + prevnode->next = tmp->next; + tmp->next->prev = prevnode->next; + tempnode = tmp; + //tmp = tmp->next; + delete tempnode; + break; + } + prevnode = tmp; + tmp = tmp->next; + } + if(found)size_of_list--; + return found; +} + +template +bool Map::eraseall() +{ + // Be careful while using this method + // it not only removes the node but FREES(not delete) the allocated + // memory. + node *tempnode; + tmp = head; + while(head) + { + tempnode = head; + head = head->next; + tempnode->next = NULL; + if(tempnode->data) + free(tempnode->data); + if(tempnode->data2) + free(tempnode->data2); + delete tempnode; + } + tail = head = NULL; + return true; +} + + +template +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..782641b59 --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h @@ -0,0 +1,120 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef AENC_SVR_H +#define AENC_SVR_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include + +#ifdef _ANDROID_ +#define LOG_TAG "QC_AMRENC" +#endif + +#ifndef LOGE +#define LOGE ALOGE +#endif + +#ifndef LOGW +#define LOGW ALOGW +#endif + +#ifndef LOGD +#define LOGD ALOGD +#endif + +#ifndef LOGV +#define LOGV ALOGV +#endif + +#ifndef LOGI +#define LOGI ALOGI +#endif + +#define DEBUG_PRINT_ERROR LOGE +#define DEBUG_PRINT LOGI +#define DEBUG_DETAIL LOGV + +typedef void (*message_func)(void* client_data, unsigned char id); + +/** + @brief audio encoder ipc info structure + + */ +struct amr_ipc_info +{ + pthread_t thr; + int pipe_in; + int pipe_out; + int dead; + message_func process_msg_cb; + void *client_data; + char thread_name[128]; +}; + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to command server + */ +struct amr_ipc_info *omx_amr_thread_create(message_func cb, + void* client_data, + char *th_name); + +struct amr_ipc_info *omx_amr_event_thread_create(message_func cb, + void* client_data, + char *th_name); +/** + @brief This function stop command server + + @param svr handle to command server + @return none + */ +void omx_amr_thread_stop(struct amr_ipc_info *amr_ipc); + + +/** + @brief This function post message in the command server + + @param svr handle to command server + @return none + */ +void omx_amr_post_msg(struct amr_ipc_info *amr_ipc, + unsigned char id); + +#ifdef __cplusplus +} +#endif + +#endif /* AENC_SVR */ diff --git a/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h b/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h new file mode 100644 index 000000000..4b8976531 --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h @@ -0,0 +1,538 @@ +/*-------------------------------------------------------------------------- + +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _AMR_ENC_H_ +#define _AMR_ENC_H_ +/*============================================================================ + Audio Encoder + +@file omx_amr_aenc.h +This module contains the class definition for openMAX encoder component. + + + +============================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see + * all DEBUG_PRINT or LOGV messaging */ +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#include "OMX_Core.h" +#include "OMX_Audio.h" +#include "aenc_svr.h" +#include "qc_omx_component.h" +#include "Map.h" +#include +#include +#include +extern "C" { + void * get_omx_component_factory_fn(void); +} + + +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// + + + +#define OMX_SPEC_VERSION 0x00000101 +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (x >= y?x:y) + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +// + + +#define PrintFrameHdr(i,bufHdr) \ + DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\ + i,\ + (unsigned) bufHdr, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags) + + +// BitMask Management logic +#define BITS_PER_BYTE 8 +#define BITMASK_SIZE(mIndex) \ + (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE) +#define BITMASK_OFFSET(mIndex)\ + ((mIndex)/BITS_PER_BYTE) +#define BITMASK_FLAG(mIndex) \ + (1 << ((mIndex) % BITS_PER_BYTE)) +#define BITMASK_CLEAR(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex)\ + ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex)\ + (((mArray)[BITMASK_OFFSET(mIndex)] & \ + BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_NUM_INPUT_BUFFERS 2 +#define OMX_CORE_NUM_OUTPUT_BUFFERS 16 + +#define OMX_CORE_INPUT_BUFFER_SIZE 8160 // Multiple of 160 +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_AENC_VOLUME_STEP 0x147 +#define OMX_AENC_MIN 0 +#define OMX_AENC_MAX 100 +#define NON_TUNNEL 1 +#define TUNNEL 0 +#define IP_PORT_BITMASK 0x02 +#define OP_PORT_BITMASK 0x01 +#define IP_OP_PORT_BITMASK 0x03 + +#define OMX_AMR_DEFAULT_SF 8000 +#define OMX_AMR_DEFAULT_CH_CFG 1 +#define OMX_AMR_DEFAULT_VOL 25 +// 14 bytes for input meta data +#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14) + +#define TRUE 1 +#define FALSE 0 + +#define NUMOFFRAMES 1 +#define MAXFRAMELENGTH 32 +#define OMX_AMR_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT) + MAXFRAMELENGTH) \ + + 1)) +#define FRAMEDURATION 20000 + +class omx_amr_aenc; + +// OMX AMR audio encoder class +class omx_amr_aenc: public qc_omx_component +{ +public: + omx_amr_aenc(); // constructor + virtual ~omx_amr_aenc(); // destructor + + OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index); + + OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup); + + OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE * specVersion, + OMX_UUIDTYPE *componentUUID); + + OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + static void process_in_port_msg(void *client_data, + unsigned char id); + + static void process_out_port_msg(void *client_data, + unsigned char id); + + static void process_command_msg(void *client_data, + unsigned char id); + + static void process_event_cb(void *client_data, + unsigned char id); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + + bool post_command(unsigned int p1, unsigned int p2, + unsigned int id); + + // Deferred callback identifiers + enum + { + //Event Callbacks from the component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + OMX_COMPONENT_GENERATE_ETB = 0x3, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x4, + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05, + OMX_COMPONENT_GENERATE_FTB = 0x06, + OMX_COMPONENT_GENERATE_EOS = 0x07, + OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08, + OMX_COMPONENT_SUSPEND = 0x09, + OMX_COMPONENT_RESUME = 0x0a + }; +private: + + /////////////////////////////////////////////////////////// + // Type definitions + /////////////////////////////////////////////////////////// + // Bit Positions + enum flags_bit_positions + { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + + OMX_COMPONENT_MUTED =0x3, + + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7 + }; + + + typedef Map + input_buffer_map; + + typedef Map + output_buffer_map; + + enum port_indexes + { + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 + }; + + struct omx_event + { + unsigned param1; + unsigned param2; + unsigned id; + }; + + struct omx_cmd_queue + { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned m_read; + unsigned m_write; + unsigned m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned p1, unsigned p2, unsigned id); + bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id); + bool get_msg_id(unsigned *id); + bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id); + }; + + typedef struct TIMESTAMP + { + unsigned long LowPart; + unsigned long HighPart; + }__attribute__((packed)) TIMESTAMP; + + typedef struct metadata_input + { + unsigned short offsetVal; + TIMESTAMP nTimeStamp; + unsigned int nFlags; + }__attribute__((packed)) META_IN; + + typedef struct enc_meta_out + { + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; + } __attribute__ ((packed))ENC_META_OUT; + + typedef struct + { + OMX_U32 tot_in_buf_len; + OMX_U32 tot_out_buf_len; + OMX_U32 tot_pb_time; + OMX_U32 fbd_cnt; + OMX_U32 ftb_cnt; + OMX_U32 etb_cnt; + OMX_U32 ebd_cnt; + }AMR_PB_STATS; + + /////////////////////////////////////////////////////////// + // Member variables + /////////////////////////////////////////////////////////// + OMX_U8 *m_tmp_meta_buf; + OMX_U8 *m_tmp_out_meta_buf; + OMX_U8 m_flush_cnt ; + OMX_U8 m_comp_deinit; + + // the below var doesnt hold good if combo of use and alloc bufs are used + OMX_S32 m_volume;//Unit to be determined + OMX_PTR m_app_data;// Application data + int nNumInputBuf; + int nNumOutputBuf; + int m_drv_fd; // Kernel device node file handle + bool bFlushinprogress; + bool is_in_th_sleep; + bool is_out_th_sleep; + unsigned int m_flags; //encapsulate the waiting states. + OMX_U64 nTimestamp; + OMX_U64 ts; + unsigned int pcm_input; //tunnel or non-tunnel + unsigned int m_inp_act_buf_count; // Num of Input Buffers + unsigned int m_out_act_buf_count; // Numb of Output Buffers + unsigned int m_inp_current_buf_count; // Num of Input Buffers + unsigned int m_out_current_buf_count; // Numb of Output Buffers + unsigned int output_buffer_size; + unsigned int input_buffer_size; + unsigned short m_session_id; + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + sem_t sem_States; + sem_t sem_read_msg; + sem_t sem_write_msg; + + volatile int m_is_event_done; + volatile int m_is_in_th_sleep; + volatile int m_is_out_th_sleep; + input_buffer_map m_input_buf_hdrs; + output_buffer_map m_output_buf_hdrs; + omx_cmd_queue m_input_q; + omx_cmd_queue m_input_ctrl_cmd_q; + omx_cmd_queue m_input_ctrl_ebd_q; + omx_cmd_queue m_command_q; + omx_cmd_queue m_output_q; + omx_cmd_queue m_output_ctrl_cmd_q; + omx_cmd_queue m_output_ctrl_fbd_q; + pthread_mutexattr_t m_outputlock_attr; + pthread_mutexattr_t m_commandlock_attr; + pthread_mutexattr_t m_lock_attr; + pthread_mutexattr_t m_state_attr; + pthread_mutexattr_t m_flush_attr; + pthread_mutexattr_t m_in_th_attr_1; + pthread_mutexattr_t m_out_th_attr_1; + pthread_mutexattr_t m_event_attr; + pthread_mutexattr_t m_in_th_attr; + pthread_mutexattr_t m_out_th_attr; + pthread_mutexattr_t out_buf_count_lock_attr; + pthread_mutexattr_t in_buf_count_lock_attr; + pthread_cond_t cond; + pthread_cond_t in_cond; + pthread_cond_t out_cond; + pthread_mutex_t m_lock; + pthread_mutex_t m_commandlock; + pthread_mutex_t m_outputlock; + // Mutexes for state change + pthread_mutex_t m_state_lock; + // Mutexes for flush acks from input and output threads + pthread_mutex_t m_flush_lock; + pthread_mutex_t m_event_lock; + pthread_mutex_t m_in_th_lock; + pthread_mutex_t m_out_th_lock; + pthread_mutex_t m_in_th_lock_1; + pthread_mutex_t m_out_th_lock_1; + pthread_mutex_t out_buf_count_lock; + pthread_mutex_t in_buf_count_lock; + + OMX_STATETYPE m_state; // OMX State + OMX_STATETYPE nState; + OMX_CALLBACKTYPE m_cb; // Application callbacks + AMR_PB_STATS m_amr_pb_stats; + struct amr_ipc_info *m_ipc_to_in_th; // for input thread + struct amr_ipc_info *m_ipc_to_out_th; // for output thread + struct amr_ipc_info *m_ipc_to_cmd_th; // for command thread + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_AUDIO_PARAM_AMRTYPE m_amr_param; // Cache AMR encoder parameter + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter + OMX_PARAM_COMPONENTROLETYPE component_Role; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + + /////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////// + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + bool allocate_done(void); + + bool release_done(OMX_U32 param1); + + bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true); + + bool execute_input_omx_flush(void); + + bool execute_output_omx_flush(void); + + bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool post_input(unsigned int p1, unsigned int p2, + unsigned int id); + + bool post_output(unsigned int p1, unsigned int p2, + unsigned int id); + + void process_events(omx_amr_aenc *client_data); + + void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void wait_for_event(); + + void event_complete(); + + void in_th_goto_sleep(); + + void in_th_wakeup(); + + void out_th_goto_sleep(); + + void out_th_wakeup(); + + void flush_ack(); + void deinit_encoder(); + +}; +#endif diff --git a/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c b/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..199358ffb --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c @@ -0,0 +1,205 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#include +#include +#include + +#include +#include + +#include + +/** + @brief This function processes posted messages + + Once thread is being spawned, this function is run to + start processing commands posted by client + + @param info pointer to context + + */ +void *omx_amr_msg(void *info) +{ + struct amr_ipc_info *amr_info = (struct amr_ipc_info*)info; + unsigned char id; + int n; + + DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__); + while (!amr_info->dead) + { + n = read(amr_info->pipe_in, &id, 1); + if (0 == n) break; + if (1 == n) + { + DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n", + amr_info->thread_name, + amr_info->pipe_in, + amr_info->pipe_out); + + amr_info->process_msg_cb(amr_info->client_data, id); + } + if ((n < 0) && (errno != EINTR)) break; + } + DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__); + + return 0; +} + +void *omx_amr_events(void *info) +{ + struct amr_ipc_info *amr_info = (struct amr_ipc_info*)info; + unsigned char id = 0; + + DEBUG_DETAIL("%s: message thread start\n", amr_info->thread_name); + amr_info->process_msg_cb(amr_info->client_data, id); + DEBUG_DETAIL("%s: message thread stop\n", amr_info->thread_name); + return 0; +} + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to msging thread + */ +struct amr_ipc_info *omx_amr_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct amr_ipc_info *amr_info; + + amr_info = calloc(1, sizeof(struct amr_ipc_info)); + if (!amr_info) + { + return 0; + } + + amr_info->client_data = client_data; + amr_info->process_msg_cb = cb; + strlcpy(amr_info->thread_name, th_name, sizeof(amr_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + amr_info->pipe_in = fds[0]; + amr_info->pipe_out = fds[1]; + + r = pthread_create(&amr_info->thr, 0, omx_amr_msg, amr_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", amr_info->thread_name); + return amr_info; + + +fail_thread: + close(amr_info->pipe_in); + close(amr_info->pipe_out); + +fail_pipe: + free(amr_info); + + return 0; +} + +/** + * @brief This function starts command server + * + * @param cb pointer to callback function from the client + * @param client_data reference client wants to get back + * through callback + * @return handle to msging thread + * */ +struct amr_ipc_info *omx_amr_event_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct amr_ipc_info *amr_info; + + amr_info = calloc(1, sizeof(struct amr_ipc_info)); + if (!amr_info) + { + return 0; + } + + amr_info->client_data = client_data; + amr_info->process_msg_cb = cb; + strlcpy(amr_info->thread_name, th_name, sizeof(amr_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + amr_info->pipe_in = fds[0]; + amr_info->pipe_out = fds[1]; + + r = pthread_create(&amr_info->thr, 0, omx_amr_events, amr_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", amr_info->thread_name); + return amr_info; + + +fail_thread: + close(amr_info->pipe_in); + close(amr_info->pipe_out); + +fail_pipe: + free(amr_info); + + return 0; +} + +void omx_amr_thread_stop(struct amr_ipc_info *amr_info) { + DEBUG_DETAIL("%s stop server\n", __FUNCTION__); + close(amr_info->pipe_in); + close(amr_info->pipe_out); + pthread_join(amr_info->thr,NULL); + amr_info->pipe_out = -1; + amr_info->pipe_in = -1; + DEBUG_DETAIL("%s: message thread close fds%d %d\n", amr_info->thread_name, + amr_info->pipe_in,amr_info->pipe_out); + free(amr_info); +} + +void omx_amr_post_msg(struct amr_ipc_info *amr_info, unsigned char id) { + DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id); + write(amr_info->pipe_out, &id, 1); +} diff --git a/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp b/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp new file mode 100644 index 000000000..c6233f88e --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp @@ -0,0 +1,4531 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +/*============================================================================ +@file omx_aenc_amr.c + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include "omx_amr_aenc.h" +#include + +using namespace std; +#define SLEEP_MS 100 + +// omx_cmd_queue destructor +omx_amr_aenc::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_amr_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE); +} + +// omx cmd queue insert +bool omx_amr_aenc::omx_cmd_queue::insert_entry(unsigned p1, + unsigned p2, + unsigned id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_write = 0; + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full"); + } + return ret; +} + +bool omx_amr_aenc::omx_cmd_queue::pop_entry(unsigned *p1, + unsigned *p2, unsigned *id) +{ + bool ret = true; + if (m_size > 0) + { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_read = 0; + + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty"); + } + return ret; +} + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return(new omx_amr_aenc); +} +bool omx_amr_aenc::omx_cmd_queue::get_msg_id(unsigned *id) +{ + if(m_size > 0) + { + *id = m_q[m_read].id; + DEBUG_PRINT("get_msg_id=%d\n",*id); + } + else{ + return false; + } + return true; +} +/*============================================================================= +FUNCTION: + wait_for_event + +DESCRIPTION: + waits for a particular event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_amr_aenc::wait_for_event() +{ + int rc; + struct timespec ts; + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (SLEEP_MS/1000); + ts.tv_nsec += ((SLEEP_MS%1000) * 1000000); + rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts); + if (rc == ETIMEDOUT && !m_is_event_done) { + DEBUG_PRINT("Timed out waiting for flush"); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + } + } + m_is_event_done = 0; + pthread_mutex_unlock(&m_event_lock); +} + +/*============================================================================= +FUNCTION: + event_complete + +DESCRIPTION: + informs about the occurance of an event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_amr_aenc::event_complete() +{ + pthread_mutex_lock(&m_event_lock); + if (0 == m_is_event_done) + { + m_is_event_done = 1; + pthread_cond_signal(&cond); + } + pthread_mutex_unlock(&m_event_lock); +} + +// All this non-sense because of a single amr object +void omx_amr_aenc::in_th_goto_sleep() +{ + pthread_mutex_lock(&m_in_th_lock); + while (0 == m_is_in_th_sleep) + { + pthread_cond_wait(&in_cond, &m_in_th_lock); + } + m_is_in_th_sleep = 0; + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_amr_aenc::in_th_wakeup() +{ + pthread_mutex_lock(&m_in_th_lock); + if (0 == m_is_in_th_sleep) + { + m_is_in_th_sleep = 1; + pthread_cond_signal(&in_cond); + } + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_amr_aenc::out_th_goto_sleep() +{ + + pthread_mutex_lock(&m_out_th_lock); + while (0 == m_is_out_th_sleep) + { + pthread_cond_wait(&out_cond, &m_out_th_lock); + } + m_is_out_th_sleep = 0; + pthread_mutex_unlock(&m_out_th_lock); +} + +void omx_amr_aenc::out_th_wakeup() +{ + pthread_mutex_lock(&m_out_th_lock); + if (0 == m_is_out_th_sleep) + { + m_is_out_th_sleep = 1; + pthread_cond_signal(&out_cond); + } + pthread_mutex_unlock(&m_out_th_lock); +} +/* ====================================================================== +FUNCTION + omx_amr_aenc::omx_amr_aenc + +DESCRIPTION + Constructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_amr_aenc::omx_amr_aenc(): m_tmp_meta_buf(NULL), + m_tmp_out_meta_buf(NULL), + m_flush_cnt(255), + m_comp_deinit(0), + m_app_data(NULL), + m_drv_fd(-1), + bFlushinprogress(0), + is_in_th_sleep(false), + is_out_th_sleep(false), + m_flags(0), + nTimestamp(0), + ts(0), + m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS), + m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS), + m_inp_current_buf_count(0), + m_out_current_buf_count(0), + output_buffer_size(OMX_AMR_OUTPUT_BUFFER_SIZE), + input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE), + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_is_event_done(0), + m_state(OMX_StateInvalid), + m_ipc_to_in_th(NULL), + m_ipc_to_out_th(NULL), + m_ipc_to_cmd_th(NULL), + pcm_input(0), + m_volume(25), + m_session_id(0), + nNumOutputBuf(0), + nNumInputBuf(0) +{ + int cond_ret = 0; + component_Role.nSize = 0; + memset(&m_cmp, 0, sizeof(m_cmp)); + memset(&m_cb, 0, sizeof(m_cb)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + memset(&m_amr_param, 0, sizeof(m_amr_param)); + memset(&m_amr_pb_stats, 0, sizeof(m_amr_pb_stats)); + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + + pthread_mutexattr_init(&m_lock_attr); + pthread_mutex_init(&m_lock, &m_lock_attr); + pthread_mutexattr_init(&m_commandlock_attr); + pthread_mutex_init(&m_commandlock, &m_commandlock_attr); + + pthread_mutexattr_init(&m_outputlock_attr); + pthread_mutex_init(&m_outputlock, &m_outputlock_attr); + + pthread_mutexattr_init(&m_state_attr); + pthread_mutex_init(&m_state_lock, &m_state_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_flush_attr); + pthread_mutex_init(&m_flush_lock, &m_flush_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_in_th_attr); + pthread_mutex_init(&m_in_th_lock, &m_in_th_attr); + + pthread_mutexattr_init(&m_out_th_attr); + pthread_mutex_init(&m_out_th_lock, &m_out_th_attr); + + pthread_mutexattr_init(&m_in_th_attr_1); + pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1); + + pthread_mutexattr_init(&m_out_th_attr_1); + pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1); + + pthread_mutexattr_init(&out_buf_count_lock_attr); + pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr); + + pthread_mutexattr_init(&in_buf_count_lock_attr); + pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr); + if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + + sem_init(&sem_read_msg,0, 0); + sem_init(&sem_write_msg,0, 0); + sem_init(&sem_States,0, 0); + return; +} + + +/* ====================================================================== +FUNCTION + omx_amr_aenc::~omx_amr_aenc + +DESCRIPTION + Destructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_amr_aenc::~omx_amr_aenc() +{ + DEBUG_PRINT_ERROR("AMR Object getting destroyed comp-deinit=%d\n", + m_comp_deinit); + if ( !m_comp_deinit ) + { + deinit_encoder(); + } + pthread_mutexattr_destroy(&m_lock_attr); + pthread_mutex_destroy(&m_lock); + + pthread_mutexattr_destroy(&m_commandlock_attr); + pthread_mutex_destroy(&m_commandlock); + + pthread_mutexattr_destroy(&m_outputlock_attr); + pthread_mutex_destroy(&m_outputlock); + + pthread_mutexattr_destroy(&m_state_attr); + pthread_mutex_destroy(&m_state_lock); + + pthread_mutexattr_destroy(&m_event_attr); + pthread_mutex_destroy(&m_event_lock); + + pthread_mutexattr_destroy(&m_flush_attr); + pthread_mutex_destroy(&m_flush_lock); + + pthread_mutexattr_destroy(&m_in_th_attr); + pthread_mutex_destroy(&m_in_th_lock); + + pthread_mutexattr_destroy(&m_out_th_attr); + pthread_mutex_destroy(&m_out_th_lock); + + pthread_mutexattr_destroy(&out_buf_count_lock_attr); + pthread_mutex_destroy(&out_buf_count_lock); + + pthread_mutexattr_destroy(&in_buf_count_lock_attr); + pthread_mutex_destroy(&in_buf_count_lock); + + pthread_mutexattr_destroy(&m_in_th_attr_1); + pthread_mutex_destroy(&m_in_th_lock_1); + + pthread_mutexattr_destroy(&m_out_th_attr_1); + pthread_mutex_destroy(&m_out_th_lock_1); + pthread_mutex_destroy(&out_buf_count_lock); + pthread_mutex_destroy(&in_buf_count_lock); + pthread_cond_destroy(&cond); + pthread_cond_destroy(&in_cond); + pthread_cond_destroy(&out_cond); + sem_destroy (&sem_read_msg); + sem_destroy (&sem_write_msg); + sem_destroy (&sem_States); + DEBUG_PRINT_ERROR("OMX AMR component destroyed\n"); + return; +} + +/** + @brief memory function for sending EmptyBufferDone event + back to IL client + + @param bufHdr OMX buffer header to be passed back to IL client + @return none + */ +void omx_amr_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.EmptyBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr); + bufHdr->nFilledLen = 0; + + m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr); + pthread_mutex_lock(&in_buf_count_lock); + m_amr_pb_stats.ebd_cnt++; + nNumInputBuf--; + DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\ + m_amr_pb_stats.tot_in_buf_len, + nNumInputBuf, m_amr_pb_stats.ebd_cnt); + pthread_mutex_unlock(&in_buf_count_lock); + } + + return; +} + +/*============================================================================= +FUNCTION: + flush_ack + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_amr_aenc::flush_ack() +{ + // Decrement the FLUSH ACK count and notify the waiting recepients + pthread_mutex_lock(&m_flush_lock); + --m_flush_cnt; + if (0 == m_flush_cnt) + { + event_complete(); + } + DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt); + pthread_mutex_unlock(&m_flush_lock); +} +void omx_amr_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.FillBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr); + m_amr_pb_stats.fbd_cnt++; + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf--; + DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\ + nNumOutputBuf, + m_amr_pb_stats.tot_out_buf_len, + m_amr_pb_stats.fbd_cnt); + m_amr_pb_stats.tot_out_buf_len += bufHdr->nFilledLen; + m_amr_pb_stats.tot_pb_time = bufHdr->nTimeStamp; + DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n", + m_amr_pb_stats.tot_in_buf_len, + m_amr_pb_stats.tot_out_buf_len); + + pthread_mutex_unlock(&out_buf_count_lock); + m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr); + } + return; +} + +/*============================================================================= +FUNCTION: + process_out_port_msg + +DESCRIPTION: + Function for handling all commands from IL client +IL client commands are processed and callbacks are generated through +this routine Audio Command Server provides the thread context for this routine + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_amr_aenc::process_out_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; // qsize + unsigned tot_qsize = 0; + omx_amr_aenc *pThis = (omx_amr_aenc *) client_data; + OMX_STATETYPE state; + +loopback_out: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n"); + return; + } + pthread_mutex_lock(&pThis->m_outputlock); + + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + + if ( 0 == tot_qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize); + return; + } + if ( (state != OMX_StateExecuting) && !qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + + if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) ) + { + // case where no port reconfig and nothing in the flush q + DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\ + qsize,tot_qsize); + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress)) + { + DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + } + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\ + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size,state); + + + if (qsize) + { + // process FLUSH message + pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // if no FLUSH and FBD's then process FTB's + pThis->m_output_q.pop_entry(&p1,&p2,&ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pthread_mutex_unlock(&pThis->m_outputlock); + pThis->out_th_goto_sleep(); + goto loopback_out; + } + } + pthread_mutex_unlock(&pThis->m_outputlock); + + if ( qsize > 0 ) + { + id = ident; + ident = 0; + DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id ) + { + pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_FTB == id ) + { + pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_EOS == id ) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + + } + else if(id == OMX_COMPONENT_RESUME) + { + DEBUG_PRINT("RESUMED...\n"); + } + else if(id == OMX_COMPONENT_GENERATE_COMMAND) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL("Executing FLUSH command on Output port\n"); + pThis->execute_output_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n"); + } + + return; +} + +/*============================================================================= +FUNCTION: + process_command_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_amr_aenc::process_command_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + omx_amr_aenc *pThis = (omx_amr_aenc*)client_data; + pthread_mutex_lock(&pThis->m_commandlock); + + qsize = pThis->m_command_q.m_size; + DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size, + pThis->m_state); + + if (!qsize) + { + DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n"); + pthread_mutex_unlock(&pThis->m_commandlock); + return; + } else + { + pThis->m_command_q.pop_entry(&p1,&p2,&ident); + } + pthread_mutex_unlock(&pThis->m_commandlock); + + id = ident; + DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\ + pThis->m_state,ident, \ + pThis->m_command_q.m_size); + + if (OMX_COMPONENT_GENERATE_EVENT == id) + { + if (pThis->m_cb.EventHandler) + { + if (OMX_CommandStateSet == p1) + { + pthread_mutex_lock(&pThis->m_state_lock); + pThis->m_state = (OMX_STATETYPE) p2; + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_PRINT("CMD:Process->state set to %d \n", \ + pThis->m_state); + + if (pThis->m_state == OMX_StateExecuting || + pThis->m_state == OMX_StateLoaded) + { + + pthread_mutex_lock(&pThis->m_in_th_lock_1); + if (pThis->is_in_th_sleep) + { + pThis->is_in_th_sleep = false; + DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n"); + pThis->in_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + + pthread_mutex_lock(&pThis->m_out_th_lock_1); + if (pThis->is_out_th_sleep) + { + DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n"); + pThis->is_out_th_sleep = false; + pThis->out_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + } + } + if (OMX_StateInvalid == pThis->m_state) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + } else if ((signed)p2 == OMX_ErrorPortUnpopulated) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + p2, + NULL, + NULL ); + } else + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventCmdComplete, + p1, p2, NULL ); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n"); + } + } else if (OMX_COMPONENT_GENERATE_COMMAND == id) + { + pThis->send_command_proxy(&pThis->m_cmp, + (OMX_COMMANDTYPE)p1, + (OMX_U32)p2,(OMX_PTR)NULL); + } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id) + { + DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED"); + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventPortSettingsChanged, + 1, 1, NULL ); + } + else + { + DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident); + } + return; +} + +/*============================================================================= +FUNCTION: + process_in_port_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_amr_aenc::process_in_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + unsigned tot_qsize = 0; + omx_amr_aenc *pThis = (omx_amr_aenc *) client_data; + OMX_STATETYPE state; + + if (!pThis) + { + DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n"); + return; + } +loopback_in: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n"); + return; + } + // Protect the shared queue data structure + pthread_mutex_lock(&pThis->m_lock); + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + if ( 0 == tot_qsize ) + { + DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP"); + pthread_mutex_unlock(&pThis->m_lock); + return; + } + + if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_DETAIL("SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + else if ((state == OMX_StatePause)) + { + if(!(pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + + DEBUG_DETAIL("IN: SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + } + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\ + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size, state); + + + if ( qsize ) + { + // process FLUSH message + pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) && + (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident); + } else if ((qsize = pThis->m_input_q.m_size) && + (state == OMX_StateExecuting)) + { + // if no FLUSH and EBD's then process ETB's + pThis->m_input_q.pop_entry(&p1, &p2, &ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\ + state,pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pthread_mutex_unlock(&pThis->m_lock); + pThis->in_th_goto_sleep(); + goto loopback_in; + } + } + pthread_mutex_unlock(&pThis->m_lock); + + if ( qsize > 0 ) + { + id = ident; + DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id ) + { + pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } + else if(id == OMX_COMPONENT_GENERATE_EOS) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventBufferFlag, 0, 1, NULL ); + } else if ( OMX_COMPONENT_GENERATE_ETB == id ) + { + pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_COMMAND == id ) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL(" Executing FLUSH command on Input port\n"); + pThis->execute_input_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } + else + { + DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n"); + } + return; +} + +/** + @brief member function for performing component initialization + + @param role C string mandating role of this component + @return Error status + */ +OMX_ERRORTYPE omx_amr_aenc::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + m_state = OMX_StateLoaded; + + /* DSP does not give information about the bitstream + randomly assign the value right now. Query will result in + incorrect param */ + memset(&m_amr_param, 0, sizeof(m_amr_param)); + m_amr_param.nSize = sizeof(m_amr_param); + m_amr_param.nChannels = OMX_AMR_DEFAULT_CH_CFG; + m_volume = OMX_AMR_DEFAULT_VOL; /* Close to unity gain */ + memset(&m_amr_pb_stats,0,sizeof(AMR_PB_STATS)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + m_pcm_param.nSize = sizeof(m_pcm_param); + m_pcm_param.nChannels = OMX_AMR_DEFAULT_CH_CFG; + m_pcm_param.nSamplingRate = OMX_AMR_DEFAULT_SF; + nTimestamp = 0; + ts = 0; + + nNumInputBuf = 0; + nNumOutputBuf = 0; + m_ipc_to_in_th = NULL; // Command server instance + m_ipc_to_out_th = NULL; // Client server instance + m_ipc_to_cmd_th = NULL; // command instance + m_is_out_th_sleep = 0; + m_is_in_th_sleep = 0; + is_out_th_sleep= false; + + is_in_th_sleep=false; + + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + m_priority_mgm.nGroupID =0; + m_priority_mgm.nGroupPriority=0; + + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified; + + DEBUG_PRINT_ERROR(" component init: role = %s\n",role); + + DEBUG_PRINT(" component init: role = %s\n",role); + component_Role.nVersion.nVersion = OMX_SPEC_VERSION; + if (!strcmp(role,"OMX.qcom.audio.encoder.amrnb")) + { + pcm_input = 1; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, (const char*)role, + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.amrnb")) + { + pcm_input = 0; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, (const char*)role, + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else + { + component_Role.nSize = sizeof("\0"); + strlcpy((char *)component_Role.cRole, (const char*)"\0", + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED is invalid\n", role); + } + if(pcm_input) + { + m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) * + (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN))); + + if (m_tmp_meta_buf == NULL){ + DEBUG_PRINT_ERROR("Mem alloc failed for tmp meta buf\n"); + return OMX_ErrorInsufficientResources; + } + } + m_tmp_out_meta_buf = + (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_AMR_OUTPUT_BUFFER_SIZE); + if ( m_tmp_out_meta_buf == NULL ){ + DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n"); + return OMX_ErrorInsufficientResources; + } + + if(0 == pcm_input) + { + m_drv_fd = open("/dev/msm_amrnb_in",O_RDONLY); + DEBUG_PRINT("Driver in Tunnel mode open\n"); + } + else + { + m_drv_fd = open("/dev/msm_amrnb_in",O_RDWR); + DEBUG_PRINT("Driver in Non Tunnel mode open\n"); + } + if (m_drv_fd < 0) + { + DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\ + m_drv_fd,errno); + + return OMX_ErrorInsufficientResources; + } + if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1) + { + DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n"); + } + if(pcm_input) + { + if (!m_ipc_to_in_th) + { + m_ipc_to_in_th = omx_amr_thread_create(process_in_port_msg, + this, (char *)"INPUT_THREAD"); + if (!m_ipc_to_in_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start \ + Input port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + } + + if (!m_ipc_to_cmd_th) + { + m_ipc_to_cmd_th = omx_amr_thread_create(process_command_msg, + this, (char *)"CMD_THREAD"); + if (!m_ipc_to_cmd_th) + { + DEBUG_PRINT_ERROR("ERROR!!!Failed to start " + "command message thread\n"); + return OMX_ErrorInsufficientResources; + } + } + + if (!m_ipc_to_out_th) + { + m_ipc_to_out_th = omx_amr_thread_create(process_out_port_msg, + this, (char *)"OUTPUT_THREAD"); + if (!m_ipc_to_out_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start output " + "port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + return eRet; +} + +/** + + @brief member function to retrieve version of component + + + + @param hComp handle to this component instance + @param componentName name of component + @param componentVersion pointer to memory space which stores the + version number + @param specVersion pointer to memory sapce which stores version of + openMax specification + @param componentUUID + @return Error status + */ +OMX_ERRORTYPE omx_amr_aenc::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID) +{ + if((hComp == NULL) || (componentName == NULL) || + (specVersion == NULL) || (componentUUID == NULL)) + { + componentVersion = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n"); + return OMX_ErrorInvalidState; + } + componentVersion->nVersion = OMX_SPEC_VERSION; + specVersion->nVersion = OMX_SPEC_VERSION; + return OMX_ErrorNone; +} +/** + @brief member function handles command from IL client + + This function simply queue up commands from IL client. + Commands will be processed in command server thread context later + + @param hComp handle to component instance + @param cmd type of command + @param param1 parameters associated with the command type + @param cmdData + @return Error status +*/ +OMX_ERRORTYPE omx_amr_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + int portIndex = (int)param1; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateInvalid == m_state) + { + return OMX_ErrorInvalidState; + } + if ( (cmd == OMX_CommandFlush) && (portIndex > 1) ) + { + return OMX_ErrorBadPortIndex; + } + post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); + DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n"); + DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1); + sem_wait (&sem_States); + DEBUG_PRINT("send_command : recieved state after semwait\n"); + return OMX_ErrorNone; +} + +/** + @brief member function performs actual processing of commands excluding + empty buffer call + + @param hComp handle to component + @param cmd command type + @param param1 parameter associated with the command + @param cmdData + + @return error status +*/ +OMX_ERRORTYPE omx_amr_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + // Handle only IDLE and executing + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1; + nState = eState; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_CommandStateSet == cmd) + { + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (OMX_StateLoaded == m_state) + { + if (OMX_StateIdle == eState) + { + + if (allocate_done() || + (m_inp_bEnabled == OMX_FALSE + && m_out_bEnabled == OMX_FALSE)) + { + DEBUG_PRINT("SCP-->Allocate Done Complete\n"); + } + else + { + DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + bFlag = 0; + } + + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } + + else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n"); + eRet = OMX_ErrorNone; + } + + else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + m_state = OMX_StateInvalid; + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (OMX_StateIdle == m_state) + { + if (OMX_StateLoaded == eState) + { + if (release_done(-1)) + { + if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1) + { + DEBUG_PRINT_ERROR("SCP:Idle->Loaded,\ + ioctl stop failed %d\n", errno); + } + + nTimestamp=0; + ts = 0; + DEBUG_PRINT("SCP-->Idle to Loaded\n"); + } else + { + DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + else if (OMX_StateExecuting == eState) + { + + struct msm_audio_amrnb_enc_config_v2 drv_amr_enc_config; + struct msm_audio_stream_config drv_stream_config; + struct msm_audio_buf_cfg buf_cfg; + struct msm_audio_config pcm_cfg; + + if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + + if(ioctl(m_drv_fd, AUDIO_GET_AMRNB_ENC_CONFIG_V2, + &drv_amr_enc_config) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_AMRNB_ENC_CONFIG_V2 \ + failed, errno[%d]\n", errno); + } + drv_amr_enc_config.band_mode = m_amr_param.eAMRBandMode; + drv_amr_enc_config.dtx_enable = m_amr_param.eAMRDTXMode; + drv_amr_enc_config.frame_format = m_amr_param.eAMRFrameFormat; + if(ioctl(m_drv_fd, AUDIO_SET_AMRNB_ENC_CONFIG_V2, &drv_amr_enc_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_AMRNB_ENC_CONFIG_V2 \ + failed, errno[%d]\n", errno); + } + if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n", + errno); + } + buf_cfg.meta_info_enable = 1; + buf_cfg.frames_per_buf = NUMOFFRAMES; + if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n", + errno); + } + if(pcm_input) + { + if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n", + errno); + } + pcm_cfg.channel_count = m_pcm_param.nChannels; + pcm_cfg.sample_rate = m_pcm_param.nSamplingRate; + DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + + if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n", + errno); + } + } + if(ioctl(m_drv_fd, AUDIO_START, 0) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n", + errno); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } + DEBUG_PRINT("SCP-->Idle to Executing\n"); + nState = eState; + } else if (eState == OMX_StateIdle) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n"); + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (OMX_StateExecuting == m_state) + { + if (OMX_StateIdle == eState) + { + DEBUG_PRINT("SCP-->Executing to Idle \n"); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + + } else if (OMX_StatePause == eState) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED PAUSE STATE\n"); + DEBUG_DETAIL("*************************\n"); + //ioctl(m_drv_fd, AUDIO_PAUSE, 0); + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n", + eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (OMX_StatePause == m_state) + { + if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) ) + { + pthread_mutex_lock(&m_out_th_lock_1); + if(is_out_th_sleep) + { + DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n"); + is_out_th_sleep = false; + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } + if ( OMX_StateExecuting == eState ) + { + nState = eState; + } else if ( OMX_StateIdle == eState ) + { + DEBUG_PRINT("SCP-->Paused to Idle \n"); + DEBUG_PRINT ("\n Internal flush issued"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + } else if ( eState == OMX_StateLoaded ) + { + DEBUG_PRINT("\n Pause --> loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n Pause --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("\n Pause --> Pause \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n Pause --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + /**************************************/ + /* Current State is WaitForResources */ + /**************************************/ + else if (m_state == OMX_StateWaitForResources) + { + if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n"); + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: \ + WaitForResources-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n", + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /****************************/ + /* Current State is Invalid */ + /****************************/ + else if (m_state == OMX_StateInvalid) + { + if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState + || OMX_StateIdle == eState || OMX_StateExecuting == eState + || OMX_StatePause == eState || OMX_StateInvalid == eState) + { + DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing" + "/Pause/Invalid/WaitForResources\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } + } else + { + DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\ + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } else if (OMX_CommandFlush == cmd) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1); + DEBUG_DETAIL("*************************\n"); + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || + param1 == OMX_CORE_OUTPUT_PORT_INDEX || + (signed)param1 == -1 ) + { + execute_omx_flush(param1); + } else + { + eRet = OMX_ErrorBadPortIndex; + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError, + OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL ); + } + } else if ( cmd == OMX_CommandPortDisable ) + { + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL ) + { + DEBUG_PRINT("SCP: Disabling Input port Indx\n"); + m_inp_bEnabled = OMX_FALSE; + if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(0) ) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_inp_bEnabled=%d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + + else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\ + " param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + // Skip the event notification + + } + + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + + DEBUG_PRINT("SCP: Disabling Output port Indx\n"); + m_out_bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(1)) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_out_bEnabled=%d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\ + "param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + // Skip the event notification + + } + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID"); + } + + } else if (cmd == OMX_CommandPortEnable) + { + bFlag = 0; + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_inp_bEnabled = OMX_TRUE; + DEBUG_PRINT("SCP: Enabling Input port Indx\n"); + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_inp_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + + } else + { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + + } + } + + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + DEBUG_PRINT("SCP: Enabling Output port Indx\n"); + m_out_bEnabled = OMX_TRUE; + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_out_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + + } + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID"); + } + + } else + { + DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd); + eRet = OMX_ErrorNotImplemented; + } + DEBUG_PRINT("posting sem_States\n"); + sem_post (&sem_States); + if (eRet == OMX_ErrorNone && bFlag) + { + post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + return eRet; +} + +/*============================================================================= +FUNCTION: + execute_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + [IN] param1 + [IN] cmd_cmpl + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_amr_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl) +{ + bool bRet = true; + + DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1); + struct timespec abs_timeout; + abs_timeout.tv_sec = 1; + abs_timeout.tv_nsec = 0; + + if ((signed)param1 == -1) + { + bFlushinprogress = true; + DEBUG_PRINT("Execute flush for both I/p O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + + // Send Flush commands to input and output threads + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + // Send Flush to the kernel so that the in and out buffers are released + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + + + // sleep till the FLUSH ACK are done by both the input and + // output threads + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + + DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\ + param1,cmd_cmpl); + + // If not going to idle state, Send FLUSH complete message + // to the Client, now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n"); + } + bFlushinprogress = false; + } + else if (param1 == OMX_CORE_INPUT_PORT_INDEX) + { + DEBUG_PRINT("Execute FLUSH for I/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + //sleep till the FLUSH ACK are done by both the input and output threads + DEBUG_DETAIL("Executing FLUSH for I/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1); + + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1) + { + DEBUG_PRINT("Executing FLUSH for O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + DEBUG_DETAIL("Executing FLUSH for O/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1) + DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + // sleep till the FLUSH ACK are done by both the input and + // output threads + wait_for_event(); + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + } + DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1); + } else + { + DEBUG_PRINT("Invalid Port ID[%lu]",param1); + } + return bRet; +} + +/*============================================================================= +FUNCTION: + execute_input_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_amr_aenc::execute_input_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on input port"); + + pthread_mutex_lock(&m_lock); + do + { + qsize = m_input_q.m_size; + tot_qsize = qsize; + tot_qsize += m_input_ctrl_ebd_q.m_size; + + DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\ + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size,qsize); + if (!tot_qsize) + { + DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_lock); + break; + } + if (qsize) + { + m_input_q.pop_entry(&p1, &p2, &ident); + if ((ident == OMX_COMPONENT_GENERATE_ETB) || + (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf); + omx_buf->nFilledLen = 0; + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else if (m_input_ctrl_ebd_q.m_size) + { + m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident); + if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + omx_buf->nFilledLen = 0; + DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else + { + } + }while (tot_qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("IN-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_lock); + return true; +} + +/*============================================================================= +FUNCTION: + execute_output_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_amr_aenc::execute_output_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on output port"); + + pthread_mutex_lock(&m_outputlock); + do + { + qsize = m_output_q.m_size; + DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\ + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size,qsize); + tot_qsize = qsize; + tot_qsize += m_output_ctrl_fbd_q.m_size; + if (!tot_qsize) + { + DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_outputlock); + break; + } + if (qsize) + { + m_output_q.pop_entry(&p1,&p2,&ident); + if ( (OMX_COMPONENT_GENERATE_FTB == ident) || + (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FBD FROM FLUSH"); + } + } else if ((qsize = m_output_ctrl_fbd_q.m_size)) + { + m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident); + if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH"); + } + } + }while (qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("OUT-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_outputlock); + return true; +} + +/*============================================================================= +FUNCTION: + post_input + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_amr_aenc::post_input(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + pthread_mutex_lock(&m_lock); + + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)) + { + // insert flush message and ebd + m_input_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id)) + { + // insert ebd + m_input_ctrl_ebd_q.insert_entry(p1,p2,id); + } else + { + // ETBS in this queue + m_input_q.insert_entry(p1,p2,id); + } + + if (m_ipc_to_in_th) + { + bRet = true; + omx_amr_post_msg(m_ipc_to_in_th, id); + } + + DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\ + m_state, + id, + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size, + m_input_q.m_size); + + pthread_mutex_unlock(&m_lock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_command + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_amr_aenc::post_command(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_commandlock); + + m_command_q.insert_entry(p1,p2,id); + + if (m_ipc_to_cmd_th) + { + bRet = true; + omx_amr_post_msg(m_ipc_to_cmd_th, id); + } + + DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\ + m_state, + id, + m_command_q.m_size, + m_flags >> 3); + + pthread_mutex_unlock(&m_commandlock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_output + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_amr_aenc::post_output(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_outputlock); + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND) + || (id == OMX_COMPONENT_RESUME)) + { + // insert flush message and fbd + m_output_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) ) + { + // insert flush message and fbd + m_output_ctrl_fbd_q.insert_entry(p1,p2,id); + } else + { + m_output_q.insert_entry(p1,p2,id); + } + if ( m_ipc_to_out_th ) + { + bRet = true; + omx_amr_post_msg(m_ipc_to_out_th, id); + } + DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + m_state, + id, + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size, + m_output_q.m_size); + + pthread_mutex_unlock(&m_outputlock); + return bRet; +} +/** + @brief member function that return parameters to IL client + + @param hComp handle to component instance + @param paramIndex Parameter type + @param paramData pointer to memory space which would hold the + paramter + @return error status +*/ +OMX_ERRORTYPE omx_amr_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Param in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) + { + DEBUG_PRINT("get_parameter: paramData is NULL\n"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + DEBUG_PRINT("OMX_IndexParamPortDefinition " \ + "portDefn->nPortIndex = %lu\n", + portDefn->nPortIndex); + + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(portDefn); + portDefn->eDomain = OMX_PortDomainAudio; + + if (0 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirInput; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + portDefn->nBufferCountActual = m_inp_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS; + portDefn->nBufferSize = input_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM; + portDefn->format.audio.pNativeRender = 0; + } else if (1 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirOutput; + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + portDefn->nBufferCountActual = m_out_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS; + portDefn->nBufferSize = output_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingAMR; + portDefn->format.audio.pNativeRender = 0; + } else + { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_ERROR("Bad Port idx %d\n",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioInit\n"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n"); + portFormatType->nVersion.nVersion = OMX_SPEC_VERSION; + portFormatType->nSize = sizeof(portFormatType); + + if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex) + { + + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX== + portFormatType->nPortIndex) + { + DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\ + "%lu\n", portFormatType->nIndex); + + portFormatType->eEncoding = OMX_AUDIO_CodingAMR; + } else + { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n", + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioAmr: + { + OMX_AUDIO_PARAM_AMRTYPE *amrParam = + (OMX_AUDIO_PARAM_AMRTYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioAmr\n"); + if (OMX_CORE_OUTPUT_PORT_INDEX== amrParam->nPortIndex) + { + memcpy(amrParam,&m_amr_param, + sizeof(OMX_AUDIO_PARAM_AMRTYPE)); + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioAmr "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)amrParam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case QOMX_IndexParamAudioSessionId: + { + QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam = + (QOMX_AUDIO_STREAM_INFO_DATA *) paramData; + streaminfoparam->sessionId = m_session_id; + break; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam = + (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(pcmparam,&m_pcm_param,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + DEBUG_PRINT("get_parameter: Sampling rate %lu",\ + pcmparam->nSamplingRate); + DEBUG_PRINT("get_parameter: Number of channels %lu",\ + pcmparam->nChannels); + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamComponentSuspended: + { + OMX_PARAM_SUSPENSIONTYPE *suspend= + (OMX_PARAM_SUSPENSIONTYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n", + suspend); + break; + } + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamPriorityMgmt: + { + OMX_PRIORITYMGMTTYPE *priorityMgmtType = + (OMX_PRIORITYMGMTTYPE*)paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n"); + priorityMgmtType->nSize = sizeof(priorityMgmtType); + priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmtType->nGroupID = m_priority_mgm.nGroupID; + priorityMgmtType->nGroupPriority = + m_priority_mgm.nGroupPriority; + break; + } + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + + bufferSupplierType->nSize = sizeof(bufferSupplierType); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if (OMX_CORE_INPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else + { + DEBUG_PRINT_ERROR("get_parameter:"\ + "OMX_IndexParamCompBufferSupplier eRet"\ + "%08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + componentRole->nSize = component_Role.nSize; + componentRole->nVersion = component_Role.nVersion; + strlcpy((char *)componentRole->cRole, + (const char*)component_Role.cRole, + sizeof(componentRole->cRole)); + DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n", + component_Role.nSize, + component_Role.nVersion, + component_Role.cRole); + break; + + } + default: + { + DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; + +} + +/** + @brief member function that set paramter from IL client + + @param hComp handle to component instance + @param paramIndex parameter type + @param paramData pointer to memory space which holds the paramter + @return error status + */ +OMX_ERRORTYPE omx_amr_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("set_parameter is not in proper state\n"); + return OMX_ErrorIncorrectStateOperation; + } + if (paramData == NULL) + { + DEBUG_PRINT("param data is NULL"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamAudioAmr: + { + DEBUG_PRINT("OMX_IndexParamAudioAmr"); + OMX_AUDIO_PARAM_AMRTYPE *amrparam + = (OMX_AUDIO_PARAM_AMRTYPE *) paramData; + memcpy(&m_amr_param,amrparam, + sizeof(OMX_AUDIO_PARAM_AMRTYPE)); + break; + } + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + if (((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources && + ((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == true)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == true))) + ||(((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == false)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == false)) && + (m_state != OMX_StateWaitForResources))) + { + DEBUG_PRINT("Set Parameter called in valid state\n"); + } else + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex " + "= %lu\n",portDefn->nPortIndex); + if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_INPUT_BUFFERS ) + { + m_inp_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS; + } + input_buffer_size = portDefn->nBufferSize; + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_OUTPUT_BUFFERS ) + { + m_out_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS; + } + output_buffer_size = portDefn->nBufferSize; + } else + { + DEBUG_PRINT(" set_parameter: Bad Port idx %d",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamPriorityMgmt: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n"); + + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype + = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n", + priorityMgmtype->nGroupID); + + DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n", + priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + case OMX_IndexParamAudioPortFormat: + { + + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n"); + + if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex) + { + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + portFormatType->nPortIndex) + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\ + " %lu\n", portFormatType->nIndex); + portFormatType->eEncoding = OMX_AUDIO_CodingAMR; + } else + { + DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \ + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("set_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\ + bufferSupplierType->eBufferSupplier); + + if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX + || bufferSupplierType->nPortIndex == + OMX_CORE_OUTPUT_PORT_INDEX) + { + DEBUG_PRINT("set_parameter:\ + OMX_IndexParamCompBufferSupplier\n"); + m_buffer_supplier.eBufferSupplier = + bufferSupplierType->eBufferSupplier; + } else + { + DEBUG_PRINT_ERROR("set_param:\ + IndexParamCompBufferSup %08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + + break; } + + case OMX_IndexParamAudioPcm: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n"); + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam + = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(&m_pcm_param,pcmparam,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + DEBUG_PRINT("set_pcm_parameter: %lu %lu",\ + m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + } else + { + DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm " + "OMX_ErrorBadPortIndex %d\n", + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamSuspensionPolicy: + { + eRet = OMX_ErrorNotImplemented; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + component_Role.nSize = componentRole->nSize; + component_Role.nVersion = componentRole->nVersion; + strlcpy((char *)component_Role.cRole, + (const char*)componentRole->cRole, + sizeof(component_Role.cRole)); + break; + } + + default: + { + DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::GetConfig + +DESCRIPTION + OMX Get Config Method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *volume = + (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex) + { + volume->nSize = sizeof(volume); + volume->nVersion.nVersion = OMX_SPEC_VERSION; + volume->bLinear = OMX_TRUE; + volume->sVolume.nValue = m_volume; + volume->sVolume.nMax = OMX_AENC_MAX; + volume->sVolume.nMin = OMX_AENC_MIN; + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = + (OMX_AUDIO_CONFIG_MUTETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex) + { + mute->nSize = sizeof(mute); + mute->nVersion.nVersion = OMX_SPEC_VERSION; + mute->bMute = (BITMASK_PRESENT(&m_flags, + OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE); + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::SetConfig + +DESCRIPTION + OMX Set Config method implementation + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Set Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if ( m_state == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *vol = + (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData; + if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if ((vol->sVolume.nValue <= OMX_AENC_MAX) && + (vol->sVolume.nValue >= OMX_AENC_MIN)) + { + m_volume = vol->sVolume.nValue; + if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED)) + { + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + + } else + { + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*) + configData; + if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if (mute->bMute == OMX_TRUE) + { + BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */ + } else + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::GetExtensionIndex + +DESCRIPTION + OMX GetExtensionIndex method implementaion. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::get_extension_index( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + if((hComp == NULL) || (paramName == NULL) || (indexType == NULL)) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId", + strlen("OMX.Qualcomm.index.audio.sessionId")) == 0) + { + *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId; + DEBUG_PRINT("Extension index type - %d\n", *indexType); + + } + else + { + return OMX_ErrorBadParameter; + + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::GetState + +DESCRIPTION + Returns the state information back to the caller. + +PARAMETERS + . + +RETURN VALUE + Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + *state = m_state; + DEBUG_PRINT("Returning the state %d\n",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::ComponentTunnelRequest + +DESCRIPTION + OMX Component Tunnel Request method implementation. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::component_tunnel_request +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n"); + + if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL)) + { + port = 0; + peerPort = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::AllocateInputBuffer + +DESCRIPTION + Helper function for allocate buffer in the input pin + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::allocate_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + if(m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc((nBufSize + \ + sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1); + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + free(buf_ptr); + return OMX_ErrorBadParameter; + } + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+ + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + m_input_buf_hdrs.insert(bufHdr, NULL); + + m_inp_current_buf_count++; + DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%d \ + bytes=%lu", bufHdr, bufHdr->pBuffer,m_inp_current_buf_count, + bytes); + + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } + else + { + DEBUG_PRINT("Input buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +OMX_ERRORTYPE omx_amr_aenc::allocate_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_out_current_buf_count < m_out_act_buf_count) + { + buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d"\ + "bytes=%lu",bufHdr, bufHdr->pBuffer,\ + m_out_current_buf_count, bytes); + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== +FUNCTION + omx_amr_aenc::AllocateBuffer + +DESCRIPTION + Returns zero if all the buffers released.. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::allocate_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n"); + return OMX_ErrorInvalidState; + } + // What if the client calls again. + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n", + (int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("allocate_buffer: before allocate_done \n"); + if (allocate_done()) + { + DEBUG_PRINT("allocate_buffer: after allocate_done \n"); + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("allocate_buffer: post idle transition event \n"); + } + DEBUG_PRINT("allocate_buffer: complete \n"); + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + m_out_bEnabled = OMX_TRUE; + + DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("AB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet); + return eRet; +} + +/*============================================================================= +FUNCTION: + use_buffer + +DESCRIPTION: + OMX Use Buffer method implementation. + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_amr_aenc::use_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("Checking for Output Allocate buffer Done"); + if (allocate_done()) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("UB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + } + } + DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet); + return eRet; +} +/*============================================================================= +FUNCTION: + use_input_buffer + +DESCRIPTION: + Helper function for Use buffer in the input pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_amr_aenc::use_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if(bytes < input_buffer_size) + { + /* return if i\p buffer size provided by client + is less than min i\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + if (m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \ + bytes=%lu", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + input_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_input_buf_hdrs.insert(bufHdr, NULL); + m_inp_current_buf_count++; + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Input buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/*============================================================================= +FUNCTION: + use_output_buffer + +DESCRIPTION: + Helper function for Use buffer in the output pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_amr_aenc::use_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (bytes < output_buffer_size) + { + /* return if o\p buffer size provided by client + is less than min o\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT("Inside omx_amr_aenc::use_output_buffer"); + if (m_out_current_buf_count < m_out_act_buf_count) + { + + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer); + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \ + len=%lu", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + output_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_amr_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_input_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_input_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_amr_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_output_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_output_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +// Free Buffer - API call +/** + @brief member function that handles free buffer command from IL client + + This function is a block-call function that handles IL client request to + freeing the buffer + + @param hComp handle to component instance + @param port id of port which holds the buffer + @param buffer buffer header + @return Error status +*/ +OMX_ERRORTYPE omx_amr_aenc::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("Free_Buffer buf %p\n", buffer); + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + DEBUG_PRINT(" free buffer while Component in Loading pending\n"); + } else if ((m_inp_bEnabled == OMX_FALSE && + port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && + port == OMX_CORE_OUTPUT_PORT_INDEX)) + { + DEBUG_PRINT("Free Buffer while port %lu disabled\n", port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) + { + DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\ + OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return eRet; + } else + { + DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\ + disabled:OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + if (m_inp_current_buf_count != 0) + { + m_inp_bPopulated = OMX_FALSE; + if (true == search_input_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer); + m_input_buf_hdrs.erase(buffer); + free(buffer); + m_inp_current_buf_count--; + } else + { + DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \ + Invalid Input buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \ + came out Invalid\n"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_done(0)) + { + DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + if (m_out_current_buf_count != 0) + { + m_out_bPopulated = OMX_FALSE; + if (true == search_output_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer); + m_output_buf_hdrs.erase(buffer); + free(buffer); + m_out_current_buf_count--; + } else + { + DEBUG_PRINT("Free_Buf:Error-->free_buffer , \ + Invalid Output buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_done(1)) + { + DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + if ((OMX_ErrorNone == eRet) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + if (release_done(-1)) + { + if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0) + DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n"); + else + DEBUG_PRINT("AUDIO STOP in free buffer passed\n"); + + + DEBUG_PRINT("Free_Buf: Free buffer\n"); + + + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + DEBUG_PRINT("Before OMX_StateLoaded \ + OMX_COMPONENT_GENERATE_EVENT\n"); + post_command(OMX_CommandStateSet, + OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n"); + + } + } + return eRet; +} + + +/** + @brief member function that that handles empty this buffer command + + This function meremly queue up the command and data would be consumed + in command server thread context + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_amr_aenc::empty_this_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \ + buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf)); + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT("Empty this buffer in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (!m_inp_bEnabled) + { + DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\ + "Port Status %d \n", m_inp_bEnabled); + return OMX_ErrorIncorrectStateOperation; + } + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_amr_aenc::etb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_amr_aenc::etb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + if ((m_state != OMX_StateExecuting) && + (m_state != OMX_StatePause)) + { + DEBUG_PRINT_ERROR("Invalid state\n"); + eRet = OMX_ErrorInvalidState; + } + if (OMX_ErrorNone == eRet) + { + if (search_input_bufhdr(buffer) == true) + { + post_input((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB); + } else + { + DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer); + eRet = OMX_ErrorBadParameter; + } + } + pthread_mutex_lock(&in_buf_count_lock); + nNumInputBuf++; + m_amr_pb_stats.etb_cnt++; + pthread_mutex_unlock(&in_buf_count_lock); + return eRet; +} +/** + @brief member function that writes data to kernel driver + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_amr_aenc::empty_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + META_IN meta_in; + //Pointer to the starting location of the data to be transcoded + OMX_U8 *srcStart; + //The total length of the data to be transcoded + srcStart = buffer->pBuffer; + OMX_U8 *data = NULL; + PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer); + memset(&meta_in,0,sizeof(meta_in)); + if ( search_input_bufhdr(buffer) == false ) + { + DEBUG_PRINT("ETBP: INVALID BUF HDR\n"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorBadParameter; + } + if (m_tmp_meta_buf) + { + data = m_tmp_meta_buf; + + // copy the metadata info from the BufHdr and insert to payload + meta_in.offsetVal = sizeof(META_IN); + meta_in.nTimeStamp.LowPart = + ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF); + meta_in.nTimeStamp.HighPart = + (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF); + meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS; + if(buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT("EOS OCCURED \n"); + meta_in.nFlags |= OMX_BUFFERFLAG_EOS; + } + memcpy(data,&meta_in, meta_in.offsetVal); + DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags); + } + + memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen); + write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN)); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (OMX_StateExecuting == state) + { + DEBUG_DETAIL("In Exe state, EBD CB"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + } else + { + /* Assume empty this buffer function has already checked + validity of buffer */ + DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer); + post_input((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_BUFFER_DONE); + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_amr_aenc::fill_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + ENC_META_OUT *meta_out = NULL; + int nReadbytes = 0; + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (true == search_output_bufhdr(buffer)) + { + DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd); + nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size ); + DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\ + buffer->nAllocLen,buffer->pBuffer, + nReadbytes,nNumOutputBuf); + if (nReadbytes <= 0) { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorNone; + } else + DEBUG_PRINT("Read bytes %d\n",nReadbytes); + // Buffer from Driver will have + // 1 byte => Nr of frame field + // (sizeof(ENC_META_OUT) * Nr of frame) bytes => meta_out->offset_to_frame + // Frame Size * Nr of frame => + + meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char)); + buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+ + meta_out->lsw_ts); + buffer->nFlags |= meta_out->nflags; + buffer->nOffset = meta_out->offset_to_frame + sizeof(unsigned char); + buffer->nFilledLen = nReadbytes - buffer->nOffset; + ts += FRAMEDURATION; + buffer->nTimeStamp = ts; + nTimestamp = buffer->nTimeStamp; + DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \ + timestamp %lld\n", meta_out->nflags, meta_out->frame_size, + meta_out->offset_to_frame, buffer->nTimeStamp); + + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n"); + m_cb.EventHandler(&m_cmp, + m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + } + + return OMX_ErrorNone; + } + DEBUG_PRINT("nState %d \n",nState ); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (state == OMX_StatePause) + { + DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\ + state); + post_output((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_FRAME_DONE); + } + else + { + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + + } + + } + else + DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n"); + + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::FillThisBuffer + +DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + + +PARAMETERS + + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::fill_this_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_amr_aenc::ftb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (m_out_bEnabled == OMX_FALSE) + { + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_amr_aenc::ftb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf++; + m_amr_pb_stats.ftb_cnt++; + DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf); + pthread_mutex_unlock(&out_buf_count_lock); + post_output((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB); + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::SetCallbacks + +DESCRIPTION + Set the callbacks. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + m_cb = *callbacks; + m_app_data = appData; + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::ComponentDeInit + +DESCRIPTION + Destroys the component and release memory allocated to the heap. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state) + { + DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n", + m_state); + } + deinit_encoder(); + +DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::deinit_encoder + +DESCRIPTION + Closes all the threads and release memory allocated to the heap. + +PARAMETERS + None. + +RETURN VALUE + None. + +========================================================================== */ +void omx_amr_aenc::deinit_encoder() +{ + DEBUG_PRINT("Component-deinit being processed\n"); + DEBUG_PRINT("********************************\n"); + DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\ + m_amr_pb_stats.tot_in_buf_len, + m_amr_pb_stats.tot_out_buf_len, + m_amr_pb_stats.tot_pb_time); + DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\ + m_amr_pb_stats.fbd_cnt,m_amr_pb_stats.ftb_cnt, + m_amr_pb_stats.etb_cnt, + m_amr_pb_stats.ebd_cnt); + memset(&m_amr_pb_stats,0,sizeof(AMR_PB_STATS)); + + if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state)) + { + DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\ + m_state); + // Get back any buffers from driver + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + // force state change to loaded so that all threads can be exited + pthread_mutex_lock(&m_state_lock); + m_state = OMX_StateLoaded; + pthread_mutex_unlock(&m_state_lock); + DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\ + m_inp_current_buf_count, + m_input_buf_hdrs.size()); + m_input_buf_hdrs.eraseall(); + DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\ + m_out_current_buf_count, + m_output_buf_hdrs.size()); + m_output_buf_hdrs.eraseall(); + + } + if(pcm_input) + { + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + if(pcm_input) + { + if (m_ipc_to_in_th != NULL) + { + omx_amr_thread_stop(m_ipc_to_in_th); + m_ipc_to_in_th = NULL; + } + } + + if (m_ipc_to_cmd_th != NULL) + { + omx_amr_thread_stop(m_ipc_to_cmd_th); + m_ipc_to_cmd_th = NULL; + } + if (m_ipc_to_out_th != NULL) + { + DEBUG_DETAIL("Inside omx_amr_thread_stop\n"); + omx_amr_thread_stop(m_ipc_to_out_th); + m_ipc_to_out_th = NULL; + } + + + if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0) + DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n"); + + if(pcm_input && m_tmp_meta_buf ) + { + free(m_tmp_meta_buf); + } + + if(m_tmp_out_meta_buf) + { + free(m_tmp_out_meta_buf); + } + nNumInputBuf = 0; + nNumOutputBuf = 0; + bFlushinprogress = 0; + + m_inp_current_buf_count=0; + m_out_current_buf_count=0; + m_out_act_buf_count = 0; + m_inp_act_buf_count = 0; + m_inp_bEnabled = OMX_FALSE; + m_out_bEnabled = OMX_FALSE; + m_inp_bPopulated = OMX_FALSE; + m_out_bPopulated = OMX_FALSE; + nTimestamp = 0; + ts = 0; + + if ( m_drv_fd >= 0 ) + { + if(close(m_drv_fd) < 0) + DEBUG_PRINT("De-init: Driver Close Failed \n"); + m_drv_fd = -1; + } + else + { + DEBUG_PRINT_ERROR(" AMR device already closed\n"); + } + m_comp_deinit=1; + m_is_out_th_sleep = 1; + m_is_in_th_sleep = 1; + DEBUG_PRINT("************************************\n"); + DEBUG_PRINT(" DEINIT COMPLETED"); + DEBUG_PRINT("************************************\n"); + +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::UseEGLImage + +DESCRIPTION + OMX Use EGL Image method implementation . + +PARAMETERS + . + +RETURN VALUE + Not Implemented error. + +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::use_EGL_image +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n"); + + if((hComp == NULL) || (appData == NULL) || (eglImage == NULL)) + { + bufferHdr = NULL; + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_amr_aenc::ComponentRoleEnum + +DESCRIPTION + OMX Component Role Enum method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_amr_aenc::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + const char *cmp_role = "audio_encoder.amr"; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (index == 0 && role) + { + memcpy(role, cmp_role, sizeof(cmp_role)); + *(((char *) role) + sizeof(cmp_role)) = '\0'; + } else + { + eRet = OMX_ErrorNoMore; + } + return eRet; +} + + + + +/* ====================================================================== +FUNCTION + omx_amr_aenc::AllocateDone + +DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + +PARAMETERS + None. + +RETURN VALUE + true/false. + +========================================================================== */ +bool omx_amr_aenc::allocate_done(void) +{ + OMX_BOOL bRet = OMX_FALSE; + if (pcm_input==1) + { + if ((m_inp_act_buf_count == m_inp_current_buf_count) + &&(m_out_act_buf_count == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + + } + if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled ) + { + m_inp_bPopulated = OMX_TRUE; + } + + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + } else if (pcm_input==0) + { + if (m_out_act_buf_count == m_out_current_buf_count) + { + bRet=OMX_TRUE; + + } + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + + } + return bRet; +} + + +/* ====================================================================== +FUNCTION + omx_amr_aenc::ReleaseDone + +DESCRIPTION + Checks if IL client has released all the buffers. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +bool omx_amr_aenc::release_done(OMX_U32 param1) +{ + DEBUG_PRINT("Inside omx_amr_aenc::release_done"); + OMX_BOOL bRet = OMX_FALSE; + + if (param1 == OMX_ALL) + { + if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_INPUT_PORT_INDEX ) + { + if ((0 == m_inp_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX) + { + if ((0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } + return bRet; +} diff --git a/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c b/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c new file mode 100644 index 000000000..a3c91b1ac --- /dev/null +++ b/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c @@ -0,0 +1,1051 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif + + +#include + +typedef unsigned char uint8; +typedef unsigned char byte; +typedef unsigned int uint32; +typedef unsigned int uint16; +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; +/* maximum ADTS frame header length */ +void Release_Encoder(); + +#ifdef AUDIOV2 +unsigned short session_id; +int device_id; +int control = 0; +const char *device="handset_tx"; +#define DIR_TX 2 +#endif + +uint32_t samplerate = 8000; +uint32_t channels = 1; +uint32_t bandmode = 7; +uint32_t dtxenable = 0; +uint32_t rectime = -1; +uint32_t recpath = -1; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t format = 1; +#define DEBUG_PRINT printf +unsigned to_idle_transition = 0; +unsigned long total_pcm_bytes; + +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define MIN_BITRATE 4 /* Bit rate 1 - 13.6 , 2 - 6.2 , 3 - 2.7 , 4 - 1.0 kbps*/ +#define MAX_BITRATE 4 +#define AMR_HEADER_SIZE 6 +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +pthread_mutex_t lock; +pthread_cond_t cond; +pthread_mutex_t elock; +pthread_cond_t econd; +pthread_cond_t fcond; +pthread_mutex_t etb_lock; +pthread_mutex_t etb_lock1; +pthread_cond_t etb_cond; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; +OMX_AUDIO_PARAM_AMRTYPE amrparam; +OMX_AUDIO_PARAM_PCMMODETYPE pcmparam; +OMX_PORT_PARAM_TYPE portParam; +OMX_PORT_PARAM_TYPE portFmt; +OMX_ERRORTYPE error; + + + + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; +struct enc_meta_out{ + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; +} __attribute__ ((packed)); + +struct qcp_header { + /* RIFF Section */ + char riff[4]; + unsigned int s_riff; + char qlcm[4]; + + /* Format chunk */ + char fmt[4]; + unsigned int s_fmt; + char mjr; + char mnr; + unsigned int data1; /* UNIQUE ID of the codec */ + unsigned short data2; + unsigned short data3; + char data4[8]; + unsigned short ver; /* Codec Info */ + char name[80]; + unsigned short abps; /* average bits per sec of the codec */ + unsigned short bytes_per_pkt; + unsigned short samp_per_block; + unsigned short samp_per_sec; + unsigned short bits_per_samp; + unsigned char vr_num_of_rates; /* Rate Header fmt info */ + unsigned char rvd1[3]; + unsigned short vr_bytes_per_pkt[8]; + unsigned int rvd2[5]; + + /* Vrat chunk */ + unsigned char vrat[4]; + unsigned int s_vrat; + unsigned int v_rate; + unsigned int size_in_pkts; + + /* Data chunk */ + unsigned char data[4]; + unsigned int s_data; +} __attribute__ ((packed)); + +static unsigned totaldatalen = 0; +static unsigned framecnt = 0; +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +volatile int etb_event_is_done = 0; +int ebd_cnt; +int bInputEosReached = 0; +int bOutputEosReached = 0; +int bInputEosReached_tunnel = 0; +static int etb_done = 0; +int bFlushing = false; +int bPause = false; +const char *in_filename; +const char *out_filename; + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* amr_enc_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Encoder(char*); +int Play_Encoder(); +OMX_STRING aud_comp; +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *amr_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +static OMX_ERRORTYPE parse_pcm_header(); +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock1); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock1); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock1); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock1); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock1); +} + + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + switch(eEvent) { + case OMX_EventCmdComplete: + DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent, + nData1,nData2); + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("\n OMX_EventError \n"); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("\n OMX_EventBufferFlag \n"); + bOutputEosReached = true; + event_complete(); + break; + case OMX_EventPortSettingsChanged: + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + size_t bytes_writen = 0; + int total_bytes_writen = 0; + unsigned int len = 0; + struct enc_meta_out *meta = NULL; + OMX_U8 *src = pBuffer->pBuffer; + unsigned int num_of_frames = 1; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT("FBD::EOS on output port\n "); + bOutputEosReached = true; + return OMX_ErrorNone; + } + if(bInputEosReached_tunnel || bOutputEosReached) + { + DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n"); + return OMX_ErrorNone; + } + if(num_of_frames != src[0]){ + + printf("Data corrupt\n"); + return OMX_ErrorNone; + } + /* Skip the first bytes */ + + + + src += sizeof(unsigned char); + meta = (struct enc_meta_out *)src; + while (num_of_frames > 0) { + meta = (struct enc_meta_out *)src; + /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n", + meta->offset_to_frame, + meta->frame_size, + meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/ + len = meta->frame_size; + + bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile); + if(bytes_writen < len) + { + DEBUG_PRINT("error: invalid AMR encoded data \n"); + return OMX_ErrorNone; + } + src += sizeof(struct enc_meta_out); + num_of_frames--; + total_bytes_writen += len; + } + DEBUG_PRINT(" FillBufferDone size writen to file %d count %d\n",total_bytes_writen, framecnt); + totaldatalen += total_bytes_writen ; + framecnt++; + + DEBUG_PRINT(" FBD calling FTB\n"); + OMX_FillThisBuffer(hComponent,pBuffer); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock); + } + + + if(bInputEosReached) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + }else if (bFlushing == true) { + DEBUG_PRINT("omx_amr_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (used_ip_buf_cnt == 0) { + bFlushing = false; + } else { + DEBUG_PRINT("omx_amr_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + return OMX_ErrorNone; + } + } + + if((readBytes = Read_Buffer(pBuffer)) > 0) { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else{ + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + bInputEosReached = true; + pBuffer->nFilledLen = 0; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) { + + /* Flush */ + if (sig_id == SIGUSR1) { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(amr_enc_handle, OMX_CommandFlush, OMX_ALL, NULL); + } else if (sig_id == SIGUSR2) { + if (bPause == true) { + DEBUG_PRINT("%s resume record\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } else { + DEBUG_PRINT("%s pause record\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + + struct sigaction sa; + char amr_header[6] = {0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A}; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + (void) signal(SIGINT, Release_Encoder); + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + + if (argc >= 8) { + in_filename = argv[1]; + out_filename = argv[2]; + tunnel = atoi(argv[3]); + bandmode = atoi(argv[4]); + dtxenable = atoi(argv[5]); + recpath = atoi(argv[6]); // No configuration support yet.. + rectime = atoi(argv[7]); + + } else { + DEBUG_PRINT(" invalid format: \n"); + DEBUG_PRINT("ex: ./mm-aenc-omxamr-test INPUTFILE OUTPUTFILE Tunnel BANDMODE DTXENABLE RECORDPATH RECORDTIME\n"); + DEBUG_PRINT("Bandmode 1-7, dtxenable 0-1\n"); + DEBUG_PRINT("RECORDPATH 0(TX),1(RX),2(BOTH),3(MIC)\n"); + DEBUG_PRINT("RECORDTIME in seconds for AST Automation\n"); + return 0; + } + if(recpath != 3) { + DEBUG_PRINT("For RECORDPATH Only MIC supported\n"); + return 0; + } + if(tunnel == 0) + aud_comp = "OMX.qcom.audio.encoder.amrnb"; + else + aud_comp = "OMX.qcom.audio.encoder.tunneled.amrnb"; + if(Init_Encoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + fcntl(0, F_SETFL, O_NONBLOCK); + + if(Play_Encoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + if(rectime && tunnel) + { + sleep(rectime); + rectime = 0; + bInputEosReached_tunnel = 1; + DEBUG_PRINT("\EOS ON INPUT PORT\n"); + } + else + { + wait_for_event(); + } + + if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel)) + { + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + + DEBUG_PRINT("\nMoving the encoder to loaded state \n"); + OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + sleep(1); + if (!tunnel) + { + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(amr_enc_handle, 0, pInputBufHdrs[bufCnt]); + } + } + + DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(amr_enc_handle, 1, pOutputBufHdrs[bufCnt]); + } + wait_for_event(); + fseek(outputBufferFile, 0,SEEK_SET); + fwrite(amr_header,1,AMR_HEADER_SIZE,outputBufferFile); + + result = OMX_FreeHandle(amr_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + if(tunnel) + { + #ifdef AUDIOV2 + if (msm_route_stream(DIR_TX,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + #endif + } + OMX_Deinit(); + ebd_cnt=0; + bOutputEosReached = false; + bInputEosReached_tunnel = false; + bInputEosReached = 0; + amr_enc_handle = NULL; + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + fclose(outputBufferFile); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...AMR ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + return 0; +} + +void Release_Encoder() +{ + static int cnt=0; + OMX_ERRORTYPE result; + + DEBUG_PRINT("END OF AMR ENCODING: EXITING PLEASE WAIT\n"); + bInputEosReached_tunnel = 1; + event_complete(); + cnt++; + if(cnt > 1) + { + /* FORCE RESET */ + amr_enc_handle = NULL; + ebd_cnt=0; + bInputEosReached_tunnel = false; + + result = OMX_FreeHandle(amr_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + + OMX_Deinit(); + + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...AMR ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + exit(0); + } +} + +int Init_Encoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + typedef OMX_U8* OMX_U8_PTR; + char *role ="audio_encoder"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Amr_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total); + + + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&amr_enc_handle), + (OMX_STRING)audio_component, NULL, &call_back); + if (FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component); + return -1; + } + else + { + DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(portParam); + omxresult = OMX_GetParameter(amr_enc_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&portParam); + + if(FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to get Port Param\n"); + return -1; + } + else + { + DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts); + DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n", + portParam.nStartPortNumber); + } + + if(OMX_ErrorNone != omxresult) + { + DEBUG_PRINT("Set parameter failed"); + } + + return 0; +} + +int Play_Encoder() +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file()) { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + + /* Query the encoder input min buf requirements */ + CONFIG_VERSION_SIZE(inputportFmt); + + /* Port for which the Client needs to obtain info */ + inputportFmt.nPortIndex = portParam.nStartPortNumber; + + OMX_GetParameter(amr_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt); + DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize); + + if(OMX_DirInput != inputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Input Port\n"); + return -1; + } + + pcmparam.nPortIndex = 0; + pcmparam.nChannels = channels; + pcmparam.nSamplingRate = samplerate; + OMX_SetParameter(amr_enc_handle,OMX_IndexParamAudioPcm,&pcmparam); + + + /* Query the encoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(amr_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Output Port\n"); + return -1; + } + + + CONFIG_VERSION_SIZE(amrparam); + + amrparam.nPortIndex = 1; + amrparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/ + amrparam.eAMRBandMode = bandmode; + amrparam.eAMRDTXMode = dtxenable; + OMX_SetParameter(amr_enc_handle,OMX_IndexParamAudioAmr,&amrparam); + OMX_GetExtensionIndex(amr_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index); + OMX_GetParameter(amr_enc_handle,index,&streaminfoparam); + if(tunnel) { + #ifdef AUDIOV2 + session_id = streaminfoparam.sessionId; + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + if (msm_route_stream(DIR_TX,session_id,device_id, 1)) + { + perror("could not set stream routing\n"); + return -1; + } + #endif + } + + DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n"); + OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + if (tunnel == 0) + { + input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(amr_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pInputBufHdrs == NULL ) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + } + output_buf_cnt = outputportFmt.nBufferCountMin ; + + /* Allocate buffer on encoder's O/Pp port */ + error = Allocate_Buffer(amr_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pOutputBufHdrs == NULL ) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + + if (tunnel == 1) + { + DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n"); + OMX_SendCommand(amr_enc_handle, OMX_CommandPortDisable,0,0); // disable input port + wait_for_event(); + } + + DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n"); + OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(amr_enc_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + +if(tunnel == 0) +{ + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) { + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + bInputEosReached = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + ret = OMX_EmptyThisBuffer(amr_enc_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock); + if(etb_done) +{ + DEBUG_PRINT("Component is waiting for EBD to be released.\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock); +} + + return 0; +} + + + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + + /* To remove warning for unused variable to keep prototype same */ + (void)avc_enc_handle; + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(amr_enc_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + + + + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + + int bytes_read=0; + + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + + bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile); + + pBufHdr->nFilledLen = bytes_read; + // Time stamp logic + ((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp = \ + + (unsigned long) ((total_pcm_bytes * 1000)/(samplerate * channels *2)); + + DEBUG_PRINT ("\n--time stamp -- %ld\n", (unsigned long)((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp); + if(bytes_read == 0) + { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + + total_pcm_bytes += bytes_read; + } + + return bytes_read;; +} + + + +//In Encoder this Should Open a PCM or WAV file for input. + +static int open_audio_file () +{ + int error_code = 0; + + if (!tunnel) + { + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); + inputBufferFile = fopen (in_filename, "rb"); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + } + if(parse_pcm_header() != 0x00) + { + DEBUG_PRINT("PCM parser failed \n"); + return -1; + } + } + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename); + outputBufferFile = fopen (out_filename, "wb"); + if (outputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + out_filename); + error_code = -1; + return error_code; + } + fseek(outputBufferFile, AMR_HEADER_SIZE, SEEK_SET); + return error_code; +} + +static OMX_ERRORTYPE parse_pcm_header() +{ + struct wav_header hdr; + + DEBUG_PRINT("\n***************************************************************\n"); + if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr)) + { + DEBUG_PRINT("Wav file cannot read header\n"); + return -1; + } + + if ((hdr.riff_id != ID_RIFF) || + (hdr.riff_fmt != ID_WAVE)|| + (hdr.fmt_id != ID_FMT)) + { + DEBUG_PRINT("Wav file is not a riff/wave file\n"); + return -1; + } + + if (hdr.audio_format != FORMAT_PCM) + { + DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n", + hdr.audio_format, hdr.fmt_sz); + return -1; + } + + DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate); + DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels); + DEBUG_PRINT("\n***************************************************************\n"); + + samplerate = hdr.sample_rate; + channels = hdr.num_channels; + total_pcm_bytes = 0; + + return OMX_ErrorNone; +} diff --git a/mm-audio/aenc-evrc/Android.mk b/mm-audio/aenc-evrc/Android.mk new file mode 100644 index 000000000..0e2ea3827 --- /dev/null +++ b/mm-audio/aenc-evrc/Android.mk @@ -0,0 +1,23 @@ +ifeq ($(TARGET_ARCH),arm) + + +AENC_EVRC_PATH:= $(call my-dir) + +ifeq ($(call is-board-platform,msm8660),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8960),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8974),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8226),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8610),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif + + +endif diff --git a/mm-audio/aenc-evrc/Makefile b/mm-audio/aenc-evrc/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/mm-audio/aenc-evrc/Makefile @@ -0,0 +1,6 @@ +all: + @echo "invoking omxaudio make" + $(MAKE) -C qdsp6 + +install: + $(MAKE) -C qdsp6 install diff --git a/mm-audio/aenc-evrc/qdsp6/Android.mk b/mm-audio/aenc-evrc/qdsp6/Android.mk new file mode 100644 index 000000000..d38d004f2 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/Android.mk @@ -0,0 +1,75 @@ +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxEvrcEnc-def := -g -O3 +libOmxEvrcEnc-def += -DQC_MODIFIED +libOmxEvrcEnc-def += -D_ANDROID_ +libOmxEvrcEnc-def += -D_ENABLE_QC_MSG_LOG_ +libOmxEvrcEnc-def += -DVERBOSE +libOmxEvrcEnc-def += -D_DEBUG +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +libOmxEvrcEnc-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxEvrcEnc) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +libOmxEvrcEnc-inc := $(LOCAL_PATH)/inc +libOmxEvrcEnc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore + +LOCAL_MODULE := libOmxEvrcEnc +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxEvrcEnc-def) +LOCAL_C_INCLUDES := $(libOmxEvrcEnc-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libutils liblog + +LOCAL_SRC_FILES := src/aenc_svr.c +LOCAL_SRC_FILES += src/omx_evrc_aenc.cpp + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +include $(BUILD_SHARED_LIBRARY) + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-aenc-omxevrc-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +mm-evrc-enc-test-inc := $(LOCAL_PATH)/inc +mm-evrc-enc-test-inc += $(LOCAL_PATH)/test +mm-evrc-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +mm-evrc-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +endif +LOCAL_MODULE := mm-aenc-omxevrc-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxEvrcEnc-def) +LOCAL_C_INCLUDES := $(mm-evrc-enc-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libmm-omxcore +LOCAL_SHARED_LIBRARIES += libOmxEvrcEnc +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +LOCAL_SHARED_LIBRARIES += libaudioalsa +endif +LOCAL_SRC_FILES := test/omx_evrc_enc_test.c + +include $(BUILD_EXECUTABLE) + +endif + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- + diff --git a/mm-audio/aenc-evrc/qdsp6/Makefile b/mm-audio/aenc-evrc/qdsp6/Makefile new file mode 100644 index 000000000..d0871dea2 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/Makefile @@ -0,0 +1,81 @@ +# --------------------------------------------------------------------------------- +# MM-AUDIO-OSS-8K-AENC-EVRC +# --------------------------------------------------------------------------------- + +# cross-compiler flags +CFLAGS += -Wall +CFLAGS += -Wundef +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wno-trigraphs + +# cross-compile flags specific to shared objects +CFLAGS_SO += -fpic + +# required pre-processor flags +CPPFLAGS := -D__packed__= +CPPFLAGS += -DIMAGE_APPS_PROC +CPPFLAGS += -DFEATURE_Q_SINGLE_LINK +CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR +CPPFLAGS += -DFEATURE_LINUX +CPPFLAGS += -DFEATURE_NATIVELINUX +CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS + +CPPFLAGS += -g +CPPFALGS += -D_DEBUG +CPPFLAGS += -Iinc + +# linker flags +LDFLAGS += -L$(SYSROOT)/usr/lib + +# linker flags for shared objects +LDFLAGS_SO := -shared + +# defintions +LIBMAJOR := $(basename $(basename $(LIBVER))) +LIBINSTALLDIR := $(DESTDIR)usr/lib +INCINSTALLDIR := $(DESTDIR)usr/include +BININSTALLDIR := $(DESTDIR)usr/bin + +# --------------------------------------------------------------------------------- +# BUILD +# --------------------------------------------------------------------------------- +all: libOmxEvrcEnc.so.$(LIBVER) mm-aenc-omxevrc-test + +install: + echo "intalling aenc-evrc in $(DESTDIR)" + if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi + if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi + if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi + install -m 555 libOmxEvrcEnc.so.$(LIBVER) $(LIBINSTALLDIR) + cd $(LIBINSTALLDIR) && ln -s libOmxEvrcEnc.so.$(LIBVER) libOmxEvrcEnc.so.$(LIBMAJOR) + cd $(LIBINSTALLDIR) && ln -s libOmxEvrcEnc.so.$(LIBMAJOR) libOmxEvrcEnc.so + install -m 555 mm-aenc-omxevrc-test $(BININSTALLDIR) + +# --------------------------------------------------------------------------------- +# COMPILE LIBRARY +# --------------------------------------------------------------------------------- +LDLIBS := -lpthread +LDLIBS += -lstdc++ +LDLIBS += -lOmxCore + +SRCS := src/omx_evrc_aenc.cpp +SRCS += src/aenc_svr.c + +libOmxEvrcEnc.so.$(LIBVER): $(SRCS) + $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxEvrcEnc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +# --------------------------------------------------------------------------------- +# COMPILE TEST APP +# --------------------------------------------------------------------------------- +TEST_LDLIBS := -lpthread +TEST_LDLIBS += -ldl +TEST_LDLIBS += -lOmxCore + +TEST_SRCS := test/omx_evrc_enc_test.c + +mm-aenc-omxevrc-test: libOmxEvrcEnc.so.$(LIBVER) $(TEST_SRCS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS) + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/aenc-evrc/qdsp6/inc/Map.h b/mm-audio/aenc-evrc/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/inc/Map.h @@ -0,0 +1,244 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _MAP_H_ +#define _MAP_H_ + +#include +using namespace std; + +template +class Map +{ + struct node + { + T data; + T2 data2; + node* prev; + node* next; + node(T t, T2 t2,node* p, node* n) : + data(t), data2(t2), prev(p), next(n) {} + }; + node* head; + node* tail; + node* tmp; + unsigned size_of_list; + static Map *m_self; +public: + Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {} + bool empty() const { return ( !head || !tail ); } + operator bool() const { return !empty(); } + void insert(T,T2); + void show(); + int size(); + T2 find(T); // Return VALUE + T find_ele(T);// Check if the KEY is present or not + T2 begin(); //give the first ele + bool erase(T); + bool eraseall(); + bool isempty(); + ~Map() + { + while(head) + { + node* temp(head); + head=head->next; + size_of_list--; + delete temp; + } + } +}; + +template +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::insert(T data, T2 data2) +{ + tail = new node(data, data2,tail, NULL); + if( tail->prev ) + tail->prev->next = tail; + + if( empty() ) + { + head = tail; + tmp=head; + } + tmp = head; + size_of_list++; +} + +template +bool Map::erase(T d) +{ + bool found = false; + tmp = head; + node* prevnode = tmp; + node *tempnode; + + while(tmp) + { + if((head == tail) && (head->data == d)) + { + found = true; + tempnode = head; + head = tail = NULL; + delete tempnode; + break; + } + if((tmp ==head) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + tmp = tmp->next; + tmp->prev = NULL; + head = tmp; + tempnode->next = NULL; + delete tempnode; + break; + } + if((tmp == tail) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + prevnode->next = NULL; + tmp->prev = NULL; + tail = prevnode; + delete tempnode; + break; + } + if(tmp->data == d) + { + found = true; + prevnode->next = tmp->next; + tmp->next->prev = prevnode->next; + tempnode = tmp; + //tmp = tmp->next; + delete tempnode; + break; + } + prevnode = tmp; + tmp = tmp->next; + } + if(found)size_of_list--; + return found; +} + +template +bool Map::eraseall() +{ + // Be careful while using this method + // it not only removes the node but FREES(not delete) the allocated + // memory. + node *tempnode; + tmp = head; + while(head) + { + tempnode = head; + head = head->next; + tempnode->next = NULL; + if(tempnode->data) + free(tempnode->data); + if(tempnode->data2) + free(tempnode->data2); + delete tempnode; + } + tail = head = NULL; + return true; +} + + +template +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..46f40ee32 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h @@ -0,0 +1,122 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef AENC_SVR_H +#define AENC_SVR_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include + +#ifdef _ANDROID_ +#define LOG_TAG "QC_EVRCENC" +#endif + +#ifndef LOGE +#define LOGE ALOGE +#endif + +#ifndef LOGW +#define LOGW ALOGW +#endif + +#ifndef LOGD +#define LOGD ALOGD +#endif + +#ifndef LOGV +#define LOGV ALOGV +#endif + +#ifndef LOGI +#define LOGI ALOGI +#endif + +#define DEBUG_PRINT_ERROR LOGE +#define DEBUG_PRINT LOGI +#define DEBUG_DETAIL LOGV + +typedef void (*message_func)(void* client_data, unsigned char id); + +/** + @brief audio encoder ipc info structure + + */ +struct evrc_ipc_info +{ + pthread_t thr; + int pipe_in; + int pipe_out; + int dead; + message_func process_msg_cb; + void *client_data; + char thread_name[128]; +}; + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to command server + */ +struct evrc_ipc_info *omx_evrc_thread_create(message_func cb, + void* client_data, + char *th_name); + +struct evrc_ipc_info *omx_evrc_event_thread_create(message_func cb, + void* client_data, + char *th_name); +/** + @brief This function stop command server + + @param svr handle to command server + @return none + */ +void omx_evrc_thread_stop(struct evrc_ipc_info *evrc_ipc); + + +/** + @brief This function post message in the command server + + @param svr handle to command server + @return none + */ +void omx_evrc_post_msg(struct evrc_ipc_info *evrc_ipc, + unsigned char id); + +void* omx_evrc_comp_timer_handler(void *); + +#ifdef __cplusplus +} +#endif + +#endif /* AENC_SVR */ diff --git a/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h b/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h new file mode 100644 index 000000000..fa83230b7 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h @@ -0,0 +1,539 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _EVRC_ENC_H_ +#define _EVRC_ENC_H_ +/*============================================================================ + Audio Encoder + +@file omx_evrc_aenc.h +This module contains the class definition for openMAX encoder component. + + + +============================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see + * all DEBUG_PRINT or LOGV messaging */ +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#include "OMX_Core.h" +#include "OMX_Audio.h" +#include "aenc_svr.h" +#include "qc_omx_component.h" +#include "Map.h" +#include +#include +#include +extern "C" { + void * get_omx_component_factory_fn(void); +} + + +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// + + + +#define OMX_SPEC_VERSION 0x00000101 +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (x >= y?x:y) + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +// + + +#define PrintFrameHdr(i,bufHdr) \ + DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\ + i,\ + (unsigned) bufHdr, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags) + + +// BitMask Management logic +#define BITS_PER_BYTE 8 +#define BITMASK_SIZE(mIndex) \ + (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE) +#define BITMASK_OFFSET(mIndex)\ + ((mIndex)/BITS_PER_BYTE) +#define BITMASK_FLAG(mIndex) \ + (1 << ((mIndex) % BITS_PER_BYTE)) +#define BITMASK_CLEAR(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex)\ + ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex)\ + (((mArray)[BITMASK_OFFSET(mIndex)] & \ + BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_NUM_INPUT_BUFFERS 2 +#define OMX_CORE_NUM_OUTPUT_BUFFERS 16 + +#define OMX_CORE_INPUT_BUFFER_SIZE 8160 // Multiple of 160 +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_AENC_VOLUME_STEP 0x147 +#define OMX_AENC_MIN 0 +#define OMX_AENC_MAX 100 +#define NON_TUNNEL 1 +#define TUNNEL 0 +#define IP_PORT_BITMASK 0x02 +#define OP_PORT_BITMASK 0x01 +#define IP_OP_PORT_BITMASK 0x03 + +#define OMX_EVRC_DEFAULT_SF 8000 +#define OMX_EVRC_DEFAULT_CH_CFG 1 +#define OMX_EVRC_DEFAULT_VOL 25 +// 14 bytes for input meta data +#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14) + +#define TRUE 1 +#define FALSE 0 + +#define NUMOFFRAMES 1 +#define MAXFRAMELENGTH 25 +#define OMX_EVRC_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT) + MAXFRAMELENGTH) \ + + 1)) + +#define OMX_EVRC_DEFAULT_MINRATE 4 +#define OMX_EVRC_DEFAULT_MAXRATE 4 + +class omx_evrc_aenc; + +// OMX EVRC audio encoder class +class omx_evrc_aenc: public qc_omx_component +{ +public: + omx_evrc_aenc(); // constructor + virtual ~omx_evrc_aenc(); // destructor + + OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index); + + OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup); + + OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE * specVersion, + OMX_UUIDTYPE *componentUUID); + + OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + static void process_in_port_msg(void *client_data, + unsigned char id); + + static void process_out_port_msg(void *client_data, + unsigned char id); + + static void process_command_msg(void *client_data, + unsigned char id); + + static void process_event_cb(void *client_data, + unsigned char id); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + + bool post_command(unsigned int p1, unsigned int p2, + unsigned int id); + + // Deferred callback identifiers + enum + { + //Event Callbacks from the component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + OMX_COMPONENT_GENERATE_ETB = 0x3, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x4, + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05, + OMX_COMPONENT_GENERATE_FTB = 0x06, + OMX_COMPONENT_GENERATE_EOS = 0x07, + OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08, + OMX_COMPONENT_SUSPEND = 0x09, + OMX_COMPONENT_RESUME = 0x0a + }; +private: + + /////////////////////////////////////////////////////////// + // Type definitions + /////////////////////////////////////////////////////////// + // Bit Positions + enum flags_bit_positions + { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + + OMX_COMPONENT_MUTED =0x3, + + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7 + }; + + + typedef Map + input_buffer_map; + + typedef Map + output_buffer_map; + + enum port_indexes + { + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 + }; + + struct omx_event + { + unsigned param1; + unsigned param2; + unsigned id; + }; + + struct omx_cmd_queue + { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned m_read; + unsigned m_write; + unsigned m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned p1, unsigned p2, unsigned id); + bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id); + bool get_msg_id(unsigned *id); + bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id); + }; + + typedef struct TIMESTAMP + { + unsigned long LowPart; + unsigned long HighPart; + }__attribute__((packed)) TIMESTAMP; + + typedef struct metadata_input + { + unsigned short offsetVal; + TIMESTAMP nTimeStamp; + unsigned int nFlags; + }__attribute__((packed)) META_IN; + + typedef struct enc_meta_out + { + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; + } __attribute__ ((packed))ENC_META_OUT; + + typedef struct + { + OMX_U32 tot_in_buf_len; + OMX_U32 tot_out_buf_len; + OMX_U32 tot_pb_time; + OMX_U32 fbd_cnt; + OMX_U32 ftb_cnt; + OMX_U32 etb_cnt; + OMX_U32 ebd_cnt; + }EVRC_PB_STATS; + + /////////////////////////////////////////////////////////// + // Member variables + /////////////////////////////////////////////////////////// + OMX_U8 *m_tmp_meta_buf; + OMX_U8 *m_tmp_out_meta_buf; + OMX_U8 m_flush_cnt ; + OMX_U8 m_comp_deinit; + + // the below var doesnt hold good if combo of use and alloc bufs are used + OMX_S32 m_volume;//Unit to be determined + OMX_PTR m_app_data;// Application data + int nNumInputBuf; + int nNumOutputBuf; + int m_drv_fd; // Kernel device node file handle + bool bFlushinprogress; + bool is_in_th_sleep; + bool is_out_th_sleep; + unsigned int m_flags; //encapsulate the waiting states. + unsigned int nTimestamp; + unsigned int pcm_input; //tunnel or non-tunnel + unsigned int m_inp_act_buf_count; // Num of Input Buffers + unsigned int m_out_act_buf_count; // Numb of Output Buffers + unsigned int m_inp_current_buf_count; // Num of Input Buffers + unsigned int m_out_current_buf_count; // Numb of Output Buffers + unsigned int output_buffer_size; + unsigned int input_buffer_size; + unsigned short m_session_id; + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + sem_t sem_States; + sem_t sem_read_msg; + sem_t sem_write_msg; + + volatile int m_is_event_done; + volatile int m_is_in_th_sleep; + volatile int m_is_out_th_sleep; + input_buffer_map m_input_buf_hdrs; + output_buffer_map m_output_buf_hdrs; + omx_cmd_queue m_input_q; + omx_cmd_queue m_input_ctrl_cmd_q; + omx_cmd_queue m_input_ctrl_ebd_q; + omx_cmd_queue m_command_q; + omx_cmd_queue m_output_q; + omx_cmd_queue m_output_ctrl_cmd_q; + omx_cmd_queue m_output_ctrl_fbd_q; + pthread_mutexattr_t m_outputlock_attr; + pthread_mutexattr_t m_commandlock_attr; + pthread_mutexattr_t m_lock_attr; + pthread_mutexattr_t m_state_attr; + pthread_mutexattr_t m_flush_attr; + pthread_mutexattr_t m_in_th_attr_1; + pthread_mutexattr_t m_out_th_attr_1; + pthread_mutexattr_t m_event_attr; + pthread_mutexattr_t m_in_th_attr; + pthread_mutexattr_t m_out_th_attr; + pthread_mutexattr_t out_buf_count_lock_attr; + pthread_mutexattr_t in_buf_count_lock_attr; + pthread_cond_t cond; + pthread_cond_t in_cond; + pthread_cond_t out_cond; + pthread_mutex_t m_lock; + pthread_mutex_t m_commandlock; + pthread_mutex_t m_outputlock; + // Mutexes for state change + pthread_mutex_t m_state_lock; + // Mutexes for flush acks from input and output threads + pthread_mutex_t m_flush_lock; + pthread_mutex_t m_event_lock; + pthread_mutex_t m_in_th_lock; + pthread_mutex_t m_out_th_lock; + pthread_mutex_t m_in_th_lock_1; + pthread_mutex_t m_out_th_lock_1; + pthread_mutex_t out_buf_count_lock; + pthread_mutex_t in_buf_count_lock; + + OMX_STATETYPE m_state; // OMX State + OMX_STATETYPE nState; + OMX_CALLBACKTYPE m_cb; // Application callbacks + EVRC_PB_STATS m_evrc_pb_stats; + struct evrc_ipc_info *m_ipc_to_in_th; // for input thread + struct evrc_ipc_info *m_ipc_to_out_th; // for output thread + struct evrc_ipc_info *m_ipc_to_cmd_th; // for command thread + struct evrc_ipc_info *m_ipc_to_event_th; //for txco event thread + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_AUDIO_PARAM_EVRCTYPE m_evrc_param; // Cache EVRC encoder parameter + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter + OMX_PARAM_COMPONENTROLETYPE component_Role; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + + /////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////// + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + bool allocate_done(void); + + bool release_done(OMX_U32 param1); + + bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true); + + bool execute_input_omx_flush(void); + + bool execute_output_omx_flush(void); + + bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool post_input(unsigned int p1, unsigned int p2, + unsigned int id); + + bool post_output(unsigned int p1, unsigned int p2, + unsigned int id); + + void process_events(omx_evrc_aenc *client_data); + + void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void wait_for_event(); + + void event_complete(); + + void in_th_goto_sleep(); + + void in_th_wakeup(); + + void out_th_goto_sleep(); + + void out_th_wakeup(); + + void flush_ack(); + void deinit_encoder(); + +}; +#endif diff --git a/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c b/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..212871867 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c @@ -0,0 +1,205 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#include +#include +#include + +#include +#include + +#include + +/** + @brief This function processes posted messages + + Once thread is being spawned, this function is run to + start processing commands posted by client + + @param info pointer to context + + */ +void *omx_evrc_msg(void *info) +{ + struct evrc_ipc_info *evrc_info = (struct evrc_ipc_info*)info; + unsigned char id; + int n; + + DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__); + while (!evrc_info->dead) + { + n = read(evrc_info->pipe_in, &id, 1); + if (0 == n) break; + if (1 == n) + { + DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n", + evrc_info->thread_name, + evrc_info->pipe_in, + evrc_info->pipe_out); + + evrc_info->process_msg_cb(evrc_info->client_data, id); + } + if ((n < 0) && (errno != EINTR)) break; + } + DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__); + + return 0; +} + +void *omx_evrc_events(void *info) +{ + struct evrc_ipc_info *evrc_info = (struct evrc_ipc_info*)info; + unsigned char id = 0; + + DEBUG_DETAIL("%s: message thread start\n", evrc_info->thread_name); + evrc_info->process_msg_cb(evrc_info->client_data, id); + DEBUG_DETAIL("%s: message thread stop\n", evrc_info->thread_name); + return 0; +} + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to msging thread + */ +struct evrc_ipc_info *omx_evrc_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct evrc_ipc_info *evrc_info; + + evrc_info = calloc(1, sizeof(struct evrc_ipc_info)); + if (!evrc_info) + { + return 0; + } + + evrc_info->client_data = client_data; + evrc_info->process_msg_cb = cb; + strlcpy(evrc_info->thread_name, th_name, sizeof(evrc_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + evrc_info->pipe_in = fds[0]; + evrc_info->pipe_out = fds[1]; + + r = pthread_create(&evrc_info->thr, 0, omx_evrc_msg, evrc_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", evrc_info->thread_name); + return evrc_info; + + +fail_thread: + close(evrc_info->pipe_in); + close(evrc_info->pipe_out); + +fail_pipe: + free(evrc_info); + + return 0; +} + +/** + * @brief This function starts command server + * + * @param cb pointer to callback function from the client + * @param client_data reference client wants to get back + * through callback + * @return handle to msging thread + * */ +struct evrc_ipc_info *omx_evrc_event_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct evrc_ipc_info *evrc_info; + + evrc_info = calloc(1, sizeof(struct evrc_ipc_info)); + if (!evrc_info) + { + return 0; + } + + evrc_info->client_data = client_data; + evrc_info->process_msg_cb = cb; + strlcpy(evrc_info->thread_name, th_name, sizeof(evrc_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + evrc_info->pipe_in = fds[0]; + evrc_info->pipe_out = fds[1]; + + r = pthread_create(&evrc_info->thr, 0, omx_evrc_events, evrc_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", evrc_info->thread_name); + return evrc_info; + + +fail_thread: + close(evrc_info->pipe_in); + close(evrc_info->pipe_out); + +fail_pipe: + free(evrc_info); + + return 0; +} + +void omx_evrc_thread_stop(struct evrc_ipc_info *evrc_info) { + DEBUG_DETAIL("%s stop server\n", __FUNCTION__); + close(evrc_info->pipe_in); + close(evrc_info->pipe_out); + pthread_join(evrc_info->thr,NULL); + evrc_info->pipe_out = -1; + evrc_info->pipe_in = -1; + DEBUG_DETAIL("%s: message thread close fds%d %d\n", evrc_info->thread_name, + evrc_info->pipe_in,evrc_info->pipe_out); + free(evrc_info); +} + +void omx_evrc_post_msg(struct evrc_ipc_info *evrc_info, unsigned char id) { + DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id); + write(evrc_info->pipe_out, &id, 1); +} diff --git a/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp b/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp new file mode 100644 index 000000000..073f1ac87 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp @@ -0,0 +1,4530 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +/*============================================================================ +@file omx_aenc_evrc.c + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include "omx_evrc_aenc.h" +#include + +using namespace std; +#define SLEEP_MS 100 + +// omx_cmd_queue destructor +omx_evrc_aenc::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_evrc_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE); +} + +// omx cmd queue insert +bool omx_evrc_aenc::omx_cmd_queue::insert_entry(unsigned p1, + unsigned p2, + unsigned id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_write = 0; + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full"); + } + return ret; +} + +bool omx_evrc_aenc::omx_cmd_queue::pop_entry(unsigned *p1, + unsigned *p2, unsigned *id) +{ + bool ret = true; + if (m_size > 0) + { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_read = 0; + + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty"); + } + return ret; +} + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return(new omx_evrc_aenc); +} +bool omx_evrc_aenc::omx_cmd_queue::get_msg_id(unsigned *id) +{ + if(m_size > 0) + { + *id = m_q[m_read].id; + DEBUG_PRINT("get_msg_id=%d\n",*id); + } + else{ + return false; + } + return true; +} +/*============================================================================= +FUNCTION: + wait_for_event + +DESCRIPTION: + waits for a particular event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_evrc_aenc::wait_for_event() +{ + int rc; + struct timespec ts; + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (SLEEP_MS/1000); + ts.tv_nsec += ((SLEEP_MS%1000) * 1000000); + rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts); + if (rc == ETIMEDOUT && !m_is_event_done) { + DEBUG_PRINT("Timed out waiting for flush"); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + } + } + m_is_event_done = 0; + pthread_mutex_unlock(&m_event_lock); +} + +/*============================================================================= +FUNCTION: + event_complete + +DESCRIPTION: + informs about the occurance of an event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_evrc_aenc::event_complete() +{ + pthread_mutex_lock(&m_event_lock); + if (0 == m_is_event_done) + { + m_is_event_done = 1; + pthread_cond_signal(&cond); + } + pthread_mutex_unlock(&m_event_lock); +} + +// All this non-sense because of a single evrc object +void omx_evrc_aenc::in_th_goto_sleep() +{ + pthread_mutex_lock(&m_in_th_lock); + while (0 == m_is_in_th_sleep) + { + pthread_cond_wait(&in_cond, &m_in_th_lock); + } + m_is_in_th_sleep = 0; + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_evrc_aenc::in_th_wakeup() +{ + pthread_mutex_lock(&m_in_th_lock); + if (0 == m_is_in_th_sleep) + { + m_is_in_th_sleep = 1; + pthread_cond_signal(&in_cond); + } + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_evrc_aenc::out_th_goto_sleep() +{ + + pthread_mutex_lock(&m_out_th_lock); + while (0 == m_is_out_th_sleep) + { + pthread_cond_wait(&out_cond, &m_out_th_lock); + } + m_is_out_th_sleep = 0; + pthread_mutex_unlock(&m_out_th_lock); +} + +void omx_evrc_aenc::out_th_wakeup() +{ + pthread_mutex_lock(&m_out_th_lock); + if (0 == m_is_out_th_sleep) + { + m_is_out_th_sleep = 1; + pthread_cond_signal(&out_cond); + } + pthread_mutex_unlock(&m_out_th_lock); +} +/* ====================================================================== +FUNCTION + omx_evrc_aenc::omx_evrc_aenc + +DESCRIPTION + Constructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_evrc_aenc::omx_evrc_aenc(): m_tmp_meta_buf(NULL), + m_tmp_out_meta_buf(NULL), + m_flush_cnt(255), + m_comp_deinit(0), + m_app_data(NULL), + m_drv_fd(-1), + bFlushinprogress(0), + is_in_th_sleep(false), + is_out_th_sleep(false), + m_flags(0), + nTimestamp(0), + m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS), + m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS), + m_inp_current_buf_count(0), + m_out_current_buf_count(0), + output_buffer_size(OMX_EVRC_OUTPUT_BUFFER_SIZE), + input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE), + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_is_event_done(0), + m_state(OMX_StateInvalid), + m_ipc_to_in_th(NULL), + m_ipc_to_out_th(NULL), + m_ipc_to_cmd_th(NULL), + nNumOutputBuf(0), + nNumInputBuf(0), + m_volume(25) +{ + int cond_ret = 0; + memset(&m_cmp, 0, sizeof(m_cmp)); + memset(&m_cb, 0, sizeof(m_cb)); + memset(&m_evrc_param, 0, sizeof(m_evrc_param)); + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + memset(&m_evrc_pb_stats, 0, sizeof(m_evrc_pb_stats)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + + pthread_mutexattr_init(&m_lock_attr); + pthread_mutex_init(&m_lock, &m_lock_attr); + pthread_mutexattr_init(&m_commandlock_attr); + pthread_mutex_init(&m_commandlock, &m_commandlock_attr); + + pthread_mutexattr_init(&m_outputlock_attr); + pthread_mutex_init(&m_outputlock, &m_outputlock_attr); + + pthread_mutexattr_init(&m_state_attr); + pthread_mutex_init(&m_state_lock, &m_state_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_flush_attr); + pthread_mutex_init(&m_flush_lock, &m_flush_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_in_th_attr); + pthread_mutex_init(&m_in_th_lock, &m_in_th_attr); + + pthread_mutexattr_init(&m_out_th_attr); + pthread_mutex_init(&m_out_th_lock, &m_out_th_attr); + + pthread_mutexattr_init(&m_in_th_attr_1); + pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1); + + pthread_mutexattr_init(&m_out_th_attr_1); + pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1); + + pthread_mutexattr_init(&out_buf_count_lock_attr); + pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr); + + pthread_mutexattr_init(&in_buf_count_lock_attr); + pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr); + if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + + sem_init(&sem_read_msg,0, 0); + sem_init(&sem_write_msg,0, 0); + sem_init(&sem_States,0, 0); + return; +} + + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::~omx_evrc_aenc + +DESCRIPTION + Destructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_evrc_aenc::~omx_evrc_aenc() +{ + DEBUG_PRINT_ERROR("EVRC Object getting destroyed comp-deinit=%d\n", + m_comp_deinit); + if ( !m_comp_deinit ) + { + deinit_encoder(); + } + pthread_mutexattr_destroy(&m_lock_attr); + pthread_mutex_destroy(&m_lock); + + pthread_mutexattr_destroy(&m_commandlock_attr); + pthread_mutex_destroy(&m_commandlock); + + pthread_mutexattr_destroy(&m_outputlock_attr); + pthread_mutex_destroy(&m_outputlock); + + pthread_mutexattr_destroy(&m_state_attr); + pthread_mutex_destroy(&m_state_lock); + + pthread_mutexattr_destroy(&m_event_attr); + pthread_mutex_destroy(&m_event_lock); + + pthread_mutexattr_destroy(&m_flush_attr); + pthread_mutex_destroy(&m_flush_lock); + + pthread_mutexattr_destroy(&m_in_th_attr); + pthread_mutex_destroy(&m_in_th_lock); + + pthread_mutexattr_destroy(&m_out_th_attr); + pthread_mutex_destroy(&m_out_th_lock); + + pthread_mutexattr_destroy(&out_buf_count_lock_attr); + pthread_mutex_destroy(&out_buf_count_lock); + + pthread_mutexattr_destroy(&in_buf_count_lock_attr); + pthread_mutex_destroy(&in_buf_count_lock); + + pthread_mutexattr_destroy(&m_in_th_attr_1); + pthread_mutex_destroy(&m_in_th_lock_1); + + pthread_mutexattr_destroy(&m_out_th_attr_1); + pthread_mutex_destroy(&m_out_th_lock_1); + pthread_mutex_destroy(&out_buf_count_lock); + pthread_mutex_destroy(&in_buf_count_lock); + pthread_cond_destroy(&cond); + pthread_cond_destroy(&in_cond); + pthread_cond_destroy(&out_cond); + sem_destroy (&sem_read_msg); + sem_destroy (&sem_write_msg); + sem_destroy (&sem_States); + DEBUG_PRINT_ERROR("OMX EVRC component destroyed\n"); + return; +} + +/** + @brief memory function for sending EmptyBufferDone event + back to IL client + + @param bufHdr OMX buffer header to be passed back to IL client + @return none + */ +void omx_evrc_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.EmptyBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr); + bufHdr->nFilledLen = 0; + + m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr); + pthread_mutex_lock(&in_buf_count_lock); + m_evrc_pb_stats.ebd_cnt++; + nNumInputBuf--; + DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\ + m_evrc_pb_stats.tot_in_buf_len, + nNumInputBuf, m_evrc_pb_stats.ebd_cnt); + pthread_mutex_unlock(&in_buf_count_lock); + } + + return; +} + +/*============================================================================= +FUNCTION: + flush_ack + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_evrc_aenc::flush_ack() +{ + // Decrement the FLUSH ACK count and notify the waiting recepients + pthread_mutex_lock(&m_flush_lock); + --m_flush_cnt; + if (0 == m_flush_cnt) + { + event_complete(); + } + DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt); + pthread_mutex_unlock(&m_flush_lock); +} +void omx_evrc_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.FillBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr); + m_evrc_pb_stats.fbd_cnt++; + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf--; + DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\ + nNumOutputBuf, + m_evrc_pb_stats.tot_out_buf_len, + m_evrc_pb_stats.fbd_cnt); + m_evrc_pb_stats.tot_out_buf_len += bufHdr->nFilledLen; + m_evrc_pb_stats.tot_pb_time = bufHdr->nTimeStamp; + DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n", + m_evrc_pb_stats.tot_in_buf_len, + m_evrc_pb_stats.tot_out_buf_len); + + pthread_mutex_unlock(&out_buf_count_lock); + m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr); + } + return; +} + +/*============================================================================= +FUNCTION: + process_out_port_msg + +DESCRIPTION: + Function for handling all commands from IL client +IL client commands are processed and callbacks are generated through +this routine Audio Command Server provides the thread context for this routine + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_evrc_aenc::process_out_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; // qsize + unsigned tot_qsize = 0; + omx_evrc_aenc *pThis = (omx_evrc_aenc *) client_data; + OMX_STATETYPE state; + +loopback_out: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n"); + return; + } + pthread_mutex_lock(&pThis->m_outputlock); + + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + + if ( 0 == tot_qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize); + return; + } + if ( (state != OMX_StateExecuting) && !qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + + if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) ) + { + // case where no port reconfig and nothing in the flush q + DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\ + qsize,tot_qsize); + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress)) + { + DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + } + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\ + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size,state); + + + if (qsize) + { + // process FLUSH message + pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // if no FLUSH and FBD's then process FTB's + pThis->m_output_q.pop_entry(&p1,&p2,&ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pthread_mutex_unlock(&pThis->m_outputlock); + pThis->out_th_goto_sleep(); + goto loopback_out; + } + } + pthread_mutex_unlock(&pThis->m_outputlock); + + if ( qsize > 0 ) + { + id = ident; + ident = 0; + DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id ) + { + pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_FTB == id ) + { + pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_EOS == id ) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + + } + else if(id == OMX_COMPONENT_RESUME) + { + DEBUG_PRINT("RESUMED...\n"); + } + else if(id == OMX_COMPONENT_GENERATE_COMMAND) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL("Executing FLUSH command on Output port\n"); + pThis->execute_output_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n"); + } + + return; +} + +/*============================================================================= +FUNCTION: + process_command_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_evrc_aenc::process_command_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + omx_evrc_aenc *pThis = (omx_evrc_aenc*)client_data; + pthread_mutex_lock(&pThis->m_commandlock); + + qsize = pThis->m_command_q.m_size; + DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size, + pThis->m_state); + + if (!qsize) + { + DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n"); + pthread_mutex_unlock(&pThis->m_commandlock); + return; + } else + { + pThis->m_command_q.pop_entry(&p1,&p2,&ident); + } + pthread_mutex_unlock(&pThis->m_commandlock); + + id = ident; + DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\ + pThis->m_state,ident, \ + pThis->m_command_q.m_size); + + if (OMX_COMPONENT_GENERATE_EVENT == id) + { + if (pThis->m_cb.EventHandler) + { + if (OMX_CommandStateSet == p1) + { + pthread_mutex_lock(&pThis->m_state_lock); + pThis->m_state = (OMX_STATETYPE) p2; + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_PRINT("CMD:Process->state set to %d \n", \ + pThis->m_state); + + if (pThis->m_state == OMX_StateExecuting || + pThis->m_state == OMX_StateLoaded) + { + + pthread_mutex_lock(&pThis->m_in_th_lock_1); + if (pThis->is_in_th_sleep) + { + pThis->is_in_th_sleep = false; + DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n"); + pThis->in_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + + pthread_mutex_lock(&pThis->m_out_th_lock_1); + if (pThis->is_out_th_sleep) + { + DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n"); + pThis->is_out_th_sleep = false; + pThis->out_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + } + } + if (OMX_StateInvalid == pThis->m_state) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + } else if ((signed)p2 == OMX_ErrorPortUnpopulated) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + p2, + NULL, + NULL ); + } else + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventCmdComplete, + p1, p2, NULL ); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n"); + } + } else if (OMX_COMPONENT_GENERATE_COMMAND == id) + { + pThis->send_command_proxy(&pThis->m_cmp, + (OMX_COMMANDTYPE)p1, + (OMX_U32)p2,(OMX_PTR)NULL); + } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id) + { + DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED"); + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventPortSettingsChanged, + 1, 1, NULL ); + } + else + { + DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident); + } + return; +} + +/*============================================================================= +FUNCTION: + process_in_port_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_evrc_aenc::process_in_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + unsigned tot_qsize = 0; + omx_evrc_aenc *pThis = (omx_evrc_aenc *) client_data; + OMX_STATETYPE state; + + if (!pThis) + { + DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n"); + return; + } +loopback_in: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n"); + return; + } + // Protect the shared queue data structure + pthread_mutex_lock(&pThis->m_lock); + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + if ( 0 == tot_qsize ) + { + DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP"); + pthread_mutex_unlock(&pThis->m_lock); + return; + } + + if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_DETAIL("SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + else if ((state == OMX_StatePause)) + { + if(!(pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + + DEBUG_DETAIL("IN: SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + } + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\ + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size, state); + + + if ( qsize ) + { + // process FLUSH message + pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) && + (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident); + } else if ((qsize = pThis->m_input_q.m_size) && + (state == OMX_StateExecuting)) + { + // if no FLUSH and EBD's then process ETB's + pThis->m_input_q.pop_entry(&p1, &p2, &ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\ + state,pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pthread_mutex_unlock(&pThis->m_lock); + pThis->in_th_goto_sleep(); + goto loopback_in; + } + } + pthread_mutex_unlock(&pThis->m_lock); + + if ( qsize > 0 ) + { + id = ident; + DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id ) + { + pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } + else if(id == OMX_COMPONENT_GENERATE_EOS) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventBufferFlag, 0, 1, NULL ); + } else if ( OMX_COMPONENT_GENERATE_ETB == id ) + { + pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_COMMAND == id ) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL(" Executing FLUSH command on Input port\n"); + pThis->execute_input_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } + else + { + DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n"); + } + return; +} + +/** + @brief member function for performing component initialization + + @param role C string mandating role of this component + @return Error status + */ +OMX_ERRORTYPE omx_evrc_aenc::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + m_state = OMX_StateLoaded; + + /* DSP does not give information about the bitstream + randomly assign the value right now. Query will result in + incorrect param */ + memset(&m_evrc_param, 0, sizeof(m_evrc_param)); + m_evrc_param.nSize = sizeof(m_evrc_param); + m_evrc_param.nChannels = OMX_EVRC_DEFAULT_CH_CFG; + //Current DSP does not have config + m_evrc_param.eCDMARate = OMX_AUDIO_CDMARateFull; + m_evrc_param.nMinBitRate = OMX_EVRC_DEFAULT_MINRATE; + m_evrc_param.nMaxBitRate = OMX_EVRC_DEFAULT_MAXRATE; + m_volume = OMX_EVRC_DEFAULT_VOL; /* Close to unity gain */ + memset(&m_evrc_pb_stats,0,sizeof(EVRC_PB_STATS)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + m_pcm_param.nSize = sizeof(m_pcm_param); + m_pcm_param.nChannels = OMX_EVRC_DEFAULT_CH_CFG; + m_pcm_param.nSamplingRate = OMX_EVRC_DEFAULT_SF; + nTimestamp = 0; + + + nNumInputBuf = 0; + nNumOutputBuf = 0; + m_ipc_to_in_th = NULL; // Command server instance + m_ipc_to_out_th = NULL; // Client server instance + m_ipc_to_cmd_th = NULL; // command instance + m_is_out_th_sleep = 0; + m_is_in_th_sleep = 0; + is_out_th_sleep= false; + + is_in_th_sleep=false; + + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + m_priority_mgm.nGroupID =0; + m_priority_mgm.nGroupPriority=0; + + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified; + + DEBUG_PRINT_ERROR(" component init: role = %s\n",role); + + DEBUG_PRINT(" component init: role = %s\n",role); + component_Role.nVersion.nVersion = OMX_SPEC_VERSION; + if (!strcmp(role,"OMX.qcom.audio.encoder.evrc")) + { + pcm_input = 1; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, + (const char*)role, sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.evrc")) + { + pcm_input = 0; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, + (const char*)role, sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else + { + component_Role.nSize = sizeof("\0"); + strlcpy((char *)component_Role.cRole, + (const char*)"\0",sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED is invalid\n", role); + } + if(pcm_input) + { + + + m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) * + (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN))); + + if (m_tmp_meta_buf == NULL){ + DEBUG_PRINT_ERROR("Mem alloc failed for in meta buf\n"); + return OMX_ErrorInsufficientResources; + } + } + m_tmp_out_meta_buf = + (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_EVRC_OUTPUT_BUFFER_SIZE); + if ( m_tmp_out_meta_buf == NULL ) { + DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n"); + return OMX_ErrorInsufficientResources; + } + + if(0 == pcm_input) + { + m_drv_fd = open("/dev/msm_evrc_in",O_RDONLY); + DEBUG_PRINT("Driver in Tunnel mode open\n"); + } + else + { + m_drv_fd = open("/dev/msm_evrc_in",O_RDWR); + DEBUG_PRINT("Driver in Non Tunnel mode open\n"); + } + if (m_drv_fd < 0) + { + DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\ + m_drv_fd,errno); + + return OMX_ErrorInsufficientResources; + } + if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1) + { + DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n"); + } + if(pcm_input) + { + if (!m_ipc_to_in_th) + { + m_ipc_to_in_th = omx_evrc_thread_create(process_in_port_msg, + this, (char *)"INPUT_THREAD"); + if (!m_ipc_to_in_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start \ + Input port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + } + + if (!m_ipc_to_cmd_th) + { + m_ipc_to_cmd_th = omx_evrc_thread_create(process_command_msg, + this, (char *)"CMD_THREAD"); + if (!m_ipc_to_cmd_th) + { + DEBUG_PRINT_ERROR("ERROR!!!Failed to start " + "command message thread\n"); + return OMX_ErrorInsufficientResources; + } + } + + if (!m_ipc_to_out_th) + { + m_ipc_to_out_th = omx_evrc_thread_create(process_out_port_msg, + this, (char *)"OUTPUT_THREAD"); + if (!m_ipc_to_out_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start output " + "port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + return eRet; +} + +/** + + @brief member function to retrieve version of component + + + + @param hComp handle to this component instance + @param componentName name of component + @param componentVersion pointer to memory space which stores the + version number + @param specVersion pointer to memory sapce which stores version of + openMax specification + @param componentUUID + @return Error status + */ +OMX_ERRORTYPE omx_evrc_aenc::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID) +{ + if((hComp == NULL) || (componentName == NULL) || + (specVersion == NULL) || (componentUUID == NULL)) + { + componentVersion = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n"); + return OMX_ErrorInvalidState; + } + componentVersion->nVersion = OMX_SPEC_VERSION; + specVersion->nVersion = OMX_SPEC_VERSION; + return OMX_ErrorNone; +} +/** + @brief member function handles command from IL client + + This function simply queue up commands from IL client. + Commands will be processed in command server thread context later + + @param hComp handle to component instance + @param cmd type of command + @param param1 parameters associated with the command type + @param cmdData + @return Error status +*/ +OMX_ERRORTYPE omx_evrc_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + int portIndex = (int)param1; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateInvalid == m_state) + { + return OMX_ErrorInvalidState; + } + if ( (cmd == OMX_CommandFlush) && (portIndex > 1) ) + { + return OMX_ErrorBadPortIndex; + } + post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); + DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n"); + DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1); + sem_wait (&sem_States); + DEBUG_PRINT("send_command : recieved state after semwait\n"); + return OMX_ErrorNone; +} + +/** + @brief member function performs actual processing of commands excluding + empty buffer call + + @param hComp handle to component + @param cmd command type + @param param1 parameter associated with the command + @param cmdData + + @return error status +*/ +OMX_ERRORTYPE omx_evrc_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + // Handle only IDLE and executing + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1; + nState = eState; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_CommandStateSet == cmd) + { + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (OMX_StateLoaded == m_state) + { + if (OMX_StateIdle == eState) + { + + if (allocate_done() || + (m_inp_bEnabled == OMX_FALSE + && m_out_bEnabled == OMX_FALSE)) + { + DEBUG_PRINT("SCP-->Allocate Done Complete\n"); + } + else + { + DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + bFlag = 0; + } + + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } + + else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n"); + eRet = OMX_ErrorNone; + } + + else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + m_state = OMX_StateInvalid; + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (OMX_StateIdle == m_state) + { + if (OMX_StateLoaded == eState) + { + if (release_done(-1)) + { + if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1) + { + DEBUG_PRINT_ERROR("SCP:Idle->Loaded,\ + ioctl stop failed %d\n", errno); + } + + nTimestamp=0; + + DEBUG_PRINT("SCP-->Idle to Loaded\n"); + } else + { + DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + else if (OMX_StateExecuting == eState) + { + + struct msm_audio_evrc_enc_config drv_evrc_enc_config; + struct msm_audio_stream_config drv_stream_config; + struct msm_audio_buf_cfg buf_cfg; + struct msm_audio_config pcm_cfg; + + if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + + if(ioctl(m_drv_fd, AUDIO_GET_EVRC_ENC_CONFIG, + &drv_evrc_enc_config) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_EVRC_ENC_CONFIG failed,\ + errno[%d]\n", errno); + } + drv_evrc_enc_config.min_bit_rate = m_evrc_param.nMinBitRate; + drv_evrc_enc_config.max_bit_rate = m_evrc_param.nMaxBitRate; + if(ioctl(m_drv_fd, AUDIO_SET_EVRC_ENC_CONFIG, &drv_evrc_enc_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_EVRC_ENC_CONFIG failed,\ + errno[%d]\n", errno); + } + if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n", + errno); + } + buf_cfg.meta_info_enable = 1; + buf_cfg.frames_per_buf = NUMOFFRAMES; + if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n", + errno); + } + if(pcm_input) + { + if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n", + errno); + } + pcm_cfg.channel_count = m_pcm_param.nChannels; + pcm_cfg.sample_rate = m_pcm_param.nSamplingRate; + DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + + if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n", + errno); + } + } + if(ioctl(m_drv_fd, AUDIO_START, 0) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n", + errno); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + + } + DEBUG_PRINT("SCP-->Idle to Executing\n"); + nState = eState; + } else if (eState == OMX_StateIdle) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n"); + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (OMX_StateExecuting == m_state) + { + if (OMX_StateIdle == eState) + { + DEBUG_PRINT("SCP-->Executing to Idle \n"); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + + } else if (OMX_StatePause == eState) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED PAUSE STATE\n"); + DEBUG_DETAIL("*************************\n"); + //ioctl(m_drv_fd, AUDIO_PAUSE, 0); + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n", + eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (OMX_StatePause == m_state) + { + if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) ) + { + pthread_mutex_lock(&m_out_th_lock_1); + if(is_out_th_sleep) + { + DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n"); + is_out_th_sleep = false; + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } + if ( OMX_StateExecuting == eState ) + { + nState = eState; + } else if ( OMX_StateIdle == eState ) + { + DEBUG_PRINT("SCP-->Paused to Idle \n"); + DEBUG_PRINT ("\n Internal flush issued"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + } else if ( eState == OMX_StateLoaded ) + { + DEBUG_PRINT("\n Pause --> loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n Pause --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("\n Pause --> Pause \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n Pause --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + /**************************************/ + /* Current State is WaitForResources */ + /**************************************/ + else if (m_state == OMX_StateWaitForResources) + { + if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n"); + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: \ + WaitForResources-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n", + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /****************************/ + /* Current State is Invalid */ + /****************************/ + else if (m_state == OMX_StateInvalid) + { + if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState + || OMX_StateIdle == eState || OMX_StateExecuting == eState + || OMX_StatePause == eState || OMX_StateInvalid == eState) + { + DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing" + "/Pause/Invalid/WaitForResources\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } + } else + { + DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\ + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } else if (OMX_CommandFlush == cmd) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1); + DEBUG_DETAIL("*************************\n"); + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || + param1 == OMX_CORE_OUTPUT_PORT_INDEX || + (signed)param1 == -1 ) + { + execute_omx_flush(param1); + } else + { + eRet = OMX_ErrorBadPortIndex; + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError, + OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL ); + } + } else if ( cmd == OMX_CommandPortDisable ) + { + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL ) + { + DEBUG_PRINT("SCP: Disabling Input port Indx\n"); + m_inp_bEnabled = OMX_FALSE; + if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(0) ) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_inp_bEnabled = %d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + + else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\ + " param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + // Skip the event notification + + } + + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + + DEBUG_PRINT("SCP: Disabling Output port Indx\n"); + m_out_bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(1)) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_out_bEnabled = %d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\ + "param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + // Skip the event notification + + } + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID"); + } + + } else if (cmd == OMX_CommandPortEnable) + { + bFlag = 0; + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_inp_bEnabled = OMX_TRUE; + DEBUG_PRINT("SCP: Enabling Input port Indx\n"); + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_inp_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + + } else + { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + + } + } + + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + DEBUG_PRINT("SCP: Enabling Output port Indx\n"); + m_out_bEnabled = OMX_TRUE; + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_out_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + + } + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID"); + } + + } else + { + DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd); + eRet = OMX_ErrorNotImplemented; + } + DEBUG_PRINT("posting sem_States\n"); + sem_post (&sem_States); + if (eRet == OMX_ErrorNone && bFlag) + { + post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + return eRet; +} + +/*============================================================================= +FUNCTION: + execute_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + [IN] param1 + [IN] cmd_cmpl + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_evrc_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl) +{ + bool bRet = true; + + DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1); + struct timespec abs_timeout; + abs_timeout.tv_sec = 1; + abs_timeout.tv_nsec = 0; + + if ((signed)param1 == -1) + { + bFlushinprogress = true; + DEBUG_PRINT("Execute flush for both I/p O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + + // Send Flush commands to input and output threads + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + // Send Flush to the kernel so that the in and out buffers are released + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + + + // sleep till the FLUSH ACK are done by both the input and + // output threads + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + + DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\ + param1,cmd_cmpl); + + // If not going to idle state, Send FLUSH complete message + // to the Client, now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n"); + } + bFlushinprogress = false; + } + else if (param1 == OMX_CORE_INPUT_PORT_INDEX) + { + DEBUG_PRINT("Execute FLUSH for I/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + //sleep till the FLUSH ACK are done by both the input and output threads + DEBUG_DETAIL("Executing FLUSH for I/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1); + + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1) + { + DEBUG_PRINT("Executing FLUSH for O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + DEBUG_DETAIL("Executing FLUSH for O/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1) + DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + // sleep till the FLUSH ACK are done by both the input and + // output threads + wait_for_event(); + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + } + DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1); + } else + { + DEBUG_PRINT("Invalid Port ID[%lu]",param1); + } + return bRet; +} + +/*============================================================================= +FUNCTION: + execute_input_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_evrc_aenc::execute_input_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on input port"); + + pthread_mutex_lock(&m_lock); + do + { + qsize = m_input_q.m_size; + tot_qsize = qsize; + tot_qsize += m_input_ctrl_ebd_q.m_size; + + DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\ + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size,qsize); + if (!tot_qsize) + { + DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_lock); + break; + } + if (qsize) + { + m_input_q.pop_entry(&p1, &p2, &ident); + if ((ident == OMX_COMPONENT_GENERATE_ETB) || + (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf); + omx_buf->nFilledLen = 0; + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else if (m_input_ctrl_ebd_q.m_size) + { + m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident); + if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + omx_buf->nFilledLen = 0; + DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else + { + } + }while (tot_qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("IN-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_lock); + return true; +} + +/*============================================================================= +FUNCTION: + execute_output_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_evrc_aenc::execute_output_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on output port"); + + pthread_mutex_lock(&m_outputlock); + do + { + qsize = m_output_q.m_size; + DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\ + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size,qsize); + tot_qsize = qsize; + tot_qsize += m_output_ctrl_fbd_q.m_size; + if (!tot_qsize) + { + DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_outputlock); + break; + } + if (qsize) + { + m_output_q.pop_entry(&p1,&p2,&ident); + if ( (OMX_COMPONENT_GENERATE_FTB == ident) || + (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FBD FROM FLUSH"); + } + } else if ((qsize = m_output_ctrl_fbd_q.m_size)) + { + m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident); + if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH"); + } + } + }while (qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("OUT-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_outputlock); + return true; +} + +/*============================================================================= +FUNCTION: + post_input + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_evrc_aenc::post_input(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + pthread_mutex_lock(&m_lock); + + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)) + { + // insert flush message and ebd + m_input_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id)) + { + // insert ebd + m_input_ctrl_ebd_q.insert_entry(p1,p2,id); + } else + { + // ETBS in this queue + m_input_q.insert_entry(p1,p2,id); + } + + if (m_ipc_to_in_th) + { + bRet = true; + omx_evrc_post_msg(m_ipc_to_in_th, id); + } + + DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\ + m_state, + id, + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size, + m_input_q.m_size); + + pthread_mutex_unlock(&m_lock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_command + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_evrc_aenc::post_command(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_commandlock); + + m_command_q.insert_entry(p1,p2,id); + + if (m_ipc_to_cmd_th) + { + bRet = true; + omx_evrc_post_msg(m_ipc_to_cmd_th, id); + } + + DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\ + m_state, + id, + m_command_q.m_size, + m_flags >> 3); + + pthread_mutex_unlock(&m_commandlock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_output + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_evrc_aenc::post_output(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_outputlock); + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND) + || (id == OMX_COMPONENT_RESUME)) + { + // insert flush message and fbd + m_output_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) ) + { + // insert flush message and fbd + m_output_ctrl_fbd_q.insert_entry(p1,p2,id); + } else + { + m_output_q.insert_entry(p1,p2,id); + } + if ( m_ipc_to_out_th ) + { + bRet = true; + omx_evrc_post_msg(m_ipc_to_out_th, id); + } + DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + m_state, + id, + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size, + m_output_q.m_size); + + pthread_mutex_unlock(&m_outputlock); + return bRet; +} +/** + @brief member function that return parameters to IL client + + @param hComp handle to component instance + @param paramIndex Parameter type + @param paramData pointer to memory space which would hold the + paramter + @return error status +*/ +OMX_ERRORTYPE omx_evrc_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Param in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) + { + DEBUG_PRINT("get_parameter: paramData is NULL\n"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + DEBUG_PRINT("OMX_IndexParamPortDefinition " \ + "portDefn->nPortIndex = %lu\n", + portDefn->nPortIndex); + + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(portDefn); + portDefn->eDomain = OMX_PortDomainAudio; + + if (0 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirInput; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + portDefn->nBufferCountActual = m_inp_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS; + portDefn->nBufferSize = input_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM; + portDefn->format.audio.pNativeRender = 0; + } else if (1 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirOutput; + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + portDefn->nBufferCountActual = m_out_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS; + portDefn->nBufferSize = output_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingEVRC; + portDefn->format.audio.pNativeRender = 0; + } else + { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_ERROR("Bad Port idx %d\n",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioInit\n"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n"); + portFormatType->nVersion.nVersion = OMX_SPEC_VERSION; + portFormatType->nSize = sizeof(portFormatType); + + if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex) + { + + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX== + portFormatType->nPortIndex) + { + DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\ + "%lu\n", portFormatType->nIndex); + + portFormatType->eEncoding = OMX_AUDIO_CodingEVRC; + } else + { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n", + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioEvrc: + { + OMX_AUDIO_PARAM_EVRCTYPE *evrcParam = + (OMX_AUDIO_PARAM_EVRCTYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioEvrc\n"); + if (OMX_CORE_OUTPUT_PORT_INDEX== evrcParam->nPortIndex) + { + memcpy(evrcParam,&m_evrc_param, + sizeof(OMX_AUDIO_PARAM_EVRCTYPE)); + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioEvrc "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)evrcParam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case QOMX_IndexParamAudioSessionId: + { + QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam = + (QOMX_AUDIO_STREAM_INFO_DATA *) paramData; + streaminfoparam->sessionId = m_session_id; + break; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam = + (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(pcmparam,&m_pcm_param,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + DEBUG_PRINT("get_parameter: Sampling rate %lu",\ + pcmparam->nSamplingRate); + DEBUG_PRINT("get_parameter: Number of channels %lu",\ + pcmparam->nChannels); + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamComponentSuspended: + { + OMX_PARAM_SUSPENSIONTYPE *suspend = + (OMX_PARAM_SUSPENSIONTYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n", + suspend); + break; + } + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamPriorityMgmt: + { + OMX_PRIORITYMGMTTYPE *priorityMgmtType = + (OMX_PRIORITYMGMTTYPE*)paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n"); + priorityMgmtType->nSize = sizeof(priorityMgmtType); + priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmtType->nGroupID = m_priority_mgm.nGroupID; + priorityMgmtType->nGroupPriority = + m_priority_mgm.nGroupPriority; + break; + } + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + + bufferSupplierType->nSize = sizeof(bufferSupplierType); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if (OMX_CORE_INPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else + { + DEBUG_PRINT_ERROR("get_parameter:"\ + "OMX_IndexParamCompBufferSupplier eRet"\ + "%08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + componentRole->nSize = component_Role.nSize; + componentRole->nVersion = component_Role.nVersion; + strlcpy((char *)componentRole->cRole, + (const char*)component_Role.cRole, + sizeof(componentRole->cRole)); + DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n", + component_Role.nSize, + component_Role.nVersion, + component_Role.cRole); + break; + + } + default: + { + DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; + +} + +/** + @brief member function that set paramter from IL client + + @param hComp handle to component instance + @param paramIndex parameter type + @param paramData pointer to memory space which holds the paramter + @return error status + */ +OMX_ERRORTYPE omx_evrc_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("set_parameter is not in proper state\n"); + return OMX_ErrorIncorrectStateOperation; + } + if (paramData == NULL) + { + DEBUG_PRINT("param data is NULL"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamAudioEvrc: + { + DEBUG_PRINT("OMX_IndexParamAudioEvrc"); + OMX_AUDIO_PARAM_AMRTYPE *evrcparam + = (OMX_AUDIO_PARAM_AMRTYPE *) paramData; + memcpy(&m_evrc_param,evrcparam, + sizeof(OMX_AUDIO_PARAM_EVRCTYPE)); + break; + } + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + if (((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources && + ((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == true)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == true))) + ||(((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == false)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == false)) && + (m_state != OMX_StateWaitForResources))) + { + DEBUG_PRINT("Set Parameter called in valid state\n"); + } else + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex " + "= %lu\n",portDefn->nPortIndex); + if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_INPUT_BUFFERS ) + { + m_inp_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS; + } + input_buffer_size = portDefn->nBufferSize; + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_OUTPUT_BUFFERS ) + { + m_out_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS; + } + output_buffer_size = portDefn->nBufferSize; + } else + { + DEBUG_PRINT(" set_parameter: Bad Port idx %d",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamPriorityMgmt: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n"); + + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype + = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n", + priorityMgmtype->nGroupID); + + DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n", + priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + case OMX_IndexParamAudioPortFormat: + { + + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n"); + + if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex) + { + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + portFormatType->nPortIndex) + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\ + " %lu\n", portFormatType->nIndex); + portFormatType->eEncoding = OMX_AUDIO_CodingEVRC; + } else + { + DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \ + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("set_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\ + bufferSupplierType->eBufferSupplier); + + if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX + || bufferSupplierType->nPortIndex == + OMX_CORE_OUTPUT_PORT_INDEX) + { + DEBUG_PRINT("set_parameter:\ + OMX_IndexParamCompBufferSupplier\n"); + m_buffer_supplier.eBufferSupplier = + bufferSupplierType->eBufferSupplier; + } else + { + DEBUG_PRINT_ERROR("set_param:\ + IndexParamCompBufferSup %08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + + break; } + + case OMX_IndexParamAudioPcm: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n"); + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam + = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(&m_pcm_param,pcmparam,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + DEBUG_PRINT("set_pcm_parameter: %lu %lu",\ + m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + } else + { + DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm " + "OMX_ErrorBadPortIndex %d\n", + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamSuspensionPolicy: + { + eRet = OMX_ErrorNotImplemented; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + component_Role.nSize = componentRole->nSize; + component_Role.nVersion = componentRole->nVersion; + strlcpy((char *)component_Role.cRole, + (const char*)componentRole->cRole, + sizeof(component_Role.cRole)); + break; + } + + default: + { + DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::GetConfig + +DESCRIPTION + OMX Get Config Method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *volume = + (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex) + { + volume->nSize = sizeof(volume); + volume->nVersion.nVersion = OMX_SPEC_VERSION; + volume->bLinear = OMX_TRUE; + volume->sVolume.nValue = m_volume; + volume->sVolume.nMax = OMX_AENC_MAX; + volume->sVolume.nMin = OMX_AENC_MIN; + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = + (OMX_AUDIO_CONFIG_MUTETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex) + { + mute->nSize = sizeof(mute); + mute->nVersion.nVersion = OMX_SPEC_VERSION; + mute->bMute = (BITMASK_PRESENT(&m_flags, + OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE); + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::SetConfig + +DESCRIPTION + OMX Set Config method implementation + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Set Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if ( m_state == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *vol = + (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData; + if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if ((vol->sVolume.nValue <= OMX_AENC_MAX) && + (vol->sVolume.nValue >= OMX_AENC_MIN)) + { + m_volume = vol->sVolume.nValue; + if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED)) + { + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + + } else + { + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*) + configData; + if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if (mute->bMute == OMX_TRUE) + { + BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */ + } else + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::GetExtensionIndex + +DESCRIPTION + OMX GetExtensionIndex method implementaion. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::get_extension_index( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + if((hComp == NULL) || (paramName == NULL) || (indexType == NULL)) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId", + strlen("OMX.Qualcomm.index.audio.sessionId")) == 0) + { + *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId; + DEBUG_PRINT("Extension index type - %d\n", *indexType); + + } + else + { + return OMX_ErrorBadParameter; + + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::GetState + +DESCRIPTION + Returns the state information back to the caller. + +PARAMETERS + . + +RETURN VALUE + Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + *state = m_state; + DEBUG_PRINT("Returning the state %d\n",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::ComponentTunnelRequest + +DESCRIPTION + OMX Component Tunnel Request method implementation. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::component_tunnel_request +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n"); + + if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL)) + { + port = 0; + peerPort = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::AllocateInputBuffer + +DESCRIPTION + Helper function for allocate buffer in the input pin + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::allocate_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + if(m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc((nBufSize + \ + sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1); + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + free(buf_ptr); + return OMX_ErrorBadParameter; + } + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+ + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + m_input_buf_hdrs.insert(bufHdr, NULL); + + m_inp_current_buf_count++; + DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%u \ + bytes=%lu", bufHdr, bufHdr->pBuffer, + m_inp_current_buf_count, bytes); + + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } + else + { + DEBUG_PRINT("Input buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +OMX_ERRORTYPE omx_evrc_aenc::allocate_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_out_current_buf_count < m_out_act_buf_count) + { + buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d "\ + "bytes=%lu",bufHdr, bufHdr->pBuffer,\ + m_out_current_buf_count, bytes); + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== +FUNCTION + omx_evrc_aenc::AllocateBuffer + +DESCRIPTION + Returns zero if all the buffers released.. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::allocate_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n"); + return OMX_ErrorInvalidState; + } + // What if the client calls again. + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n", + (int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("allocate_buffer: before allocate_done \n"); + if (allocate_done()) + { + DEBUG_PRINT("allocate_buffer: after allocate_done \n"); + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("allocate_buffer: post idle transition event \n"); + } + DEBUG_PRINT("allocate_buffer: complete \n"); + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + m_out_bEnabled = OMX_TRUE; + + DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("AB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet); + return eRet; +} + +/*============================================================================= +FUNCTION: + use_buffer + +DESCRIPTION: + OMX Use Buffer method implementation. + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_evrc_aenc::use_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("Checking for Output Allocate buffer Done"); + if (allocate_done()) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("UB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + } + } + DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet); + return eRet; +} +/*============================================================================= +FUNCTION: + use_input_buffer + +DESCRIPTION: + Helper function for Use buffer in the input pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_evrc_aenc::use_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if(bytes < input_buffer_size) + { + /* return if i\p buffer size provided by client + is less than min i\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + if (m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \ + bytes=%lu", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + input_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_input_buf_hdrs.insert(bufHdr, NULL); + m_inp_current_buf_count++; + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Input buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/*============================================================================= +FUNCTION: + use_output_buffer + +DESCRIPTION: + Helper function for Use buffer in the output pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_evrc_aenc::use_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (bytes < output_buffer_size) + { + /* return if o\p buffer size provided by client + is less than min o\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT("Inside omx_evrc_aenc::use_output_buffer"); + if (m_out_current_buf_count < m_out_act_buf_count) + { + + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer); + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \ + len=%lu\n", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + output_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_evrc_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_input_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_input_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_evrc_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_output_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_output_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +// Free Buffer - API call +/** + @brief member function that handles free buffer command from IL client + + This function is a block-call function that handles IL client request to + freeing the buffer + + @param hComp handle to component instance + @param port id of port which holds the buffer + @param buffer buffer header + @return Error status +*/ +OMX_ERRORTYPE omx_evrc_aenc::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("Free_Buffer buf %p\n", buffer); + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + DEBUG_PRINT(" free buffer while Component in Loading pending\n"); + } else if ((m_inp_bEnabled == OMX_FALSE && + port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && + port == OMX_CORE_OUTPUT_PORT_INDEX)) + { + DEBUG_PRINT("Free Buffer while port %lu disabled\n", port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) + { + DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\ + OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return eRet; + } else + { + DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\ + disabled:OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + if (m_inp_current_buf_count != 0) + { + m_inp_bPopulated = OMX_FALSE; + if (true == search_input_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer); + m_input_buf_hdrs.erase(buffer); + free(buffer); + m_inp_current_buf_count--; + } else + { + DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \ + Invalid Input buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \ + came out Invalid\n"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_done(0)) + { + DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + if (m_out_current_buf_count != 0) + { + m_out_bPopulated = OMX_FALSE; + if (true == search_output_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer); + m_output_buf_hdrs.erase(buffer); + free(buffer); + m_out_current_buf_count--; + } else + { + DEBUG_PRINT("Free_Buf:Error-->free_buffer , \ + Invalid Output buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_done(1)) + { + DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + if ((OMX_ErrorNone == eRet) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + if (release_done(-1)) + { + if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0) + DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n"); + else + DEBUG_PRINT("AUDIO STOP in free buffer passed\n"); + + + DEBUG_PRINT("Free_Buf: Free buffer\n"); + + + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + DEBUG_PRINT("Before OMX_StateLoaded \ + OMX_COMPONENT_GENERATE_EVENT\n"); + post_command(OMX_CommandStateSet, + OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n"); + + } + } + return eRet; +} + + +/** + @brief member function that that handles empty this buffer command + + This function meremly queue up the command and data would be consumed + in command server thread context + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_evrc_aenc::empty_this_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \ + buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf)); + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT("Empty this buffer in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (!m_inp_bEnabled) + { + DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\ + "Port Status %d \n", m_inp_bEnabled); + return OMX_ErrorIncorrectStateOperation; + } + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_evrc_aenc::etb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_evrc_aenc::etb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + if ((m_state != OMX_StateExecuting) && + (m_state != OMX_StatePause)) + { + DEBUG_PRINT_ERROR("Invalid state\n"); + eRet = OMX_ErrorInvalidState; + } + if (OMX_ErrorNone == eRet) + { + if (search_input_bufhdr(buffer) == true) + { + post_input((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB); + } else + { + DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer); + eRet = OMX_ErrorBadParameter; + } + } + pthread_mutex_lock(&in_buf_count_lock); + nNumInputBuf++; + m_evrc_pb_stats.etb_cnt++; + pthread_mutex_unlock(&in_buf_count_lock); + return eRet; +} +/** + @brief member function that writes data to kernel driver + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_evrc_aenc::empty_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + META_IN meta_in; + //Pointer to the starting location of the data to be transcoded + OMX_U8 *srcStart; + //The total length of the data to be transcoded + srcStart = buffer->pBuffer; + OMX_U8 *data = NULL; + PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer); + memset(&meta_in,0,sizeof(meta_in)); + if ( search_input_bufhdr(buffer) == false ) + { + DEBUG_PRINT("ETBP: INVALID BUF HDR\n"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorBadParameter; + } + if (m_tmp_meta_buf) + { + data = m_tmp_meta_buf; + + // copy the metadata info from the BufHdr and insert to payload + meta_in.offsetVal = sizeof(META_IN); + meta_in.nTimeStamp.LowPart = + ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF); + meta_in.nTimeStamp.HighPart = + (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF); + meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS; + if(buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT("EOS OCCURED \n"); + meta_in.nFlags |= OMX_BUFFERFLAG_EOS; + } + memcpy(data,&meta_in, meta_in.offsetVal); + DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags); + } + + memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen); + write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN)); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (OMX_StateExecuting == state) + { + DEBUG_DETAIL("In Exe state, EBD CB"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + } else + { + /* Assume empty this buffer function has already checked + validity of buffer */ + DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer); + post_input((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_BUFFER_DONE); + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_evrc_aenc::fill_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + ENC_META_OUT *meta_out = NULL; + int nReadbytes = 0; + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (true == search_output_bufhdr(buffer)) + { + DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd); + nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size ); + DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\ + buffer->nAllocLen,buffer->pBuffer, + nReadbytes,nNumOutputBuf); + if (nReadbytes <= 0) { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorNone; + } else + DEBUG_PRINT("Read bytes %d\n",nReadbytes); + // Buffer from Driver will have + // 1 byte => Nr of frame field + // (sizeof(ENC_META_OUT) * Nr of frame) bytes => meta_out->offset_to_frame + // Frame Size * Nr of frame => + + meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char)); + buffer->nTimeStamp = (((OMX_TICKS) meta_out->msw_ts << 32)+ + meta_out->lsw_ts); + buffer->nFlags |= meta_out->nflags; + buffer->nOffset = meta_out->offset_to_frame + sizeof(unsigned char); + buffer->nFilledLen = nReadbytes - buffer->nOffset; + nTimestamp = buffer->nTimeStamp; + DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \ + timestamp %lld\n", meta_out->nflags, + meta_out->frame_size, meta_out->offset_to_frame, + buffer->nTimeStamp); + + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n"); + m_cb.EventHandler(&m_cmp, + m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + } + + return OMX_ErrorNone; + } + DEBUG_PRINT("nState %d \n",nState ); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (state == OMX_StatePause) + { + DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\ + state); + post_output((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_FRAME_DONE); + } + else + { + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + + } + + } + else + DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n"); + + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::FillThisBuffer + +DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + + +PARAMETERS + + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::fill_this_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_evrc_aenc::ftb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (m_out_bEnabled == OMX_FALSE) + { + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_evrc_aenc::ftb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf++; + m_evrc_pb_stats.ftb_cnt++; + DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf); + pthread_mutex_unlock(&out_buf_count_lock); + post_output((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB); + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::SetCallbacks + +DESCRIPTION + Set the callbacks. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + m_cb = *callbacks; + m_app_data = appData; + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::ComponentDeInit + +DESCRIPTION + Destroys the component and release memory allocated to the heap. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state) + { + DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n", + m_state); + } + deinit_encoder(); + +DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::deinit_encoder + +DESCRIPTION + Closes all the threads and release memory allocated to the heap. + +PARAMETERS + None. + +RETURN VALUE + None. + +========================================================================== */ +void omx_evrc_aenc::deinit_encoder() +{ + DEBUG_PRINT("Component-deinit being processed\n"); + DEBUG_PRINT("********************************\n"); + DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\ + m_evrc_pb_stats.tot_in_buf_len, + m_evrc_pb_stats.tot_out_buf_len, + m_evrc_pb_stats.tot_pb_time); + DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\ + m_evrc_pb_stats.fbd_cnt,m_evrc_pb_stats.ftb_cnt, + m_evrc_pb_stats.etb_cnt, + m_evrc_pb_stats.ebd_cnt); + memset(&m_evrc_pb_stats,0,sizeof(EVRC_PB_STATS)); + + if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state)) + { + DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\ + m_state); + // Get back any buffers from driver + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + // force state change to loaded so that all threads can be exited + pthread_mutex_lock(&m_state_lock); + m_state = OMX_StateLoaded; + pthread_mutex_unlock(&m_state_lock); + DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\ + m_inp_current_buf_count, + m_input_buf_hdrs.size()); + m_input_buf_hdrs.eraseall(); + DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\ + m_out_current_buf_count, + m_output_buf_hdrs.size()); + m_output_buf_hdrs.eraseall(); + + } + if(pcm_input) + { + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + if(pcm_input) + { + if (m_ipc_to_in_th != NULL) + { + omx_evrc_thread_stop(m_ipc_to_in_th); + m_ipc_to_in_th = NULL; + } + } + + if (m_ipc_to_cmd_th != NULL) + { + omx_evrc_thread_stop(m_ipc_to_cmd_th); + m_ipc_to_cmd_th = NULL; + } + if (m_ipc_to_out_th != NULL) + { + DEBUG_DETAIL("Inside omx_evrc_thread_stop\n"); + omx_evrc_thread_stop(m_ipc_to_out_th); + m_ipc_to_out_th = NULL; + } + + + if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0) + DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n"); + + if(pcm_input && m_tmp_meta_buf ) + { + free(m_tmp_meta_buf); + } + + if(m_tmp_out_meta_buf) + { + free(m_tmp_out_meta_buf); + } + nNumInputBuf = 0; + nNumOutputBuf = 0; + bFlushinprogress = 0; + + m_inp_current_buf_count=0; + m_out_current_buf_count=0; + m_out_act_buf_count = 0; + m_inp_act_buf_count = 0; + m_inp_bEnabled = OMX_FALSE; + m_out_bEnabled = OMX_FALSE; + m_inp_bPopulated = OMX_FALSE; + m_out_bPopulated = OMX_FALSE; + + if ( m_drv_fd >= 0 ) + { + if(close(m_drv_fd) < 0) + DEBUG_PRINT("De-init: Driver Close Failed \n"); + m_drv_fd = -1; + } + else + { + DEBUG_PRINT_ERROR(" EVRC device already closed\n"); + } + m_comp_deinit=1; + m_is_out_th_sleep = 1; + m_is_in_th_sleep = 1; + DEBUG_PRINT("************************************\n"); + DEBUG_PRINT(" DEINIT COMPLETED"); + DEBUG_PRINT("************************************\n"); + +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::UseEGLImage + +DESCRIPTION + OMX Use EGL Image method implementation . + +PARAMETERS + . + +RETURN VALUE + Not Implemented error. + +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::use_EGL_image +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n"); + + if((hComp == NULL) || (appData == NULL) || (eglImage == NULL)) + { + bufferHdr = NULL; + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::ComponentRoleEnum + +DESCRIPTION + OMX Component Role Enum method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_evrc_aenc::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + const char *cmp_role = "audio_encoder.evrc"; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (index == 0 && role) + { + memcpy(role, cmp_role, sizeof(cmp_role)); + *(((char *) role) + sizeof(cmp_role)) = '\0'; + } else + { + eRet = OMX_ErrorNoMore; + } + return eRet; +} + + + + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::AllocateDone + +DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + +PARAMETERS + None. + +RETURN VALUE + true/false. + +========================================================================== */ +bool omx_evrc_aenc::allocate_done(void) +{ + OMX_BOOL bRet = OMX_FALSE; + if (pcm_input==1) + { + if ((m_inp_act_buf_count == m_inp_current_buf_count) + &&(m_out_act_buf_count == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + + } + if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled ) + { + m_inp_bPopulated = OMX_TRUE; + } + + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + } else if (pcm_input==0) + { + if (m_out_act_buf_count == m_out_current_buf_count) + { + bRet=OMX_TRUE; + + } + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + + } + return bRet; +} + + +/* ====================================================================== +FUNCTION + omx_evrc_aenc::ReleaseDone + +DESCRIPTION + Checks if IL client has released all the buffers. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +bool omx_evrc_aenc::release_done(OMX_U32 param1) +{ + DEBUG_PRINT("Inside omx_evrc_aenc::release_done"); + OMX_BOOL bRet = OMX_FALSE; + + if (param1 == OMX_ALL) + { + if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_INPUT_PORT_INDEX ) + { + if ((0 == m_inp_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX) + { + if ((0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } + return bRet; +} diff --git a/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c b/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c new file mode 100644 index 000000000..e01759e84 --- /dev/null +++ b/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif + + +#include + +typedef unsigned char uint8; +typedef unsigned char byte; +typedef unsigned int uint32; +typedef unsigned int uint16; +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; +/* maximum ADTS frame header length */ +void Release_Encoder(); + +#ifdef AUDIOV2 +unsigned short session_id; +int device_id; +int control = 0; +const char *device="handset_tx"; +#define DIR_TX 2 +#endif + +uint32_t samplerate = 8000; +uint32_t channels = 1; +uint32_t min_bitrate = 0; +uint32_t max_bitrate = 0; +uint32_t cdmarate = 0; +uint32_t rectime = -1; +uint32_t recpath = -1; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t format = 1; +#define DEBUG_PRINT printf +unsigned to_idle_transition = 0; +unsigned long total_pcm_bytes; + +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define QCP_HEADER_SIZE sizeof(struct qcp_header) +#define MIN_BITRATE 4 /* Bit rate 1 - 13.6 , 2 - 6.2 , 3 - 2.7 , 4 - 1.0 kbps*/ +#define MAX_BITRATE 4 + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +pthread_mutex_t lock; +pthread_cond_t cond; +pthread_mutex_t elock; +pthread_cond_t econd; +pthread_cond_t fcond; +pthread_mutex_t etb_lock; +pthread_mutex_t etb_lock1; +pthread_cond_t etb_cond; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; +OMX_AUDIO_PARAM_EVRCTYPE evrcparam; +OMX_AUDIO_PARAM_PCMMODETYPE pcmparam; +OMX_PORT_PARAM_TYPE portParam; +OMX_PORT_PARAM_TYPE portFmt; +OMX_ERRORTYPE error; + + + + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; +struct enc_meta_out{ + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; +} __attribute__ ((packed)); + +struct qcp_header { + /* RIFF Section */ + char riff[4]; + unsigned int s_riff; + char qlcm[4]; + + /* Format chunk */ + char fmt[4]; + unsigned int s_fmt; + char mjr; + char mnr; + unsigned int data1; /* UNIQUE ID of the codec */ + unsigned short data2; + unsigned short data3; + char data4[8]; + unsigned short ver; /* Codec Info */ + char name[80]; + unsigned short abps; /* average bits per sec of the codec */ + unsigned short bytes_per_pkt; + unsigned short samp_per_block; + unsigned short samp_per_sec; + unsigned short bits_per_samp; + unsigned char vr_num_of_rates; /* Rate Header fmt info */ + unsigned char rvd1[3]; + unsigned short vr_bytes_per_pkt[8]; + unsigned int rvd2[5]; + + /* Vrat chunk */ + unsigned char vrat[4]; + unsigned int s_vrat; + unsigned int v_rate; + unsigned int size_in_pkts; + + /* Data chunk */ + unsigned char data[4]; + unsigned int s_data; +} __attribute__ ((packed)); + + /* Common part */ + static struct qcp_header append_header = { + {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, + {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, + {'v','r','a','t'},0, 0, 0,{'d','a','t','a'},0 + }; + +static unsigned totaldatalen = 0; +static unsigned framecnt = 0; +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +volatile int etb_event_is_done = 0; +int ebd_cnt; +int bInputEosReached = 0; +int bOutputEosReached = 0; +int bInputEosReached_tunnel = 0; +static int etb_done = 0; +int bFlushing = false; +int bPause = false; +const char *in_filename; +const char *out_filename; + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* evrc_enc_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Encoder(char*); +int Play_Encoder(); +OMX_STRING aud_comp; +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *evrc_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +static OMX_ERRORTYPE parse_pcm_header(); +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock1); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock1); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock1); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock1); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock1); +} + +static void create_qcp_header(int Datasize, int Frames) +{ + append_header.s_riff = Datasize + QCP_HEADER_SIZE - 8; + /* exclude riff id and size field */ + append_header.data1 = 0xe689d48d; + append_header.data2 = 0x9076; + append_header.data3 = 0x46b5; + append_header.data4[0] = 0x91; + append_header.data4[1] = 0xef; + append_header.data4[2] = 0x73; + append_header.data4[3] = 0x6a; + append_header.data4[4] = 0x51; + append_header.data4[5] = 0x00; + append_header.data4[6] = 0xce; + append_header.data4[7] = 0xb4; + append_header.ver = 0x0001; + memcpy(append_header.name, "TIA IS-127 Enhanced Variable Rate Codec, Speech Service Option 3", 64); + append_header.abps = 9600; + append_header.bytes_per_pkt = 23; + append_header.vr_num_of_rates = 4; + append_header.vr_bytes_per_pkt[0] = 0x0416; + append_header.vr_bytes_per_pkt[1] = 0x030a; + append_header.vr_bytes_per_pkt[2] = 0x0200; + append_header.vr_bytes_per_pkt[3] = 0x0102; + append_header.s_vrat = 0x00000008; + append_header.v_rate = 0x00000001; + append_header.size_in_pkts = Frames; + append_header.s_data = Datasize; + return; +} + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + switch(eEvent) { + case OMX_EventCmdComplete: + DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent, + nData1,nData2); + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("\n OMX_EventError \n"); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("\n OMX_EventBufferFlag \n"); + bOutputEosReached = true; + event_complete(); + break; + case OMX_EventPortSettingsChanged: + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + size_t bytes_writen = 0; + int total_bytes_writen = 0; + unsigned int len = 0; + struct enc_meta_out *meta = NULL; + OMX_U8 *src = pBuffer->pBuffer; + unsigned int num_of_frames = 1; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT("FBD::EOS on output port\n "); + bOutputEosReached = true; + return OMX_ErrorNone; + } + if(bInputEosReached_tunnel || bOutputEosReached) + { + DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n"); + return OMX_ErrorNone; + } + if(num_of_frames != src[0]){ + + printf("Data corrupt\n"); + return OMX_ErrorNone; + } + /* Skip the first bytes */ + + + + src += sizeof(unsigned char); + meta = (struct enc_meta_out *)src; + while (num_of_frames > 0) { + meta = (struct enc_meta_out *)src; + /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n", + meta->offset_to_frame, + meta->frame_size, + meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/ + len = meta->frame_size; + + bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile); + if(bytes_writen < len) + { + DEBUG_PRINT("error: invalid EVRC encoded data \n"); + return OMX_ErrorNone; + } + src += sizeof(struct enc_meta_out); + num_of_frames--; + total_bytes_writen += len; + } + DEBUG_PRINT(" FillBufferDone size writen to file %d count %d\n",total_bytes_writen, framecnt); + totaldatalen += total_bytes_writen ; + framecnt++; + + DEBUG_PRINT(" FBD calling FTB\n"); + OMX_FillThisBuffer(hComponent,pBuffer); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock); + } + + + if(bInputEosReached) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + }else if (bFlushing == true) { + DEBUG_PRINT("omx_evrc13_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (used_ip_buf_cnt == 0) { + bFlushing = false; + } else { + DEBUG_PRINT("omx_evrc13_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + return OMX_ErrorNone; + } + } + + if((readBytes = Read_Buffer(pBuffer)) > 0) { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else{ + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + bInputEosReached = true; + pBuffer->nFilledLen = 0; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) { + + /* Flush */ + if (sig_id == SIGUSR1) { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(evrc_enc_handle, OMX_CommandFlush, OMX_ALL, NULL); + } else if (sig_id == SIGUSR2) { + if (bPause == true) { + DEBUG_PRINT("%s resume record\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } else { + DEBUG_PRINT("%s pause record\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + (void) signal(SIGINT, Release_Encoder); + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + + if (argc >= 9) { + in_filename = argv[1]; + out_filename = argv[2]; + tunnel = atoi(argv[3]); + min_bitrate = atoi(argv[4]); + max_bitrate = atoi(argv[5]); + cdmarate = atoi(argv[6]); + recpath = atoi(argv[7]); // No configuration support yet.. + rectime = atoi(argv[8]); + + } else { + DEBUG_PRINT(" invalid format: \n"); + DEBUG_PRINT("ex: ./mm-aenc-omxevrc-test INPUTFILE OUTPUTFILE Tunnel MINRATE MAXRATE CDMARATE RECORDPATH RECORDTIME\n"); + DEBUG_PRINT("MINRATE MAXRATE and CDMARATE 1 to 4\n"); + DEBUG_PRINT("RECORDPATH 0(TX),1(RX),2(BOTH),3(MIC)\n"); + DEBUG_PRINT("RECORDTIME in seconds for AST Automation\n"); + return 0; + } + if(recpath != 3) { + DEBUG_PRINT("For RECORDPATH Only MIC supported\n"); + return 0; + } + if(tunnel == 0) + aud_comp = "OMX.qcom.audio.encoder.evrc"; + else + aud_comp = "OMX.qcom.audio.encoder.tunneled.evrc"; + if(Init_Encoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + fcntl(0, F_SETFL, O_NONBLOCK); + + if(Play_Encoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + if(rectime && tunnel) + { + sleep(rectime); + rectime = 0; + bInputEosReached_tunnel = 1; + DEBUG_PRINT("\EOS ON INPUT PORT\n"); + } + else + { + wait_for_event(); + } + + if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel)) + { + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + + DEBUG_PRINT("\nMoving the encoder to loaded state \n"); + OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + sleep(1); + if (!tunnel) + { + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(evrc_enc_handle, 0, pInputBufHdrs[bufCnt]); + } + } + + DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(evrc_enc_handle, 1, pOutputBufHdrs[bufCnt]); + } + wait_for_event(); + create_qcp_header(totaldatalen, framecnt); + fseek(outputBufferFile, 0,SEEK_SET); + fwrite(&append_header,1,QCP_HEADER_SIZE,outputBufferFile); + + + result = OMX_FreeHandle(evrc_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + if(tunnel) + { + #ifdef AUDIOV2 + if (msm_route_stream(DIR_TX,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + #endif + } + OMX_Deinit(); + ebd_cnt=0; + bOutputEosReached = false; + bInputEosReached_tunnel = false; + bInputEosReached = 0; + evrc_enc_handle = NULL; + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + fclose(outputBufferFile); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...EVRC ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + return 0; +} + +void Release_Encoder() +{ + static int cnt=0; + OMX_ERRORTYPE result; + + DEBUG_PRINT("END OF EVRC ENCODING: EXITING PLEASE WAIT\n"); + bInputEosReached_tunnel = 1; + event_complete(); + cnt++; + if(cnt > 1) + { + /* FORCE RESET */ + evrc_enc_handle = NULL; + ebd_cnt=0; + bInputEosReached_tunnel = false; + + result = OMX_FreeHandle(evrc_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + + OMX_Deinit(); + + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...EVRC ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + exit(0); + } +} + +int Init_Encoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + typedef OMX_U8* OMX_U8_PTR; + char *role ="audio_encoder"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Evrc_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total); + + + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&evrc_enc_handle), + (OMX_STRING)audio_component, NULL, &call_back); + if (FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component); + return -1; + } + else + { + DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(portParam); + omxresult = OMX_GetParameter(evrc_enc_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&portParam); + + if(FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to get Port Param\n"); + return -1; + } + else + { + DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts); + DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n", + portParam.nStartPortNumber); + } + + if(OMX_ErrorNone != omxresult) + { + DEBUG_PRINT("Set parameter failed"); + } + + return 0; +} + +int Play_Encoder() +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file()) { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + + /* Query the encoder input min buf requirements */ + CONFIG_VERSION_SIZE(inputportFmt); + + /* Port for which the Client needs to obtain info */ + inputportFmt.nPortIndex = portParam.nStartPortNumber; + + OMX_GetParameter(evrc_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt); + DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize); + + if(OMX_DirInput != inputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Input Port\n"); + return -1; + } + + pcmparam.nPortIndex = 0; + pcmparam.nChannels = channels; + pcmparam.nSamplingRate = samplerate; + OMX_SetParameter(evrc_enc_handle,OMX_IndexParamAudioPcm,&pcmparam); + + + /* Query the encoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(evrc_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Output Port\n"); + return -1; + } + + + CONFIG_VERSION_SIZE(evrcparam); + + evrcparam.nPortIndex = 1; + evrcparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/ + evrcparam.nMinBitRate = min_bitrate; + evrcparam.nMaxBitRate = max_bitrate; + OMX_SetParameter(evrc_enc_handle,OMX_IndexParamAudioEvrc,&evrcparam); + OMX_GetExtensionIndex(evrc_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index); + OMX_GetParameter(evrc_enc_handle,index,&streaminfoparam); + if(tunnel) { + #ifdef AUDIOV2 + session_id = streaminfoparam.sessionId; + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + if (msm_route_stream(DIR_TX,session_id,device_id, 1)) + { + perror("could not set stream routing\n"); + return -1; + } + #endif + } + + DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n"); + OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + if (tunnel == 0) + { + input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(evrc_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pInputBufHdrs == NULL) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + } + output_buf_cnt = outputportFmt.nBufferCountMin ; + + /* Allocate buffer on encoder's O/Pp port */ + error = Allocate_Buffer(evrc_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pOutputBufHdrs == NULL) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + + if (tunnel == 1) + { + DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n"); + OMX_SendCommand(evrc_enc_handle, OMX_CommandPortDisable,0,0); // disable input port + wait_for_event(); + } + + DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n"); + OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(evrc_enc_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + +if(tunnel == 0) +{ + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) { + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + bInputEosReached = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + ret = OMX_EmptyThisBuffer(evrc_enc_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock); + if(etb_done) +{ + DEBUG_PRINT("Component is waiting for EBD to be released.\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock); +} + + return 0; +} + + + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + + /* To remove warning for unused variable to keep prototype same */ + (void)avc_enc_handle; + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(evrc_enc_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + + + + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + + int bytes_read=0; + + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + + bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile); + + pBufHdr->nFilledLen = bytes_read; + // Time stamp logic + ((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp = \ + + (unsigned long) ((total_pcm_bytes * 1000)/(samplerate * channels *2)); + + DEBUG_PRINT ("\n--time stamp -- %ld\n", (unsigned long)((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp); + if(bytes_read == 0) + { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + + total_pcm_bytes += bytes_read; + } + + return bytes_read;; +} + + + +//In Encoder this Should Open a PCM or WAV file for input. + +static int open_audio_file () +{ + int error_code = 0; + + if (!tunnel) + { + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); + inputBufferFile = fopen (in_filename, "rb"); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + } + if(parse_pcm_header() != 0x00) + { + DEBUG_PRINT("PCM parser failed \n"); + return -1; + } + } + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename); + outputBufferFile = fopen (out_filename, "wb"); + if (outputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + out_filename); + error_code = -1; + return error_code; + } + fseek(outputBufferFile, QCP_HEADER_SIZE, SEEK_SET); + return error_code; +} + +static OMX_ERRORTYPE parse_pcm_header() +{ + struct wav_header hdr; + + DEBUG_PRINT("\n***************************************************************\n"); + if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr)) + { + DEBUG_PRINT("Wav file cannot read header\n"); + return -1; + } + + if ((hdr.riff_id != ID_RIFF) || + (hdr.riff_fmt != ID_WAVE)|| + (hdr.fmt_id != ID_FMT)) + { + DEBUG_PRINT("Wav file is not a riff/wave file\n"); + return -1; + } + + if (hdr.audio_format != FORMAT_PCM) + { + DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n", + hdr.audio_format, hdr.fmt_sz); + return -1; + } + + DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate); + DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels); + DEBUG_PRINT("\n***************************************************************\n"); + + samplerate = hdr.sample_rate; + channels = hdr.num_channels; + total_pcm_bytes = 0; + + return OMX_ErrorNone; +} diff --git a/mm-audio/aenc-qcelp13/Android.mk b/mm-audio/aenc-qcelp13/Android.mk new file mode 100644 index 000000000..d8b589c96 --- /dev/null +++ b/mm-audio/aenc-qcelp13/Android.mk @@ -0,0 +1,23 @@ +ifeq ($(TARGET_ARCH),arm) + + +AENC_QCELP13_PATH:= $(call my-dir) + +ifeq ($(call is-board-platform,msm8660),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8960),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8974),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8226),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif +ifeq ($(call is-board-platform,msm8610),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif + + +endif diff --git a/mm-audio/aenc-qcelp13/Makefile b/mm-audio/aenc-qcelp13/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/mm-audio/aenc-qcelp13/Makefile @@ -0,0 +1,6 @@ +all: + @echo "invoking omxaudio make" + $(MAKE) -C qdsp6 + +install: + $(MAKE) -C qdsp6 install diff --git a/mm-audio/aenc-qcelp13/qdsp6/Android.mk b/mm-audio/aenc-qcelp13/qdsp6/Android.mk new file mode 100644 index 000000000..5aaa3bf7d --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/Android.mk @@ -0,0 +1,78 @@ +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libOmxQcelp13Enc-def := -g -O3 +libOmxQcelp13Enc-def += -DQC_MODIFIED +libOmxQcelp13Enc-def += -D_ANDROID_ +libOmxQcelp13Enc-def += -D_ENABLE_QC_MSG_LOG_ +libOmxQcelp13Enc-def += -DVERBOSE +libOmxQcelp13Enc-def += -D_DEBUG +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +libOmxQcelp13Enc-def += -DAUDIOV2 +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxQcelp13Enc) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +libOmxQcelp13Enc-inc := $(LOCAL_PATH)/inc +libOmxQcelp13Enc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore + +LOCAL_MODULE := libOmxQcelp13Enc +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxQcelp13Enc-def) +LOCAL_C_INCLUDES := $(libOmxQcelp13Enc-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libutils liblog + +LOCAL_SRC_FILES := src/aenc_svr.c +LOCAL_SRC_FILES += src/omx_qcelp13_aenc.cpp + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + + +include $(BUILD_SHARED_LIBRARY) + + +# --------------------------------------------------------------------------------- +# Make the apps-test (mm-aenc-omxqcelp13-test) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +mm-qcelp13-enc-test-inc := $(LOCAL_PATH)/inc +mm-qcelp13-enc-test-inc += $(LOCAL_PATH)/test + +mm-qcelp13-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +mm-qcelp13-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa +endif +LOCAL_MODULE := mm-aenc-omxqcelp13-test +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libOmxQcelp13Enc-def) +LOCAL_C_INCLUDES := $(mm-qcelp13-enc-test-inc) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := libmm-omxcore +LOCAL_SHARED_LIBRARIES += libOmxQcelp13Enc +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) +LOCAL_SHARED_LIBRARIES += libaudioalsa +endif +LOCAL_SRC_FILES := test/omx_qcelp13_enc_test.c + +include $(BUILD_EXECUTABLE) + +endif + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- + diff --git a/mm-audio/aenc-qcelp13/qdsp6/Makefile b/mm-audio/aenc-qcelp13/qdsp6/Makefile new file mode 100644 index 000000000..b14655bda --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/Makefile @@ -0,0 +1,81 @@ +# --------------------------------------------------------------------------------- +# MM-AUDIO-OSS-8K-AENC-QCELP13 +# --------------------------------------------------------------------------------- + +# cross-compiler flags +CFLAGS += -Wall +CFLAGS += -Wundef +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wno-trigraphs + +# cross-compile flags specific to shared objects +CFLAGS_SO += -fpic + +# required pre-processor flags +CPPFLAGS := -D__packed__= +CPPFLAGS += -DIMAGE_APPS_PROC +CPPFLAGS += -DFEATURE_Q_SINGLE_LINK +CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR +CPPFLAGS += -DFEATURE_LINUX +CPPFLAGS += -DFEATURE_NATIVELINUX +CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS + +CPPFLAGS += -g +CPPFALGS += -D_DEBUG +CPPFLAGS += -Iinc + +# linker flags +LDFLAGS += -L$(SYSROOT)/usr/lib + +# linker flags for shared objects +LDFLAGS_SO := -shared + +# defintions +LIBMAJOR := $(basename $(basename $(LIBVER))) +LIBINSTALLDIR := $(DESTDIR)usr/lib +INCINSTALLDIR := $(DESTDIR)usr/include +BININSTALLDIR := $(DESTDIR)usr/bin + +# --------------------------------------------------------------------------------- +# BUILD +# --------------------------------------------------------------------------------- +all: libOmxQcelp13Enc.so.$(LIBVER) mm-aenc-omxqcelp13-test + +install: + echo "intalling aenc-qcelp13 in $(DESTDIR)" + if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi + if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi + if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi + install -m 555 libOmxQcelp13Enc.so.$(LIBVER) $(LIBINSTALLDIR) + cd $(LIBINSTALLDIR) && ln -s libOmxQcelp13Enc.so.$(LIBVER) libOmxQcelp13Enc.so.$(LIBMAJOR) + cd $(LIBINSTALLDIR) && ln -s libOmxQcelp13Enc.so.$(LIBMAJOR) libOmxQcelp13Enc.so + install -m 555 mm-aenc-omxqcelp13-test $(BININSTALLDIR) + +# --------------------------------------------------------------------------------- +# COMPILE LIBRARY +# --------------------------------------------------------------------------------- +LDLIBS := -lpthread +LDLIBS += -lstdc++ +LDLIBS += -lOmxCore + +SRCS := src/omx_qcelp13_aenc.cpp +SRCS += src/aenc_svr.c + +libOmxQcelp13Enc.so.$(LIBVER): $(SRCS) + $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxQcelp13Enc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +# --------------------------------------------------------------------------------- +# COMPILE TEST APP +# --------------------------------------------------------------------------------- +TEST_LDLIBS := -lpthread +TEST_LDLIBS += -ldl +TEST_LDLIBS += -lOmxCore + +TEST_SRCS := test/omx_qcelp13_enc_test.c + +mm-aenc-omxqcelp13-test: libOmxQcelp13Enc.so.$(LIBVER) $(TEST_SRCS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS) + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h b/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h @@ -0,0 +1,244 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _MAP_H_ +#define _MAP_H_ + +#include +using namespace std; + +template +class Map +{ + struct node + { + T data; + T2 data2; + node* prev; + node* next; + node(T t, T2 t2,node* p, node* n) : + data(t), data2(t2), prev(p), next(n) {} + }; + node* head; + node* tail; + node* tmp; + unsigned size_of_list; + static Map *m_self; +public: + Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {} + bool empty() const { return ( !head || !tail ); } + operator bool() const { return !empty(); } + void insert(T,T2); + void show(); + int size(); + T2 find(T); // Return VALUE + T find_ele(T);// Check if the KEY is present or not + T2 begin(); //give the first ele + bool erase(T); + bool eraseall(); + bool isempty(); + ~Map() + { + while(head) + { + node* temp(head); + head=head->next; + size_of_list--; + delete temp; + } + } +}; + +template +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::insert(T data, T2 data2) +{ + tail = new node(data, data2,tail, NULL); + if( tail->prev ) + tail->prev->next = tail; + + if( empty() ) + { + head = tail; + tmp=head; + } + tmp = head; + size_of_list++; +} + +template +bool Map::erase(T d) +{ + bool found = false; + tmp = head; + node* prevnode = tmp; + node *tempnode; + + while(tmp) + { + if((head == tail) && (head->data == d)) + { + found = true; + tempnode = head; + head = tail = NULL; + delete tempnode; + break; + } + if((tmp ==head) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + tmp = tmp->next; + tmp->prev = NULL; + head = tmp; + tempnode->next = NULL; + delete tempnode; + break; + } + if((tmp == tail) && (tmp->data ==d)) + { + found = true; + tempnode = tmp; + prevnode->next = NULL; + tmp->prev = NULL; + tail = prevnode; + delete tempnode; + break; + } + if(tmp->data == d) + { + found = true; + prevnode->next = tmp->next; + tmp->next->prev = prevnode->next; + tempnode = tmp; + //tmp = tmp->next; + delete tempnode; + break; + } + prevnode = tmp; + tmp = tmp->next; + } + if(found)size_of_list--; + return found; +} + +template +bool Map::eraseall() +{ + // Be careful while using this method + // it not only removes the node but FREES(not delete) the allocated + // memory. + node *tempnode; + tmp = head; + while(head) + { + tempnode = head; + head = head->next; + tempnode->next = NULL; + if(tempnode->data) + free(tempnode->data); + if(tempnode->data2) + free(tempnode->data2); + delete tempnode; + } + tail = head = NULL; + return true; +} + + +template +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..940d863ae --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h @@ -0,0 +1,120 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef AENC_SVR_H +#define AENC_SVR_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include + +#ifdef _ANDROID_ +#define LOG_TAG "QC_QCELP13ENC" +#endif + +#ifndef LOGE +#define LOGE ALOGE +#endif + +#ifndef LOGW +#define LOGW ALOGW +#endif + +#ifndef LOGD +#define LOGD ALOGD +#endif + +#ifndef LOGV +#define LOGV ALOGV +#endif + +#ifndef LOGI +#define LOGI ALOGI +#endif + +#define DEBUG_PRINT_ERROR LOGE +#define DEBUG_PRINT LOGI +#define DEBUG_DETAIL LOGV + +typedef void (*message_func)(void* client_data, unsigned char id); + +/** + @brief audio encoder ipc info structure + + */ +struct qcelp13_ipc_info +{ + pthread_t thr; + int pipe_in; + int pipe_out; + int dead; + message_func process_msg_cb; + void *client_data; + char thread_name[128]; +}; + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to command server + */ +struct qcelp13_ipc_info *omx_qcelp13_thread_create(message_func cb, + void* client_data, + char *th_name); + +struct qcelp13_ipc_info *omx_qcelp13_event_thread_create(message_func cb, + void* client_data, + char *th_name); +/** + @brief This function stop command server + + @param svr handle to command server + @return none + */ +void omx_qcelp13_thread_stop(struct qcelp13_ipc_info *qcelp13_ipc); + + +/** + @brief This function post message in the command server + + @param svr handle to command server + @return none + */ +void omx_qcelp13_post_msg(struct qcelp13_ipc_info *qcelp13_ipc, + unsigned char id); + +#ifdef __cplusplus +} +#endif + +#endif /* AENC_SVR */ diff --git a/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h b/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h new file mode 100644 index 000000000..c54780998 --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h @@ -0,0 +1,539 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#ifndef _QCELP13_ENC_H_ +#define _QCELP13_ENC_H_ +/*============================================================================ + Audio Encoder + +@file omx_qcelp13_aenc.h +This module contains the class definition for openMAX encoder component. + + + +============================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see + * all DEBUG_PRINT or LOGV messaging */ +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#include "OMX_Core.h" +#include "OMX_Audio.h" +#include "aenc_svr.h" +#include "qc_omx_component.h" +#include "Map.h" +#include +#include +#include +extern "C" { + void * get_omx_component_factory_fn(void); +} + + +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// + + + +#define OMX_SPEC_VERSION 0x00000101 +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (x >= y?x:y) + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +// + + +#define PrintFrameHdr(i,bufHdr) \ + DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\ + i,\ + (unsigned) bufHdr, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags) + + +// BitMask Management logic +#define BITS_PER_BYTE 8 +#define BITMASK_SIZE(mIndex) \ + (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE) +#define BITMASK_OFFSET(mIndex)\ + ((mIndex)/BITS_PER_BYTE) +#define BITMASK_FLAG(mIndex) \ + (1 << ((mIndex) % BITS_PER_BYTE)) +#define BITMASK_CLEAR(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex)\ + (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex)\ + ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex)\ + (((mArray)[BITMASK_OFFSET(mIndex)] & \ + BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_NUM_INPUT_BUFFERS 2 +#define OMX_CORE_NUM_OUTPUT_BUFFERS 16 + +#define OMX_CORE_INPUT_BUFFER_SIZE 8160 // Multiple of 160 +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_AENC_VOLUME_STEP 0x147 +#define OMX_AENC_MIN 0 +#define OMX_AENC_MAX 100 +#define NON_TUNNEL 1 +#define TUNNEL 0 +#define IP_PORT_BITMASK 0x02 +#define OP_PORT_BITMASK 0x01 +#define IP_OP_PORT_BITMASK 0x03 + +#define OMX_QCELP13_DEFAULT_SF 8000 +#define OMX_QCELP13_DEFAULT_CH_CFG 1 +#define OMX_QCELP13_DEFAULT_VOL 25 +// 14 bytes for input meta data +#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14) + +#define TRUE 1 +#define FALSE 0 + +#define NUMOFFRAMES 1 +#define MAXFRAMELENGTH 35 +#define OMX_QCELP13_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT) + MAXFRAMELENGTH) \ + + 1)) + +#define OMX_QCELP13_DEFAULT_MINRATE 4 +#define OMX_QCELP13_DEFAULT_MAXRATE 4 + +class omx_qcelp13_aenc; + +// OMX mo3 audio encoder class +class omx_qcelp13_aenc: public qc_omx_component +{ +public: + omx_qcelp13_aenc(); // constructor + virtual ~omx_qcelp13_aenc(); // destructor + + OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index); + + OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup); + + OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + + OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE * specVersion, + OMX_UUIDTYPE *componentUUID); + + OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + static void process_in_port_msg(void *client_data, + unsigned char id); + + static void process_out_port_msg(void *client_data, + unsigned char id); + + static void process_command_msg(void *client_data, + unsigned char id); + + static void process_event_cb(void *client_data, + unsigned char id); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + + bool post_command(unsigned int p1, unsigned int p2, + unsigned int id); + + // Deferred callback identifiers + enum + { + //Event Callbacks from the component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + OMX_COMPONENT_GENERATE_ETB = 0x3, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x4, + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05, + OMX_COMPONENT_GENERATE_FTB = 0x06, + OMX_COMPONENT_GENERATE_EOS = 0x07, + OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08, + OMX_COMPONENT_SUSPEND = 0x09, + OMX_COMPONENT_RESUME = 0x0a + }; +private: + + /////////////////////////////////////////////////////////// + // Type definitions + /////////////////////////////////////////////////////////// + // Bit Positions + enum flags_bit_positions + { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + + OMX_COMPONENT_MUTED =0x3, + + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7 + }; + + + typedef Map + input_buffer_map; + + typedef Map + output_buffer_map; + + enum port_indexes + { + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 + }; + + struct omx_event + { + unsigned param1; + unsigned param2; + unsigned id; + }; + + struct omx_cmd_queue + { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned m_read; + unsigned m_write; + unsigned m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned p1, unsigned p2, unsigned id); + bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id); + bool get_msg_id(unsigned *id); + bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id); + }; + + typedef struct TIMESTAMP + { + unsigned long LowPart; + unsigned long HighPart; + }__attribute__((packed)) TIMESTAMP; + + typedef struct metadata_input + { + unsigned short offsetVal; + TIMESTAMP nTimeStamp; + unsigned int nFlags; + }__attribute__((packed)) META_IN; + + typedef struct enc_meta_out + { + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; + } __attribute__ ((packed))ENC_META_OUT; + + typedef struct + { + OMX_U32 tot_in_buf_len; + OMX_U32 tot_out_buf_len; + OMX_U32 tot_pb_time; + OMX_U32 fbd_cnt; + OMX_U32 ftb_cnt; + OMX_U32 etb_cnt; + OMX_U32 ebd_cnt; + }QCELP13_PB_STATS; + + /////////////////////////////////////////////////////////// + // Member variables + /////////////////////////////////////////////////////////// + OMX_U8 *m_tmp_meta_buf; + OMX_U8 *m_tmp_out_meta_buf; + OMX_U8 m_flush_cnt ; + OMX_U8 m_comp_deinit; + + // the below var doesnt hold good if combo of use and alloc bufs are used + OMX_S32 m_volume;//Unit to be determined + OMX_PTR m_app_data;// Application data + int nNumInputBuf; + int nNumOutputBuf; + int m_drv_fd; // Kernel device node file handle + bool bFlushinprogress; + bool is_in_th_sleep; + bool is_out_th_sleep; + unsigned int m_flags; //encapsulate the waiting states. + unsigned int nTimestamp; + unsigned int pcm_input; //tunnel or non-tunnel + unsigned int m_inp_act_buf_count; // Num of Input Buffers + unsigned int m_out_act_buf_count; // Numb of Output Buffers + unsigned int m_inp_current_buf_count; // Num of Input Buffers + unsigned int m_out_current_buf_count; // Numb of Output Buffers + unsigned int output_buffer_size; + unsigned int input_buffer_size; + unsigned short m_session_id; + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + sem_t sem_States; + sem_t sem_read_msg; + sem_t sem_write_msg; + + volatile int m_is_event_done; + volatile int m_is_in_th_sleep; + volatile int m_is_out_th_sleep; + input_buffer_map m_input_buf_hdrs; + output_buffer_map m_output_buf_hdrs; + omx_cmd_queue m_input_q; + omx_cmd_queue m_input_ctrl_cmd_q; + omx_cmd_queue m_input_ctrl_ebd_q; + omx_cmd_queue m_command_q; + omx_cmd_queue m_output_q; + omx_cmd_queue m_output_ctrl_cmd_q; + omx_cmd_queue m_output_ctrl_fbd_q; + pthread_mutexattr_t m_outputlock_attr; + pthread_mutexattr_t m_commandlock_attr; + pthread_mutexattr_t m_lock_attr; + pthread_mutexattr_t m_state_attr; + pthread_mutexattr_t m_flush_attr; + pthread_mutexattr_t m_in_th_attr_1; + pthread_mutexattr_t m_out_th_attr_1; + pthread_mutexattr_t m_event_attr; + pthread_mutexattr_t m_in_th_attr; + pthread_mutexattr_t m_out_th_attr; + pthread_mutexattr_t out_buf_count_lock_attr; + pthread_mutexattr_t in_buf_count_lock_attr; + pthread_cond_t cond; + pthread_cond_t in_cond; + pthread_cond_t out_cond; + pthread_mutex_t m_lock; + pthread_mutex_t m_commandlock; + pthread_mutex_t m_outputlock; + // Mutexes for state change + pthread_mutex_t m_state_lock; + // Mutexes for flush acks from input and output threads + pthread_mutex_t m_flush_lock; + pthread_mutex_t m_event_lock; + pthread_mutex_t m_in_th_lock; + pthread_mutex_t m_out_th_lock; + pthread_mutex_t m_in_th_lock_1; + pthread_mutex_t m_out_th_lock_1; + pthread_mutex_t out_buf_count_lock; + pthread_mutex_t in_buf_count_lock; + + OMX_STATETYPE m_state; // OMX State + OMX_STATETYPE nState; + OMX_CALLBACKTYPE m_cb; // Application callbacks + QCELP13_PB_STATS m_qcelp13_pb_stats; + struct qcelp13_ipc_info *m_ipc_to_in_th; // for input thread + struct qcelp13_ipc_info *m_ipc_to_out_th; // for output thread + struct qcelp13_ipc_info *m_ipc_to_cmd_th; // for command thread + struct qcelp13_ipc_info *m_ipc_to_event_th; //for txco event thread + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_AUDIO_PARAM_QCELP13TYPE m_qcelp13_param; // Cache QCELP13 encoder parameter + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter + OMX_PARAM_COMPONENTROLETYPE component_Role; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + + /////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////// + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + bool allocate_done(void); + + bool release_done(OMX_U32 param1); + + bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true); + + bool execute_input_omx_flush(void); + + bool execute_output_omx_flush(void); + + bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer); + + bool post_input(unsigned int p1, unsigned int p2, + unsigned int id); + + bool post_output(unsigned int p1, unsigned int p2, + unsigned int id); + + void process_events(omx_qcelp13_aenc *client_data); + + void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr); + + void wait_for_event(); + + void event_complete(); + + void in_th_goto_sleep(); + + void in_th_wakeup(); + + void out_th_goto_sleep(); + + void out_th_wakeup(); + + void flush_ack(); + void deinit_encoder(); + +}; +#endif diff --git a/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c b/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..b39f62522 --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c @@ -0,0 +1,208 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +#include +#include +#include + +#include +#include + +#include + +/** + @brief This function processes posted messages + + Once thread is being spawned, this function is run to + start processing commands posted by client + + @param info pointer to context + + */ +void *omx_qcelp13_msg(void *info) +{ + struct qcelp13_ipc_info *qcelp13_info = (struct qcelp13_ipc_info*)info; + unsigned char id; + int n; + + DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__); + while (!qcelp13_info->dead) + { + n = read(qcelp13_info->pipe_in, &id, 1); + if (0 == n) break; + if (1 == n) + { + DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n", + qcelp13_info->thread_name, + qcelp13_info->pipe_in, + qcelp13_info->pipe_out); + + qcelp13_info->process_msg_cb(qcelp13_info->client_data, id); + } + if ((n < 0) && (errno != EINTR)) break; + } + DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__); + + return 0; +} + +void *omx_qcelp13_events(void *info) +{ + struct qcelp13_ipc_info *qcelp13_info = (struct qcelp13_ipc_info*)info; + unsigned char id = 0; + + DEBUG_DETAIL("%s: message thread start\n", qcelp13_info->thread_name); + qcelp13_info->process_msg_cb(qcelp13_info->client_data, id); + DEBUG_DETAIL("%s: message thread stop\n", qcelp13_info->thread_name); + return 0; +} + +/** + @brief This function starts command server + + @param cb pointer to callback function from the client + @param client_data reference client wants to get back + through callback + @return handle to msging thread + */ +struct qcelp13_ipc_info *omx_qcelp13_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct qcelp13_ipc_info *qcelp13_info; + + qcelp13_info = calloc(1, sizeof(struct qcelp13_ipc_info)); + if (!qcelp13_info) + { + return 0; + } + + qcelp13_info->client_data = client_data; + qcelp13_info->process_msg_cb = cb; + strlcpy(qcelp13_info->thread_name, th_name, + sizeof(qcelp13_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + qcelp13_info->pipe_in = fds[0]; + qcelp13_info->pipe_out = fds[1]; + + r = pthread_create(&qcelp13_info->thr, 0, omx_qcelp13_msg, qcelp13_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", qcelp13_info->thread_name); + return qcelp13_info; + + +fail_thread: + close(qcelp13_info->pipe_in); + close(qcelp13_info->pipe_out); + +fail_pipe: + free(qcelp13_info); + + return 0; +} + +/** + * @brief This function starts command server + * + * @param cb pointer to callback function from the client + * @param client_data reference client wants to get back + * through callback + * @return handle to msging thread + * */ +struct qcelp13_ipc_info *omx_qcelp13_event_thread_create( + message_func cb, + void* client_data, + char* th_name) +{ + int r; + int fds[2]; + struct qcelp13_ipc_info *qcelp13_info; + + qcelp13_info = calloc(1, sizeof(struct qcelp13_ipc_info)); + if (!qcelp13_info) + { + return 0; + } + + qcelp13_info->client_data = client_data; + qcelp13_info->process_msg_cb = cb; + strlcpy(qcelp13_info->thread_name, th_name, + sizeof(qcelp13_info->thread_name)); + + if (pipe(fds)) + { + DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__); + goto fail_pipe; + } + + qcelp13_info->pipe_in = fds[0]; + qcelp13_info->pipe_out = fds[1]; + + r = pthread_create(&qcelp13_info->thr, 0, omx_qcelp13_events, qcelp13_info); + if (r < 0) goto fail_thread; + + DEBUG_DETAIL("Created thread for %s \n", qcelp13_info->thread_name); + return qcelp13_info; + + +fail_thread: + close(qcelp13_info->pipe_in); + close(qcelp13_info->pipe_out); + +fail_pipe: + free(qcelp13_info); + + return 0; +} + +void omx_qcelp13_thread_stop(struct qcelp13_ipc_info *qcelp13_info) { + DEBUG_DETAIL("%s stop server\n", __FUNCTION__); + close(qcelp13_info->pipe_in); + close(qcelp13_info->pipe_out); + pthread_join(qcelp13_info->thr,NULL); + qcelp13_info->pipe_out = -1; + qcelp13_info->pipe_in = -1; + DEBUG_DETAIL("%s: message thread close fds%d %d\n", qcelp13_info->thread_name, + qcelp13_info->pipe_in,qcelp13_info->pipe_out); + free(qcelp13_info); +} + +void omx_qcelp13_post_msg(struct qcelp13_ipc_info *qcelp13_info, unsigned char id) { + DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id); + + write(qcelp13_info->pipe_out, &id, 1); +} diff --git a/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp b/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp new file mode 100644 index 000000000..f080e1fb4 --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp @@ -0,0 +1,4531 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ +/*============================================================================ +@file omx_aenc_qcelp13.c + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include "omx_qcelp13_aenc.h" +#include + +using namespace std; +#define SLEEP_MS 100 + +// omx_cmd_queue destructor +omx_qcelp13_aenc::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_qcelp13_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE); +} + +// omx cmd queue insert +bool omx_qcelp13_aenc::omx_cmd_queue::insert_entry(unsigned p1, + unsigned p2, + unsigned id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_write = 0; + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full"); + } + return ret; +} + +bool omx_qcelp13_aenc::omx_cmd_queue::pop_entry(unsigned *p1, + unsigned *p2, unsigned *id) +{ + bool ret = true; + if (m_size > 0) + { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_read = 0; + + } + } else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty"); + } + return ret; +} + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return(new omx_qcelp13_aenc); +} +bool omx_qcelp13_aenc::omx_cmd_queue::get_msg_id(unsigned *id) +{ + if(m_size > 0) + { + *id = m_q[m_read].id; + DEBUG_PRINT("get_msg_id=%d\n",*id); + } + else{ + return false; + } + return true; +} +/*============================================================================= +FUNCTION: + wait_for_event + +DESCRIPTION: + waits for a particular event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_qcelp13_aenc::wait_for_event() +{ + int rc; + struct timespec ts; + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (SLEEP_MS/1000); + ts.tv_nsec += ((SLEEP_MS%1000) * 1000000); + rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts); + if (rc == ETIMEDOUT && !m_is_event_done) { + DEBUG_PRINT("Timed out waiting for flush"); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + } + } + m_is_event_done = 0; + pthread_mutex_unlock(&m_event_lock); +} + +/*============================================================================= +FUNCTION: + event_complete + +DESCRIPTION: + informs about the occurance of an event + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_qcelp13_aenc::event_complete() +{ + pthread_mutex_lock(&m_event_lock); + if (0 == m_is_event_done) + { + m_is_event_done = 1; + pthread_cond_signal(&cond); + } + pthread_mutex_unlock(&m_event_lock); +} + +// All this non-sense because of a single qcelp13 object +void omx_qcelp13_aenc::in_th_goto_sleep() +{ + pthread_mutex_lock(&m_in_th_lock); + while (0 == m_is_in_th_sleep) + { + pthread_cond_wait(&in_cond, &m_in_th_lock); + } + m_is_in_th_sleep = 0; + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_qcelp13_aenc::in_th_wakeup() +{ + pthread_mutex_lock(&m_in_th_lock); + if (0 == m_is_in_th_sleep) + { + m_is_in_th_sleep = 1; + pthread_cond_signal(&in_cond); + } + pthread_mutex_unlock(&m_in_th_lock); +} + +void omx_qcelp13_aenc::out_th_goto_sleep() +{ + + pthread_mutex_lock(&m_out_th_lock); + while (0 == m_is_out_th_sleep) + { + pthread_cond_wait(&out_cond, &m_out_th_lock); + } + m_is_out_th_sleep = 0; + pthread_mutex_unlock(&m_out_th_lock); +} + +void omx_qcelp13_aenc::out_th_wakeup() +{ + pthread_mutex_lock(&m_out_th_lock); + if (0 == m_is_out_th_sleep) + { + m_is_out_th_sleep = 1; + pthread_cond_signal(&out_cond); + } + pthread_mutex_unlock(&m_out_th_lock); +} +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::omx_qcelp13_aenc + +DESCRIPTION + Constructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_qcelp13_aenc::omx_qcelp13_aenc(): m_tmp_meta_buf(NULL), + m_tmp_out_meta_buf(NULL), + m_flush_cnt(255), + m_comp_deinit(0), + m_app_data(NULL), + m_drv_fd(-1), + bFlushinprogress(0), + is_in_th_sleep(false), + is_out_th_sleep(false), + m_flags(0), + nTimestamp(0), + m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS), + m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS), + m_inp_current_buf_count(0), + m_out_current_buf_count(0), + output_buffer_size(OMX_QCELP13_OUTPUT_BUFFER_SIZE), + input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE), + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_is_event_done(0), + m_state(OMX_StateInvalid), + m_ipc_to_in_th(NULL), + m_ipc_to_out_th(NULL), + m_ipc_to_cmd_th(NULL), + m_volume(25), + pcm_input(0), + nNumOutputBuf(0), + m_session_id(0), + m_ipc_to_event_th(NULL), + nNumInputBuf(0) +{ + int cond_ret = 0; + component_Role.nSize = 0; + memset(&m_cmp, 0, sizeof(m_cmp)); + memset(&m_cb, 0, sizeof(m_cb)); + memset(&m_qcelp13_pb_stats, 0, sizeof(m_qcelp13_pb_stats)); + memset(&m_qcelp13_param, 0, sizeof(m_qcelp13_param)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + + pthread_mutexattr_init(&m_lock_attr); + pthread_mutex_init(&m_lock, &m_lock_attr); + pthread_mutexattr_init(&m_commandlock_attr); + pthread_mutex_init(&m_commandlock, &m_commandlock_attr); + + pthread_mutexattr_init(&m_outputlock_attr); + pthread_mutex_init(&m_outputlock, &m_outputlock_attr); + + pthread_mutexattr_init(&m_state_attr); + pthread_mutex_init(&m_state_lock, &m_state_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_flush_attr); + pthread_mutex_init(&m_flush_lock, &m_flush_attr); + + pthread_mutexattr_init(&m_event_attr); + pthread_mutex_init(&m_event_lock, &m_event_attr); + + pthread_mutexattr_init(&m_in_th_attr); + pthread_mutex_init(&m_in_th_lock, &m_in_th_attr); + + pthread_mutexattr_init(&m_out_th_attr); + pthread_mutex_init(&m_out_th_lock, &m_out_th_attr); + + pthread_mutexattr_init(&m_in_th_attr_1); + pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1); + + pthread_mutexattr_init(&m_out_th_attr_1); + pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1); + + pthread_mutexattr_init(&out_buf_count_lock_attr); + pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr); + + pthread_mutexattr_init(&in_buf_count_lock_attr); + pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr); + if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0) + { + DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n"); + if (cond_ret == EAGAIN) + DEBUG_PRINT_ERROR("The system lacked necessary \ + resources(other than mem)\n"); + else if (cond_ret == ENOMEM) + DEBUG_PRINT_ERROR("Insufficient memory to initialise \ + condition variable\n"); + } + + sem_init(&sem_read_msg,0, 0); + sem_init(&sem_write_msg,0, 0); + sem_init(&sem_States,0, 0); + return; +} + + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::~omx_qcelp13_aenc + +DESCRIPTION + Destructor + +PARAMETERS + None + +RETURN VALUE + None. +========================================================================== */ +omx_qcelp13_aenc::~omx_qcelp13_aenc() +{ + DEBUG_PRINT_ERROR("QCELP13 Object getting destroyed comp-deinit=%d\n", + m_comp_deinit); + if ( !m_comp_deinit ) + { + deinit_encoder(); + } + pthread_mutexattr_destroy(&m_lock_attr); + pthread_mutex_destroy(&m_lock); + + pthread_mutexattr_destroy(&m_commandlock_attr); + pthread_mutex_destroy(&m_commandlock); + + pthread_mutexattr_destroy(&m_outputlock_attr); + pthread_mutex_destroy(&m_outputlock); + + pthread_mutexattr_destroy(&m_state_attr); + pthread_mutex_destroy(&m_state_lock); + + pthread_mutexattr_destroy(&m_event_attr); + pthread_mutex_destroy(&m_event_lock); + + pthread_mutexattr_destroy(&m_flush_attr); + pthread_mutex_destroy(&m_flush_lock); + + pthread_mutexattr_destroy(&m_in_th_attr); + pthread_mutex_destroy(&m_in_th_lock); + + pthread_mutexattr_destroy(&m_out_th_attr); + pthread_mutex_destroy(&m_out_th_lock); + + pthread_mutexattr_destroy(&out_buf_count_lock_attr); + pthread_mutex_destroy(&out_buf_count_lock); + + pthread_mutexattr_destroy(&in_buf_count_lock_attr); + pthread_mutex_destroy(&in_buf_count_lock); + + pthread_mutexattr_destroy(&m_in_th_attr_1); + pthread_mutex_destroy(&m_in_th_lock_1); + + pthread_mutexattr_destroy(&m_out_th_attr_1); + pthread_mutex_destroy(&m_out_th_lock_1); + pthread_cond_destroy(&cond); + pthread_cond_destroy(&in_cond); + pthread_cond_destroy(&out_cond); + sem_destroy (&sem_read_msg); + sem_destroy (&sem_write_msg); + sem_destroy (&sem_States); + DEBUG_PRINT_ERROR("OMX QCELP13 component destroyed\n"); + return; +} + +/** + @brief memory function for sending EmptyBufferDone event + back to IL client + + @param bufHdr OMX buffer header to be passed back to IL client + @return none + */ +void omx_qcelp13_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.EmptyBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr); + bufHdr->nFilledLen = 0; + + m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr); + pthread_mutex_lock(&in_buf_count_lock); + m_qcelp13_pb_stats.ebd_cnt++; + nNumInputBuf--; + DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\ + m_qcelp13_pb_stats.tot_in_buf_len, + nNumInputBuf, m_qcelp13_pb_stats.ebd_cnt); + pthread_mutex_unlock(&in_buf_count_lock); + } + + return; +} + +/*============================================================================= +FUNCTION: + flush_ack + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_qcelp13_aenc::flush_ack() +{ + // Decrement the FLUSH ACK count and notify the waiting recepients + pthread_mutex_lock(&m_flush_lock); + --m_flush_cnt; + if (0 == m_flush_cnt) + { + event_complete(); + } + DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt); + pthread_mutex_unlock(&m_flush_lock); +} +void omx_qcelp13_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr) +{ + if (m_cb.FillBufferDone) + { + PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr); + m_qcelp13_pb_stats.fbd_cnt++; + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf--; + DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\ + nNumOutputBuf, + m_qcelp13_pb_stats.tot_out_buf_len, + m_qcelp13_pb_stats.fbd_cnt); + m_qcelp13_pb_stats.tot_out_buf_len += bufHdr->nFilledLen; + m_qcelp13_pb_stats.tot_pb_time = bufHdr->nTimeStamp; + DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n", + m_qcelp13_pb_stats.tot_in_buf_len, + m_qcelp13_pb_stats.tot_out_buf_len); + + pthread_mutex_unlock(&out_buf_count_lock); + m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr); + } + return; +} + +/*============================================================================= +FUNCTION: + process_out_port_msg + +DESCRIPTION: + Function for handling all commands from IL client +IL client commands are processed and callbacks are generated through +this routine Audio Command Server provides the thread context for this routine + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_qcelp13_aenc::process_out_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; // qsize + unsigned tot_qsize = 0; + omx_qcelp13_aenc *pThis = (omx_qcelp13_aenc *) client_data; + OMX_STATETYPE state; + +loopback_out: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n"); + return; + } + pthread_mutex_lock(&pThis->m_outputlock); + + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + + if ( 0 == tot_qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize); + return; + } + if ( (state != OMX_StateExecuting) && !qsize ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + + if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) ) + { + // case where no port reconfig and nothing in the flush q + DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\ + qsize,tot_qsize); + pthread_mutex_unlock(&pThis->m_outputlock); + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + return; + + if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress)) + { + DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pThis->out_th_goto_sleep(); + } + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize = pThis->m_output_ctrl_cmd_q.m_size; + tot_qsize += pThis->m_output_ctrl_fbd_q.m_size; + tot_qsize += pThis->m_output_q.m_size; + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\ + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size,state); + + + if (qsize) + { + // process FLUSH message + pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_output_q.m_size) && + (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) ) + { + // if no FLUSH and FBD's then process FTB's + pThis->m_output_q.pop_entry(&p1,&p2,&ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_outputlock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n"); + pthread_mutex_lock(&pThis->m_out_th_lock_1); + pThis->is_out_th_sleep = true; + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + pthread_mutex_unlock(&pThis->m_outputlock); + pThis->out_th_goto_sleep(); + goto loopback_out; + } + } + pthread_mutex_unlock(&pThis->m_outputlock); + + if ( qsize > 0 ) + { + id = ident; + ident = 0; + DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_output_ctrl_cmd_q.m_size, + pThis->m_output_ctrl_fbd_q.m_size, + pThis->m_output_q.m_size); + + if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id ) + { + pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_FTB == id ) + { + pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_EOS == id ) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + + } + else if(id == OMX_COMPONENT_RESUME) + { + DEBUG_PRINT("RESUMED...\n"); + } + else if(id == OMX_COMPONENT_GENERATE_COMMAND) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL("Executing FLUSH command on Output port\n"); + pThis->execute_output_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n"); + } + + return; +} + +/*============================================================================= +FUNCTION: + process_command_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_qcelp13_aenc::process_command_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + omx_qcelp13_aenc *pThis = (omx_qcelp13_aenc*)client_data; + pthread_mutex_lock(&pThis->m_commandlock); + + qsize = pThis->m_command_q.m_size; + DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size, + pThis->m_state); + + if (!qsize) + { + DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n"); + pthread_mutex_unlock(&pThis->m_commandlock); + return; + } else + { + pThis->m_command_q.pop_entry(&p1,&p2,&ident); + } + pthread_mutex_unlock(&pThis->m_commandlock); + + id = ident; + DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\ + pThis->m_state,ident, \ + pThis->m_command_q.m_size); + + if (OMX_COMPONENT_GENERATE_EVENT == id) + { + if (pThis->m_cb.EventHandler) + { + if (OMX_CommandStateSet == p1) + { + pthread_mutex_lock(&pThis->m_state_lock); + pThis->m_state = (OMX_STATETYPE) p2; + pthread_mutex_unlock(&pThis->m_state_lock); + DEBUG_PRINT("CMD:Process->state set to %d \n", \ + pThis->m_state); + + if (pThis->m_state == OMX_StateExecuting || + pThis->m_state == OMX_StateLoaded) + { + + pthread_mutex_lock(&pThis->m_in_th_lock_1); + if (pThis->is_in_th_sleep) + { + pThis->is_in_th_sleep = false; + DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n"); + pThis->in_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + + pthread_mutex_lock(&pThis->m_out_th_lock_1); + if (pThis->is_out_th_sleep) + { + DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n"); + pThis->is_out_th_sleep = false; + pThis->out_th_wakeup(); + } + pthread_mutex_unlock(&pThis->m_out_th_lock_1); + } + } + if (OMX_StateInvalid == pThis->m_state) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + } else if ((signed)p2 == OMX_ErrorPortUnpopulated) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventError, + p2, + NULL, + NULL ); + } else + { + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventCmdComplete, + p1, p2, NULL ); + } + } else + { + DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n"); + } + } else if (OMX_COMPONENT_GENERATE_COMMAND == id) + { + pThis->send_command_proxy(&pThis->m_cmp, + (OMX_COMMANDTYPE)p1, + (OMX_U32)p2,(OMX_PTR)NULL); + } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id) + { + DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED"); + pThis->m_cb.EventHandler(&pThis->m_cmp, + pThis->m_app_data, + OMX_EventPortSettingsChanged, + 1, 1, NULL ); + } + else + { + DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident); + } + return; +} + +/*============================================================================= +FUNCTION: + process_in_port_msg + +DESCRIPTION: + + +INPUT/OUTPUT PARAMETERS: + [INOUT] client_data + [IN] id + +RETURN VALUE: + None + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +void omx_qcelp13_aenc::process_in_port_msg(void *client_data, unsigned char id) +{ + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize = 0; + unsigned tot_qsize = 0; + omx_qcelp13_aenc *pThis = (omx_qcelp13_aenc *) client_data; + OMX_STATETYPE state; + + if (!pThis) + { + DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n"); + return; + } +loopback_in: + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + if ( state == OMX_StateLoaded ) + { + DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n"); + return; + } + // Protect the shared queue data structure + pthread_mutex_lock(&pThis->m_lock); + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + if ( 0 == tot_qsize ) + { + DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP"); + pthread_mutex_unlock(&pThis->m_lock); + return; + } + + if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_DETAIL("SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + /* Get the updated state */ + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + else if ((state == OMX_StatePause)) + { + if(!(pThis->m_input_ctrl_cmd_q.m_size)) + { + pthread_mutex_unlock(&pThis->m_lock); + + DEBUG_DETAIL("IN: SLEEPING IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pThis->in_th_goto_sleep(); + + pthread_mutex_lock(&pThis->m_state_lock); + pThis->get_state(&pThis->m_cmp, &state); + pthread_mutex_unlock(&pThis->m_state_lock); + } + } + + qsize = pThis->m_input_ctrl_cmd_q.m_size; + tot_qsize = qsize; + tot_qsize += pThis->m_input_ctrl_ebd_q.m_size; + tot_qsize += pThis->m_input_q.m_size; + + DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\ + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size, state); + + + if ( qsize ) + { + // process FLUSH message + pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident); + } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) && + (state == OMX_StateExecuting) ) + { + // then process EBD's + pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident); + } else if ((qsize = pThis->m_input_q.m_size) && + (state == OMX_StateExecuting)) + { + // if no FLUSH and EBD's then process ETB's + pThis->m_input_q.pop_entry(&p1, &p2, &ident); + } else if ( state == OMX_StateLoaded ) + { + pthread_mutex_unlock(&pThis->m_lock); + DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n"); + return ; + } else + { + qsize = 0; + DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\ + state,pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + + if(state == OMX_StatePause) + { + DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n"); + pthread_mutex_lock(&pThis->m_in_th_lock_1); + pThis->is_in_th_sleep = true; + pthread_mutex_unlock(&pThis->m_in_th_lock_1); + pthread_mutex_unlock(&pThis->m_lock); + pThis->in_th_goto_sleep(); + goto loopback_in; + } + } + pthread_mutex_unlock(&pThis->m_lock); + + if ( qsize > 0 ) + { + id = ident; + DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + pThis->m_state, + ident, + pThis->m_input_ctrl_cmd_q.m_size, + pThis->m_input_ctrl_ebd_q.m_size, + pThis->m_input_q.m_size); + if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id ) + { + pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2); + } + else if(id == OMX_COMPONENT_GENERATE_EOS) + { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventBufferFlag, 0, 1, NULL ); + } else if ( OMX_COMPONENT_GENERATE_ETB == id ) + { + pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, + (OMX_BUFFERHEADERTYPE *)p2); + } else if ( OMX_COMPONENT_GENERATE_COMMAND == id ) + { + // Execute FLUSH command + if ( OMX_CommandFlush == p1 ) + { + DEBUG_DETAIL(" Executing FLUSH command on Input port\n"); + pThis->execute_input_omx_flush(); + } else + { + DEBUG_DETAIL("Invalid command[%d]\n",p1); + } + } + else + { + DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id); + } + } else + { + DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n"); + } + return; +} + +/** + @brief member function for performing component initialization + + @param role C string mandating role of this component + @return Error status + */ +OMX_ERRORTYPE omx_qcelp13_aenc::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + m_state = OMX_StateLoaded; + + /* DSP does not give information about the bitstream + randomly assign the value right now. Query will result in + incorrect param */ + memset(&m_qcelp13_param, 0, sizeof(m_qcelp13_param)); + m_qcelp13_param.nSize = sizeof(m_qcelp13_param); + m_qcelp13_param.nChannels = OMX_QCELP13_DEFAULT_CH_CFG; + //Current DSP does not have config + m_qcelp13_param.eCDMARate = OMX_AUDIO_CDMARateFull; + m_qcelp13_param.nMinBitRate = OMX_QCELP13_DEFAULT_MINRATE; + m_qcelp13_param.nMaxBitRate = OMX_QCELP13_DEFAULT_MAXRATE; + m_volume = OMX_QCELP13_DEFAULT_VOL; /* Close to unity gain */ + memset(&m_qcelp13_pb_stats,0,sizeof(QCELP13_PB_STATS)); + memset(&m_pcm_param, 0, sizeof(m_pcm_param)); + m_pcm_param.nSize = sizeof(m_pcm_param); + m_pcm_param.nChannels = OMX_QCELP13_DEFAULT_CH_CFG; + m_pcm_param.nSamplingRate = OMX_QCELP13_DEFAULT_SF; + nTimestamp = 0; + + + nNumInputBuf = 0; + nNumOutputBuf = 0; + m_ipc_to_in_th = NULL; // Command server instance + m_ipc_to_out_th = NULL; // Client server instance + m_ipc_to_cmd_th = NULL; // command instance + m_is_out_th_sleep = 0; + m_is_in_th_sleep = 0; + is_out_th_sleep= false; + + is_in_th_sleep=false; + + memset(&m_priority_mgm, 0, sizeof(m_priority_mgm)); + m_priority_mgm.nGroupID =0; + m_priority_mgm.nGroupPriority=0; + + memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier)); + m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified; + + DEBUG_PRINT_ERROR(" component init: role = %s\n",role); + + DEBUG_PRINT(" component init: role = %s\n",role); + component_Role.nVersion.nVersion = OMX_SPEC_VERSION; + if (!strcmp(role,"OMX.qcom.audio.encoder.qcelp13")) + { + pcm_input = 1; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, (const char*)role, + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.qcelp13")) + { + pcm_input = 0; + component_Role.nSize = sizeof(role); + strlcpy((char *)component_Role.cRole, (const char*)role, + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role); + } else + { + component_Role.nSize = sizeof("\0"); + strlcpy((char *)component_Role.cRole, (const char*)"\0", + sizeof(component_Role.cRole)); + DEBUG_PRINT("\ncomponent_init: Component %s LOADED is invalid\n", role); + } + if(pcm_input) + { + + + m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) * + (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN))); + + if (m_tmp_meta_buf == NULL){ + DEBUG_PRINT_ERROR("Mem alloc failed for in meta buf\n"); + return OMX_ErrorInsufficientResources; + } + } + m_tmp_out_meta_buf = + (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_QCELP13_OUTPUT_BUFFER_SIZE); + if ( m_tmp_out_meta_buf == NULL ) { + DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n"); + return OMX_ErrorInsufficientResources; + } + + if(0 == pcm_input) + { + m_drv_fd = open("/dev/msm_qcelp_in",O_RDONLY); + DEBUG_PRINT("Driver in Tunnel mode open\n"); + } + else + { + m_drv_fd = open("/dev/msm_qcelp_in",O_RDWR); + DEBUG_PRINT("Driver in Non Tunnel mode open\n"); + } + if (m_drv_fd < 0) + { + DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\ + m_drv_fd,errno); + + return OMX_ErrorInsufficientResources; + } + if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1) + { + DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n"); + } + if(pcm_input) + { + if (!m_ipc_to_in_th) + { + m_ipc_to_in_th = omx_qcelp13_thread_create(process_in_port_msg, + this, (char *)"INPUT_THREAD"); + if (!m_ipc_to_in_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start \ + Input port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + } + + if (!m_ipc_to_cmd_th) + { + m_ipc_to_cmd_th = omx_qcelp13_thread_create(process_command_msg, + this, (char *)"CMD_THREAD"); + if (!m_ipc_to_cmd_th) + { + DEBUG_PRINT_ERROR("ERROR!!!Failed to start " + "command message thread\n"); + return OMX_ErrorInsufficientResources; + } + } + + if (!m_ipc_to_out_th) + { + m_ipc_to_out_th = omx_qcelp13_thread_create(process_out_port_msg, + this, (char *)"OUTPUT_THREAD"); + if (!m_ipc_to_out_th) + { + DEBUG_PRINT_ERROR("ERROR!!! Failed to start output " + "port thread\n"); + return OMX_ErrorInsufficientResources; + } + } + return eRet; +} + +/** + + @brief member function to retrieve version of component + + + + @param hComp handle to this component instance + @param componentName name of component + @param componentVersion pointer to memory space which stores the + version number + @param specVersion pointer to memory sapce which stores version of + openMax specification + @param componentUUID + @return Error status + */ +OMX_ERRORTYPE omx_qcelp13_aenc::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID) +{ + if((hComp == NULL) || (componentName == NULL) || + (specVersion == NULL) || (componentUUID == NULL)) + { + componentVersion = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n"); + return OMX_ErrorInvalidState; + } + componentVersion->nVersion = OMX_SPEC_VERSION; + specVersion->nVersion = OMX_SPEC_VERSION; + return OMX_ErrorNone; +} +/** + @brief member function handles command from IL client + + This function simply queue up commands from IL client. + Commands will be processed in command server thread context later + + @param hComp handle to component instance + @param cmd type of command + @param param1 parameters associated with the command type + @param cmdData + @return Error status +*/ +OMX_ERRORTYPE omx_qcelp13_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + int portIndex = (int)param1; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateInvalid == m_state) + { + return OMX_ErrorInvalidState; + } + if ( (cmd == OMX_CommandFlush) && (portIndex > 1) ) + { + return OMX_ErrorBadPortIndex; + } + post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); + DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n"); + DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1); + sem_wait (&sem_States); + DEBUG_PRINT("send_command : recieved state after semwait\n"); + return OMX_ErrorNone; +} + +/** + @brief member function performs actual processing of commands excluding + empty buffer call + + @param hComp handle to component + @param cmd command type + @param param1 parameter associated with the command + @param cmdData + + @return error status +*/ +OMX_ERRORTYPE omx_qcelp13_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + // Handle only IDLE and executing + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1; + nState = eState; + + if(hComp == NULL) + { + cmdData = NULL; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_CommandStateSet == cmd) + { + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (OMX_StateLoaded == m_state) + { + if (OMX_StateIdle == eState) + { + + if (allocate_done() || + (m_inp_bEnabled == OMX_FALSE + && m_out_bEnabled == OMX_FALSE)) + { + DEBUG_PRINT("SCP-->Allocate Done Complete\n"); + } + else + { + DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + bFlag = 0; + } + + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } + + else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n"); + eRet = OMX_ErrorNone; + } + + else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + m_state = OMX_StateInvalid; + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (OMX_StateIdle == m_state) + { + if (OMX_StateLoaded == eState) + { + if (release_done(-1)) + { + if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1) + { + DEBUG_PRINT_ERROR("SCP:Idle->Loaded,\ + ioctl stop failed %d\n", errno); + } + + nTimestamp=0; + + DEBUG_PRINT("SCP-->Idle to Loaded\n"); + } else + { + DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + else if (OMX_StateExecuting == eState) + { + + struct msm_audio_qcelp_enc_config drv_qcelp13_enc_config; + struct msm_audio_stream_config drv_stream_config; + struct msm_audio_buf_cfg buf_cfg; + struct msm_audio_config pcm_cfg; + + if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \ + errno[%d]\n", errno); + } + + if(ioctl(m_drv_fd, AUDIO_GET_QCELP_ENC_CONFIG, + &drv_qcelp13_enc_config) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_QCELP_ENC_CONFIG failed,\ + errno[%d]\n", errno); + } + drv_qcelp13_enc_config.min_bit_rate = m_qcelp13_param.nMinBitRate; + drv_qcelp13_enc_config.max_bit_rate = m_qcelp13_param.nMaxBitRate; + if(ioctl(m_drv_fd, AUDIO_SET_QCELP_ENC_CONFIG, &drv_qcelp13_enc_config) + == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_QCELP_ENC_CONFIG \ + failed, errno[%d]\n", errno); + } + if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n", + errno); + } + buf_cfg.meta_info_enable = 1; + buf_cfg.frames_per_buf = NUMOFFRAMES; + if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n", + errno); + } + if(pcm_input) + { + if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n", + errno); + } + pcm_cfg.channel_count = m_pcm_param.nChannels; + pcm_cfg.sample_rate = m_pcm_param.nSamplingRate; + DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + + if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n", + errno); + } + } + if(ioctl(m_drv_fd, AUDIO_START, 0) == -1) + { + DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n", + errno); + } + DEBUG_PRINT("SCP-->Idle to Executing\n"); + nState = eState; + } else if (eState == OMX_StateIdle) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n"); + m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } + + else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n"); + } + + else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, + this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (OMX_StateExecuting == m_state) + { + if (OMX_StateIdle == eState) + { + DEBUG_PRINT("SCP-->Executing to Idle \n"); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + + } else if (OMX_StatePause == eState) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED PAUSE STATE\n"); + DEBUG_DETAIL("*************************\n"); + //ioctl(m_drv_fd, AUDIO_PAUSE, 0); + } else if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n", + eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (OMX_StatePause == m_state) + { + if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) ) + { + pthread_mutex_lock(&m_out_th_lock_1); + if(is_out_th_sleep) + { + DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n"); + is_out_th_sleep = false; + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } + if ( OMX_StateExecuting == eState ) + { + nState = eState; + } else if ( OMX_StateIdle == eState ) + { + DEBUG_PRINT("SCP-->Paused to Idle \n"); + DEBUG_PRINT ("\n Internal flush issued"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + + } else if ( eState == OMX_StateLoaded ) + { + DEBUG_PRINT("\n Pause --> loaded \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("\n Pause --> WaitForResources \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("\n Pause --> Pause \n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("\n Pause --> Invalid \n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState); + eRet = OMX_ErrorBadParameter; + } + } + /**************************************/ + /* Current State is WaitForResources */ + /**************************************/ + else if (m_state == OMX_StateWaitForResources) + { + if (eState == OMX_StateLoaded) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n"); + } else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT("OMXCORE-SM: \ + WaitForResources-->WaitForResources\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorSameState, + 0, NULL ); + eRet = OMX_ErrorSameState; + } else if (eState == OMX_StateExecuting) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StatePause) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n"); + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorIncorrectStateTransition, + 0, NULL ); + eRet = OMX_ErrorIncorrectStateTransition; + } else if (eState == OMX_StateInvalid) + { + DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, + OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } else + { + DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n", + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /****************************/ + /* Current State is Invalid */ + /****************************/ + else if (m_state == OMX_StateInvalid) + { + if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState + || OMX_StateIdle == eState || OMX_StateExecuting == eState + || OMX_StatePause == eState || OMX_StateInvalid == eState) + { + DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing" + "/Pause/Invalid/WaitForResources\n"); + m_state = OMX_StateInvalid; + this->m_cb.EventHandler(&this->m_cmp, this->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, + 0, NULL ); + eRet = OMX_ErrorInvalidState; + } + } else + { + DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\ + m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } else if (OMX_CommandFlush == cmd) + { + DEBUG_DETAIL("*************************\n"); + DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1); + DEBUG_DETAIL("*************************\n"); + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || + param1 == OMX_CORE_OUTPUT_PORT_INDEX || + (signed)param1 == -1 ) + { + execute_omx_flush(param1); + } else + { + eRet = OMX_ErrorBadPortIndex; + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError, + OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL ); + } + } else if ( cmd == OMX_CommandPortDisable ) + { + bFlag = 0; + if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL ) + { + DEBUG_PRINT("SCP: Disabling Input port Indx\n"); + m_inp_bEnabled = OMX_FALSE; + if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(0) ) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_inp_bEnabled=%d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + + else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\ + " param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_INPUT_PORT_INDEX \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + // Skip the event notification + + } + + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + + DEBUG_PRINT("SCP: Disabling Output port Indx\n"); + m_out_bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_done(1)) + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + DEBUG_PRINT("************* OMX_CommandPortDisable:\ + m_out_bEnabled=%d********\n",m_inp_bEnabled); + + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\ + "param1=%lu m_state=%d \n",param1, m_state); + execute_omx_flush(param1); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + // Skip the event notification + + } + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID"); + } + + } else if (cmd == OMX_CommandPortEnable) + { + bFlag = 0; + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_inp_bEnabled = OMX_TRUE; + DEBUG_PRINT("SCP: Enabling Input port Indx\n"); + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_inp_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + + } else + { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + + } + } + + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + DEBUG_PRINT("SCP: Enabling Output port Indx\n"); + m_out_bEnabled = OMX_TRUE; + if ((m_state == OMX_StateLoaded + && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources) + || (m_out_bPopulated == OMX_TRUE)) + { + post_command(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else + { + DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\ + OMX_CORE_OUTPUT_PORT_INDEX:release_done \n"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + + } + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + } else + { + DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID"); + } + + } else + { + DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd); + eRet = OMX_ErrorNotImplemented; + } + DEBUG_PRINT("posting sem_States\n"); + sem_post (&sem_States); + if (eRet == OMX_ErrorNone && bFlag) + { + post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + return eRet; +} + +/*============================================================================= +FUNCTION: + execute_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + [IN] param1 + [IN] cmd_cmpl + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_qcelp13_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl) +{ + bool bRet = true; + + DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1); + struct timespec abs_timeout; + abs_timeout.tv_sec = 1; + abs_timeout.tv_nsec = 0; + + if ((signed)param1 == -1) + { + bFlushinprogress = true; + DEBUG_PRINT("Execute flush for both I/p O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 2; + pthread_mutex_unlock(&m_flush_lock); + + // Send Flush commands to input and output threads + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + // Send Flush to the kernel so that the in and out buffers are released + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + + + // sleep till the FLUSH ACK are done by both the input and + // output threads + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + + DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\ + param1,cmd_cmpl); + + // If not going to idle state, Send FLUSH complete message + // to the Client, now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n"); + } + bFlushinprogress = false; + } + else if (param1 == OMX_CORE_INPUT_PORT_INDEX) + { + DEBUG_PRINT("Execute FLUSH for I/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + post_input(OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1) + DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + //sleep till the FLUSH ACK are done by both the input and output threads + DEBUG_DETAIL("Executing FLUSH for I/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + wait_for_event(); + DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1); + + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX, + NULL ); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1) + { + DEBUG_PRINT("Executing FLUSH for O/p port\n"); + pthread_mutex_lock(&m_flush_lock); + m_flush_cnt = 1; + pthread_mutex_unlock(&m_flush_lock); + DEBUG_DETAIL("Executing FLUSH for O/p port\n"); + DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1); + post_output(OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND); + if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1) + DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n", + errno); + DEBUG_DETAIL("****************************************"); + DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\ + is_in_th_sleep,is_out_th_sleep); + DEBUG_DETAIL("****************************************"); + if (is_in_th_sleep) + { + pthread_mutex_lock(&m_in_th_lock_1); + is_in_th_sleep = false; + pthread_mutex_unlock(&m_in_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + + if (is_out_th_sleep) + { + pthread_mutex_lock(&m_out_th_lock_1); + is_out_th_sleep = false; + pthread_mutex_unlock(&m_out_th_lock_1); + DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + + // sleep till the FLUSH ACK are done by both the input and + // output threads + wait_for_event(); + // Send FLUSH complete message to the Client, + // now that FLUSH ACK's have been recieved. + if (cmd_cmpl) + { + m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete, + OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX, + NULL ); + } + DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1); + } else + { + DEBUG_PRINT("Invalid Port ID[%lu]",param1); + } + return bRet; +} + +/*============================================================================= +FUNCTION: + execute_input_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_qcelp13_aenc::execute_input_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on input port"); + + pthread_mutex_lock(&m_lock); + do + { + qsize = m_input_q.m_size; + tot_qsize = qsize; + tot_qsize += m_input_ctrl_ebd_q.m_size; + + DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\ + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size,qsize); + if (!tot_qsize) + { + DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_lock); + break; + } + if (qsize) + { + m_input_q.pop_entry(&p1, &p2, &ident); + if ((ident == OMX_COMPONENT_GENERATE_ETB) || + (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf); + omx_buf->nFilledLen = 0; + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else if (m_input_ctrl_ebd_q.m_size) + { + m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident); + if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + omx_buf->nFilledLen = 0; + DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + } + } else + { + } + }while (tot_qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("IN-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_lock); + return true; +} + +/*============================================================================= +FUNCTION: + execute_output_omx_flush + +DESCRIPTION: + Function that flushes buffers that are pending to be written to driver + +INPUT/OUTPUT PARAMETERS: + None + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_qcelp13_aenc::execute_output_omx_flush() +{ + OMX_BUFFERHEADERTYPE *omx_buf; + unsigned p1; // Parameter - 1 + unsigned p2; // Parameter - 2 + unsigned ident; + unsigned qsize=0; // qsize + unsigned tot_qsize=0; // qsize + + DEBUG_PRINT("Execute_omx_flush on output port"); + + pthread_mutex_lock(&m_outputlock); + do + { + qsize = m_output_q.m_size; + DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\ + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size,qsize); + tot_qsize = qsize; + tot_qsize += m_output_ctrl_fbd_q.m_size; + if (!tot_qsize) + { + DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP"); + pthread_mutex_unlock(&m_outputlock); + break; + } + if (qsize) + { + m_output_q.pop_entry(&p1,&p2,&ident); + if ( (OMX_COMPONENT_GENERATE_FTB == ident) || + (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FBD FROM FLUSH"); + } + } else if ((qsize = m_output_ctrl_fbd_q.m_size)) + { + m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident); + if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident) + { + omx_buf = (OMX_BUFFERHEADERTYPE *) p2; + DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \ + omx_buf,nTimestamp); + omx_buf->nTimeStamp = nTimestamp; + omx_buf->nFilledLen = 0; + frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf); + DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH"); + } + } + }while (qsize>0); + DEBUG_DETAIL("*************************\n"); + DEBUG_DETAIL("OUT-->FLUSHING DONE\n"); + DEBUG_DETAIL("*************************\n"); + flush_ack(); + pthread_mutex_unlock(&m_outputlock); + return true; +} + +/*============================================================================= +FUNCTION: + post_input + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_qcelp13_aenc::post_input(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + pthread_mutex_lock(&m_lock); + + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)) + { + // insert flush message and ebd + m_input_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id)) + { + // insert ebd + m_input_ctrl_ebd_q.insert_entry(p1,p2,id); + } else + { + // ETBS in this queue + m_input_q.insert_entry(p1,p2,id); + } + + if (m_ipc_to_in_th) + { + bRet = true; + omx_qcelp13_post_msg(m_ipc_to_in_th, id); + } + + DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\ + m_state, + id, + m_input_ctrl_cmd_q.m_size, + m_input_ctrl_ebd_q.m_size, + m_input_q.m_size); + + pthread_mutex_unlock(&m_lock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_command + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_qcelp13_aenc::post_command(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_commandlock); + + m_command_q.insert_entry(p1,p2,id); + + if (m_ipc_to_cmd_th) + { + bRet = true; + omx_qcelp13_post_msg(m_ipc_to_cmd_th, id); + } + + DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\ + m_state, + id, + m_command_q.m_size, + m_flags >> 3); + + pthread_mutex_unlock(&m_commandlock); + return bRet; +} + +/*============================================================================= +FUNCTION: + post_output + +DESCRIPTION: + Function that posts command in the command queue + +INPUT/OUTPUT PARAMETERS: + [IN] p1 + [IN] p2 + [IN] id - command ID + [IN] lock - self-locking mode + +RETURN VALUE: + true + false + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +bool omx_qcelp13_aenc::post_output(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_outputlock); + if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND) + || (id == OMX_COMPONENT_RESUME)) + { + // insert flush message and fbd + m_output_ctrl_cmd_q.insert_entry(p1,p2,id); + } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) ) + { + // insert flush message and fbd + m_output_ctrl_fbd_q.insert_entry(p1,p2,id); + } else + { + m_output_q.insert_entry(p1,p2,id); + } + if ( m_ipc_to_out_th ) + { + bRet = true; + omx_qcelp13_post_msg(m_ipc_to_out_th, id); + } + DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\ + m_state, + id, + m_output_ctrl_cmd_q.m_size, + m_output_ctrl_fbd_q.m_size, + m_output_q.m_size); + + pthread_mutex_unlock(&m_outputlock); + return bRet; +} +/** + @brief member function that return parameters to IL client + + @param hComp handle to component instance + @param paramIndex Parameter type + @param paramData pointer to memory space which would hold the + paramter + @return error status +*/ +OMX_ERRORTYPE omx_qcelp13_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Param in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) + { + DEBUG_PRINT("get_parameter: paramData is NULL\n"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + DEBUG_PRINT("OMX_IndexParamPortDefinition " \ + "portDefn->nPortIndex = %lu\n", + portDefn->nPortIndex); + + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(portDefn); + portDefn->eDomain = OMX_PortDomainAudio; + + if (0 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirInput; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + portDefn->nBufferCountActual = m_inp_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS; + portDefn->nBufferSize = input_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM; + portDefn->format.audio.pNativeRender = 0; + } else if (1 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirOutput; + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + portDefn->nBufferCountActual = m_out_act_buf_count; + portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS; + portDefn->nBufferSize = output_buffer_size; + portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE; + portDefn->format.audio.eEncoding = OMX_AUDIO_CodingQCELP13; + portDefn->format.audio.pNativeRender = 0; + } else + { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_ERROR("Bad Port idx %d\n",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioInit\n"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n"); + portFormatType->nVersion.nVersion = OMX_SPEC_VERSION; + portFormatType->nSize = sizeof(portFormatType); + + if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex) + { + + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + portFormatType->nPortIndex) + { + DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\ + "%lu\n", portFormatType->nIndex); + + portFormatType->eEncoding = OMX_AUDIO_CodingQCELP13; + } else + { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n", + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamAudioQcelp13: + { + OMX_AUDIO_PARAM_QCELP13TYPE *qcelp13Param = + (OMX_AUDIO_PARAM_QCELP13TYPE *) paramData; + DEBUG_PRINT("OMX_IndexParamAudioQcelp13\n"); + if (OMX_CORE_OUTPUT_PORT_INDEX== qcelp13Param->nPortIndex) + { + memcpy(qcelp13Param,&m_qcelp13_param, + sizeof(OMX_AUDIO_PARAM_QCELP13TYPE)); + } else + { + DEBUG_PRINT_ERROR("get_parameter:\ + OMX_IndexParamAudioQcelp13 \ + OMX_ErrorBadPortIndex %d\n", \ + (int)qcelp13Param->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case QOMX_IndexParamAudioSessionId: + { + QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam = + (QOMX_AUDIO_STREAM_INFO_DATA *) paramData; + streaminfoparam->sessionId = m_session_id; + break; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam = + (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(pcmparam,&m_pcm_param,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + DEBUG_PRINT("get_parameter: Sampling rate %lu",\ + pcmparam->nSamplingRate); + DEBUG_PRINT("get_parameter: Number of channels %lu",\ + pcmparam->nChannels); + } else + { + DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\ + "OMX_ErrorBadPortIndex %d\n", \ + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamComponentSuspended: + { + OMX_PARAM_SUSPENSIONTYPE *suspend = + (OMX_PARAM_SUSPENSIONTYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n", + suspend); + break; + } + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamPriorityMgmt: + { + OMX_PRIORITYMGMTTYPE *priorityMgmtType = + (OMX_PRIORITYMGMTTYPE*)paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n"); + priorityMgmtType->nSize = sizeof(priorityMgmtType); + priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmtType->nGroupID = m_priority_mgm.nGroupID; + priorityMgmtType->nGroupPriority = + m_priority_mgm.nGroupPriority; + break; + } + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("get_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + + bufferSupplierType->nSize = sizeof(bufferSupplierType); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if (OMX_CORE_INPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + bufferSupplierType->nPortIndex) + { + bufferSupplierType->nPortIndex = + OMX_BufferSupplyUnspecified; + } else + { + DEBUG_PRINT_ERROR("get_parameter:"\ + "OMX_IndexParamCompBufferSupplier eRet"\ + "%08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n"); + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 0; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + componentRole->nSize = component_Role.nSize; + componentRole->nVersion = component_Role.nVersion; + strlcpy((char *)componentRole->cRole, + (const char*)component_Role.cRole, + sizeof(componentRole->cRole)); + DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n", + component_Role.nSize, + component_Role.nVersion, + component_Role.cRole); + break; + + } + default: + { + DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; + +} + +/** + @brief member function that set paramter from IL client + + @param hComp handle to component instance + @param paramIndex parameter type + @param paramData pointer to memory space which holds the paramter + @return error status + */ +OMX_ERRORTYPE omx_qcelp13_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("set_parameter is not in proper state\n"); + return OMX_ErrorIncorrectStateOperation; + } + if (paramData == NULL) + { + DEBUG_PRINT("param data is NULL"); + return OMX_ErrorBadParameter; + } + + switch (paramIndex) + { + case OMX_IndexParamAudioQcelp13: + { + DEBUG_PRINT("OMX_IndexParamAudioQcelp13"); + OMX_AUDIO_PARAM_QCELP13TYPE *qcelp13param + = (OMX_AUDIO_PARAM_QCELP13TYPE *) paramData; + memcpy(&m_qcelp13_param,qcelp13param, + sizeof(OMX_AUDIO_PARAM_QCELP13TYPE)); + break; + } + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + if (((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (m_state == OMX_StateWaitForResources && + ((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == true)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == true))) + ||(((OMX_DirInput == portDefn->eDir && + m_inp_bEnabled == false)|| + (OMX_DirInput == portDefn->eDir && + m_out_bEnabled == false)) && + (m_state != OMX_StateWaitForResources))) + { + DEBUG_PRINT("Set Parameter called in valid state\n"); + } else + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex " + "= %lu\n",portDefn->nPortIndex); + if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_INPUT_BUFFERS ) + { + m_inp_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS; + } + input_buffer_size = portDefn->nBufferSize; + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex) + { + if ( portDefn->nBufferCountActual > + OMX_CORE_NUM_OUTPUT_BUFFERS ) + { + m_out_act_buf_count = portDefn->nBufferCountActual; + } else + { + m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS; + } + output_buffer_size = portDefn->nBufferSize; + } else + { + DEBUG_PRINT(" set_parameter: Bad Port idx %d",\ + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamPriorityMgmt: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n"); + + if (m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("Set Parameter called in \ + Invalid State\n"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype + = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n", + priorityMgmtype->nGroupID); + + DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n", + priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + case OMX_IndexParamAudioPortFormat: + { + + OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData; + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n"); + + if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex) + { + portFormatType->eEncoding = OMX_AUDIO_CodingPCM; + } else if (OMX_CORE_OUTPUT_PORT_INDEX == + portFormatType->nPortIndex) + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\ + " %lu\n", portFormatType->nIndex); + portFormatType->eEncoding = OMX_AUDIO_CodingQCELP13; + } else + { + DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \ + (int)portFormatType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT("set_parameter: \ + OMX_IndexParamCompBufferSupplier\n"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType + = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\ + bufferSupplierType->eBufferSupplier); + + if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX + || bufferSupplierType->nPortIndex == + OMX_CORE_OUTPUT_PORT_INDEX) + { + DEBUG_PRINT("set_parameter:\ + OMX_IndexParamCompBufferSupplier\n"); + m_buffer_supplier.eBufferSupplier = + bufferSupplierType->eBufferSupplier; + } else + { + DEBUG_PRINT_ERROR("set_param:\ + IndexParamCompBufferSup %08x\n", eRet); + eRet = OMX_ErrorBadPortIndex; + } + + break; } + + case OMX_IndexParamAudioPcm: + { + DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n"); + OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam + = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData; + + if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex) + { + memcpy(&m_pcm_param,pcmparam,\ + sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + DEBUG_PRINT("set_pcm_parameter: %lu %lu",\ + m_pcm_param.nChannels, + m_pcm_param.nSamplingRate); + } else + { + DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm " + "OMX_ErrorBadPortIndex %d\n", + (int)pcmparam->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamSuspensionPolicy: + { + eRet = OMX_ErrorNotImplemented; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *componentRole; + componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData; + component_Role.nSize = componentRole->nSize; + component_Role.nVersion = componentRole->nVersion; + strlcpy((char *)component_Role.cRole, + (const char*)componentRole->cRole, + sizeof(component_Role.cRole)); + break; + } + + default: + { + DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::GetConfig + +DESCRIPTION + OMX Get Config Method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *volume = + (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex) + { + volume->nSize = sizeof(volume); + volume->nVersion.nVersion = OMX_SPEC_VERSION; + volume->bLinear = OMX_TRUE; + volume->sVolume.nValue = m_volume; + volume->sVolume.nMax = OMX_AENC_MAX; + volume->sVolume.nMin = OMX_AENC_MIN; + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = + (OMX_AUDIO_CONFIG_MUTETYPE*) configData; + + if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex) + { + mute->nSize = sizeof(mute); + mute->nVersion.nVersion = OMX_SPEC_VERSION; + mute->bMute = (BITMASK_PRESENT(&m_flags, + OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE); + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::SetConfig + +DESCRIPTION + OMX Set Config method implementation + +PARAMETERS + . + +RETURN VALUE + OMX Error None if successful. +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Set Config in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if ( m_state == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n"); + return OMX_ErrorInvalidState; + } + + switch (configIndex) + { + case OMX_IndexConfigAudioVolume: + { + OMX_AUDIO_CONFIG_VOLUMETYPE *vol = + (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData; + if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if ((vol->sVolume.nValue <= OMX_AENC_MAX) && + (vol->sVolume.nValue >= OMX_AENC_MIN)) + { + m_volume = vol->sVolume.nValue; + if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED)) + { + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + + } else + { + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + case OMX_IndexConfigAudioMute: + { + OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*) + configData; + if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) + { + if (mute->bMute == OMX_TRUE) + { + BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */ + } else + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED); + /* ioctl(m_drv_fd, AUDIO_VOLUME, + m_volume * OMX_AENC_VOLUME_STEP); */ + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + } + break; + + default: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::GetExtensionIndex + +DESCRIPTION + OMX GetExtensionIndex method implementaion. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::get_extension_index( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + if((hComp == NULL) || (paramName == NULL) || (indexType == NULL)) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId", + strlen("OMX.Qualcomm.index.audio.sessionId")) == 0) + { + *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId; + DEBUG_PRINT("Extension index type - %d\n", *indexType); + + } + else + { + return OMX_ErrorBadParameter; + + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::GetState + +DESCRIPTION + Returns the state information back to the caller. + +PARAMETERS + . + +RETURN VALUE + Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + *state = m_state; + DEBUG_PRINT("Returning the state %d\n",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::ComponentTunnelRequest + +DESCRIPTION + OMX Component Tunnel Request method implementation. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::component_tunnel_request +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n"); + + if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL)) + { + port = 0; + peerPort = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::AllocateInputBuffer + +DESCRIPTION + Helper function for allocate buffer in the input pin + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::allocate_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + if(m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc((nBufSize + \ + sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1); + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + free(buf_ptr); + return OMX_ErrorBadParameter; + } + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+ + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + m_input_buf_hdrs.insert(bufHdr, NULL); + + m_inp_current_buf_count++; + DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%d \ + bytes=%lu", bufHdr, bufHdr->pBuffer,m_inp_current_buf_count, + bytes); + + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } + else + { + DEBUG_PRINT("Input buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +OMX_ERRORTYPE omx_qcelp13_aenc::allocate_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_out_current_buf_count < m_out_act_buf_count) + { + buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + + sizeof(OMX_BUFFERHEADERTYPE)); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d "\ + "bytes=%lu",bufHdr, bufHdr->pBuffer,\ + m_out_current_buf_count, bytes); + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::AllocateBuffer + +DESCRIPTION + Returns zero if all the buffers released.. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::allocate_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n"); + return OMX_ErrorInvalidState; + } + // What if the client calls again. + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n", + (int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("allocate_buffer: before allocate_done \n"); + if (allocate_done()) + { + DEBUG_PRINT("allocate_buffer: after allocate_done \n"); + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("allocate_buffer: post idle transition event \n"); + } + DEBUG_PRINT("allocate_buffer: complete \n"); + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + m_out_bEnabled = OMX_TRUE; + + DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("AB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet); + return eRet; +} + +/*============================================================================= +FUNCTION: + use_buffer + +DESCRIPTION: + OMX Use Buffer method implementation. + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_qcelp13_aenc::use_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + } else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) + { + DEBUG_PRINT("Checking for Output Allocate buffer Done"); + if (allocate_done()) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING); + post_command(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + pthread_mutex_lock(&m_in_th_lock_1); + if(is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("UB:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + } + } + DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet); + return eRet; +} +/*============================================================================= +FUNCTION: + use_input_buffer + +DESCRIPTION: + Helper function for Use buffer in the input pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_qcelp13_aenc::use_input_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes, input_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if(bytes < input_buffer_size) + { + /* return if i\p buffer size provided by client + is less than min i\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + if (m_inp_current_buf_count < m_inp_act_buf_count) + { + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \ + bytes=%lu", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + input_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_input_buf_hdrs.insert(bufHdr, NULL); + m_inp_current_buf_count++; + } else + { + DEBUG_PRINT("Input buffer memory allocation failed 1 \n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Input buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/*============================================================================= +FUNCTION: + use_output_buffer + +DESCRIPTION: + Helper function for Use buffer in the output pin + +INPUT/OUTPUT PARAMETERS: + [INOUT] bufferHdr + [IN] hComp + [IN] port + [IN] appData + [IN] bytes + [IN] buffer + +RETURN VALUE: + OMX_ERRORTYPE + +Dependency: + None + +SIDE EFFECTS: + None +=============================================================================*/ +OMX_ERRORTYPE omx_qcelp13_aenc::use_output_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr; + unsigned nBufSize = MAX(bytes,output_buffer_size); + char *buf_ptr; + + if(hComp == NULL) + { + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (bytes < output_buffer_size) + { + /* return if o\p buffer size provided by client + is less than min o\p buffer size supported by omx component*/ + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT("Inside omx_qcelp13_aenc::use_output_buffer"); + if (m_out_current_buf_count < m_out_act_buf_count) + { + + buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1); + + if (buf_ptr != NULL) + { + bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr; + DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer); + *bufferHdr = bufHdr; + memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE)); + + bufHdr->pBuffer = (OMX_U8 *)(buffer); + DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \ + len=%lu\n", bufHdr, bufHdr->pBuffer,bytes); + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = nBufSize; + output_buffer_size = nBufSize; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + bufHdr->nOffset = 0; + m_output_buf_hdrs.insert(bufHdr, NULL); + m_out_current_buf_count++; + + } else + { + DEBUG_PRINT("Output buffer memory allocation failed\n"); + eRet = OMX_ErrorInsufficientResources; + } + } else + { + DEBUG_PRINT("Output buffer memory allocation failed 2\n"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_qcelp13_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_input_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_input_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +/** + @brief member function that searches for caller buffer + + @param buffer pointer to buffer header + @return bool value indicating whether buffer is found + */ +bool omx_qcelp13_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer) +{ + + bool eRet = false; + OMX_BUFFERHEADERTYPE *temp = NULL; + + //access only in IL client context + temp = m_output_buf_hdrs.find_ele(buffer); + if (buffer && temp) + { + DEBUG_DETAIL("search_output_bufhdr %x \n", buffer); + eRet = true; + } + return eRet; +} + +// Free Buffer - API call +/** + @brief member function that handles free buffer command from IL client + + This function is a block-call function that handles IL client request to + freeing the buffer + + @param hComp handle to component instance + @param port id of port which holds the buffer + @param buffer buffer header + @return Error status +*/ +OMX_ERRORTYPE omx_qcelp13_aenc::free_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("Free_Buffer buf %p\n", buffer); + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + DEBUG_PRINT(" free buffer while Component in Loading pending\n"); + } else if ((m_inp_bEnabled == OMX_FALSE && + port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && + port == OMX_CORE_OUTPUT_PORT_INDEX)) + { + DEBUG_PRINT("Free Buffer while port %lu disabled\n", port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) + { + DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\ + OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return eRet; + } else + { + DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\ + disabled:OMX_ErrorPortUnpopulated\n"); + post_command(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + if (OMX_CORE_INPUT_PORT_INDEX == port) + { + if (m_inp_current_buf_count != 0) + { + m_inp_bPopulated = OMX_FALSE; + if (true == search_input_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer); + m_input_buf_hdrs.erase(buffer); + free(buffer); + m_inp_current_buf_count--; + } else + { + DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \ + Invalid Input buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \ + came out Invalid\n"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_done(0)) + { + DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (OMX_CORE_OUTPUT_PORT_INDEX == port) + { + if (m_out_current_buf_count != 0) + { + m_out_bPopulated = OMX_FALSE; + if (true == search_output_bufhdr(buffer)) + { + /* Buffer exist */ + //access only in IL client context + DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer); + m_output_buf_hdrs.erase(buffer); + free(buffer); + m_out_current_buf_count--; + } else + { + DEBUG_PRINT("Free_Buf:Error-->free_buffer , \ + Invalid Output buffer header\n"); + eRet = OMX_ErrorBadParameter; + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_done(1)) + { + DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + post_command(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } + } else + { + eRet = OMX_ErrorBadPortIndex; + } + if ((OMX_ErrorNone == eRet) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + if (release_done(-1)) + { + if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0) + DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n"); + else + DEBUG_PRINT("AUDIO STOP in free buffer passed\n"); + + + DEBUG_PRINT("Free_Buf: Free buffer\n"); + + + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + DEBUG_PRINT("Before OMX_StateLoaded \ + OMX_COMPONENT_GENERATE_EVENT\n"); + post_command(OMX_CommandStateSet, + OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT); + DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n"); + + } + } + return eRet; +} + + +/** + @brief member function that that handles empty this buffer command + + This function meremly queue up the command and data would be consumed + in command server thread context + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_qcelp13_aenc::empty_this_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \ + buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf)); + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT("Empty this buffer in Invalid State\n"); + return OMX_ErrorInvalidState; + } + if (!m_inp_bEnabled) + { + DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\ + "Port Status %d \n", m_inp_bEnabled); + return OMX_ErrorIncorrectStateOperation; + } + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_qcelp13_aenc::etb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_qcelp13_aenc::etb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + if ((m_state != OMX_StateExecuting) && + (m_state != OMX_StatePause)) + { + DEBUG_PRINT_ERROR("Invalid state\n"); + eRet = OMX_ErrorInvalidState; + } + if (OMX_ErrorNone == eRet) + { + if (search_input_bufhdr(buffer) == true) + { + post_input((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB); + } else + { + DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer); + eRet = OMX_ErrorBadParameter; + } + } + pthread_mutex_lock(&in_buf_count_lock); + nNumInputBuf++; + m_qcelp13_pb_stats.etb_cnt++; + pthread_mutex_unlock(&in_buf_count_lock); + return eRet; +} +/** + @brief member function that writes data to kernel driver + + @param hComp handle to component instance + @param buffer pointer to buffer header + @return error status + */ +OMX_ERRORTYPE omx_qcelp13_aenc::empty_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + META_IN meta_in; + //Pointer to the starting location of the data to be transcoded + OMX_U8 *srcStart; + //The total length of the data to be transcoded + srcStart = buffer->pBuffer; + OMX_U8 *data = NULL; + PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer); + memset(&meta_in,0,sizeof(meta_in)); + if ( search_input_bufhdr(buffer) == false ) + { + DEBUG_PRINT("ETBP: INVALID BUF HDR\n"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorBadParameter; + } + if (m_tmp_meta_buf) + { + data = m_tmp_meta_buf; + + // copy the metadata info from the BufHdr and insert to payload + meta_in.offsetVal = sizeof(META_IN); + meta_in.nTimeStamp.LowPart = + ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF); + meta_in.nTimeStamp.HighPart = + (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF); + meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS; + if(buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT("EOS OCCURED \n"); + meta_in.nFlags |= OMX_BUFFERFLAG_EOS; + } + memcpy(data,&meta_in, meta_in.offsetVal); + DEBUG_PRINT("meta_in.nFlags = 0x%8x\n",meta_in.nFlags); + } + + memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen); + write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN)); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (OMX_StateExecuting == state) + { + DEBUG_DETAIL("In Exe state, EBD CB"); + buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + } else + { + /* Assume empty this buffer function has already checked + validity of buffer */ + DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer); + post_input((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_BUFFER_DONE); + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_qcelp13_aenc::fill_this_buffer_proxy +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_STATETYPE state; + ENC_META_OUT *meta_out = NULL; + int nReadbytes = 0; + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (true == search_output_bufhdr(buffer)) + { + DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd); + nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size ); + DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\ + buffer->nAllocLen,buffer->pBuffer, + nReadbytes,nNumOutputBuf); + if (nReadbytes <= 0) { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + return OMX_ErrorNone; + } else + DEBUG_PRINT("Read bytes %d\n",nReadbytes); + + // Buffer from Driver will have + // 1 byte => Nr of frame field + // (sizeof(ENC_META_OUT) * Nr of frame) bytes => meta_out->offset_to_frame + // Frame Size * Nr of frame => + + meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char)); + buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+ + meta_out->lsw_ts); + buffer->nFlags |= meta_out->nflags; + buffer->nOffset = meta_out->offset_to_frame + sizeof(unsigned char); + buffer->nFilledLen = nReadbytes - buffer->nOffset; + nTimestamp = buffer->nTimeStamp; + DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \ + timestamp %lld\n", meta_out->nflags, + meta_out->frame_size, meta_out->offset_to_frame, + buffer->nTimeStamp); + + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + buffer->nFilledLen = 0; + buffer->nOffset = 0; + buffer->nTimeStamp = nTimestamp; + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS ) + { + DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n"); + m_cb.EventHandler(&m_cmp, + m_app_data, + OMX_EventBufferFlag, + 1, 1, NULL ); + } + + return OMX_ErrorNone; + } + DEBUG_PRINT("nState %d \n",nState ); + + pthread_mutex_lock(&m_state_lock); + get_state(&m_cmp, &state); + pthread_mutex_unlock(&m_state_lock); + + if (state == OMX_StatePause) + { + DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\ + state); + post_output((unsigned) & hComp,(unsigned) buffer, + OMX_COMPONENT_GENERATE_FRAME_DONE); + } + else + { + frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer); + + } + + } + else + DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n"); + + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::FillThisBuffer + +DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + + +PARAMETERS + + None. + +RETURN VALUE + true/false + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::fill_this_buffer +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE)) + { + DEBUG_PRINT("omx_qcelp13_aenc::ftb--> Buffer Size Invalid\n"); + return OMX_ErrorBadParameter; + } + if (m_out_bEnabled == OMX_FALSE) + { + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) + { + DEBUG_PRINT("omx_qcelp13_aenc::ftb--> OMX Version Invalid\n"); + return OMX_ErrorVersionMismatch; + } + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) + { + return OMX_ErrorBadPortIndex; + } + pthread_mutex_lock(&out_buf_count_lock); + nNumOutputBuf++; + m_qcelp13_pb_stats.ftb_cnt++; + DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf); + pthread_mutex_unlock(&out_buf_count_lock); + post_output((unsigned)hComp, + (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB); + return eRet; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::SetCallbacks + +DESCRIPTION + Set the callbacks. + +PARAMETERS + None. + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::set_callbacks( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + m_cb = *callbacks; + m_app_data = appData; + + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::ComponentDeInit + +DESCRIPTION + Destroys the component and release memory allocated to the heap. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state) + { + DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n", + m_state); + } + deinit_encoder(); + +DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::deinit_encoder + +DESCRIPTION + Closes all the threads and release memory allocated to the heap. + +PARAMETERS + None. + +RETURN VALUE + None. + +========================================================================== */ +void omx_qcelp13_aenc::deinit_encoder() +{ + DEBUG_PRINT("Component-deinit being processed\n"); + DEBUG_PRINT("********************************\n"); + DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\ + m_qcelp13_pb_stats.tot_in_buf_len, + m_qcelp13_pb_stats.tot_out_buf_len, + m_qcelp13_pb_stats.tot_pb_time); + DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\ + m_qcelp13_pb_stats.fbd_cnt,m_qcelp13_pb_stats.ftb_cnt, + m_qcelp13_pb_stats.etb_cnt, + m_qcelp13_pb_stats.ebd_cnt); + memset(&m_qcelp13_pb_stats,0,sizeof(QCELP13_PB_STATS)); + + if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state)) + { + DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\ + m_state); + // Get back any buffers from driver + if(pcm_input) + execute_omx_flush(-1,false); + else + execute_omx_flush(1,false); + // force state change to loaded so that all threads can be exited + pthread_mutex_lock(&m_state_lock); + m_state = OMX_StateLoaded; + pthread_mutex_unlock(&m_state_lock); + DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\ + m_inp_current_buf_count, + m_input_buf_hdrs.size()); + m_input_buf_hdrs.eraseall(); + DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\ + m_out_current_buf_count, + m_output_buf_hdrs.size()); + m_output_buf_hdrs.eraseall(); + + } + if(pcm_input) + { + pthread_mutex_lock(&m_in_th_lock_1); + if (is_in_th_sleep) + { + is_in_th_sleep = false; + DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n"); + in_th_wakeup(); + } + pthread_mutex_unlock(&m_in_th_lock_1); + } + pthread_mutex_lock(&m_out_th_lock_1); + if (is_out_th_sleep) + { + is_out_th_sleep = false; + DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n"); + out_th_wakeup(); + } + pthread_mutex_unlock(&m_out_th_lock_1); + if(pcm_input) + { + if (m_ipc_to_in_th != NULL) + { + omx_qcelp13_thread_stop(m_ipc_to_in_th); + m_ipc_to_in_th = NULL; + } + } + + if (m_ipc_to_cmd_th != NULL) + { + omx_qcelp13_thread_stop(m_ipc_to_cmd_th); + m_ipc_to_cmd_th = NULL; + } + if (m_ipc_to_out_th != NULL) + { + DEBUG_DETAIL("Inside omx_qcelp13_thread_stop\n"); + omx_qcelp13_thread_stop(m_ipc_to_out_th); + m_ipc_to_out_th = NULL; + } + + + if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0) + DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n"); + + if(pcm_input && m_tmp_meta_buf ) + { + free(m_tmp_meta_buf); + } + + if(m_tmp_out_meta_buf) + { + free(m_tmp_out_meta_buf); + } + nNumInputBuf = 0; + nNumOutputBuf = 0; + bFlushinprogress = 0; + + m_inp_current_buf_count=0; + m_out_current_buf_count=0; + m_out_act_buf_count = 0; + m_inp_act_buf_count = 0; + m_inp_bEnabled = OMX_FALSE; + m_out_bEnabled = OMX_FALSE; + m_inp_bPopulated = OMX_FALSE; + m_out_bPopulated = OMX_FALSE; + + if ( m_drv_fd >= 0 ) + { + if(close(m_drv_fd) < 0) + DEBUG_PRINT("De-init: Driver Close Failed \n"); + m_drv_fd = -1; + } + else + { + DEBUG_PRINT_ERROR(" QCELP13 device already closed\n"); + } + m_comp_deinit=1; + m_is_out_th_sleep = 1; + m_is_in_th_sleep = 1; + DEBUG_PRINT("************************************\n"); + DEBUG_PRINT(" DEINIT COMPLETED"); + DEBUG_PRINT("************************************\n"); + +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::UseEGLImage + +DESCRIPTION + OMX Use EGL Image method implementation . + +PARAMETERS + . + +RETURN VALUE + Not Implemented error. + +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::use_EGL_image +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n"); + + if((hComp == NULL) || (appData == NULL) || (eglImage == NULL)) + { + bufferHdr = NULL; + port = 0; + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::ComponentRoleEnum + +DESCRIPTION + OMX Component Role Enum method implementation. + +PARAMETERS + . + +RETURN VALUE + OMX Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_qcelp13_aenc::component_role_enum( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + const char *cmp_role = "audio_encoder.qcelp13"; + + if(hComp == NULL) + { + DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n"); + return OMX_ErrorBadParameter; + } + if (index == 0 && role) + { + memcpy(role, cmp_role, sizeof(cmp_role)); + *(((char *) role) + sizeof(cmp_role)) = '\0'; + } else + { + eRet = OMX_ErrorNoMore; + } + return eRet; +} + + + + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::AllocateDone + +DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + +PARAMETERS + None. + +RETURN VALUE + true/false. + +========================================================================== */ +bool omx_qcelp13_aenc::allocate_done(void) +{ + OMX_BOOL bRet = OMX_FALSE; + if (pcm_input==1) + { + if ((m_inp_act_buf_count == m_inp_current_buf_count) + &&(m_out_act_buf_count == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + + } + if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled ) + { + m_inp_bPopulated = OMX_TRUE; + } + + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + } else if (pcm_input==0) + { + if (m_out_act_buf_count == m_out_current_buf_count) + { + bRet=OMX_TRUE; + + } + if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled ) + { + m_out_bPopulated = OMX_TRUE; + } + + } + return bRet; +} + + +/* ====================================================================== +FUNCTION + omx_qcelp13_aenc::ReleaseDone + +DESCRIPTION + Checks if IL client has released all the buffers. + +PARAMETERS + None. + +RETURN VALUE + true/false + +========================================================================== */ +bool omx_qcelp13_aenc::release_done(OMX_U32 param1) +{ + DEBUG_PRINT("Inside omx_qcelp13_aenc::release_done"); + OMX_BOOL bRet = OMX_FALSE; + + if (param1 == OMX_ALL) + { + if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_INPUT_PORT_INDEX ) + { + if ((0 == m_inp_current_buf_count)) + { + bRet=OMX_TRUE; + } + } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX) + { + if ((0 == m_out_current_buf_count)) + { + bRet=OMX_TRUE; + } + } + return bRet; +} diff --git a/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c b/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c new file mode 100644 index 000000000..5c59349c8 --- /dev/null +++ b/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c @@ -0,0 +1,1097 @@ + +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + + +/* + An Open max test application .... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif + + +#include + +typedef unsigned char uint8; +typedef unsigned char byte; +typedef unsigned int uint32; +typedef unsigned int uint16; +QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam; +/* maximum ADTS frame header length */ +void Release_Encoder(); + +#ifdef AUDIOV2 +unsigned short session_id; +int device_id; +int control = 0; +const char *device="handset_tx"; +#define DIR_TX 2 +#endif + +uint32_t samplerate = 8000; +uint32_t channels = 1; +uint32_t min_bitrate = 0; +uint32_t max_bitrate = 0; +uint32_t cdmarate = 0; +uint32_t rectime = -1; +uint32_t recpath = -1; +uint32_t pcmplayback = 0; +uint32_t tunnel = 0; +uint32_t format = 1; +#define DEBUG_PRINT printf +unsigned to_idle_transition = 0; +unsigned long total_pcm_bytes; + +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +/************************************************************************/ +/* #DEFINES */ +/************************************************************************/ +#define false 0 +#define true 1 + +#define CONFIG_VERSION_SIZE(param) \ + param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ + param.nSize = sizeof(param); + +#define QCP_HEADER_SIZE sizeof(struct qcp_header) +#define MIN_BITRATE 4 /* Bit rate 1 - 13.6 , 2 - 6.2 , 3 - 2.7 , 4 - 1.0 kbps*/ +#define MAX_BITRATE 4 + +#define FAILED(result) (result != OMX_ErrorNone) + +#define SUCCEEDED(result) (result == OMX_ErrorNone) + +/************************************************************************/ +/* GLOBAL DECLARATIONS */ +/************************************************************************/ + +pthread_mutex_t lock; +pthread_cond_t cond; +pthread_mutex_t elock; +pthread_cond_t econd; +pthread_cond_t fcond; +pthread_mutex_t etb_lock; +pthread_mutex_t etb_lock1; +pthread_cond_t etb_cond; +FILE * inputBufferFile; +FILE * outputBufferFile; +OMX_PARAM_PORTDEFINITIONTYPE inputportFmt; +OMX_PARAM_PORTDEFINITIONTYPE outputportFmt; +OMX_AUDIO_PARAM_QCELP13TYPE qcelp13param; +OMX_AUDIO_PARAM_PCMMODETYPE pcmparam; +OMX_PORT_PARAM_TYPE portParam; +OMX_PORT_PARAM_TYPE portFmt; +OMX_ERRORTYPE error; + + + + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; +struct enc_meta_out{ + unsigned int offset_to_frame; + unsigned int frame_size; + unsigned int encoded_pcm_samples; + unsigned int msw_ts; + unsigned int lsw_ts; + unsigned int nflags; +} __attribute__ ((packed)); + +struct qcp_header { + /* RIFF Section */ + char riff[4]; + unsigned int s_riff; + char qlcm[4]; + + /* Format chunk */ + char fmt[4]; + unsigned int s_fmt; + char mjr; + char mnr; + unsigned int data1; /* UNIQUE ID of the codec */ + unsigned short data2; + unsigned short data3; + char data4[8]; + unsigned short ver; /* Codec Info */ + char name[80]; + unsigned short abps; /* average bits per sec of the codec */ + unsigned short bytes_per_pkt; + unsigned short samp_per_block; + unsigned short samp_per_sec; + unsigned short bits_per_samp; + unsigned char vr_num_of_rates; /* Rate Header fmt info */ + unsigned char rvd1[3]; + unsigned short vr_bytes_per_pkt[8]; + unsigned int rvd2[5]; + + /* Vrat chunk */ + unsigned char vrat[4]; + unsigned int s_vrat; + unsigned int v_rate; + unsigned int size_in_pkts; + + /* Data chunk */ + unsigned char data[4]; + unsigned int s_data; +} __attribute__ ((packed)); + + /* Common part */ + static struct qcp_header append_header = { + {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, + {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, + {'v','r','a','t'},0, 0, 0,{'d','a','t','a'},0 + }; + +static unsigned totaldatalen = 0; +static unsigned framecnt = 0; +/************************************************************************/ +/* GLOBAL INIT */ +/************************************************************************/ + +int input_buf_cnt = 0; +int output_buf_cnt = 0; +int used_ip_buf_cnt = 0; +volatile int event_is_done = 0; +volatile int ebd_event_is_done = 0; +volatile int fbd_event_is_done = 0; +volatile int etb_event_is_done = 0; +int ebd_cnt; +int bInputEosReached = 0; +int bOutputEosReached = 0; +int bInputEosReached_tunnel = 0; +static int etb_done = 0; +int bFlushing = false; +int bPause = false; +const char *in_filename; +const char *out_filename; + +int timeStampLfile = 0; +int timestampInterval = 100; + +//* OMX Spec Version supported by the wrappers. Version = 1.1 */ +const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; +OMX_COMPONENTTYPE* qcelp13_enc_handle = 0; + +OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; +OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL; + +/************************************************************************/ +/* GLOBAL FUNC DECL */ +/************************************************************************/ +int Init_Encoder(char*); +int Play_Encoder(); +OMX_STRING aud_comp; +/**************************************************************************/ +/* STATIC DECLARATIONS */ +/**************************************************************************/ + +static int open_audio_file (); +static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr ); +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *qcelp13_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize); + + +static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); +static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); +static OMX_ERRORTYPE parse_pcm_header(); +void wait_for_event(void) +{ + pthread_mutex_lock(&lock); + DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done); + while (event_is_done == 0) { + pthread_cond_wait(&cond, &lock); + } + event_is_done = 0; + pthread_mutex_unlock(&lock); +} + +void event_complete(void ) +{ + pthread_mutex_lock(&lock); + if (event_is_done == 0) { + event_is_done = 1; + pthread_cond_broadcast(&cond); + } + pthread_mutex_unlock(&lock); +} + +void etb_wait_for_event(void) +{ + pthread_mutex_lock(&etb_lock1); + DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done); + while (etb_event_is_done == 0) { + pthread_cond_wait(&etb_cond, &etb_lock1); + } + etb_event_is_done = 0; + pthread_mutex_unlock(&etb_lock1); +} + +void etb_event_complete(void ) +{ + pthread_mutex_lock(&etb_lock1); + if (etb_event_is_done == 0) { + etb_event_is_done = 1; + pthread_cond_broadcast(&etb_cond); + } + pthread_mutex_unlock(&etb_lock1); +} + +static void create_qcp_header(int Datasize, int Frames) +{ + append_header.s_riff = Datasize + QCP_HEADER_SIZE - 8; + /* exclude riff id and size field */ + append_header.data1 = 0x5E7F6D41; + append_header.data2 = 0xB115; + append_header.data3 = 0x11D0; + append_header.data4[0] = 0xBA; + append_header.data4[1] = 0x91; + append_header.data4[2] = 0x00; + append_header.data4[3] = 0x80; + append_header.data4[4] = 0x5F; + append_header.data4[5] = 0xB4; + append_header.data4[6] = 0xB9; + append_header.data4[7] = 0x7E; + append_header.ver = 0x0002; + memcpy(append_header.name, "Qcelp 13K", 9); + append_header.abps = 13000; + append_header.bytes_per_pkt = 35; + append_header.vr_num_of_rates = 5; + append_header.vr_bytes_per_pkt[0] = 0x0422; + append_header.vr_bytes_per_pkt[1] = 0x0310; + append_header.vr_bytes_per_pkt[2] = 0x0207; + append_header.vr_bytes_per_pkt[3] = 0x0103; + append_header.s_vrat = 0x00000008; + append_header.v_rate = 0x00000001; + append_header.size_in_pkts = Frames; + append_header.s_data = Datasize; + return; +} + +OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + DEBUG_PRINT("Function %s \n", __FUNCTION__); + + /* To remove warning for unused variable to keep prototype same */ + (void)hComponent; + (void)pAppData; + (void)pEventData; + + switch(eEvent) { + case OMX_EventCmdComplete: + DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent, + nData1,nData2); + event_complete(); + break; + case OMX_EventError: + DEBUG_PRINT("\n OMX_EventError \n"); + break; + case OMX_EventBufferFlag: + DEBUG_PRINT("\n OMX_EventBufferFlag \n"); + bOutputEosReached = true; + event_complete(); + break; + case OMX_EventPortSettingsChanged: + DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n"); + break; + default: + DEBUG_PRINT("\n Unknown Event \n"); + break; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + size_t bytes_writen = 0; + int total_bytes_writen = 0; + unsigned int len = 0; + struct enc_meta_out *meta = NULL; + OMX_U8 *src = pBuffer->pBuffer; + unsigned int num_of_frames = 1; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT("FBD::EOS on output port\n "); + bOutputEosReached = true; + return OMX_ErrorNone; + } + if(bInputEosReached_tunnel || bOutputEosReached) + { + DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n"); + return OMX_ErrorNone; + } + if(num_of_frames != src[0]){ + + printf("Data corrupt\n"); + return OMX_ErrorNone; + } + /* Skip the first bytes */ + + + + src += sizeof(unsigned char); + meta = (struct enc_meta_out *)src; + while (num_of_frames > 0) { + meta = (struct enc_meta_out *)src; + /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n", + meta->offset_to_frame, + meta->frame_size, + meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/ + len = meta->frame_size; + + bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile); + if(bytes_writen < len) + { + DEBUG_PRINT("error: invalid QCELP13 encoded data \n"); + return OMX_ErrorNone; + } + src += sizeof(struct enc_meta_out); + num_of_frames--; + total_bytes_writen += len; + } + DEBUG_PRINT(" FillBufferDone size writen to file %d count %d\n",total_bytes_writen, framecnt); + totaldatalen += total_bytes_writen ; + framecnt++; + + DEBUG_PRINT(" FBD calling FTB\n"); + OMX_FillThisBuffer(hComponent,pBuffer); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) +{ + int readBytes =0; + + /* To remove warning for unused variable to keep prototype same */ + (void)pAppData; + + ebd_cnt++; + used_ip_buf_cnt--; + pthread_mutex_lock(&etb_lock); + if(!etb_done) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT("Wait till first set of buffers are given to component\n"); + DEBUG_PRINT("\n*********************************************\n"); + etb_done++; + pthread_mutex_unlock(&etb_lock); + etb_wait_for_event(); + } + else + { + pthread_mutex_unlock(&etb_lock); + } + + + if(bInputEosReached) + { + DEBUG_PRINT("\n*********************************************\n"); + DEBUG_PRINT(" EBD::EOS on input port\n "); + DEBUG_PRINT("*********************************************\n"); + return OMX_ErrorNone; + }else if (bFlushing == true) { + DEBUG_PRINT("omx_qcelp13_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + if (used_ip_buf_cnt == 0) { + bFlushing = false; + } else { + DEBUG_PRINT("omx_qcelp13_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt); + return OMX_ErrorNone; + } + } + + if((readBytes = Read_Buffer(pBuffer)) > 0) { + pBuffer->nFilledLen = readBytes; + used_ip_buf_cnt++; + OMX_EmptyThisBuffer(hComponent,pBuffer); + } + else{ + pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + used_ip_buf_cnt++; + bInputEosReached = true; + pBuffer->nFilledLen = 0; + OMX_EmptyThisBuffer(hComponent,pBuffer); + DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n"); + } + return OMX_ErrorNone; +} + +void signal_handler(int sig_id) { + + /* Flush */ + if (sig_id == SIGUSR1) { + DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__); + bFlushing = true; + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandFlush, OMX_ALL, NULL); + } else if (sig_id == SIGUSR2) { + if (bPause == true) { + DEBUG_PRINT("%s resume record\n", __FUNCTION__); + bPause = false; + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); + } else { + DEBUG_PRINT("%s pause record\n", __FUNCTION__); + bPause = true; + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL); + } + } +} + +int main(int argc, char **argv) +{ + int bufCnt=0; + OMX_ERRORTYPE result; + + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + (void) signal(SIGINT, Release_Encoder); + + pthread_cond_init(&cond, 0); + pthread_mutex_init(&lock, 0); + pthread_cond_init(&etb_cond, 0); + pthread_mutex_init(&etb_lock, 0); + pthread_mutex_init(&etb_lock1, 0); + + if (argc >= 9) { + in_filename = argv[1]; + out_filename = argv[2]; + tunnel = atoi(argv[3]); + min_bitrate = atoi(argv[4]); + max_bitrate = atoi(argv[5]); + cdmarate = atoi(argv[6]); + recpath = atoi(argv[7]); // No configuration support yet.. + rectime = atoi(argv[8]); + + } else { + DEBUG_PRINT(" invalid format: \n"); + DEBUG_PRINT("ex: ./mm-aenc-omxqcelp13-test INPUTFILE OUTPUTFILE Tunnel MINRATE MAXRATE CDMARATE RECORDPATH RECORDTIME\n"); + DEBUG_PRINT("MINRATE, MAXRATE and CDMARATE 1 to 4\n"); + DEBUG_PRINT("RECORDPATH 0(TX),1(RX),2(BOTH),3(MIC)\n"); + DEBUG_PRINT("RECORDTIME in seconds for AST Automation\n"); + return 0; + } + if(recpath != 3) { + DEBUG_PRINT("For RECORDPATH Only MIC supported\n"); + return 0; + } + + if(tunnel == 0) + aud_comp = "OMX.qcom.audio.encoder.qcelp13"; + else + aud_comp = "OMX.qcom.audio.encoder.tunneled.qcelp13"; + if(Init_Encoder(aud_comp)!= 0x00) + { + DEBUG_PRINT("Decoder Init failed\n"); + return -1; + } + + fcntl(0, F_SETFL, O_NONBLOCK); + + if(Play_Encoder() != 0x00) + { + DEBUG_PRINT("Play_Decoder failed\n"); + return -1; + } + + // Wait till EOS is reached... + if(rectime && tunnel) + { + sleep(rectime); + rectime = 0; + bInputEosReached_tunnel = 1; + DEBUG_PRINT("\EOS ON INPUT PORT\n"); + } + else + { + wait_for_event(); + } + + if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel)) + { + + DEBUG_PRINT("\nMoving the decoder to idle state \n"); + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + wait_for_event(); + + DEBUG_PRINT("\nMoving the encoder to loaded state \n"); + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0); + sleep(1); + if (!tunnel) + { + DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n"); + for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(qcelp13_enc_handle, 0, pInputBufHdrs[bufCnt]); + } + } + + DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n"); + for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) { + OMX_FreeBuffer(qcelp13_enc_handle, 1, pOutputBufHdrs[bufCnt]); + } + wait_for_event(); + create_qcp_header(totaldatalen, framecnt); + fseek(outputBufferFile, 0,SEEK_SET); + fwrite(&append_header,1,QCP_HEADER_SIZE,outputBufferFile); + + + result = OMX_FreeHandle(qcelp13_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + if(tunnel) + { + #ifdef AUDIOV2 + if (msm_route_stream(DIR_TX,session_id,device_id, 0)) + { + DEBUG_PRINT("\ncould not set stream routing\n"); + return -1; + } + if (msm_en_device(device_id, 0)) + { + DEBUG_PRINT("\ncould not enable device\n"); + return -1; + } + msm_mixer_close(); + #endif + } + OMX_Deinit(); + ebd_cnt=0; + bOutputEosReached = false; + bInputEosReached_tunnel = false; + bInputEosReached = 0; + qcelp13_enc_handle = NULL; + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + fclose(outputBufferFile); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...QCELP13 ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + } + return 0; +} + +void Release_Encoder() +{ + static int cnt=0; + OMX_ERRORTYPE result; + + DEBUG_PRINT("END OF QCELP13 ENCODING: EXITING PLEASE WAIT\n"); + bInputEosReached_tunnel = 1; + event_complete(); + cnt++; + if(cnt > 1) + { + /* FORCE RESET */ + qcelp13_enc_handle = NULL; + ebd_cnt=0; + bInputEosReached_tunnel = false; + + result = OMX_FreeHandle(qcelp13_enc_handle); + if (result != OMX_ErrorNone) { + DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result); + } + + /* Deinit OpenMAX */ + + OMX_Deinit(); + + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&lock); + DEBUG_PRINT("*****************************************\n"); + DEBUG_PRINT("******...QCELP13 ENC TEST COMPLETED...***************\n"); + DEBUG_PRINT("*****************************************\n"); + exit(0); + } +} + +int Init_Encoder(OMX_STRING audio_component) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE omxresult; + OMX_U32 total = 0; + typedef OMX_U8* OMX_U8_PTR; + char *role ="audio_encoder"; + + static OMX_CALLBACKTYPE call_back = { + &EventHandler,&EmptyBufferDone,&FillBufferDone + }; + + /* Init. the OpenMAX Core */ + DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); + omxresult = OMX_Init(); + + if(OMX_ErrorNone != omxresult) { + DEBUG_PRINT("\n Failed to Init OpenMAX core"); + return -1; + } + else { + DEBUG_PRINT("\nOpenMAX Core Init Done\n"); + } + + /* Query for audio decoders*/ + DEBUG_PRINT("Qcelp13_test: Before entering OMX_GetComponentOfRole"); + OMX_GetComponentsOfRole(role, &total, 0); + DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total); + + + omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&qcelp13_enc_handle), + (OMX_STRING)audio_component, NULL, &call_back); + if (FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component); + return -1; + } + else + { + DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component); + } + + /* Get the port information */ + CONFIG_VERSION_SIZE(portParam); + omxresult = OMX_GetParameter(qcelp13_enc_handle, OMX_IndexParamAudioInit, + (OMX_PTR)&portParam); + + if(FAILED(omxresult)) { + DEBUG_PRINT("\nFailed to get Port Param\n"); + return -1; + } + else + { + DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts); + DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n", + portParam.nStartPortNumber); + } + + if(OMX_ErrorNone != omxresult) + { + DEBUG_PRINT("Set parameter failed"); + } + + return 0; +} + +int Play_Encoder() +{ + int i; + int Size=0; + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE ret; + OMX_INDEXTYPE index; + DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE)); + + /* open the i/p and o/p files based on the video file format passed */ + if(open_audio_file()) { + DEBUG_PRINT("\n Returning -1"); + return -1; + } + + /* Query the encoder input min buf requirements */ + CONFIG_VERSION_SIZE(inputportFmt); + + /* Port for which the Client needs to obtain info */ + inputportFmt.nPortIndex = portParam.nStartPortNumber; + + OMX_GetParameter(qcelp13_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt); + DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize); + + if(OMX_DirInput != inputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Input Port\n"); + return -1; + } + + pcmparam.nPortIndex = 0; + pcmparam.nChannels = channels; + pcmparam.nSamplingRate = samplerate; + OMX_SetParameter(qcelp13_enc_handle,OMX_IndexParamAudioPcm,&pcmparam); + + + /* Query the encoder outport's min buf requirements */ + CONFIG_VERSION_SIZE(outputportFmt); + /* Port for which the Client needs to obtain info */ + outputportFmt.nPortIndex = portParam.nStartPortNumber + 1; + + OMX_GetParameter(qcelp13_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt); + DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin); + DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize); + + if(OMX_DirOutput != outputportFmt.eDir) { + DEBUG_PRINT ("\nEnc: Expect Output Port\n"); + return -1; + } + + + CONFIG_VERSION_SIZE(qcelp13param); + + qcelp13param.nPortIndex = 1; + qcelp13param.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/ + qcelp13param.nMinBitRate = min_bitrate; + qcelp13param.nMaxBitRate = max_bitrate; + OMX_SetParameter(qcelp13_enc_handle,OMX_IndexParamAudioQcelp13,&qcelp13param); + OMX_GetExtensionIndex(qcelp13_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index); + OMX_GetParameter(qcelp13_enc_handle,index,&streaminfoparam); + if(tunnel) { + #ifdef AUDIOV2 + session_id = streaminfoparam.sessionId; + control = msm_mixer_open("/dev/snd/controlC0", 0); + if(control < 0) + printf("ERROR opening the device\n"); + device_id = msm_get_device(device); + DEBUG_PRINT ("\ndevice_id = %d\n",device_id); + DEBUG_PRINT("\nsession_id = %d\n",session_id); + if (msm_en_device(device_id, 1)) + { + perror("could not enable device\n"); + return -1; + } + if (msm_route_stream(DIR_TX,session_id,device_id, 1)) + { + perror("could not set stream routing\n"); + return -1; + } + #endif + } + + DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n"); + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0); + /* wait_for_event(); should not wait here event complete status will + not come until enough buffer are allocated */ + if (tunnel == 0) + { + input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5; + DEBUG_PRINT("Transition to Idle State succesful...\n"); + /* Allocate buffer on decoder's i/p port */ + error = Allocate_Buffer(qcelp13_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex, + input_buf_cnt, inputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pInputBufHdrs == NULL) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n"); + } + } + output_buf_cnt = outputportFmt.nBufferCountMin ; + + /* Allocate buffer on encoder's O/Pp port */ + error = Allocate_Buffer(qcelp13_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex, + output_buf_cnt, outputportFmt.nBufferSize); + if (error != OMX_ErrorNone || pOutputBufHdrs == NULL ) { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n"); + return -1; + } + else { + DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n"); + } + + wait_for_event(); + + + if (tunnel == 1) + { + DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n"); + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandPortDisable,0,0); // disable input port + wait_for_event(); + } + + DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n"); + OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0); + wait_for_event(); + + DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n"); + + for(i=0; i < output_buf_cnt; i++) { + DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i); + pOutputBufHdrs[i]->nOutputPortIndex = 1; + pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS; + ret = OMX_FillThisBuffer(qcelp13_enc_handle, pOutputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_FillThisBuffer success!\n"); + } + } + +if(tunnel == 0) +{ + DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n"); + for (i = 0;i < input_buf_cnt;i++) { + DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i); + pInputBufHdrs[i]->nInputPortIndex = 0; + Size = Read_Buffer(pInputBufHdrs[i]); + if(Size <=0 ){ + DEBUG_PRINT("NO DATA READ\n"); + bInputEosReached = true; + pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS; + } + pInputBufHdrs[i]->nFilledLen = Size; + pInputBufHdrs[i]->nInputPortIndex = 0; + used_ip_buf_cnt++; + ret = OMX_EmptyThisBuffer(qcelp13_enc_handle, pInputBufHdrs[i]); + if (OMX_ErrorNone != ret) { + DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret); + } + else { + DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); + } + if(Size <=0 ){ + break;//eos reached + } + } + pthread_mutex_lock(&etb_lock); + if(etb_done) +{ + DEBUG_PRINT("Component is waiting for EBD to be released.\n"); + etb_event_complete(); + } + else + { + DEBUG_PRINT("\n****************************\n"); + DEBUG_PRINT("EBD not yet happened ...\n"); + DEBUG_PRINT("\n****************************\n"); + etb_done++; + } + pthread_mutex_unlock(&etb_lock); +} + + return 0; +} + + + +static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle, + OMX_BUFFERHEADERTYPE ***pBufHdrs, + OMX_U32 nPortIndex, + long bufCntMin, long bufSize) +{ + DEBUG_PRINT("Inside %s \n", __FUNCTION__); + OMX_ERRORTYPE error=OMX_ErrorNone; + long bufCnt=0; + + /* To remove warning for unused variable to keep prototype same */ + (void)avc_enc_handle; + + *pBufHdrs= (OMX_BUFFERHEADERTYPE **) + malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin); + + for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { + DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt); + error = OMX_AllocateBuffer(qcelp13_enc_handle, &((*pBufHdrs)[bufCnt]), + nPortIndex, NULL, bufSize); + } + + return error; +} + + + + +static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr ) +{ + + int bytes_read=0; + + + pBufHdr->nFilledLen = 0; + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + + bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile); + + pBufHdr->nFilledLen = bytes_read; + // Time stamp logic + ((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp = \ + + (unsigned long) ((total_pcm_bytes * 1000)/(samplerate * channels *2)); + + DEBUG_PRINT ("\n--time stamp -- %ld\n", (unsigned long)((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp); + if(bytes_read == 0) + { + pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS; + DEBUG_PRINT ("\nBytes read zero\n"); + } + else + { + pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS; + + total_pcm_bytes += bytes_read; + } + + return bytes_read;; +} + + + +//In Encoder this Should Open a PCM or WAV file for input. + +static int open_audio_file () +{ + int error_code = 0; + + if (!tunnel) + { + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); + inputBufferFile = fopen (in_filename, "rb"); + if (inputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + in_filename); + error_code = -1; + } + if(parse_pcm_header() != 0x00) + { + DEBUG_PRINT("PCM parser failed \n"); + return -1; + } + } + + DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename); + outputBufferFile = fopen (out_filename, "wb"); + if (outputBufferFile == NULL) { + DEBUG_PRINT("\ni/p file %s could NOT be opened\n", + out_filename); + error_code = -1; + return error_code; + } + fseek(outputBufferFile, QCP_HEADER_SIZE, SEEK_SET); + return error_code; +} + +static OMX_ERRORTYPE parse_pcm_header() +{ + struct wav_header hdr; + + DEBUG_PRINT("\n***************************************************************\n"); + if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr)) + { + DEBUG_PRINT("Wav file cannot read header\n"); + return -1; + } + + if ((hdr.riff_id != ID_RIFF) || + (hdr.riff_fmt != ID_WAVE)|| + (hdr.fmt_id != ID_FMT)) + { + DEBUG_PRINT("Wav file is not a riff/wave file\n"); + return -1; + } + + if (hdr.audio_format != FORMAT_PCM) + { + DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n", + hdr.audio_format, hdr.fmt_sz); + return -1; + } + + DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate); + DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels); + DEBUG_PRINT("\n***************************************************************\n"); + + samplerate = hdr.sample_rate; + channels = hdr.num_channels; + total_pcm_bytes = 0; + + return OMX_ErrorNone; +} diff --git a/mm-audio/autogen.sh b/mm-audio/autogen.sh new file mode 100644 index 000000000..de72aa199 --- /dev/null +++ b/mm-audio/autogen.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# autogen.sh -- Autotools bootstrapping + +libtoolize --copy --force +aclocal &&\ +autoheader &&\ +autoconf &&\ +automake --add-missing --copy + diff --git a/mm-audio/configure.ac b/mm-audio/configure.ac new file mode 100644 index 000000000..b75d2ed8e --- /dev/null +++ b/mm-audio/configure.ac @@ -0,0 +1,44 @@ +# -*- Autoconf -*- + +# configure.ac -- Autoconf script for mm-omxaudio +# + +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.61) +AC_INIT([omxaudio], + 1.0.0) +AM_INIT_AUTOMAKE([-Wall -Werror gnu foreign]) +AM_MAINTAINER_MODE +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +#release versioning +OMXAUDIO_MAJOR_VERSION=1 +OMXAUDIO_MINOR_VERSION=0 +OMXAUDIO_MICRO_VERSION=0 + +OMXAUDIO_LIBRARY_VERSION=$OMXAUDIO_MAJOR_VERSION:$OMXAUDIO_MINOR_VERSION:$OMXAUDIO_MICRO_VERSION +AC_SUBST(OMXAUDIO_LIBRARY_VERSION) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CPP +AC_PROG_CXX +AM_PROG_CC_C_O +AC_PROG_LIBTOOL +AC_PROG_AWK +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +AC_CONFIG_FILES([ \ + Makefile \ + adec-aac/Makefile \ + adec-mp3/Makefile \ + aenc-aac/Makefile \ + adec-aac/qdsp6/Makefile \ + adec-mp3/qdsp6/Makefile \ + aenc-aac/qdsp6/Makefile \ + ]) +AC_OUTPUT -- GitLab From 9eaf94ee8ce16f1922d0cb3cdd4fa91d5d2497a9 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Fri, 4 Oct 2013 16:13:44 -0700 Subject: [PATCH 041/298] hal: Support for anc/aanc/proxy audio features Added support for anc/aanc/proxy audio features Change-Id: Id6ebdb9094635563cfafce9dc1d3449efe25bda4 --- hal/Android.mk | 13 ++- hal/audio_extn/audio_extn.c | 208 ++++++++++++++++++++++++++++++++++++ hal/audio_extn/audio_extn.h | 47 ++++++++ hal/audio_hw.c | 7 +- hal/msm8974/platform.c | 58 +++++++++- hal/msm8974/platform.h | 10 ++ 6 files changed, 337 insertions(+), 6 deletions(-) create mode 100644 hal/audio_extn/audio_extn.c create mode 100644 hal/audio_extn/audio_extn.h diff --git a/hal/Android.mk b/hal/Android.mk index 71e6d5ae8..649f6fe29 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -19,6 +19,16 @@ LOCAL_SRC_FILES := \ audio_hw.c \ $(AUDIO_PLATFORM)/platform.c +LOCAL_SRC_FILES += audio_extn/audio_extn.c + +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true) + LOCAL_CFLAGS += -DANC_HEADSET_ENABLED +endif + +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) + LOCAL_CFLAGS += -DAFE_PROXY_ENABLED +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ @@ -31,7 +41,8 @@ LOCAL_C_INCLUDES += \ external/tinyalsa/include \ $(call include-path-for, audio-route) \ $(call include-path-for, audio-effects) \ - $(LOCAL_PATH)/$(AUDIO_PLATFORM) + $(LOCAL_PATH)/$(AUDIO_PLATFORM) \ + $(LOCAL_PATH)/audio_extn LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c new file mode 100644 index 000000000..610e0d117 --- /dev/null +++ b/hal/audio_extn/audio_extn.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_extn" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include + +#include "audio_hw.h" +#include "audio_extn.h" + +struct audio_extn_module { + bool anc_enabled; + bool aanc_enabled; + uint32_t proxy_channel_num; +}; + +static struct audio_extn_module aextnmod = { + .anc_enabled = 0, + .aanc_enabled = 0, + .proxy_channel_num = 2, +}; + +#define AUDIO_PARAMETER_KEY_ANC "anc_enabled" +#define AUDIO_PARAMETER_KEY_WFD "wfd_channel_cap" +#define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy" + +#ifndef ANC_HEADSET_ENABLED +#define audio_extn_set_anc_parameters(parms) (0) +#else +bool audio_extn_get_anc_enabled(void) +{ + ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled); + return (aextnmod.anc_enabled ? true: false); +} + +bool audio_extn_should_use_handset_anc(int in_channels) +{ + char prop_aanc[128] = "false"; + + property_get("persist.aanc.enable", prop_aanc, "0"); + if (!strncmp("true", prop_aanc, 4)) { + ALOGD("%s: AANC enabled in the property", __func__); + aextnmod.aanc_enabled = 1; + } + + return (aextnmod.aanc_enabled && aextnmod.anc_enabled + && (in_channels == 1)); +} + +bool audio_extn_should_use_fb_anc(void) +{ + char prop_anc[128] = "feedforward"; + + property_get("persist.headset.anc.type", prop_anc, "0"); + if (!strncmp("feedback", prop_anc, sizeof("feedback"))) { + ALOGD("%s: FB ANC headset type enabled\n", __func__); + return true; + } + return false; +} + +void audio_extn_set_anc_parameters(struct str_parms *parms) +{ + int ret; + char value[32] ={0}; + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ANC, value, + sizeof(value)); + if (ret >= 0) { + if (strcmp(value, "true") == 0) + aextnmod.anc_enabled = true; + else + aextnmod.anc_enabled = false; + } + + ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled); +} +#endif /* ANC_HEADSET_ENABLED */ + +#ifndef AFE_PROXY_ENABLED +#define audio_extn_set_afe_proxy_parameters(parms) (0) +#define audio_extn_get_afe_proxy_parameters(query, reply) (0) +#else +int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) +{ + int32_t ret = 0; + const char *channel_cnt_str = NULL; + struct mixer_ctl *ctl = NULL; + const char *mixer_ctl_name = "PROXY_RX Channels"; + + + ALOGD("%s: entry", __func__); + /* use the existing channel count set by hardware params to + configure the back end for stereo as usb/a2dp would be + stereo by default */ + ALOGD("%s: channels = %d", __func__, + aextnmod.proxy_channel_num); + switch (aextnmod.proxy_channel_num) { + case 8: channel_cnt_str = "Eight"; break; + case 7: channel_cnt_str = "Seven"; break; + case 6: channel_cnt_str = "Six"; break; + case 5: channel_cnt_str = "Five"; break; + case 4: channel_cnt_str = "Four"; break; + case 3: channel_cnt_str = "Three"; break; + default: channel_cnt_str = "Two"; break; + } + + if(aextnmod.proxy_channel_num >= 2 && aextnmod.proxy_channel_num < 8) { + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + } + mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); + + ALOGD("%s: exit", __func__); + return ret; +} + +void audio_extn_set_afe_proxy_parameters(struct str_parms *parms) +{ + int ret, val; + char value[32]={0}; + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_WFD, value, + sizeof(value)); + if (ret >= 0) { + val = atoi(value); + aextnmod.proxy_channel_num = val; + ALOGD("%s: channel capability set to: %d", __func__, + aextnmod.proxy_channel_num); + } +} + +char* audio_extn_get_afe_proxy_parameters(struct str_parms *query, + struct str_parms *reply) +{ + int ret, val; + char value[32]={0}; + char *str = NULL; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_CAN_OPEN_PROXY, value, + sizeof(value)); + if (ret >= 0) { + /* Todo: check if proxy is free by maintaining a state flag*/ + val = 1; + str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val); + str = str_parms_to_str(reply); + } + + return str; +} +#endif /* AFE_PROXY_ENABLED */ + +void audio_extn_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + audio_extn_set_anc_parameters(parms); + audio_extn_set_afe_proxy_parameters(parms); +} + +char* audio_extn_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + struct str_parms *query = str_parms_create_str(keys); + struct str_parms *reply = str_parms_create(); + char *str = NULL; + + ALOGD("%s: enter: keys - %s", __func__, keys); + + if (NULL != (str = audio_extn_get_afe_proxy_parameters(query, reply))) + { + ALOGD("%s: handled %s", __func__, str); + goto exit; + } else { + str = strdup(keys); + } + +exit: + str_parms_destroy(query); + str_parms_destroy(reply); + + ALOGD("%s: exit: returns %s", __func__, str); + return str; +} diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h new file mode 100644 index 000000000..c537b774a --- /dev/null +++ b/hal/audio_extn/audio_extn.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef AUDIO_EXTN_H +#define AUDIO_EXTN_H + +#include + +void audio_extn_set_parameters(struct audio_device *adev, + struct str_parms *parms); + +char* audio_extn_get_parameters(const struct audio_hw_device *dev, + const char *keys); + +#ifndef ANC_HEADSET_ENABLED +#define audio_extn_get_anc_enabled() (0) +#define audio_extn_should_use_fb_anc() (0) +#define audio_extn_should_use_handset_anc(in_channels) (0) +#else +bool audio_extn_get_anc_enabled(void); +bool audio_extn_should_use_fb_anc(void); +bool audio_extn_should_use_handset_anc(int in_channels); +#endif + +#ifndef AFE_PROXY_ENABLED +#define audio_extn_set_afe_proxy_channel_mixer(adev) (0) +#else +int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev); +#endif + +#endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 5e966d92d..1f2cdbb11 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,6 +38,7 @@ #include "audio_hw.h" #include "platform_api.h" #include +#include "audio_extn.h" struct pcm_config pcm_config_deep_buffer = { .channels = 2, @@ -1508,6 +1512,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) pthread_mutex_unlock(&adev->lock); } + audio_extn_set_parameters(adev, parms); str_parms_destroy(parms); ALOGV("%s: exit with code(%d)", __func__, ret); return ret; @@ -1516,7 +1521,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) static char* adev_get_parameters(const struct audio_hw_device *dev, const char *keys) { - return strdup(""); + return audio_extn_get_parameters(dev, keys); } static int adev_init_check(const struct audio_hw_device *dev) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 3d13c7df9..85c57fce7 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +28,7 @@ #include #include #include "platform.h" +#include "audio_extn.h" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define LIB_ACDB_LOADER "libacdbloader.so" @@ -50,7 +54,7 @@ #define MAX_VOL_INDEX 5 #define MIN_VOL_INDEX 0 #define percent_to_index(val, min, max) \ - ((val) * ((max) - (min)) * 0.01 + (min) + .5) + ((val) * ((max) - (min)) * 0.01 + (min) + .5) struct audio_block_header { @@ -110,6 +114,12 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones", + [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones", + [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones", + [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones", + [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones", + [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset", /* Capture sound devices */ [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", @@ -132,6 +142,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef", [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", + [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic", }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ @@ -152,6 +163,12 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + [SND_DEVICE_OUT_ANC_HEADSET] = 26, + [SND_DEVICE_OUT_ANC_FB_HEADSET] = 26, + [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26, + [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 26, + [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26, + [SND_DEVICE_OUT_ANC_HANDSET] = 103, [SND_DEVICE_IN_HANDSET_MIC] = 4, [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */ @@ -171,6 +188,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_REC_MIC] = 62, + [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, /* TODO: Update with proper acdb ids */ [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, @@ -490,6 +508,10 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi audio_mode_t mode = adev->mode; snd_device_t snd_device = SND_DEVICE_NONE; + audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? + AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; + int channel_count = popcount(channel_mask); + ALOGV("%s: enter: output devices(%#x)", __func__, devices); if (devices == AUDIO_DEVICE_NONE || devices & AUDIO_DEVICE_BIT_IN) { @@ -497,6 +519,11 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi goto exit; } + if(devices & AUDIO_DEVICE_OUT_PROXY) { + ALOGD("%s: setting sink capability for Proxy", __func__); + audio_extn_set_afe_proxy_channel_mixer(adev); + } + if (mode == AUDIO_MODE_IN_CALL) { if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { @@ -506,6 +533,12 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; else if (adev->tty_mode == TTY_MODE_HCO) snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; + else if (audio_extn_get_anc_enabled()) { + if (audio_extn_should_use_fb_anc()) + snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET; + else + snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET; + } else snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES; } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { @@ -515,6 +548,8 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { if (is_operator_tmus()) snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; + else if (audio_extn_should_use_handset_anc(channel_count)) + snd_device = SND_DEVICE_OUT_ANC_HANDSET; else snd_device = SND_DEVICE_OUT_VOICE_HANDSET; } @@ -529,7 +564,10 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + if (audio_extn_get_anc_enabled()) + snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET; + else + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_DEVICE_OUT_SPEAKER)) { snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; @@ -549,7 +587,15 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - snd_device = SND_DEVICE_OUT_HEADPHONES; + if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET + && audio_extn_get_anc_enabled()) { + if (audio_extn_should_use_fb_anc()) + snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET; + else + snd_device = SND_DEVICE_OUT_ANC_HEADSET; + } + else + snd_device = SND_DEVICE_OUT_HEADPHONES; } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { if (adev->speaker_lr_swap) snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE; @@ -583,6 +629,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; snd_device_t snd_device = SND_DEVICE_NONE; + int channel_count = popcount(channel_mask); ALOGV("%s: enter: out_device(%#x) in_device(%#x)", __func__, out_device, in_device); @@ -612,7 +659,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } if (out_device & AUDIO_DEVICE_OUT_EARPIECE || out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { - if (my_data->fluence_type == FLUENCE_NONE || + if (out_device & AUDIO_DEVICE_OUT_EARPIECE && + audio_extn_should_use_handset_anc(channel_count)) { + snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC; + } else if (my_data->fluence_type == FLUENCE_NONE || my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 26d4a9f34..bbbb8216e 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -57,6 +60,12 @@ enum { SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_ANC_HEADSET, + SND_DEVICE_OUT_ANC_FB_HEADSET, + SND_DEVICE_OUT_VOICE_ANC_HEADSET, + SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_OUT_ANC_HANDSET, SND_DEVICE_OUT_END, /* @@ -86,6 +95,7 @@ enum { SND_DEVICE_IN_VOICE_REC_MIC, SND_DEVICE_IN_VOICE_REC_DMIC, SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_AANC_HANDSET_MIC, SND_DEVICE_IN_END, SND_DEVICE_MAX = SND_DEVICE_IN_END, -- GitLab From a5ad5ea866dd47362979b2cecc433e471b24fa1c Mon Sep 17 00:00:00 2001 From: David Ng Date: Thu, 10 Oct 2013 20:36:49 -0700 Subject: [PATCH 042/298] audio: Enable support for APQ8084 Route APQ8084 targets through B-family audio path. Change-Id: I3fcd950d0e808da365c2488c9f89911e23b25400 --- Android.mk | 2 +- hal/Android.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Android.mk b/Android.mk index 03929fcbd..3acfd6eda 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,4 @@ -ifneq ($(filter msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74,$(TARGET_BOARD_PLATFORM)),) +ifneq ($(filter msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084,$(TARGET_BOARD_PLATFORM)),) MY_LOCAL_PATH := $(call my-dir) diff --git a/hal/Android.mk b/hal/Android.mk index 71e6d5ae8..343963bba 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -7,7 +7,7 @@ include $(CLEAR_VARS) LOCAL_ARM_MODE := arm AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) -ifneq ($(filter msm8974 msm8226 msm8610,$(TARGET_BOARD_PLATFORM)),) +ifneq ($(filter msm8974 msm8226 msm8610 apq8084,$(TARGET_BOARD_PLATFORM)),) # B-family platform uses msm8974 code base AUDIO_PLATFORM = msm8974 ifneq ($(filter msm8610,$(TARGET_BOARD_PLATFORM)),) -- GitLab From 07eeafd9390a85c5b9ad1642e89d3973615584cb Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Sun, 6 Oct 2013 12:52:49 -0700 Subject: [PATCH 043/298] audio/hal: Configure HDMI channels based on output stream channels - Current HAL configures HDMI channels based on sink capabilities, even when the output content is stereo. DSP upmixes the content if the HDMI backend is configured for 5.1 channels. - This change ensures that HDMI backend is configured based on output stream channels. Bug: 7290997. Change-Id: I42b2773b8f4ccc62203c13ff9ac6a6511df0705f --- hal/audio_hw.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++---- hal/audio_hw.h | 2 ++ 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c5e44aa23..08d9c32c1 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -783,6 +783,83 @@ static int destroy_offload_callback_thread(struct stream_out *out) return 0; } +static bool allow_hdmi_channel_config(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool ret = true; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + /* + * If voice call is already existing, do not proceed further to avoid + * disabling/enabling both RX and TX devices, CSD calls, etc. + * Once the voice call done, the HDMI channels can be configured to + * max channels of remaining use cases. + */ + if (usecase->id == USECASE_VOICE_CALL) { + ALOGD("%s: voice call is active, no change in HDMI channels", + __func__); + ret = false; + break; + } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) { + ALOGD("%s: multi channel playback is active, " + "no change in HDMI channels", __func__); + ret = false; + break; + } + } + } + return ret; +} + +static int check_and_set_hdmi_channels(struct audio_device *adev, + unsigned int channels) +{ + struct listnode *node; + struct audio_usecase *usecase; + + /* Check if change in HDMI channel config is allowed */ + if (!allow_hdmi_channel_config(adev)) + return 0; + + if (channels == adev->cur_hdmi_channels) { + ALOGD("%s: Requested channels are same as current", __func__); + return 0; + } + + platform_set_hdmi_channels(adev->platform, channels); + adev->cur_hdmi_channels = channels; + + /* + * Deroute all the playback streams routed to HDMI so that + * the back end is deactivated. Note that backend will not + * be deactivated if any one stream is connected to it. + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + disable_audio_route(adev, usecase, true); + } + } + + /* + * Enable all the streams disabled above. Now the HDMI backend + * will be activated with new channel configuration + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + enable_audio_route(adev, usecase, true); + } + } + + return 0; +} + static int stop_output_stream(struct stream_out *out) { int i, ret = 0; @@ -811,6 +888,10 @@ static int stop_output_stream(struct stream_out *out) list_remove(&uc_info->list); free(uc_info); + /* Must be called after removing the usecase from list */ + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS); + ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -839,6 +920,10 @@ int start_output_stream(struct stream_out *out) uc_info->in_snd_device = SND_DEVICE_NONE; uc_info->out_snd_device = SND_DEVICE_NONE; + /* This must be called before adding this usecase to the list */ + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + check_and_set_hdmi_channels(adev, out->config.channels); + list_add_tail(&adev->usecase_list, &uc_info->list); select_devices(adev, out->usecase); @@ -1776,12 +1861,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, pthread_mutex_lock(&adev->lock); ret = read_hdmi_channel_masks(out); pthread_mutex_unlock(&adev->lock); - if (ret != 0) { - /* If HDMI does not support multi channel playback, set the default */ - out->config.channels = popcount(out->channel_mask); - platform_set_hdmi_channels(adev->platform, out->config.channels); + if (ret != 0) goto error_open; - } if (config->sample_rate == 0) config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; @@ -1795,7 +1876,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config.rate = config->sample_rate; out->config.channels = popcount(out->channel_mask); out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); - platform_set_hdmi_channels(adev->platform, out->config.channels); } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; out->config = pcm_config_deep_buffer; @@ -2277,6 +2357,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->bluetooth_nrec = true; adev->in_call = false; adev->acdb_settings = TTY_MODE_OFF; + /* adev->cur_hdmi_channels = 0; by calloc() */ adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); list_init(&adev->usecase_list); pthread_mutex_unlock(&adev->lock); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 717c0a6cd..0da43243c 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -39,6 +39,7 @@ #define ACDB_DEV_TYPE_IN 2 #define MAX_SUPPORTED_CHANNEL_MASKS 2 +#define DEFAULT_HDMI_OUT_CHANNELS 2 typedef int snd_device_t; @@ -188,6 +189,7 @@ struct audio_device { struct audio_route *audio_route; int acdb_settings; bool speaker_lr_swap; + unsigned int cur_hdmi_channels; void *platform; -- GitLab From 60caf20d81c83a1bf2c0085904991a2cbbfbb2ba Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 2 Oct 2013 09:56:18 -0700 Subject: [PATCH 044/298] hal: Fix for Tx Mute issue when a new call accepted while in call - While in a voice call, if an incoming call is accepted, Tx path is muted on some specific networks. - If there is an incoming call, Telephony sets the mode to RINGTONE, and the condition check in audio HAL leads to voice call tear down. When the call is accepted, the mode is set back to IN_CALL and voice call path is re-enabled but the voice drivers will be operating with default settings as there is no notification from Modem side in this case. For modem, there is no change in the call state i.e. just switched from caller 1 to caller2. - Fix the issue by ensuring that the voice call is teared down only if mode is set to NORMAL while call is progress. Change-Id: Iac5c4d2e6852ccda0da2ea13927d2a95bfb6938b --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1f2cdbb11..045f03160 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -962,7 +962,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } } - if ((adev->mode != AUDIO_MODE_IN_CALL) && adev->in_call && + if ((adev->mode == AUDIO_MODE_NORMAL) && adev->in_call && (out == adev->primary_output)) { stop_voice_call(adev); } -- GitLab From 89a8142a189f39db225385d5a122f42d281b24d7 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Tue, 8 Oct 2013 23:47:55 -0700 Subject: [PATCH 045/298] policy_hal: Initial commit for target specific audio policy - Derive target specific audio policy manager from the base class. - Allow selection of USB analog dock headset device for voice calls. Change-Id: I351e88a6abe02e56a14b4eef4c04862e79c5777c --- policy_hal/Android.mk | 25 +++ policy_hal/AudioPolicyManager.cpp | 277 ++++++++++++++++++++++++++++++ policy_hal/AudioPolicyManager.h | 57 ++++++ 3 files changed, 359 insertions(+) create mode 100644 policy_hal/Android.mk create mode 100644 policy_hal/AudioPolicyManager.cpp create mode 100644 policy_hal/AudioPolicyManager.h diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk new file mode 100644 index 000000000..127b732f7 --- /dev/null +++ b/policy_hal/Android.mk @@ -0,0 +1,25 @@ +ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := AudioPolicyManager.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + liblog + +LOCAL_STATIC_LIBRARIES := \ + libmedia_helper + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libaudiopolicy_legacy + +LOCAL_MODULE := audio_policy.$(TARGET_BOARD_PLATFORM) +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp new file mode 100644 index 000000000..223b43e68 --- /dev/null +++ b/policy_hal/AudioPolicyManager.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "AudioPolicyManager" +//#define LOG_NDEBUG 0 + +//#define VERY_VERBOSE_LOGGING +#ifdef VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif + +// A device mask for all audio input devices that are considered "virtual" when evaluating +// active inputs in getActiveInput() +#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX +// A device mask for all audio output devices that are considered "remote" when evaluating +// active output devices in isStreamActiveRemotely() +#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX + +#include +#include "AudioPolicyManager.h" +#include +#include +#include +#include +#include + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- +// AudioPolicyInterface implementation +// ---------------------------------------------------------------------------- + +audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, + bool fromCache) +{ + uint32_t device = AUDIO_DEVICE_NONE; + + if (fromCache) { + ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x", + strategy, mDeviceForStrategy[strategy]); + return mDeviceForStrategy[strategy]; + } + + switch (strategy) { + + case STRATEGY_SONIFICATION_RESPECTFUL: + if (isInCall()) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + } else if (isStreamActiveRemotely(AudioSystem::MUSIC, + SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { + // while media is playing on a remote device, use the the sonification behavior. + // Note that we test this usecase before testing if media is playing because + // the isStreamActive() method only informs about the activity of a stream, not + // if it's for local playback. Note also that we use the same delay between both tests + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { + // while media is playing (or has recently played), use the same device + device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); + } else { + // when media is not playing anymore, fall back on the sonification behavior + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + } + + break; + + case STRATEGY_DTMF: + if (!isInCall()) { + // when off call, DTMF strategy follows the same rules as MEDIA strategy + device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); + break; + } + // when in call, DTMF and PHONE strategies follow the same rules + // FALL THROUGH + + case STRATEGY_PHONE: + // for phone strategy, we first consider the forced use and then the available devices by order + // of priority + switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { + case AudioSystem::FORCE_BT_SCO: + if (!isInCall() || strategy != STRATEGY_DTMF) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO; + if (device) break; + // if SCO device is requested but no SCO device is available, fall back to default case + // FALL THROUGH + + default: // FORCE_NONE + // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP + if (mHasA2dp && !isInCall() && + (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + (getA2dpOutput() != 0) && !mA2dpSuspended) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + if (device) break; + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + if (device) break; + } + + // Allow voice call on USB ANLG DOCK headset + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + if (device) break; + + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; + + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE; + if (device) break; + device = mDefaultOutputDevice; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE"); + } + break; + + case AudioSystem::FORCE_SPEAKER: + // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to + // A2DP speaker when forcing to speaker output + if (mHasA2dp && !isInCall() && + (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + (getA2dpOutput() != 0) && !mA2dpSuspended) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + if (device) break; + } + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + if (device) break; + device = mDefaultOutputDevice; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER"); + } + break; + } + break; + + case STRATEGY_SONIFICATION: + + // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by + // handleIncallSonification(). + if (isInCall()) { + device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); + break; + } + // FALL THROUGH + + case STRATEGY_ENFORCED_AUDIBLE: + // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION + // except: + // - when in call where it doesn't default to STRATEGY_PHONE behavior + // - in countries where not enforced in which case it follows STRATEGY_MEDIA + + if ((strategy == STRATEGY_SONIFICATION) || + (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION"); + } + } + // The second device used for sonification is the same as the device used by media strategy + // FALL THROUGH + + case STRATEGY_MEDIA: { + uint32_t device2 = AUDIO_DEVICE_NONE; + if (strategy != STRATEGY_SONIFICATION) { + // no sonification on remote submix (e.g. WFD) + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } + if ((device2 == AUDIO_DEVICE_NONE) && + mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + (getA2dpOutput() != 0) && !mA2dpSuspended) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + } + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + } + if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) { + // no sonification on aux digital (e.g. HDMI) + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + } + if ((device2 == AUDIO_DEVICE_NONE) && + (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + } + + // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or + // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise + device |= device2; + if (device) break; + device = mDefaultOutputDevice; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); + } + } break; + + default: + ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy); + break; + } + + ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device); + return device; +} + +AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) +{ + return new AudioPolicyManager(clientInterface); +} + +void destroyAudioPolicyManager(AudioPolicyInterface *interface) +{ + delete interface; +} + +}; // namespace android diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h new file mode 100644 index 000000000..b0615204d --- /dev/null +++ b/policy_hal/AudioPolicyManager.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2009 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include + + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- + +class AudioPolicyManager: public AudioPolicyManagerBase +{ + +public: + AudioPolicyManager(AudioPolicyClientInterface *clientInterface) + : AudioPolicyManagerBase(clientInterface) {} + + virtual ~AudioPolicyManager() {} + +protected: + // return appropriate device for streams handled by the specified strategy according to current + // phone state, connected devices... + // if fromCache is true, the device is returned from mDeviceForStrategy[], + // otherwise it is determine by current state + // (device connected,phone state, force use, a2dp output...) + // This allows to: + // 1 speed up process when the state is stable (when starting or stopping an output) + // 2 access to either current device selection (fromCache == true) or + // "future" device selection (fromCache == false) when called from a context + // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND + // before updateDevicesAndOutputs() is called. + virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, + bool fromCache = true); +}; +}; -- GitLab From 88d28cba5dc3b9517a2285180e7c179c3122d251 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Tue, 15 Oct 2013 16:59:57 -0700 Subject: [PATCH 046/298] policy_hal: Add support for FM and WFD features - Override the base class functions and add support for FM and WFD audio features. Change-Id: If14afda8e2b507ca40a06c709fd33adbe5f70727 --- policy_hal/Android.mk | 10 + policy_hal/AudioPolicyManager.cpp | 628 +++++++++++++++++++++++++++++- policy_hal/AudioPolicyManager.h | 25 ++ 3 files changed, 656 insertions(+), 7 deletions(-) diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index 127b732f7..b6a06e4c7 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -20,6 +20,16 @@ LOCAL_MODULE := audio_policy.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_MODULE_TAGS := optional +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_FM_ENABLED +endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED +endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_INCALL_MUSIC_ENABLED +endif + include $(BUILD_SHARED_LIBRARY) endif diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 223b43e68..5992c876b 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -48,6 +48,387 @@ namespace android_audio_legacy { // AudioPolicyInterface implementation // ---------------------------------------------------------------------------- +status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address) +{ + SortedVector outputs; + + ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); + + // connect/disconnect only 1 device at a time + if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; + + if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { + ALOGE("setDeviceConnectionState() invalid address: %s", device_address); + return BAD_VALUE; + } + + // handle output devices + if (audio_is_output_device(device)) { + + if (!mHasA2dp && audio_is_a2dp_device(device)) { + ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device); + return BAD_VALUE; + } + if (!mHasUsb && audio_is_usb_device(device)) { + ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device); + return BAD_VALUE; + } + if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) { + ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device); + return BAD_VALUE; + } + + // save a copy of the opened output descriptors before any output is opened or closed + // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies() + mPreviousOutputs = mOutputs; + switch (state) + { + // handle output device connection + case AudioSystem::DEVICE_STATE_AVAILABLE: + if (mAvailableOutputDevices & device) { + ALOGW("setDeviceConnectionState() device already connected: %x", device); + return INVALID_OPERATION; + } + ALOGV("setDeviceConnectionState() connecting device %x", device); + + if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) { + return INVALID_OPERATION; + } + ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", + outputs.size()); + // register new device as available + mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device); + + if (!outputs.isEmpty()) { + String8 paramStr; + if (mHasA2dp && audio_is_a2dp_device(device)) { + // handle A2DP device connection + AudioParameter param; + param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address)); + paramStr = param.toString(); + mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + mA2dpSuspended = false; + } else if (audio_is_bluetooth_sco_device(device)) { + // handle SCO device connection + mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + } else if (mHasUsb && audio_is_usb_device(device)) { + // handle USB device connection + mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + paramStr = mUsbCardAndDevice; + } + // not currently handling multiple simultaneous submixes: ignoring remote submix + // case and address + if (!paramStr.isEmpty()) { + for (size_t i = 0; i < outputs.size(); i++) { + mpClientInterface->setParameters(outputs[i], paramStr); + } + } + } + break; + // handle output device disconnection + case AudioSystem::DEVICE_STATE_UNAVAILABLE: { + if (!(mAvailableOutputDevices & device)) { + ALOGW("setDeviceConnectionState() device not connected: %x", device); + return INVALID_OPERATION; + } + + ALOGV("setDeviceConnectionState() disconnecting device %x", device); + // remove device from available output devices + mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device); + + checkOutputsForDevice(device, state, outputs); + if (mHasA2dp && audio_is_a2dp_device(device)) { + // handle A2DP device disconnection + mA2dpDeviceAddress = ""; + mA2dpSuspended = false; + } else if (audio_is_bluetooth_sco_device(device)) { + // handle SCO device disconnection + mScoDeviceAddress = ""; + } else if (mHasUsb && audio_is_usb_device(device)) { + // handle USB device disconnection + mUsbCardAndDevice = ""; + } + // not currently handling multiple simultaneous submixes: ignoring remote submix + // case and address + } break; + + default: + ALOGE("setDeviceConnectionState() invalid state: %x", state); + return BAD_VALUE; + } + + checkA2dpSuspend(); + checkOutputForAllStrategies(); + // outputs must be closed after checkOutputForAllStrategies() is executed + if (!outputs.isEmpty()) { + for (size_t i = 0; i < outputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]); + // close unused outputs after device disconnection or direct outputs that have been + // opened by checkOutputsForDevice() to query dynamic parameters + if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) || + (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) && + (desc->mDirectOpenCount == 0))) { + closeOutput(outputs[i]); + } + } + } + + updateDevicesAndOutputs(); + audio_devices_t newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); +#ifdef AUDIO_EXTN_FM_ENABLED + if(device == AUDIO_DEVICE_OUT_FM) { + if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { + mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::MUSIC, 1); + newDevice = (audio_devices_t)(getNewDevice(mPrimaryOutput, false) | AUDIO_DEVICE_OUT_FM); + } else { + mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::MUSIC, -1); + } + + AudioParameter param = AudioParameter(); + param.addInt(String8("handle_fm"), (int)newDevice); + ALOGV("setDeviceConnectionState() setParameters handle_fm"); + mpClientInterface->setParameters(mPrimaryOutput, param.toString()); + } +#endif + for (size_t i = 0; i < mOutputs.size(); i++) { + // do not force device change on duplicated output because if device is 0, it will + // also force a device 0 for the two outputs it is duplicated to which may override + // a valid device selection on those outputs. + setOutputDevice(mOutputs.keyAt(i), + getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), + !mOutputs.valueAt(i)->isDuplicated(), + 0); + } + + if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) { + device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO || + device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET || + device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { + device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else if(device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET){ + device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; + } else { + return NO_ERROR; + } + } + // handle input devices + if (audio_is_input_device(device)) { + + switch (state) + { + // handle input device connection + case AudioSystem::DEVICE_STATE_AVAILABLE: { + if (mAvailableInputDevices & device) { + ALOGW("setDeviceConnectionState() device already connected: %d", device); + return INVALID_OPERATION; + } + mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN); + } + break; + + // handle input device disconnection + case AudioSystem::DEVICE_STATE_UNAVAILABLE: { + if (!(mAvailableInputDevices & device)) { + ALOGW("setDeviceConnectionState() device not connected: %d", device); + return INVALID_OPERATION; + } + mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device); + } break; + + default: + ALOGE("setDeviceConnectionState() invalid state: %x", state); + return BAD_VALUE; + } + + audio_io_handle_t activeInput = getActiveInput(); + if (activeInput != 0) { + AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); + audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); + if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { + ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", + inputDesc->mDevice, newDevice, activeInput); + inputDesc->mDevice = newDevice; + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); + mpClientInterface->setParameters(activeInput, param.toString()); + } + } + + return NO_ERROR; + } + + ALOGW("setDeviceConnectionState() invalid device: %x", device); + return BAD_VALUE; +} + +void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) +{ + ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); + + bool forceVolumeReeval = false; + switch(usage) { + case AudioSystem::FOR_COMMUNICATION: + if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO && + config != AudioSystem::FORCE_NONE) { + ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); + return; + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + case AudioSystem::FOR_MEDIA: + if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP && +#ifdef AUDIO_EXTN_FM_ENABLED + config != AudioSystem::FORCE_SPEAKER && +#endif + config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_ANALOG_DOCK && + config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE && + config != AudioSystem::FORCE_NO_BT_A2DP) { + ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_RECORD: + if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_NONE) { + ALOGW("setForceUse() invalid config %d for FOR_RECORD", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_DOCK: + if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK && + config != AudioSystem::FORCE_BT_DESK_DOCK && + config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_ANALOG_DOCK && + config != AudioSystem::FORCE_DIGITAL_DOCK) { + ALOGW("setForceUse() invalid config %d for FOR_DOCK", config); + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + case AudioSystem::FOR_SYSTEM: + if (config != AudioSystem::FORCE_NONE && + config != AudioSystem::FORCE_SYSTEM_ENFORCED) { + ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config); + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + default: + ALOGW("setForceUse() invalid usage %d", usage); + break; + } + + // check for device and output changes triggered by new force usage + checkA2dpSuspend(); + checkOutputForAllStrategies(); + updateDevicesAndOutputs(); + for (int i = mOutputs.size() -1; i >= 0; i--) { + audio_io_handle_t output = mOutputs.keyAt(i); + audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/); + setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { + applyStreamVolumes(output, newDevice, 0, true); + } + } + + audio_io_handle_t activeInput = getActiveInput(); + if (activeInput != 0) { + AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); + audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); + if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { + ALOGV("setForceUse() changing device from %x to %x for input %d", + inputDesc->mDevice, newDevice, activeInput); + inputDesc->mDevice = newDevice; + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); + mpClientInterface->setParameters(activeInput, param.toString()); + } + } + +} + +audio_io_handle_t AudioPolicyManager::getInput(int inputSource, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + AudioSystem::audio_in_acoustics acoustics) +{ + audio_io_handle_t input = 0; + audio_devices_t device = getDeviceForInputSource(inputSource); + + ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x", + inputSource, samplingRate, format, channelMask, acoustics); + + if (device == AUDIO_DEVICE_NONE) { + ALOGW("getInput() could not find device for inputSource %d", inputSource); + return 0; + } + + + IOProfile *profile = getInputProfile(device, + samplingRate, + format, + channelMask); + if (profile == NULL) { + ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d," + "channelMask %04x", + device, samplingRate, format, channelMask); + return 0; + } + + if (profile->mModule->mHandle == 0) { + ALOGE("getInput(): HW module %s not opened", profile->mModule->mName); + return 0; + } + + AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile); + + inputDesc->mInputSource = inputSource; + inputDesc->mDevice = device; + inputDesc->mSamplingRate = samplingRate; + inputDesc->mFormat = (audio_format_t)format; + inputDesc->mChannelMask = (audio_channel_mask_t)channelMask; + inputDesc->mRefCount = 0; + input = mpClientInterface->openInput(profile->mModule->mHandle, + &inputDesc->mDevice, + &inputDesc->mSamplingRate, + &inputDesc->mFormat, + &inputDesc->mChannelMask); + + // only accept input with the exact requested set of parameters + if (input == 0 || + (samplingRate != inputDesc->mSamplingRate) || + (format != inputDesc->mFormat) || + (channelMask != inputDesc->mChannelMask)) { + ALOGV("getInput() failed opening input: samplingRate %d, format %d, channelMask %d", + samplingRate, format, channelMask); + if (input != 0) { + mpClientInterface->closeInput(input); + } + delete inputDesc; + return 0; + } + mInputs.add(input, inputDesc); + return input; +} + +AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(AudioSystem::stream_type stream) +{ +#ifdef QCOM_INCALL_MUSIC_ENABLED + if (stream == AudioSystem::INCALL_MUSIC) + return STRATEGY_MEDIA; +#endif + + return getStrategy(stream); +} + audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache) { @@ -125,14 +506,13 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (device) break; device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + if (device) break; device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; } // Allow voice call on USB ANLG DOCK headset - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; if (device) break; @@ -162,9 +542,9 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (device) break; device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; - if (device) break; } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; if (device) break; device = mDefaultOutputDevice; @@ -173,6 +553,15 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate } break; } + // FIXME: Why do need to replace with speaker? If voice call is active + // We should use device from STRATEGY_PHONE +#ifdef AUDIO_EXTN_FM_ENABLED + if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) { + if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) { + device = AUDIO_DEVICE_OUT_SPEAKER; + } + } +#endif break; case STRATEGY_SONIFICATION: @@ -203,6 +592,19 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate case STRATEGY_MEDIA: { uint32_t device2 = AUDIO_DEVICE_NONE; + + if (isInCall()) { + // when in call, get the device for Phone strategy + device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); + break; + } +#ifdef AUDIO_EXTN_FM_ENABLED + if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) { + device = AUDIO_DEVICE_OUT_SPEAKER; + break; + } +#endif + if (strategy != STRATEGY_SONIFICATION) { // no sonification on remote submix (e.g. WFD) device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; @@ -241,6 +643,17 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) { device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; } +#ifdef AUDIO_EXTN_FM_ENABLED + if ((strategy != STRATEGY_SONIFICATION) && (device2 == AUDIO_DEVICE_NONE)) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX; + } +#endif +#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED + if ((strategy != STRATEGY_SONIFICATION) && (device2 == AUDIO_DEVICE_NONE)) { + // no sonification on WFD sink + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY; + } +#endif if (device2 == AUDIO_DEVICE_NONE) { device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; } @@ -264,12 +677,213 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate return device; } -AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) +audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource) +{ + uint32_t device = AUDIO_DEVICE_NONE; + + switch (inputSource) { + case AUDIO_SOURCE_VOICE_UPLINK: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { + device = AUDIO_DEVICE_IN_VOICE_CALL; + break; + } + // FALL THROUGH + + case AUDIO_SOURCE_DEFAULT: + case AUDIO_SOURCE_MIC: + case AUDIO_SOURCE_VOICE_RECOGNITION: + case AUDIO_SOURCE_HOTWORD: + case AUDIO_SOURCE_VOICE_COMMUNICATION: + if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && + mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) { + device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) { + device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; + } + break; + case AUDIO_SOURCE_CAMCORDER: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) { + device = AUDIO_DEVICE_IN_BACK_MIC; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; + } + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + case AUDIO_SOURCE_VOICE_CALL: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { + device = AUDIO_DEVICE_IN_VOICE_CALL; + } + break; + case AUDIO_SOURCE_REMOTE_SUBMIX: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; + } + break; +#ifdef AUDIO_EXTN_FM_ENABLED + case AUDIO_SOURCE_FM_RX: + case AUDIO_SOURCE_FM_RX_A2DP: + device = AUDIO_DEVICE_IN_FM_RX; + break; +#endif + default: + ALOGW("getDeviceForInputSource() invalid input source %d", inputSource); + break; + } + ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device); + return device; +} + +AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device) +{ + switch(getDeviceForVolume(device)) { + case AUDIO_DEVICE_OUT_EARPIECE: + return DEVICE_CATEGORY_EARPIECE; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: +#ifdef AUDIO_EXTN_FM_ENABLED + case AUDIO_DEVICE_OUT_FM: +#endif + return DEVICE_CATEGORY_HEADSET; + case AUDIO_DEVICE_OUT_SPEAKER: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: + case AUDIO_DEVICE_OUT_AUX_DIGITAL: + case AUDIO_DEVICE_OUT_USB_ACCESSORY: + case AUDIO_DEVICE_OUT_USB_DEVICE: + case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: +#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED + case AUDIO_DEVICE_OUT_PROXY: +#endif + default: + return DEVICE_CATEGORY_SPEAKER; + } +} + +status_t AudioPolicyManager::checkAndSetVolume(int stream, + int index, + audio_io_handle_t output, + audio_devices_t device, + int delayMs, + bool force) +{ + ALOGV("checkAndSetVolume: index %d output %d device %x", index, output, device); + // do not change actual stream volume if the stream is muted + if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { + ALOGVV("checkAndSetVolume() stream %d muted count %d", + stream, mOutputs.valueFor(output)->mMuteCount[stream]); + return NO_ERROR; + } + + // do not change in call volume if bluetooth is connected and vice versa + if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || + (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { + ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", + stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); + return INVALID_OPERATION; + } + + float volume = computeVolume(stream, index, output, device); + // We actually change the volume if: + // - the float value returned by computeVolume() changed + // - the force flag is set + if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || + force) { + mOutputs.valueFor(output)->mCurVolume[stream] = volume; + ALOGV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); + // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is + // enabled + if (stream == AudioSystem::BLUETOOTH_SCO) { + mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs); +#ifdef AUDIO_EXTN_FM_ENABLED + } else if (stream == AudioSystem::MUSIC && + output == mPrimaryOutput) { + float fmVolume = -1.0; + fmVolume = computeVolume(stream, index, output, device); + if (fmVolume >= 0) { + AudioParameter param = AudioParameter(); + param.addFloat(String8("fm_volume"), fmVolume); + ALOGV("checkAndSetVolume setParameters fm_volume, volume=:%f delay=:%d",fmVolume,delayMs*2); + //Double delayMs to avoid sound burst while device switch. + mpClientInterface->setParameters(mPrimaryOutput, param.toString(), delayMs*2); + } +#endif + } + mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); + } + + if (stream == AudioSystem::VOICE_CALL || + stream == AudioSystem::BLUETOOTH_SCO) { + float voiceVolume; + + voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; + + // Force voice volume to max when Vgs is set for bluetooth SCO as volume is managed by the headset + if (stream == AudioSystem::BLUETOOTH_SCO) { + String8 key ("bt_headset_vgs"); + mpClientInterface->getParameters(output,key); + AudioParameter result(mpClientInterface->getParameters(0,key)); + int value; + if (result.getInt(String8("isVGS"),value) == NO_ERROR) { + ALOGV("Use BT-SCO Voice Volume"); + voiceVolume = 1.0; + } + } + + if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) { + mpClientInterface->setVoiceVolume(voiceVolume, delayMs); + mLastVoiceVolume = voiceVolume; + } + } + + return NO_ERROR; +} + + +float AudioPolicyManager::computeVolume(int stream, + int index, + audio_io_handle_t output, + audio_devices_t device) +{ + float volume = 1.0; + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + + if (device == AUDIO_DEVICE_NONE) { + device = outputDesc->device(); + } + + // if volume is not 0 (not muted), force media volume to max on digital output + if (stream == AudioSystem::MUSIC && + index != mStreams[stream].mIndexMin && + (device == AUDIO_DEVICE_OUT_AUX_DIGITAL || + device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET || + device == AUDIO_DEVICE_OUT_USB_ACCESSORY || +#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED + device == AUDIO_DEVICE_OUT_PROXY || +#endif + device == AUDIO_DEVICE_OUT_USB_DEVICE )) { + return 1.0; + } +#ifdef AUDIO_EXTN_INCALL_MUSIC_ENABLED + if (stream == AudioSystem::INCALL_MUSIC) { + return 1.0; + } +#endif + return AudioPolicyManagerBase::computeVolume(stream, index, output, device); +} +extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) { return new AudioPolicyManager(clientInterface); } -void destroyAudioPolicyManager(AudioPolicyInterface *interface) +extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) { delete interface; } diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index b0615204d..7a8cfa911 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -39,7 +39,19 @@ public: virtual ~AudioPolicyManager() {} + virtual status_t setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address); + virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); + virtual audio_io_handle_t getInput(int inputSource, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::audio_in_acoustics acoustics); protected: + // return the strategy corresponding to a given stream type + static routing_strategy getStrategy(AudioSystem::stream_type stream); + // return appropriate device for streams handled by the specified strategy according to current // phone state, connected devices... // if fromCache is true, the device is returned from mDeviceForStrategy[], @@ -53,5 +65,18 @@ protected: // before updateDevicesAndOutputs() is called. virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache = true); + // select input device corresponding to requested audio source + virtual audio_devices_t getDeviceForInputSource(int inputSource); + + // compute the actual volume for a given stream according to the requested index and a particular + // device + virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device); + + // check that volume change is permitted, compute and send new volume to audio hardware + status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); + + // returns the category the device belongs to with regard to volume curve management + static device_category getDeviceCategory(audio_devices_t device); + }; }; -- GitLab From 6e26284a706120e34e2301103223316be452a164 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Sun, 6 Oct 2013 14:39:35 -0700 Subject: [PATCH 047/298] hal: Support for fm audio features Added support for fm audio feature and hal single instance fix Change-Id: I189fd089b45a7e268e0af4ba4ef3eefd22a3f2ff --- hal/Android.mk | 5 + hal/audio_extn/audio_extn.c | 7 + hal/audio_extn/fm.c | 258 ++++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 39 ++++-- hal/audio_hw.h | 12 ++ hal/msm8974/platform.c | 19 +++ hal/msm8974/platform.h | 5 + 7 files changed, 336 insertions(+), 9 deletions(-) create mode 100644 hal/audio_extn/fm.c diff --git a/hal/Android.mk b/hal/Android.mk index 649f6fe29..9cb9817ff 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -29,6 +29,11 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAFE_PROXY_ENABLED endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) + LOCAL_CFLAGS += -DFM_ENABLED + LOCAL_SRC_FILES += audio_extn/fm.c +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 610e0d117..b10a5e909 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -44,6 +44,12 @@ static struct audio_extn_module aextnmod = { #define AUDIO_PARAMETER_KEY_ANC "anc_enabled" #define AUDIO_PARAMETER_KEY_WFD "wfd_channel_cap" #define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy" +#ifndef FM_ENABLED +#define audio_extn_fm_set_parameters(adev, parms) (0) +#else +void audio_extn_fm_set_parameters(struct audio_device *adev, + struct str_parms *parms); +#endif #ifndef ANC_HEADSET_ENABLED #define audio_extn_set_anc_parameters(parms) (0) @@ -180,6 +186,7 @@ void audio_extn_set_parameters(struct audio_device *adev, { audio_extn_set_anc_parameters(parms); audio_extn_set_afe_proxy_parameters(parms); + audio_extn_fm_set_parameters(adev, parms); } char* audio_extn_get_parameters(const struct audio_hw_device *dev, diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c new file mode 100644 index 000000000..53499b9b1 --- /dev/null +++ b/hal/audio_extn/fm.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_fm" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include + +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" +#include +#include + +#ifdef FM_ENABLED +#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm" +#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume" + +static struct pcm_config pcm_config_fm = { + .channels = 2, + .rate = 48000, + .period_size = 256, + .period_count = 4, + .format = PCM_FORMAT_S16_LE, + .start_threshold = 0, + .stop_threshold = INT_MAX, + .avail_min = 0, +}; + +struct fm_module { + struct pcm *fm_pcm_rx; + struct pcm *fm_pcm_tx; + bool is_fm_running; + int fm_volume; +}; + +static struct fm_module fmmod = { + .fm_pcm_rx = NULL, + .fm_pcm_tx = NULL, + .fm_volume = 0, + .is_fm_running = 0, +}; + +static int32_t fm_set_volume(struct audio_device *adev, float value) +{ + int32_t vol, ret = 0; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Internal FM RX Volume"; + + ALOGD("%s: entry", __func__); + ALOGD("%s: (%f)\n", __func__, value); + + if (value < 0.0) { + ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value); + value = 0.0; + } else if (value > 1.0) { + ALOGW("%s: (%f) Over 1.0, assuming 1.0\n", __func__, value); + value = 1.0; + } + vol = lrint((value * 0x2000) + 0.5); + + fmmod.fm_volume = vol; + + if (!fmmod.is_fm_running) { + ALOGV("%s: FM not active, ignoring set_fm_volume call", __func__); + return -EIO; + } + + ALOGD("%s: Setting FM volume to %d \n", __func__, vol); + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_value(ctl, 0, fmmod.fm_volume); + + ALOGD("%s: exit", __func__); + return ret; +} + +static int32_t fm_stop(struct audio_device *adev) +{ + int32_t i, ret = 0; + struct audio_usecase *uc_info; + + ALOGD("%s: enter", __func__); + fmmod.is_fm_running = false; + + /* 1. Close the PCM devices */ + if (fmmod.fm_pcm_rx) { + pcm_close(fmmod.fm_pcm_rx); + fmmod.fm_pcm_rx = NULL; + } + if (fmmod.fm_pcm_tx) { + pcm_close(fmmod.fm_pcm_tx); + fmmod.fm_pcm_tx = NULL; + } + + uc_info = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_FM); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, USECASE_VOICE_CALL); + return -EINVAL; + } + + /* 2. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 3. Disable the rx and tx devices */ + disable_snd_device(adev, uc_info->out_snd_device, false); + disable_snd_device(adev, uc_info->in_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + + ALOGD("%s: exit: status(%d)", __func__, ret); + return ret; +} + +static int32_t fm_start(struct audio_device *adev) +{ + int32_t i, ret = 0; + struct audio_usecase *uc_info; + int32_t pcm_dev_rx_id, pcm_dev_tx_id; + + ALOGD("%s: enter", __func__); + + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = USECASE_AUDIO_PLAYBACK_FM; + uc_info->type = PCM_PLAYBACK; + uc_info->stream.out = adev->primary_output; + uc_info->devices = adev->primary_output->devices; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, USECASE_AUDIO_PLAYBACK_FM); + + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); + + if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { + ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); + ret = -EIO; + goto exit; + } + + ALOGV("%s: FM PCM devices (rx: %d tx: %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); + + ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_rx_id); + fmmod.fm_pcm_rx = pcm_open(SOUND_CARD, + pcm_dev_rx_id, + PCM_OUT, &pcm_config_fm); + if (fmmod.fm_pcm_rx && !pcm_is_ready(fmmod.fm_pcm_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_rx)); + ret = -EIO; + goto exit; + } + + ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_tx_id); + fmmod.fm_pcm_tx = pcm_open(SOUND_CARD, + pcm_dev_tx_id, + PCM_IN, &pcm_config_fm); + if (fmmod.fm_pcm_tx && !pcm_is_ready(fmmod.fm_pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_tx)); + ret = -EIO; + goto exit; + } + pcm_start(fmmod.fm_pcm_rx); + pcm_start(fmmod.fm_pcm_tx); + + fmmod.is_fm_running = true; + fm_set_volume(adev, fmmod.fm_volume); + + ALOGD("%s: exit: status(%d)", __func__, ret); + return 0; + +exit: + fm_stop(adev); + ALOGE("%s: Problem in FM start: status(%d)", __func__, ret); + return ret; +} + +void audio_extn_fm_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + int ret, val; + char value[32]={0}; + float vol =0.0; + + ALOGV("%s: enter", __func__); + if(fmmod.is_fm_running) { + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, + value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + if(val > 0) + select_devices(adev, USECASE_AUDIO_PLAYBACK_FM); + } + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HANDLE_FM, + value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + ALOGD("%s: FM usecase", __func__); + if (val != 0) { + if(val & AUDIO_DEVICE_OUT_FM + && fmmod.is_fm_running == false) + fm_start(adev); + else if (!(val & AUDIO_DEVICE_OUT_FM) + && fmmod.is_fm_running == true) + fm_stop(adev); + } + } + + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FM_VOLUME, + value, sizeof(value)); + if (ret >= 0) { + if (sscanf(value, "%f", &vol) != 1){ + ALOGE("%s: error in retrieving fm volume", __func__); + ret = -EIO; + goto exit; + } + ALOGD("%s: set_fm_volume usecase", __func__); + fm_set_volume(adev, vol); + } + +exit: + ALOGV("%s: exit", __func__); +} +#endif /* FM_ENABLED end */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 045f03160..e80f88f6d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -94,6 +94,7 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", [USECASE_VOICE_CALL] = "voice-call", + [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", }; @@ -110,13 +111,16 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), }; +static struct audio_device *adev = NULL; +static pthread_mutex_t adev_init_lock; +static bool is_adev_initialised = false; static int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, bool update_mixer) { snd_device_t snd_device; - char mixer_path[50]; + char mixer_path[MIXER_PATH_MAX_LENGTH]; if (usecase == NULL) return -EINVAL; @@ -139,12 +143,12 @@ static int enable_audio_route(struct audio_device *adev, return 0; } -static int disable_audio_route(struct audio_device *adev, +int disable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, bool update_mixer) { snd_device_t snd_device; - char mixer_path[50]; + char mixer_path[MIXER_PATH_MAX_LENGTH]; if (usecase == NULL) return -EINVAL; @@ -196,7 +200,7 @@ static int enable_snd_device(struct audio_device *adev, return 0; } -static int disable_snd_device(struct audio_device *adev, +int disable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool update_mixer) { @@ -384,7 +388,7 @@ static int read_hdmi_channel_masks(struct stream_out *out) return ret; } -static struct audio_usecase *get_usecase_from_list(struct audio_device *adev, +struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id) { struct audio_usecase *usecase; @@ -398,7 +402,7 @@ static struct audio_usecase *get_usecase_from_list(struct audio_device *adev, return NULL; } -static int select_devices(struct audio_device *adev, +int select_devices(struct audio_device *adev, audio_usecase_t uc_id) { snd_device_t out_snd_device = SND_DEVICE_NONE; @@ -970,6 +974,13 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&out->lock); } + + if (out == adev->primary_output) { + pthread_mutex_lock(&adev->lock); + audio_extn_set_parameters(adev, parms); + pthread_mutex_unlock(&adev->lock); + } + str_parms_destroy(parms); ALOGV("%s: exit: code(%d)", __func__, ret); return ret; @@ -1710,12 +1721,20 @@ static int adev_close(hw_device_t *device) static int adev_open(const hw_module_t *module, const char *name, hw_device_t **device) { - struct audio_device *adev; int i, ret; ALOGD("%s: enter", __func__); if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL; + pthread_mutex_lock(&adev_init_lock); + if (is_adev_initialised == true){ + *device = &adev->device.common; + ALOGD("%s: returning existing instance of adev", __func__); + ALOGD("%s: exit", __func__); + pthread_mutex_unlock(&adev_init_lock); + return 0; + } + adev = calloc(1, sizeof(struct audio_device)); adev->device.common.tag = HARDWARE_DEVICE_TAG; @@ -1742,7 +1761,6 @@ static int adev_open(const hw_module_t *module, const char *name, adev->device.dump = adev_dump; /* Set the default route before the PCM stream is opened */ - pthread_mutex_lock(&adev->lock); adev->mode = AUDIO_MODE_NORMAL; adev->active_input = NULL; adev->primary_output = NULL; @@ -1756,7 +1774,6 @@ static int adev_open(const hw_module_t *module, const char *name, adev->acdb_settings = TTY_MODE_OFF; adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); list_init(&adev->usecase_list); - pthread_mutex_unlock(&adev->lock); /* Loads platform specific libraries dynamically */ adev->platform = platform_init(adev); @@ -1769,6 +1786,10 @@ static int adev_open(const hw_module_t *module, const char *name, } *device = &adev->device.common; + /* update init flag*/ + is_adev_initialised = true; + pthread_mutex_unlock(&adev_init_lock); + ALOGV("%s: exit", __func__); return 0; } diff --git a/hal/audio_hw.h b/hal/audio_hw.h index ecb624545..59f82d280 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -50,6 +50,8 @@ typedef enum { USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0, USECASE_AUDIO_PLAYBACK_LOW_LATENCY, USECASE_AUDIO_PLAYBACK_MULTI_CH, + /* FM usecase */ + USECASE_AUDIO_PLAYBACK_FM, /* Capture usecases */ USECASE_AUDIO_RECORD, @@ -151,6 +153,16 @@ struct audio_device { void *platform; }; +int select_devices(struct audio_device *adev, + audio_usecase_t uc_id); +int disable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer); +int disable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer); +struct audio_usecase *get_usecase_from_list(struct audio_device *adev, + audio_usecase_t uc_id); /* * NOTE: when multiple mutexes have to be acquired, always take the * stream_in or stream_out mutex first, followed by the audio_device mutex. diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 85c57fce7..02940b4c2 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -93,6 +93,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, }; /* Array to store sound devices */ @@ -114,6 +115,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm", [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones", [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones", [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones", @@ -142,6 +144,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef", [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", + [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm", [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic", }; @@ -163,6 +166,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + [SND_DEVICE_OUT_TRANSMISSION_FM] = 0, [SND_DEVICE_OUT_ANC_HEADSET] = 26, [SND_DEVICE_OUT_ANC_FB_HEADSET] = 26, [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26, @@ -188,6 +192,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_REC_MIC] = 62, + [SND_DEVICE_IN_CAPTURE_FM] = 0, [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, /* TODO: Update with proper acdb ids */ [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, @@ -361,6 +366,10 @@ void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) strcat(mixer_path, " hdmi"); else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) strcat(mixer_path, " speaker-and-hdmi"); + else if (snd_device == SND_DEVICE_IN_CAPTURE_FM) + strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM) + strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH); } int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) @@ -545,6 +554,8 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { + snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { if (is_operator_tmus()) snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; @@ -605,6 +616,8 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { snd_device = SND_DEVICE_OUT_HDMI ; + } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { + snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { snd_device = SND_DEVICE_OUT_HANDSET; } else { @@ -724,6 +737,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else set_echo_reference(adev->mixer, "NONE"); } + } else if (source == AUDIO_SOURCE_FM_RX) { + if (in_device & AUDIO_DEVICE_IN_FM_RX) { + snd_device = SND_DEVICE_IN_CAPTURE_FM; + } } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; } @@ -746,6 +763,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_BT_SCO_MIC ; } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { snd_device = SND_DEVICE_IN_HDMI_MIC; + } else if (in_device & AUDIO_DEVICE_IN_FM_RX) { + snd_device = SND_DEVICE_IN_CAPTURE_FM; } else { ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); ALOGW("%s: Using default handset-mic", __func__); diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index bbbb8216e..1bc4fc42f 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -60,6 +60,7 @@ enum { SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_TRANSMISSION_FM, SND_DEVICE_OUT_ANC_HEADSET, SND_DEVICE_OUT_ANC_FB_HEADSET, SND_DEVICE_OUT_VOICE_ANC_HEADSET, @@ -95,6 +96,7 @@ enum { SND_DEVICE_IN_VOICE_REC_MIC, SND_DEVICE_IN_VOICE_REC_DMIC, SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_CAPTURE_FM, SND_DEVICE_IN_AANC_HANDSET_MIC, SND_DEVICE_IN_END, @@ -113,6 +115,7 @@ enum { #define VOLUME_SET 0 #define MUTE_SET 1 #define VOLUME_CTL_PARAM_NUM 3 +#define MIXER_PATH_MAX_LENGTH 100 /* * tinyAlsa library interprets period size as number of frames @@ -138,6 +141,8 @@ enum { #define DEEP_BUFFER_PCM_DEVICE 0 #define MULTI_CHANNEL_PCM_DEVICE 1 #define VOICE_CALL_PCM_DEVICE 2 +#define FM_PLAYBACK_PCM_DEVICE 5 +#define FM_CAPTURE_PCM_DEVICE 6 #ifdef PLATFORM_MSM8610 #define LOWLATENCY_PCM_DEVICE 12 -- GitLab From 50378039db25b3774dbb1635db1480d3216c0ed3 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Fri, 18 Oct 2013 18:20:52 -0700 Subject: [PATCH 048/298] hal: enable compilation of AudioPolicyManager - Enable compilation of AudioPolicyManager. Change-Id: I52fd5ba07a13e2456246329b1932701e2b2c434a --- Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/Android.mk b/Android.mk index 505c9d5a8..111e2720c 100644 --- a/Android.mk +++ b/Android.mk @@ -8,6 +8,7 @@ else include $(MY_LOCAL_PATH)/hal/Android.mk include $(MY_LOCAL_PATH)/voice_processing/Android.mk include $(MY_LOCAL_PATH)/mm-audio/Android.mk +include $(MY_LOCAL_PATH)/policy_hal/Android.mk endif endif -- GitLab From 34b585f05ad04f1c4c7d72a945a527c50d396a1b Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Tue, 1 Oct 2013 15:49:05 -0700 Subject: [PATCH 049/298] audio_hal: Add support for multi voice sessions Update HAL to add multi SIM voice support. Seperate out voice features to voice files. Add getprop/setprop for BT sample rate, Fluence and Slow talk. Change-Id: Ief61466f78c7b915549981a28fc7ff32731607a5 --- hal/Android.mk | 18 ++ hal/audio_extn/audio_extn.c | 34 +--- hal/audio_extn/audio_extn.h | 5 +- hal/audio_hw.c | 317 +++++++++++-------------------- hal/audio_hw.h | 19 +- hal/msm8960/platform.c | 27 ++- hal/msm8960/platform.h | 5 +- hal/msm8974/platform.c | 220 ++++++++++++++------- hal/msm8974/platform.h | 17 +- hal/platform_api.h | 7 + hal/voice.c | 337 +++++++++++++++++++++++++++++++++ hal/voice.h | 68 +++++++ hal/voice_extn/voice_extn.c | 367 ++++++++++++++++++++++++++++++++++++ hal/voice_extn/voice_extn.h | 62 ++++++ 14 files changed, 1188 insertions(+), 315 deletions(-) create mode 100644 hal/voice.c create mode 100644 hal/voice.h create mode 100644 hal/voice_extn/voice_extn.c create mode 100644 hal/voice_extn/voice_extn.h diff --git a/hal/Android.mk b/hal/Android.mk index 5f5c7aec6..588df7d4b 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -6,6 +6,12 @@ include $(CLEAR_VARS) LOCAL_ARM_MODE := arm +#MULTI_VOICE_SESSION_ENABLED := true + +ifdef MULTI_VOICE_SESSION_ENABLED +LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED +endif + AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) ifneq ($(filter msm8974 msm8226 msm8610 apq8084,$(TARGET_BOARD_PLATFORM)),) # B-family platform uses msm8974 code base @@ -13,12 +19,20 @@ ifneq ($(filter msm8974 msm8226 msm8610 apq8084,$(TARGET_BOARD_PLATFORM)),) ifneq ($(filter msm8610,$(TARGET_BOARD_PLATFORM)),) LOCAL_CFLAGS := -DPLATFORM_MSM8610 endif +ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),) + LOCAL_CFLAGS := -DPLATFORM_MSM8x26 +endif endif LOCAL_SRC_FILES := \ audio_hw.c \ + voice.c \ $(AUDIO_PLATFORM)/platform.c +ifdef MULTI_VOICE_SESSION_ENABLED +LOCAL_SRC_FILES += voice_extn/voice_extn.c +endif + LOCAL_SRC_FILES += audio_extn/audio_extn.c ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true) @@ -49,6 +63,10 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \ $(LOCAL_PATH)/audio_extn +ifdef MULTI_VOICE_SESSION_ENABLED +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +endif + LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index b10a5e909..068ab4631 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -161,8 +161,8 @@ void audio_extn_set_afe_proxy_parameters(struct str_parms *parms) } } -char* audio_extn_get_afe_proxy_parameters(struct str_parms *query, - struct str_parms *reply) +int audio_extn_get_afe_proxy_parameters(struct str_parms *query, + struct str_parms *reply) { int ret, val; char value[32]={0}; @@ -174,10 +174,9 @@ char* audio_extn_get_afe_proxy_parameters(struct str_parms *query, /* Todo: check if proxy is free by maintaining a state flag*/ val = 1; str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val); - str = str_parms_to_str(reply); } - return str; + return 0; } #endif /* AFE_PROXY_ENABLED */ @@ -189,27 +188,10 @@ void audio_extn_set_parameters(struct audio_device *adev, audio_extn_fm_set_parameters(adev, parms); } -char* audio_extn_get_parameters(const struct audio_hw_device *dev, - const char *keys) +void audio_extn_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply) { - struct str_parms *query = str_parms_create_str(keys); - struct str_parms *reply = str_parms_create(); - char *str = NULL; - - ALOGD("%s: enter: keys - %s", __func__, keys); - - if (NULL != (str = audio_extn_get_afe_proxy_parameters(query, reply))) - { - ALOGD("%s: handled %s", __func__, str); - goto exit; - } else { - str = strdup(keys); - } - -exit: - str_parms_destroy(query); - str_parms_destroy(reply); - - ALOGD("%s: exit: returns %s", __func__, str); - return str; + audio_extn_get_afe_proxy_parameters(query, reply); + ALOGD("%s: exit: returns %s", __func__, str_parms_to_str(reply)); } diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index c537b774a..1cd6c67e4 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -25,8 +25,9 @@ void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms); -char* audio_extn_get_parameters(const struct audio_hw_device *dev, - const char *keys); +void audio_extn_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply); #ifndef ANC_HEADSET_ENABLED #define audio_extn_get_anc_enabled() (0) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index e80f88f6d..3155ab652 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -79,22 +79,17 @@ struct pcm_config pcm_config_audio_capture = { .format = PCM_FORMAT_S16_LE, }; -struct pcm_config pcm_config_voice_call = { - .channels = 1, - .rate = 8000, - .period_size = 160, - .period_count = 2, - .format = PCM_FORMAT_S16_LE, -}; - static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback", [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", - [USECASE_VOICE_CALL] = "voice-call", [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", + [USECASE_VOICE_CALL] = "voice-call", + [USECASE_VOICE2_CALL] = "voice2-call", + [USECASE_VOLTE_CALL] = "volte-call", + [USECASE_QCHAT_CALL] = "qchat-call", }; @@ -144,8 +139,8 @@ static int enable_audio_route(struct audio_device *adev, } int disable_audio_route(struct audio_device *adev, - struct audio_usecase *usecase, - bool update_mixer) + struct audio_usecase *usecase, + bool update_mixer) { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; @@ -201,8 +196,8 @@ static int enable_snd_device(struct audio_device *adev, } int disable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool update_mixer) + snd_device_t snd_device, + bool update_mixer) { if (snd_device < SND_DEVICE_MIN || snd_device >= SND_DEVICE_MAX) { @@ -250,7 +245,7 @@ static void check_usecases_codec_backend(struct audio_device *adev, list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type != PCM_CAPTURE && + if (usecase->type == PCM_PLAYBACK && usecase != uc_info && usecase->out_snd_device != snd_device && usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { @@ -317,7 +312,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type != PCM_PLAYBACK && + if (usecase->type == PCM_CAPTURE && usecase != uc_info && usecase->in_snd_device != snd_device) { ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", @@ -359,6 +354,51 @@ static void check_and_route_capture_usecases(struct audio_device *adev, } } +static int disable_all_usecases_of_type(struct audio_device *adev, + usecase_type_t usecase_type, + bool update_mixer) +{ + struct audio_usecase *usecase; + struct listnode *node; + int ret = 0; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == usecase_type) { + ALOGV("%s: usecase id %d", __func__, usecase->id); + ret = disable_audio_route(adev, usecase, update_mixer); + if (ret) { + ALOGE("%s: Failed to disable usecase id %d", + __func__, usecase->id); + } + } + } + + return ret; +} + +static int enable_all_usecases_of_type(struct audio_device *adev, + usecase_type_t usecase_type, + bool update_mixer) +{ + struct audio_usecase *usecase; + struct listnode *node; + int ret = 0; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == usecase_type) { + ALOGV("%s: usecase id %d", __func__, usecase->id); + ret = enable_audio_route(adev, usecase, update_mixer); + if (ret) { + ALOGE("%s: Failed to enable usecase id %d", + __func__, usecase->id); + } + } + } + + return ret; +} /* must be called with hw device mutex locked */ static int read_hdmi_channel_masks(struct stream_out *out) @@ -388,8 +428,23 @@ static int read_hdmi_channel_masks(struct stream_out *out) return ret; } +static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev) +{ + struct audio_usecase *usecase; + struct listnode *node; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == VOICE_CALL) { + ALOGV("%s: usecase id %d", __func__, usecase->id); + return usecase->id; + } + } + return USECASE_INVALID; +} + struct audio_usecase *get_usecase_from_list(struct audio_device *adev, - audio_usecase_t uc_id) + audio_usecase_t uc_id) { struct audio_usecase *usecase; struct listnode *node; @@ -402,8 +457,7 @@ struct audio_usecase *get_usecase_from_list(struct audio_device *adev, return NULL; } -int select_devices(struct audio_device *adev, - audio_usecase_t uc_id) +int select_devices(struct audio_device *adev, audio_usecase_t uc_id) { snd_device_t out_snd_device = SND_DEVICE_NONE; snd_device_t in_snd_device = SND_DEVICE_NONE; @@ -431,8 +485,9 @@ int select_devices(struct audio_device *adev, * usecase. This is to avoid switching devices for voice call when * check_usecases_codec_backend() is called below. */ - if (adev->in_call) { - vc_usecase = get_usecase_from_list(adev, USECASE_VOICE_CALL); + if (voice_is_in_call(adev)) { + vc_usecase = get_usecase_from_list(adev, + get_voice_usecase_id_from_list(adev)); if (vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { in_snd_device = vc_usecase->in_snd_device; out_snd_device = vc_usecase->out_snd_device; @@ -481,6 +536,7 @@ int select_devices(struct audio_device *adev, * device. */ if (usecase->type == VOICE_CALL) { + disable_all_usecases_of_type(adev, VOICE_CALL, true); status = platform_switch_voice_call_device_pre(adev->platform); } @@ -517,7 +573,10 @@ int select_devices(struct audio_device *adev, usecase->in_snd_device = in_snd_device; usecase->out_snd_device = out_snd_device; - enable_audio_route(adev, usecase, true); + if (usecase->type == VOICE_CALL) + enable_all_usecases_of_type(adev, VOICE_CALL, true); + else + enable_audio_route(adev, usecase, true); return status; } @@ -679,117 +738,6 @@ error_config: return ret; } -static int stop_voice_call(struct audio_device *adev) -{ - int i, ret = 0; - struct audio_usecase *uc_info; - - ALOGV("%s: enter", __func__); - adev->in_call = false; - - ret = platform_stop_voice_call(adev->platform); - - /* 1. Close the PCM devices */ - if (adev->voice_call_rx) { - pcm_close(adev->voice_call_rx); - adev->voice_call_rx = NULL; - } - if (adev->voice_call_tx) { - pcm_close(adev->voice_call_tx); - adev->voice_call_tx = NULL; - } - - uc_info = get_usecase_from_list(adev, USECASE_VOICE_CALL); - if (uc_info == NULL) { - ALOGE("%s: Could not find the usecase (%d) in the list", - __func__, USECASE_VOICE_CALL); - return -EINVAL; - } - - /* 2. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); - - /* 3. Disable the rx and tx devices */ - disable_snd_device(adev, uc_info->out_snd_device, false); - disable_snd_device(adev, uc_info->in_snd_device, true); - - list_remove(&uc_info->list); - free(uc_info); - - ALOGV("%s: exit: status(%d)", __func__, ret); - return ret; -} - -static int start_voice_call(struct audio_device *adev) -{ - int i, ret = 0; - struct audio_usecase *uc_info; - int pcm_dev_rx_id, pcm_dev_tx_id; - - ALOGV("%s: enter", __func__); - - uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); - uc_info->id = USECASE_VOICE_CALL; - uc_info->type = VOICE_CALL; - uc_info->stream.out = adev->primary_output; - uc_info->devices = adev->primary_output->devices; - uc_info->in_snd_device = SND_DEVICE_NONE; - uc_info->out_snd_device = SND_DEVICE_NONE; - - list_add_tail(&adev->usecase_list, &uc_info->list); - - select_devices(adev, USECASE_VOICE_CALL); - - pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); - pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); - - if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { - ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", - __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); - ret = -EIO; - goto error_start_voice; - } - - ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_rx_id); - adev->voice_call_rx = pcm_open(SOUND_CARD, - pcm_dev_rx_id, - PCM_OUT, &pcm_config_voice_call); - if (adev->voice_call_rx && !pcm_is_ready(adev->voice_call_rx)) { - ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_rx)); - ret = -EIO; - goto error_start_voice; - } - - ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_tx_id); - adev->voice_call_tx = pcm_open(SOUND_CARD, - pcm_dev_tx_id, - PCM_IN, &pcm_config_voice_call); - if (adev->voice_call_tx && !pcm_is_ready(adev->voice_call_tx)) { - ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_tx)); - ret = -EIO; - goto error_start_voice; - } - pcm_start(adev->voice_call_rx); - pcm_start(adev->voice_call_tx); - - ret = platform_start_voice_call(adev->platform); - if (ret < 0) { - ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); - goto error_start_voice; - } - - adev->in_call = true; - return 0; - -error_start_voice: - stop_voice_call(adev); - - ALOGD("%s: exit: status(%d)", __func__, ret); - return ret; -} - static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count) @@ -957,18 +905,21 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if (!out->standby) select_devices(adev, out->usecase); - if ((adev->mode == AUDIO_MODE_IN_CALL) && !adev->in_call && + if ((adev->mode == AUDIO_MODE_IN_CALL) && + !voice_is_in_call(adev) && (out == adev->primary_output)) { - start_voice_call(adev); - } else if ((adev->mode == AUDIO_MODE_IN_CALL) && adev->in_call && - (out == adev->primary_output)) { - select_devices(adev, USECASE_VOICE_CALL); + voice_start_call(adev); + } else if ((adev->mode == AUDIO_MODE_IN_CALL) && + voice_is_in_call(adev) && + (out == adev->primary_output)) { + select_devices(adev, get_voice_usecase_id_from_list(adev)); } } - if ((adev->mode == AUDIO_MODE_NORMAL) && adev->in_call && + if ((adev->mode == AUDIO_MODE_NORMAL) && + voice_is_in_call(adev) && (out == adev->primary_output)) { - stop_voice_call(adev); + voice_stop_call(adev); } pthread_mutex_unlock(&adev->lock); @@ -1249,7 +1200,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, * Instead of writing zeroes here, we could trust the hardware * to always provide zeroes when muted. */ - if (ret == 0 && adev->mic_mute) + if (ret == 0 && voice_get_mic_mute(adev)) memset(buffer, 0, bytes); exit: @@ -1443,32 +1394,10 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) int ret; ALOGV("%s: enter: %s", __func__, kvpairs); - parms = str_parms_create_str(kvpairs); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); - if (ret >= 0) { - int tty_mode; - - if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0) - tty_mode = TTY_MODE_OFF; - else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0) - tty_mode = TTY_MODE_VCO; - else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0) - tty_mode = TTY_MODE_HCO; - else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0) - tty_mode = TTY_MODE_FULL; - else - return -EINVAL; - pthread_mutex_lock(&adev->lock); - if (tty_mode != adev->tty_mode) { - adev->tty_mode = tty_mode; - adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode; - if (adev->in_call) - select_devices(adev, USECASE_VOICE_CALL); - } - pthread_mutex_unlock(&adev->lock); - } + voice_set_parameters(adev, parms); + platform_set_parameters(adev->platform, parms); ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); if (ret >= 0) { @@ -1532,7 +1461,19 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) static char* adev_get_parameters(const struct audio_hw_device *dev, const char *keys) { - return audio_extn_get_parameters(dev, keys); + struct audio_device *adev = (struct audio_device *)dev; + struct str_parms *reply = str_parms_create(); + struct str_parms *query = str_parms_create_str(keys); + char *str; + + audio_extn_get_parameters(adev, query, reply); + platform_get_parameters(adev->platform, query, reply); + str = str_parms_to_str(reply); + str_parms_destroy(query); + str_parms_destroy(reply); + + ALOGV("%s: exit: returns - %s", __func__, str); + return str; } static int adev_init_check(const struct audio_hw_device *dev) @@ -1542,29 +1483,7 @@ static int adev_init_check(const struct audio_hw_device *dev) static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) { - struct audio_device *adev = (struct audio_device *)dev; - int vol, err = 0; - - pthread_mutex_lock(&adev->lock); - adev->voice_volume = volume; - if (adev->mode == AUDIO_MODE_IN_CALL) { - if (volume < 0.0) { - volume = 0.0; - } else if (volume > 1.0) { - volume = 1.0; - } - - vol = lrint(volume * 100.0); - - // Voice volume levels from android are mapped to driver volume levels as follows. - // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 - // So adjust the volume to get the correct volume index in driver - vol = 100 - vol; - - err = platform_set_voice_volume(adev->platform, vol); - } - pthread_mutex_unlock(&adev->lock); - return err; + return voice_set_volume((struct audio_device *)dev, volume); } static int adev_set_master_volume(struct audio_hw_device *dev, float volume) @@ -1591,7 +1510,6 @@ static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) { struct audio_device *adev = (struct audio_device *)dev; - pthread_mutex_lock(&adev->lock); if (adev->mode != mode) { adev->mode = mode; @@ -1602,23 +1520,12 @@ static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) { - struct audio_device *adev = (struct audio_device *)dev; - int err = 0; - - pthread_mutex_lock(&adev->lock); - adev->mic_mute = state; - - err = platform_set_mic_mute(adev->platform, state); - pthread_mutex_unlock(&adev->lock); - return err; + return voice_set_mic_mute((struct audio_device *)dev, state); } static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) { - struct audio_device *adev = (struct audio_device *)dev; - - *state = adev->mic_mute; - + *state = voice_get_mic_mute((struct audio_device *)dev); return 0; } @@ -1765,14 +1672,10 @@ static int adev_open(const hw_module_t *module, const char *name, adev->active_input = NULL; adev->primary_output = NULL; adev->out_device = AUDIO_DEVICE_NONE; - adev->voice_call_rx = NULL; - adev->voice_call_tx = NULL; - adev->voice_volume = 1.0f; - adev->tty_mode = TTY_MODE_OFF; adev->bluetooth_nrec = true; - adev->in_call = false; adev->acdb_settings = TTY_MODE_OFF; adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); + voice_init(adev); list_init(&adev->usecase_list); /* Loads platform specific libraries dynamically */ diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 59f82d280..2eb161620 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,10 +22,10 @@ #include #include - #include #include +#include "voice.h" /* Flags used to initialize acdb_settings variable that goes to ACDB library */ #define DMIC_FLAG 0x00000002 @@ -57,8 +60,14 @@ typedef enum { USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_LOW_LATENCY, + /* Voice usecase */ USECASE_VOICE_CALL, + /* Voice extension usecases */ + USECASE_VOICE2_CALL, + USECASE_VOLTE_CALL, + USECASE_QCHAT_CALL, + AUDIO_USECASE_MAX } audio_usecase_t; @@ -136,20 +145,14 @@ struct audio_device { audio_devices_t out_device; struct stream_in *active_input; struct stream_out *primary_output; - int in_call; - float voice_volume; - bool mic_mute; - int tty_mode; bool bluetooth_nrec; bool screen_off; - struct pcm *voice_call_rx; - struct pcm *voice_call_tx; int *snd_dev_ref_cnt; struct listnode usecase_list; struct audio_route *audio_route; int acdb_settings; bool speaker_lr_swap; - + struct voice voice; void *platform; }; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index a24ca83e4..a2eefdd07 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -364,13 +367,17 @@ const char *platform_get_snd_device_name(snd_device_t snd_device) void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) { if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) - strcat(mixer_path, " bt-sco"); + strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB) + strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH); else if(snd_device == SND_DEVICE_OUT_BT_SCO) - strcat(mixer_path, " bt-sco"); + strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH); + else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB) + strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_HDMI) - strcat(mixer_path, " hdmi"); + strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) - strcat(mixer_path, " speaker-and-hdmi"); + strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH); } int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) @@ -864,3 +871,15 @@ int platform_edid_get_max_channels(void *platform) return max_channels; } + +void platform_get_parameters(void *platform, struct str_parms *query, + struct str_parms *reply) +{ + LOGE("%s: Not implemented", __func__); +} + +int platform_set_parameters(void *platform, struct str_parms *parms) +{ + LOGE("%s: Not implemented", __func__); + return -ENOSYS; +} diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h index f09b9b124..d58356081 100644 --- a/hal/msm8960/platform.h +++ b/hal/msm8960/platform.h @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -95,7 +98,7 @@ enum { #define SOUND_CARD 0 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000 - +#define MIXER_PATH_MAX_LENGTH 100 /* * tinyAlsa library interprets period size as number of frames * one frame = channel_count * sizeof (pcm sample) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 02940b4c2..ee069d77d 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "platform.h" @@ -51,10 +52,17 @@ #define RETRY_NUMBER 10 #define RETRY_US 500000 +#define SAMPLE_RATE_8KHZ 8000 +#define SAMPLE_RATE_16KHZ 16000 + #define MAX_VOL_INDEX 5 #define MIN_VOL_INDEX 0 #define percent_to_index(val, min, max) \ - ((val) * ((max) - (min)) * 0.01 + (min) + .5) + ((val) * ((max) - (min)) * 0.01 + (min) + .5) + +#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence" +#define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate" +#define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable" struct audio_block_header { @@ -74,6 +82,8 @@ struct platform_data { bool fluence_in_voice_call; bool fluence_in_voice_rec; int fluence_type; + int btsco_sample_rate; + bool slowtalk; void *acdb_handle; acdb_init_t acdb_init; @@ -92,8 +102,11 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_RECORD] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, - [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, + [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, + [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, + [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, + [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE}, }; /* Array to store sound devices */ @@ -111,6 +124,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_HDMI] = "hdmi", [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", + [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb", [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus", [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", @@ -134,6 +148,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", + [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb", [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus", @@ -162,6 +177,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_HDMI] = 18, [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, [SND_DEVICE_OUT_BT_SCO] = 22, + [SND_DEVICE_OUT_BT_SCO_WB] = 39, [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88, [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, @@ -184,6 +200,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, [SND_DEVICE_IN_HDMI_MIC] = 4, [SND_DEVICE_IN_BT_SCO_MIC] = 21, + [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38, [SND_DEVICE_IN_CAMCORDER_MIC] = 61, [SND_DEVICE_IN_VOICE_DMIC] = 41, [SND_DEVICE_IN_VOICE_DMIC_TMUS] = 89, @@ -225,24 +242,6 @@ bool is_operator_tmus() return is_tmus; } -static int set_volume_values(int type, int volume, int* values) -{ - values[0] = volume; - values[1] = ALL_SESSION_VSID; - - switch(type) { - case VOLUME_SET: - values[2] = DEFAULT_VOLUME_RAMP_DURATION_MS; - break; - case MUTE_SET: - values[2] = DEFAULT_MUTE_RAMP_DURATION; - break; - default: - return -EINVAL; - } - return 0; -} - static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -287,6 +286,7 @@ void *platform_init(struct audio_device *adev) my_data = calloc(1, sizeof(struct platform_data)); my_data->adev = adev; + my_data->btsco_sample_rate = SAMPLE_RATE_8KHZ; my_data->fluence_in_spkr_mode = false; my_data->fluence_in_voice_call = false; my_data->fluence_in_voice_rec = false; @@ -359,11 +359,15 @@ const char *platform_get_snd_device_name(snd_device_t snd_device) void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) { if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) - strcat(mixer_path, " bt-sco"); + strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB) + strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH); else if(snd_device == SND_DEVICE_OUT_BT_SCO) - strcat(mixer_path, " bt-sco"); + strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH); + else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB) + strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_HDMI) - strcat(mixer_path, " hdmi"); + strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) strcat(mixer_path, " speaker-and-hdmi"); else if (snd_device == SND_DEVICE_IN_CAPTURE_FM) @@ -450,13 +454,16 @@ int platform_set_voice_volume(void *platform, int volume) struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Rx Gain"; - int values[VOLUME_CTL_PARAM_NUM]; - int ret = 0; + int vol_index = 0; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID, + DEFAULT_VOLUME_RAMP_DURATION_MS}; // Voice volume levels are mapped to adsp volume levels as follows. // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 // But this values don't changed in kernel. So, below change is need. - volume = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); + vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); + set_values[0] = vol_index; ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { @@ -464,16 +471,8 @@ int platform_set_voice_volume(void *platform, int volume) __func__, mixer_ctl_name); return -EINVAL; } - ret = set_volume_values(VOLUME_SET, volume, values); - if (ret < 0) { - ALOGV("%s: failed setting volume by incorrect type", __func__); - return -EINVAL; - } - ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int)); - if (ret < 0) { - ALOGV("%s: failed set mixer ctl by %d", __func__, ret); - return -EINVAL; - } + ALOGV("Setting voice volume index: %d", set_values[0]); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); return 0; } @@ -484,27 +483,20 @@ int platform_set_mic_mute(void *platform, bool state) struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Tx Mute"; - int values[VOLUME_CTL_PARAM_NUM]; - int ret = 0; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID, + DEFAULT_VOLUME_RAMP_DURATION_MS}; if (adev->mode == AUDIO_MODE_IN_CALL) { + set_values[0] = state; ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name); return -EINVAL; } - ALOGV("Setting mic mute: %d", state); - ret = set_volume_values(MUTE_SET, state, values); - if (ret < 0) { - ALOGV("%s: failed setting mute by incorrect type", __func__); - return -EINVAL; - } - ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int)); - if (ret < 0) { - ALOGV("%s: failed set mixer ctl by %d", __func__, ret); - return -EINVAL; - } + ALOGV("Setting voice mute state: %d", state); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); } return 0; @@ -536,22 +528,25 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi if (mode == AUDIO_MODE_IN_CALL) { if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - if (adev->tty_mode == TTY_MODE_FULL) + if (adev->voice.tty_mode == TTY_MODE_FULL) { snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES; - else if (adev->tty_mode == TTY_MODE_VCO) + } else if (adev->voice.tty_mode == TTY_MODE_VCO) { snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; - else if (adev->tty_mode == TTY_MODE_HCO) + } else if (adev->voice.tty_mode == TTY_MODE_HCO) { snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; - else if (audio_extn_get_anc_enabled()) { + } else if (audio_extn_get_anc_enabled()) { if (audio_extn_should_use_fb_anc()) snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET; else snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET; - } - else + } else { snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES; + } } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_OUT_BT_SCO; + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_OUT_BT_SCO_WB; + else + snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { @@ -613,7 +608,10 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi else snd_device = SND_DEVICE_OUT_SPEAKER; } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_OUT_BT_SCO; + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_OUT_BT_SCO_WB; + else + snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { snd_device = SND_DEVICE_OUT_HDMI ; } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { @@ -651,10 +649,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d ALOGE("%s: No output device set for voice call", __func__); goto exit; } - if (adev->tty_mode != TTY_MODE_OFF) { + if (adev->voice.tty_mode != TTY_MODE_OFF) { if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - switch (adev->tty_mode) { + switch (adev->voice.tty_mode) { case TTY_MODE_FULL: snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC; break; @@ -665,7 +663,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC; break; default: - ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode); + ALOGE("%s: Invalid TTY mode (%#x)", + __func__, adev->voice.tty_mode); } goto exit; } @@ -688,7 +687,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC ; + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; + else + snd_device = SND_DEVICE_IN_BT_SCO_MIC; } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { if (my_data->fluence_type != FLUENCE_NONE && my_data->fluence_in_voice_call && @@ -760,7 +762,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC; } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC ; + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; + else + snd_device = SND_DEVICE_IN_BT_SCO_MIC; } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { snd_device = SND_DEVICE_IN_HDMI_MIC; } else if (in_device & AUDIO_DEVICE_IN_FM_RX) { @@ -780,7 +785,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC; + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; + else + snd_device = SND_DEVICE_IN_BT_SCO_MIC; } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { snd_device = SND_DEVICE_IN_HDMI_MIC; } else { @@ -882,3 +890,89 @@ int platform_edid_get_max_channels(void *platform) return max_channels; } + +static int platform_set_slowtalk(struct platform_data *my_data, bool state) +{ + int ret = 0; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Slowtalk Enable"; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID}; + + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + ret = -EINVAL; + } else { + ALOGV("Setting slowtalk state: %d", state); + ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + my_data->slowtalk = state; + } + + return ret; +} + +int platform_set_parameters(void *platform, struct str_parms *parms) +{ + struct platform_data *my_data = (struct platform_data *)platform; + char *str; + char value[32]; + int val; + int ret = 0; + + ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + + ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO); + pthread_mutex_lock(&my_data->adev->lock); + my_data->btsco_sample_rate = val; + pthread_mutex_unlock(&my_data->adev->lock); + } + + ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK); + pthread_mutex_lock(&my_data->adev->lock); + ret = platform_set_slowtalk(my_data, val); + if (ret) + ALOGE("%s: Failed to set slow talk err: %d", __func__, ret); + pthread_mutex_unlock(&my_data->adev->lock); + } + + ALOGV("%s: exit with code(%d)", __func__, ret); + return ret; +} + +void platform_get_parameters(void *platform, + struct str_parms *query, + struct str_parms *reply) +{ + struct platform_data *my_data = (struct platform_data *)platform; + char *str = NULL; + char value[256] = {0}; + int ret; + int fluence_type; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, + value, sizeof(value)); + if (ret >= 0) { + pthread_mutex_lock(&my_data->adev->lock); + if (my_data->fluence_type == FLUENCE_QUAD_MIC) { + strlcpy(value, "fluencepro", sizeof(value)); + } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) { + strlcpy(value, "fluence", sizeof(value)); + } else { + strlcpy(value, "none", sizeof(value)); + } + pthread_mutex_unlock(&my_data->adev->lock); + + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value); + } + + ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply)); +} + diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 1bc4fc42f..dd8dfda9f 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -56,6 +56,7 @@ enum { SND_DEVICE_OUT_HDMI, SND_DEVICE_OUT_SPEAKER_AND_HDMI, SND_DEVICE_OUT_BT_SCO, + SND_DEVICE_OUT_BT_SCO_WB, SND_DEVICE_OUT_VOICE_HANDSET_TMUS, SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, @@ -85,6 +86,7 @@ enum { SND_DEVICE_IN_VOICE_HEADSET_MIC, SND_DEVICE_IN_HDMI_MIC, SND_DEVICE_IN_BT_SCO_MIC, + SND_DEVICE_IN_BT_SCO_MIC_WB, SND_DEVICE_IN_CAMCORDER_MIC, SND_DEVICE_IN_VOICE_DMIC, SND_DEVICE_IN_VOICE_DMIC_TMUS, @@ -109,12 +111,9 @@ enum { #define DEFAULT_OUTPUT_SAMPLING_RATE 48000 -#define ALL_SESSION_VSID 0xFFFFFFFF +#define ALL_SESSION_VSID 0xFFFFFFFF #define DEFAULT_MUTE_RAMP_DURATION 500 #define DEFAULT_VOLUME_RAMP_DURATION_MS 20 -#define VOLUME_SET 0 -#define MUTE_SET 1 -#define VOLUME_CTL_PARAM_NUM 3 #define MIXER_PATH_MAX_LENGTH 100 /* @@ -144,6 +143,16 @@ enum { #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 +#ifdef PLATFORM_MSM8x26 +#define VOICE2_CALL_PCM_DEVICE 14 +#define VOLTE_CALL_PCM_DEVICE 17 +#define QCHAT_CALL_PCM_DEVICE 18 +#else +#define VOICE2_CALL_PCM_DEVICE 13 +#define VOLTE_CALL_PCM_DEVICE 14 +#define QCHAT_CALL_PCM_DEVICE 20 +#endif + #ifdef PLATFORM_MSM8610 #define LOWLATENCY_PCM_DEVICE 12 #else diff --git a/hal/platform_api.h b/hal/platform_api.h index 2362a5b3f..b1d0420e0 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -1,4 +1,7 @@ /* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,5 +38,9 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device); int platform_set_hdmi_channels(void *platform, int channel_count); int platform_edid_get_max_channels(void *platform); +void platform_get_parameters(void *platform, struct str_parms *query, + struct str_parms *reply); +int platform_set_parameters(void *platform, struct str_parms *parms); + #endif // QCOM_AUDIO_PLATFORM_API_H diff --git a/hal/voice.c b/hal/voice.c new file mode 100644 index 000000000..2b1ac87cb --- /dev/null +++ b/hal/voice.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "voice" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include + +#include "audio_hw.h" +#include "voice.h" +#include "voice_extn/voice_extn.h" +#include "platform.h" +#include "platform_api.h" + +struct pcm_config pcm_config_voice_call = { + .channels = 1, + .rate = 8000, + .period_size = 160, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +extern struct audio_usecase *get_usecase_from_list(struct audio_device *adev, + audio_usecase_t uc_id); +extern int disable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer); +extern int disable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer); + +extern int disable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer); +extern int select_devices(struct audio_device *adev, + audio_usecase_t uc_id); + +static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev, + audio_usecase_t usecase_id) +{ + struct voice_session *session = NULL; + int ret = 0; + + ret = voice_extn_get_session_from_use_case(adev, usecase_id, &session); + if (ret == -ENOSYS) { + session = &adev->voice.session[VOICE_SESS_IDX]; + } + + return session; +} + +int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + struct voice_session *session = NULL; + + ALOGD("%s: enter", __func__); + + session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); + session->state.current = CALL_INACTIVE; + + ret = platform_stop_voice_call(adev->platform); + + /* 1. Close the PCM devices */ + if (session->pcm_rx) { + pcm_close(session->pcm_rx); + session->pcm_rx = NULL; + } + if (session->pcm_tx) { + pcm_close(session->pcm_tx); + session->pcm_tx = NULL; + } + + uc_info = get_usecase_from_list(adev, usecase_id); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, usecase_id); + return -EINVAL; + } + + /* 2. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 3. Disable the rx and tx devices */ + disable_snd_device(adev, uc_info->out_snd_device, false); + disable_snd_device(adev, uc_info->in_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + + ALOGD("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int start_call(struct audio_device *adev, audio_usecase_t usecase_id) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + int pcm_dev_rx_id, pcm_dev_tx_id; + struct voice_session *session = NULL; + + ALOGD("%s: enter", __func__); + + session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); + + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = usecase_id; + uc_info->type = VOICE_CALL; + uc_info->stream.out = adev->primary_output; + uc_info->devices = adev->primary_output->devices; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, usecase_id); + + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); + + if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { + ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); + ret = -EIO; + goto error_start_voice; + } + + ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_rx_id); + session->pcm_rx = pcm_open(SOUND_CARD, + pcm_dev_rx_id, + PCM_OUT, &pcm_config_voice_call); + if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx)); + ret = -EIO; + goto error_start_voice; + } + + ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_tx_id); + session->pcm_tx = pcm_open(SOUND_CARD, + pcm_dev_tx_id, + PCM_IN, &pcm_config_voice_call); + if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx)); + ret = -EIO; + goto error_start_voice; + } + pcm_start(session->pcm_rx); + pcm_start(session->pcm_tx); + + ret = platform_start_voice_call(adev->platform); + if (ret < 0) { + ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); + goto error_start_voice; + } + + session->state.current = CALL_ACTIVE; + return 0; + +error_start_voice: + stop_call(adev, usecase_id); + + ALOGD("%s: exit: status(%d)", __func__, ret); + return ret; +} + +bool voice_is_in_call(struct audio_device *adev) +{ + bool in_call = false; + int ret = 0; + + ret = voice_extn_is_in_call(adev, &in_call); + if (ret == -ENOSYS) { + in_call = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false; + } + + return in_call; +} + +int voice_set_mic_mute(struct audio_device *adev, bool state) +{ + int err = 0; + + pthread_mutex_lock(&adev->lock); + + err = platform_set_mic_mute(adev->platform, state); + if (!err) { + adev->voice.mic_mute = state; + } + + pthread_mutex_unlock(&adev->lock); + return err; +} + +bool voice_get_mic_mute(struct audio_device *adev) +{ + return adev->voice.mic_mute; +} + +int voice_set_volume(struct audio_device *adev, float volume) +{ + int vol, err = 0; + + pthread_mutex_lock(&adev->lock); + if (adev->mode == AUDIO_MODE_IN_CALL) { + if (volume < 0.0) { + volume = 0.0; + } else if (volume > 1.0) { + volume = 1.0; + } + + vol = lrint(volume * 100.0); + + // Voice volume levels from android are mapped to driver volume levels as follows. + // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 + // So adjust the volume to get the correct volume index in driver + vol = 100 - vol; + + err = platform_set_voice_volume(adev->platform, vol); + if (!err) { + adev->voice.volume = volume; + } + } + pthread_mutex_unlock(&adev->lock); + return err; +} + +int voice_start_call(struct audio_device *adev) +{ + int ret = 0; + + ret = voice_extn_update_calls(adev); + if (ret == -ENOSYS) { + ret = start_call(adev, USECASE_VOICE_CALL); + } + + return ret; +} + +int voice_stop_call(struct audio_device *adev) +{ + int ret = 0; + + ret = voice_extn_update_calls(adev); + if (ret == -ENOSYS) { + ret = stop_call(adev, USECASE_VOICE_CALL); + } + + return ret; +} + +int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) +{ + char *str; + char value[32]; + int val; + int ret = 0; + + ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + + voice_extn_set_parameters(adev, parms); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); + if (ret >= 0) { + int tty_mode; + str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE); + if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0) + tty_mode = TTY_MODE_OFF; + else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0) + tty_mode = TTY_MODE_VCO; + else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0) + tty_mode = TTY_MODE_HCO; + else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0) + tty_mode = TTY_MODE_FULL; + else { + ret = -EINVAL; + goto done; + } + + pthread_mutex_lock(&adev->lock); + if (tty_mode != adev->voice.tty_mode) { + adev->voice.tty_mode = tty_mode; + adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode; + if (voice_is_in_call(adev)) + //todo: what about voice2, volte and qchat usecases? + select_devices(adev, USECASE_VOICE_CALL); + } + pthread_mutex_unlock(&adev->lock); + } + +done: + ALOGV("%s: exit with code(%d)", __func__, ret); + return ret; +} + +void voice_init(struct audio_device *adev) +{ + int i = 0; + + memset(&adev->voice, 0, sizeof(adev->voice)); + adev->voice.tty_mode = TTY_MODE_OFF; + adev->voice.volume = 1.0f; + adev->voice.mic_mute = false; + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + adev->voice.session[i].pcm_rx = NULL; + adev->voice.session[i].pcm_tx = NULL; + adev->voice.session[i].state.current = CALL_INACTIVE; + adev->voice.session[i].state.new = CALL_INACTIVE; + adev->voice.session[i].vsid = 0; + } + + voice_extn_init(adev); +} + + diff --git a/hal/voice.h b/hal/voice.h new file mode 100644 index 000000000..22c359d55 --- /dev/null +++ b/hal/voice.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef VOICE_H +#define VOICE_H + +#define BASE_SESS_IDX 0 +#define VOICE_SESS_IDX (BASE_SESS_IDX) + +#ifdef MULTI_VOICE_SESSION_ENABLED +#define MAX_VOICE_SESSIONS 4 +#else +#define MAX_VOICE_SESSIONS 1 +#endif + +#define BASE_CALL_STATE 1 +#define CALL_INACTIVE (BASE_CALL_STATE) +#define CALL_ACTIVE (BASE_CALL_STATE + 1) + +#define VOICE_VSID 0x10C01000 + +struct audio_device; +struct str_parms; + +struct call_state { + int current; + int new; +}; + +struct voice_session { + struct pcm *pcm_rx; + struct pcm *pcm_tx; + struct call_state state; + uint32_t vsid; +}; + +struct voice { + struct voice_session session[MAX_VOICE_SESSIONS]; + int tty_mode; + bool mic_mute; + float volume; +}; + +int voice_start_call(struct audio_device *adev); +int voice_stop_call(struct audio_device *adev); +int voice_set_parameters(struct audio_device *adev, struct str_parms *parms); +void voice_init(struct audio_device *adev); +bool voice_is_in_call(struct audio_device *adev); +int voice_set_mic_mute(struct audio_device *dev, bool state); +bool voice_get_mic_mute(struct audio_device *dev); +int voice_set_volume(struct audio_device *adev, float volume); +#endif //VOICE_H diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c new file mode 100644 index 000000000..ac3d9f2bb --- /dev/null +++ b/hal/voice_extn/voice_extn.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifdef MULTI_VOICE_SESSION_ENABLED + +#define LOG_TAG "voice_extn" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include + +#include "audio_hw.h" +#include "voice.h" +#include "platform.h" +#include "platform_api.h" + +#define AUDIO_PARAMETER_KEY_VSID "vsid" +#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state" + +#define VOICE2_VSID 0x10DC1000 +#define VOLTE_VSID 0x10C02000 +#define QCHAT_VSID 0x10803000 +#define ALL_VSID 0xFFFFFFFF + +/* Voice Session Indices */ +#define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1) +#define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2) +#define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3) + +/* Call States */ +#define CALL_HOLD (BASE_CALL_STATE + 2) +#define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3) + +extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id); +extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id); +int voice_extn_update_calls(struct audio_device *adev); + +static bool is_valid_call_state(int call_state) +{ + if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD) + return false; + else + return true; +} + +static bool is_valid_vsid(uint32_t vsid) +{ + if (vsid == VOICE_VSID || + vsid == VOICE2_VSID || + vsid == VOLTE_VSID || + vsid == QCHAT_VSID) + return true; + else + return false; +} + +static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index) +{ + audio_usecase_t usecase_id = -1; + + switch(index) { + case VOICE_SESS_IDX: + usecase_id = USECASE_VOICE_CALL; + break; + + case VOICE2_SESS_IDX: + usecase_id = USECASE_VOICE2_CALL; + break; + + case VOLTE_SESS_IDX: + usecase_id = USECASE_VOLTE_CALL; + break; + + case QCHAT_SESS_IDX: + usecase_id = USECASE_QCHAT_CALL; + break; + + default: + ALOGE("%s: Invalid voice session index\n", __func__); + } + + return usecase_id; +} + +int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) +{ + struct voice_session *session = NULL; + int i = 0; + *in_call = false; + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + session = &adev->voice.session[i]; + if(session->state.current != CALL_INACTIVE){ + *in_call = true; + break; + } + } + + return 0; +} + +static int voice_extn_update_call_states(struct audio_device *adev, + const uint32_t vsid, const int call_state) +{ + struct voice_session *session = NULL; + int i = 0; + bool is_in_call; + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + if (vsid == adev->voice.session[i].vsid) { + session = &adev->voice.session[i]; + break; + } + } + + if (session) { + session->state.new = call_state; + voice_extn_is_in_call(adev, &is_in_call); + if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) { + /* Device routing is not triggered for voice calls on the subsequent + * subs, Hence update the call states if voice call is already + * active on other sub. + */ + voice_extn_update_calls(adev); + } + } else { + return -EINVAL; + } + + return 0; + +} + +void voice_extn_init(struct audio_device *adev) +{ + adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID; + adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID; + adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID; + adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID; +} + +int voice_extn_get_session_from_use_case(struct audio_device *adev, + const audio_usecase_t usecase_id, + struct voice_session **session) +{ + + switch(usecase_id) + { + case USECASE_VOICE_CALL: + *session = &adev->voice.session[VOICE_SESS_IDX]; + break; + + case USECASE_VOICE2_CALL: + *session = &adev->voice.session[VOICE2_SESS_IDX]; + break; + + case USECASE_VOLTE_CALL: + *session = &adev->voice.session[VOLTE_SESS_IDX]; + break; + + case USECASE_QCHAT_CALL: + *session = &adev->voice.session[QCHAT_SESS_IDX]; + break; + + default: + ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id); + *session = NULL; + return -EINVAL; + } + + return 0; +} + +int voice_extn_update_calls(struct audio_device *adev) +{ + int i = 0; + audio_usecase_t usecase_id = 0; + enum voice_lch_mode lch_mode; + struct voice_session *session = NULL; + int fd = 0; + int ret = 0; + + ALOGD("%s: enter:", __func__); + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + usecase_id = voice_extn_get_usecase_for_session_idx(i); + session = &adev->voice.session[i]; + ALOGV("%s: cur_state=%d new_state=%d vsid=%x", + __func__, session->state.current, session->state.new, session->vsid); + + switch(session->state.new) + { + case CALL_ACTIVE: + switch(session->state.current) + { + case CALL_INACTIVE: + ALOGD("%s: INACTIVE ->ACTIVE vsid:%x", __func__, session->vsid); + ret = start_call(adev, usecase_id); + if(ret < 0) { + ALOGE("%s: voice_start_call() failed for usecase: %d\n", + __func__, usecase_id); + } + session->state.current = session->state.new; + break; + + case CALL_HOLD: + ALOGD("%s: HOLD ->ACTIVE vsid:%x", __func__, session->vsid); + session->state.current = session->state.new; + break; + + case CALL_LOCAL_HOLD: + ALOGD("%s: LOCAL_HOLD ->ACTIVE vsid:%x", __func__, session->vsid); + lch_mode = VOICE_LCH_STOP; + if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { + ALOGE("LOCAL_HOLD ->ACTIVE failed"); + } else { + session->state.current = session->state.new; + } + break; + + default: + ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x", + __func__, session->state.current, session->vsid); + break; + } + break; + + case CALL_INACTIVE: + switch(session->state.current) + { + case CALL_ACTIVE: + case CALL_HOLD: + case CALL_LOCAL_HOLD: + ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD ->INACTIVE vsid:%x", __func__, session->vsid); + ret = stop_call(adev, usecase_id); + if(ret < 0) { + ALOGE("%s: voice_end_call() failed for usecase: %d\n", + __func__, usecase_id); + } + session->state.current = session->state.new; + break; + + default: + ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x", + __func__, session->state.current, session->vsid); + break; + } + break; + + case CALL_HOLD: + switch(session->state.current) + { + case CALL_ACTIVE: + ALOGD("%s: CALL_ACTIVE ->HOLD vsid:%x", __func__, session->vsid); + session->state.current = session->state.new; + break; + + case CALL_LOCAL_HOLD: + ALOGD("%s: CALL_LOCAL_HOLD ->HOLD vsid:%x", __func__, session->vsid); + lch_mode = VOICE_LCH_STOP; + if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { + ALOGE("LOCAL_HOLD ->HOLD failed"); + } else { + session->state.current = session->state.new; + } + break; + + default: + ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x", + __func__, session->state.current, session->vsid); + break; + } + break; + + case CALL_LOCAL_HOLD: + switch(session->state.current) + { + case CALL_ACTIVE: + case CALL_HOLD: + ALOGD("%s: ACTIVE/CALL_HOLD ->LOCAL_HOLD vsid:%x", __func__, session->vsid); + lch_mode = VOICE_LCH_START; + if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { + ALOGE("LOCAL_HOLD ->HOLD failed"); + } else { + session->state.current = session->state.new; + } + break; + + default: + ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x", + __func__, session->state.current, session->vsid); + break; + } + break; + + default: + break; + } //end out switch loop + } //end for loop + + return ret; +} + +int voice_extn_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + char *str; + int value; + int ret = 0; + + ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + + ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID); + int vsid = value; + int call_state = -1; + ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value); + if (ret >= 0) { + call_state = value; + //validate callstate + } else { + ALOGE("%s: call_state key not found", __func__); + ret = -EINVAL; + goto done; + } + + if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) { + pthread_mutex_lock(&adev->lock); + voice_extn_update_call_states(adev, vsid, call_state); + pthread_mutex_unlock(&adev->lock); + } else { + ALOGE("%s: invalid vsid or call_state", __func__); + ret = -EINVAL; + goto done; + } + } else { + ALOGD("%s: Not handled here", __func__); + } + +done: + ALOGV("%s: exit with code(%d)", __func__, ret); + return ret; +} + +#endif diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h new file mode 100644 index 000000000..ae983e1c0 --- /dev/null +++ b/hal/voice_extn/voice_extn.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef VOICE_EXTN_H +#define VOICE_EXTN_H + +int voice_extn_update_calls(struct audio_device *adev); +int voice_extn_get_session_from_use_case(struct audio_device *adev, + const audio_usecase_t usecase_id, + struct voice_session **session); +int voice_extn_init(struct audio_device *adev); +int voice_extn_set_parameters(struct audio_device *adev, + struct str_parms *parms); +int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); + +#ifndef MULTI_VOICE_SESSION_ENABLED +int voice_extn_update_calls(struct audio_device *adev) +{ + return -ENOSYS; +} + +int voice_extn_get_session_from_use_case(struct audio_device *adev, + const audio_usecase_t usecase_id, + struct voice_session **session) +{ + return -ENOSYS; +} + +int voice_extn_init(struct audio_device *adev) +{ + return -ENOSYS; +} + +int voice_extn_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + return -ENOSYS; +} + +int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) +{ + return -ENOSYS; +} +#endif + +#endif //VOICE_EXTN_H -- GitLab From 5792d4b17cc32b23f2bc97789e6a91b00e6b3fe8 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Mon, 7 Oct 2013 18:40:05 -0700 Subject: [PATCH 050/298] hal: Support for usb audio features Added support for usb audio feature and related proxy device support Change-Id: Ia64e9eff20fbbada6f08795686cdbc0ba462bafb --- hal/Android.mk | 5 + hal/audio_extn/audio_extn.c | 10 +- hal/audio_extn/audio_extn.h | 20 ++ hal/audio_extn/usb.c | 673 ++++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 19 + hal/msm8974/platform.c | 48 ++- hal/msm8974/platform.h | 4 + 7 files changed, 769 insertions(+), 10 deletions(-) create mode 100644 hal/audio_extn/usb.c diff --git a/hal/Android.mk b/hal/Android.mk index 5f5c7aec6..b4527bf69 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -34,6 +34,11 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) LOCAL_SRC_FILES += audio_extn/fm.c endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_USBAUDIO)),true) + LOCAL_CFLAGS += -DUSB_HEADSET_ENABLED + LOCAL_SRC_FILES += audio_extn/usb.c +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index b10a5e909..1500471ff 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -62,7 +62,7 @@ bool audio_extn_get_anc_enabled(void) bool audio_extn_should_use_handset_anc(int in_channels) { - char prop_aanc[128] = "false"; + char prop_aanc[PROPERTY_VALUE_MAX] = "false"; property_get("persist.aanc.enable", prop_aanc, "0"); if (!strncmp("true", prop_aanc, 4)) { @@ -76,7 +76,7 @@ bool audio_extn_should_use_handset_anc(int in_channels) bool audio_extn_should_use_fb_anc(void) { - char prop_anc[128] = "feedforward"; + char prop_anc[PROPERTY_VALUE_MAX] = "feedforward"; property_get("persist.headset.anc.type", prop_anc, "0"); if (!strncmp("feedback", prop_anc, sizeof("feedback"))) { @@ -171,8 +171,10 @@ char* audio_extn_get_afe_proxy_parameters(struct str_parms *query, ret = str_parms_get_str(query, AUDIO_PARAMETER_CAN_OPEN_PROXY, value, sizeof(value)); if (ret >= 0) { - /* Todo: check if proxy is free by maintaining a state flag*/ - val = 1; + if (audio_extn_usb_is_proxy_inuse()) + val = 0; + else + val = 1; str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val); str = str_parms_to_str(reply); } diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index c537b774a..28c7883a1 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -44,4 +44,24 @@ bool audio_extn_should_use_handset_anc(int in_channels); int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev); #endif +#ifndef USB_HEADSET_ENABLED +#define audio_extn_usb_init(adev) (0) +#define audio_extn_usb_deinit() (0) +#define audio_extn_usb_start_playback(adev) (0) +#define audio_extn_usb_stop_playback() (0) +#define audio_extn_usb_start_capture(adev) (0) +#define audio_extn_usb_stop_capture() (0) +#define audio_extn_usb_set_proxy_sound_card(sndcard_idx) (0) +#define audio_extn_usb_is_proxy_inuse() (0) +#else +void audio_extn_usb_init(void *adev); +void audio_extn_usb_deinit(); +void audio_extn_usb_start_playback(void *adev); +void audio_extn_usb_stop_playback(); +void audio_extn_usb_start_capture(void *adev); +void audio_extn_usb_stop_capture(); +void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx); +bool audio_extn_usb_is_proxy_inuse(); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c new file mode 100644 index 000000000..5b045ea73 --- /dev/null +++ b/hal/audio_extn/usb.c @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_usb" +#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef USB_HEADSET_ENABLED +#define USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE 512 +#define USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT 8 +#define USB_DEFAULT_OUTPUT_SAMPLING_RATE 48000 + +#define USB_PROXY_DEFAULT_SAMPLING_RATE 48000 +#define USB_PROXY_OPEN_RETRY_COUNT 100 +#define USB_PROXY_OPEN_WAIT_TIME 20 +#define USB_PROXY_PERIOD_SIZE 3072 +#define USB_PROXY_RATE_8000 8000 +#define USB_PROXY_RATE_16000 16000 +#define USB_PROXY_RATE_48000 48000 +#define USB_PERIOD_SIZE 2048 +#define USB_BUFF_SIZE 2048 +#define AFE_PROXY_PERIOD_COUNT 32 +#define AFE_PROXY_PLAYBACK_DEVICE 8 +#define AFE_PROXY_CAPTURE_DEVICE 7 + +struct usb_module { + uint32_t usb_card; + uint32_t proxy_card; + uint32_t usb_device_id; + uint32_t proxy_device_id; + + int32_t channels_playback; + int32_t sample_rate_playback; + int32_t channels_record; + int32_t sample_rate_record; + + bool is_playback_running; + bool is_record_running; + + pthread_t usb_playback_thr; + pthread_t usb_record_thr; + pthread_mutex_t usb_playback_lock; + pthread_mutex_t usb_record_lock; + + struct pcm *proxy_pcm_playback_handle; + struct pcm *usb_pcm_playback_handle; + struct pcm *proxy_pcm_record_handle; + struct pcm *usb_pcm_record_handle; + struct audio_device *adev; +}; + +static struct usb_module *usbmod = NULL; +static pthread_once_t alloc_usbmod_once_ctl = PTHREAD_ONCE_INIT; + +struct pcm_config pcm_config_usbmod = { + .channels = 2, + .rate = USB_DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE, + .period_count = USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, +}; + +static void usb_alloc() +{ + usbmod = calloc(1, sizeof(struct usb_module)); +} + +static int usb_get_numof_rates(char *rates_str) +{ + int i, size = 0; + char *next_sr_string, *temp_ptr; + next_sr_string = strtok_r(rates_str, " ,", &temp_ptr); + + if (next_sr_string == NULL) { + ALOGE("%s: get_numof_rates: could not find rates string", __func__); + return (int)NULL; + } + + for (i = 1; next_sr_string != NULL; i++) { + size ++; + next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr); + } + return size; +} + +static int usb_get_capability(char *type, int32_t *channels, + int32_t *sample_rate) +{ + ALOGD("%s: for %s", __func__, type); + long unsigned file_size; + FILE *fp; + char *buffer; + int32_t err = 1; + int32_t size = 0; + int32_t fd, i, channels_playback; + char *read_buf, *str_start, *channel_start, *rates_str, *rates_str_for_val, + *rates_str_start, *next_sr_str, *test, *next_sr_string, *temp_ptr; + struct stat st; + int rates_supported[size]; + char path[128]; + + memset(&st, 0x0, sizeof(struct stat)); + *sample_rate = 0; + snprintf(path, sizeof(path), "/proc/asound/card%u/stream0", + usbmod->usb_card); + + fd = open(path, O_RDONLY); + if (fd <0) { + ALOGE("%s: error failed to open config file %s error: %d\n", + __func__, path, errno); + close(fd); + return -EINVAL; + } + + if (fstat(fd, &st) < 0) { + ALOGE("%s: error failed to stat %s error %d\n", + __func__, path, errno); + close(fd); + return -EINVAL; + } + + file_size = st.st_size; + + read_buf = (char *)calloc(1, USB_BUFF_SIZE); + err = read(fd, read_buf, USB_BUFF_SIZE); + str_start = strstr(read_buf, type); + if (str_start == NULL) { + ALOGE("%s: error %s section not found in usb config file", + __func__, type); + close(fd); + free(read_buf); + return -EINVAL; + } + + channel_start = strstr(str_start, "Channels:"); + if (channel_start == NULL) { + ALOGE("%s: error could not find Channels information", __func__); + close(fd); + free(read_buf); + return -EINVAL; + } + + channel_start = strstr(channel_start, " "); + if (channel_start == NULL) { + ALOGE("%s: error channel section not found in usb config file", + __func__); + close(fd); + free(read_buf); + return -EINVAL; + } + + channels_playback = atoi(channel_start); + if (channels_playback == 1) { + *channels = 1; + } else { + *channels = 2; + } + + ALOGD("%s: channels supported by device: %d", __func__, *channels); + rates_str_start = strstr(str_start, "Rates:"); + if (rates_str_start == NULL) { + ALOGE("%s: error cant find rates information", __func__); + close(fd); + free(read_buf); + return -EINVAL; + } + + rates_str_start = strstr(rates_str_start, " "); + if (rates_str_start == NULL) { + ALOGE("%s: error channel section not found in usb config file", + __func__); + close(fd); + free(read_buf); + return -EINVAL; + } + + char *target = strchr(rates_str_start, '\n'); + if (target == NULL) { + ALOGE("%s: error end of line not found", __func__); + close(fd); + free(read_buf); + return -EINVAL; + } + + size = target - rates_str_start; + if ((rates_str = (char *)malloc(size + 1)) == NULL) { + ALOGE("%s: error unable to allocate memory to hold sample rate strings", + __func__); + close(fd); + free(read_buf); + return -ENOMEM; + } + + if ((rates_str_for_val = (char *)malloc(size + 1)) == NULL) { + ALOGE("%s: error unable to allocate memory to hold sample rate string", + __func__); + close(fd); + free(rates_str); + free(read_buf); + return -ENOMEM; + } + + memcpy(rates_str, rates_str_start, size); + memcpy(rates_str_for_val, rates_str_start, size); + rates_str[size] = '\0'; + rates_str_for_val[size] = '\0'; + + size = usb_get_numof_rates(rates_str); + if (!size) { + ALOGE("%s: error could not get rate size, returning", __func__); + close(fd); + free(rates_str_for_val); + free(rates_str); + free(read_buf); + return -EINVAL; + } + + next_sr_string = strtok_r(rates_str_for_val, " ,", &temp_ptr); + if (next_sr_string == NULL) { + ALOGE("%s: error could not get first rate val", __func__); + close(fd); + free(rates_str_for_val); + free(rates_str); + free(read_buf); + return -EINVAL; + } + + rates_supported[0] = atoi(next_sr_string); + ALOGD("%s: rates_supported[0] for playback: %d", + __func__, rates_supported[0]); + for (i = 1; i *sample_rate) && + (rates_supported[i] <= 48000)) { + /* Sample Rate should be one of the proxy supported rates only + This is because proxy port is used to read from/write to DSP */ + if ((rates_supported[i] == USB_PROXY_RATE_8000) || + (rates_supported[i] == USB_PROXY_RATE_16000) || + (rates_supported[i] == USB_PROXY_RATE_48000)) { + *sample_rate = rates_supported[i]; + } + } + } + ALOGD("%s: sample_rate: %d", __func__, *sample_rate); + + close(fd); + free(rates_str_for_val); + free(rates_str); + free(read_buf); + return 0; +} + +static int32_t usb_playback_entry(void *adev) +{ + unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0}; + int32_t ret, bytes, proxy_open_retry_count; + + ALOGD("%s: entry", __func__); + /* update audio device pointer */ + usbmod->adev = (struct audio_device*)adev; + proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT; + + /* get capabilities */ + pthread_mutex_lock(&usbmod->usb_playback_lock); + ret = usb_get_capability((char *)"Playback:", + &usbmod->channels_playback, &usbmod->sample_rate_playback); + if (ret) { + ALOGE("%s: could not get playback capabilities from usb device", + __func__); + pthread_mutex_unlock(&usbmod->usb_playback_lock); + return -EINVAL; + } + /* update config for usb + 1 pcm frame(sample)= 4 bytes since two channels*/ + pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4; + pcm_config_usbmod.channels = usbmod->channels_playback; + pcm_config_usbmod.rate = usbmod->sample_rate_playback; + ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__, + pcm_config_usbmod.period_size, pcm_config_usbmod.channels, + pcm_config_usbmod.rate); + + usbmod->usb_pcm_playback_handle = pcm_open(usbmod->usb_card, \ + usbmod->usb_device_id, PCM_OUT | + PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod); + + if ((usbmod->usb_pcm_playback_handle \ + && !pcm_is_ready(usbmod->usb_pcm_playback_handle)) + || (!usbmod->is_playback_running)) { + ALOGE("%s: failed: %s", __func__, + pcm_get_error(usbmod->usb_pcm_playback_handle)); + pcm_close(usbmod->usb_pcm_playback_handle); + usbmod->usb_pcm_playback_handle = NULL; + pthread_mutex_unlock(&usbmod->usb_playback_lock); + return -ENOMEM; + } + ALOGD("%s: USB configured for playback", __func__); + + /* update config for proxy*/ + pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/3; + pcm_config_usbmod.rate = usbmod->sample_rate_playback; + pcm_config_usbmod.channels = usbmod->channels_playback; + pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT; + usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE; + ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__, + pcm_config_usbmod.period_size, pcm_config_usbmod.channels, + pcm_config_usbmod.rate); + + while(proxy_open_retry_count){ + usbmod->proxy_pcm_playback_handle = pcm_open(usbmod->proxy_card, + usbmod->proxy_device_id, PCM_IN | + PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod); + if(!usbmod->proxy_pcm_playback_handle){ + proxy_open_retry_count--; + usleep(USB_PROXY_OPEN_WAIT_TIME * 1000); + ALOGE("%s: pcm_open for proxy failed retrying = %d", + __func__, proxy_open_retry_count); + } + else{ + break; + } + } + + if ((usbmod->proxy_pcm_playback_handle + && !pcm_is_ready(usbmod->proxy_pcm_playback_handle)) + || (!usbmod->is_playback_running)) { + ALOGE("%s: failed: %s", __func__, + pcm_get_error(usbmod->proxy_pcm_playback_handle)); + pcm_close(usbmod->proxy_pcm_playback_handle); + usbmod->proxy_pcm_playback_handle = NULL; + pthread_mutex_unlock(&usbmod->usb_playback_lock); + return -ENOMEM; + } + ALOGD("%s: PROXY configured for playback", __func__); + pthread_mutex_unlock(&usbmod->usb_playback_lock); + + /* main loop to read from proxy and write to usb */ + while (usbmod->is_playback_running) { + /* read data from proxy */ + ret = pcm_mmap_read(usbmod->proxy_pcm_playback_handle, + (void *)usbbuf, USB_PROXY_PERIOD_SIZE); + /* Write to usb */ + ret = pcm_mmap_write(usbmod->usb_pcm_playback_handle, + (void *)usbbuf, USB_PROXY_PERIOD_SIZE); + if(!usbmod->is_playback_running) + break; + + memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE); + } /* main loop end */ + + ALOGD("%s: exiting USB playback thread",__func__); + return 0; +} + +static void* usb_playback_launcher(void *adev) +{ + int32_t ret; + + usbmod->is_playback_running = true; + ret = usb_playback_entry(adev); + + if (ret) { + ALOGE("%s: failed with err:%d", __func__, ret); + usbmod->is_playback_running = false; + } + return NULL; +} + +static int32_t usb_record_entry(void *adev) +{ + unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0}; + int32_t ret, bytes, proxy_open_retry_count; + ALOGD("%s: entry", __func__); + + /* update audio device pointer */ + usbmod->adev = (struct audio_device*)adev; + proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT; + + /* get capabilities */ + pthread_mutex_lock(&usbmod->usb_record_lock); + ret = usb_get_capability((char *)"Capture:", + &usbmod->channels_record, &usbmod->sample_rate_record); + if (ret) { + ALOGE("%s: could not get capture capabilities from usb device", + __func__); + pthread_mutex_unlock(&usbmod->usb_record_lock); + return -EINVAL; + } + /* update config for usb + 1 pcm frame(sample)= 4 bytes since two channels*/ + pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4; + pcm_config_usbmod.channels = usbmod->channels_record; + pcm_config_usbmod.rate = usbmod->sample_rate_record; + ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__, + pcm_config_usbmod.period_size, pcm_config_usbmod.channels, + pcm_config_usbmod.rate); + + usbmod->usb_pcm_record_handle = pcm_open(usbmod->usb_card, \ + usbmod->usb_device_id, PCM_IN | + PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod); + + if ((usbmod->usb_pcm_record_handle \ + && !pcm_is_ready(usbmod->usb_pcm_record_handle)) + || (!usbmod->is_record_running)) { + ALOGE("%s: failed: %s", __func__, + pcm_get_error(usbmod->usb_pcm_record_handle)); + pcm_close(usbmod->usb_pcm_record_handle); + usbmod->usb_pcm_record_handle = NULL; + pthread_mutex_unlock(&usbmod->usb_record_lock); + return -ENOMEM; + } + ALOGD("%s: USB configured for capture", __func__); + + /* update config for proxy*/ + pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/4; + pcm_config_usbmod.rate = usbmod->sample_rate_record; + pcm_config_usbmod.channels = usbmod->channels_record; + pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT * 2; + usbmod->proxy_device_id = AFE_PROXY_CAPTURE_DEVICE; + ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__, + pcm_config_usbmod.period_size, pcm_config_usbmod.channels, + pcm_config_usbmod.rate); + + while(proxy_open_retry_count){ + usbmod->proxy_pcm_record_handle = pcm_open(usbmod->proxy_card, + usbmod->proxy_device_id, PCM_OUT | + PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod); + if(!usbmod->proxy_pcm_record_handle){ + proxy_open_retry_count--; + usleep(USB_PROXY_OPEN_WAIT_TIME * 1000); + ALOGE("%s: pcm_open for proxy(recording) failed retrying = %d", + __func__, proxy_open_retry_count); + } + else{ + break; + } + } + if ((usbmod->proxy_pcm_record_handle + && !pcm_is_ready(usbmod->proxy_pcm_record_handle)) + || (!usbmod->is_record_running)) { + ALOGE("%s: failed: %s", __func__, + pcm_get_error(usbmod->proxy_pcm_record_handle)); + pcm_close(usbmod->proxy_pcm_record_handle); + usbmod->proxy_pcm_record_handle = NULL; + pthread_mutex_unlock(&usbmod->usb_record_lock); + return -ENOMEM; + } + ALOGD("%s: PROXY configured for capture", __func__); + pthread_mutex_unlock(&usbmod->usb_record_lock); + + /* main loop to read from usb and write to proxy */ + while (usbmod->is_record_running) { + /* read data from usb */ + ret = pcm_mmap_read(usbmod->usb_pcm_record_handle, + (void *)usbbuf, USB_PROXY_PERIOD_SIZE); + /* Write to proxy */ + ret = pcm_mmap_write(usbmod->proxy_pcm_record_handle, + (void *)usbbuf, USB_PROXY_PERIOD_SIZE); + if(!usbmod->is_record_running) + break; + + memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE); + } /* main loop end */ + + ALOGD("%s: exiting USB capture thread",__func__); + return 0; +} + +static void* usb_capture_launcher(void *adev) +{ + int32_t ret; + + usbmod->is_record_running = true; + ret = usb_record_entry(adev); + + if (ret) { + ALOGE("%s: failed with err:%d", __func__, ret); + usbmod->is_record_running = false; + } + return NULL; +} + +void audio_extn_usb_init(void *adev) +{ + pthread_once(&alloc_usbmod_once_ctl, usb_alloc); + + usbmod->is_playback_running = false; + usbmod->is_record_running = false; + + usbmod->usb_pcm_playback_handle = NULL; + usbmod->proxy_pcm_playback_handle = NULL; + + usbmod->usb_pcm_record_handle = NULL; + usbmod->proxy_pcm_record_handle = NULL; + + usbmod->usb_card = 1; + usbmod->usb_device_id = 0; + usbmod->proxy_card = 0; + usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE; + usbmod->adev = (struct audio_device*)adev; +} + +void audio_extn_usb_deinit() +{ + if (NULL != usbmod){ + free(usbmod); + usbmod = NULL; + } +} + +void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx) +{ + /* Proxy port and USB headset are related to two different sound cards */ + if (sndcard_idx == usbmod->usb_card) { + usbmod->usb_card = usbmod->proxy_card; + } + + usbmod->proxy_card = sndcard_idx; +} + +void audio_extn_usb_start_playback(void *adev) +{ + int32_t ret; + + if (NULL == usbmod){ + ALOGE("%s: USB device object is NULL", __func__); + return; + } + + if (usbmod->is_playback_running){ + ALOGE("%s: USB playback thread already running", __func__); + return; + } + + ALOGD("%s: creating USB playback thread", __func__); + ret = pthread_create(&usbmod->usb_playback_thr, NULL, + usb_playback_launcher, (void*)adev); + if (ret) + ALOGE("%s: failed to create USB playback thread with err:%d", + __func__, ret); +} + +void audio_extn_usb_stop_playback() +{ + int32_t ret; + ALOGD("%s: entry", __func__); + + usbmod->is_playback_running = false; + if (NULL != usbmod->proxy_pcm_playback_handle) + pcm_stop(usbmod->proxy_pcm_playback_handle); + + if (NULL != usbmod->usb_pcm_playback_handle) + pcm_stop(usbmod->usb_pcm_playback_handle); + + if(usbmod->usb_playback_thr) { + ret = pthread_join(usbmod->usb_playback_thr,NULL); + ALOGE("%s: return for pthread_join = %d", __func__, ret); + usbmod->usb_playback_thr = (pthread_t)NULL; + } + + pthread_mutex_lock(&usbmod->usb_playback_lock); + if (NULL != usbmod->usb_pcm_playback_handle){ + pcm_close(usbmod->usb_pcm_playback_handle); + usbmod->usb_pcm_playback_handle = NULL; + } + + if (NULL != usbmod->proxy_pcm_playback_handle){ + pcm_close(usbmod->proxy_pcm_playback_handle); + usbmod->proxy_pcm_playback_handle = NULL; + } + pthread_mutex_unlock(&usbmod->usb_playback_lock); + + ALOGD("%s: exiting",__func__); +} + +void audio_extn_usb_start_capture(void *adev) +{ + int32_t ret; + + if (NULL == usbmod){ + ALOGE("%s: USB device object is NULL", __func__); + return; + } + + if (usbmod->is_record_running){ + ALOGE("%s: USB capture thread already running", __func__); + return; + } + + ALOGD("%s: creating USB capture thread", __func__); + ret = pthread_create(&usbmod->usb_record_thr, NULL, + usb_capture_launcher, (void*)adev); + if (ret) + ALOGE("%s: failed to create USB capture thread with err:%d", + __func__, ret); +} + +void audio_extn_usb_stop_capture() +{ + int32_t ret; + ALOGD("%s: entry", __func__); + + usbmod->is_record_running = false; + if (NULL != usbmod->proxy_pcm_record_handle) + pcm_stop(usbmod->proxy_pcm_record_handle); + + if (NULL != usbmod->usb_pcm_record_handle) + pcm_stop(usbmod->usb_pcm_record_handle); + + if(usbmod->usb_record_thr) { + ret = pthread_join(usbmod->usb_record_thr,NULL); + ALOGE("%s: return for pthread_join = %d", __func__, ret); + usbmod->usb_record_thr = (pthread_t)NULL; + } + + pthread_mutex_lock(&usbmod->usb_record_lock); + if (NULL != usbmod->usb_pcm_record_handle){ + pcm_close(usbmod->usb_pcm_record_handle); + usbmod->usb_pcm_record_handle = NULL; + } + + if (NULL != usbmod->proxy_pcm_record_handle){ + pcm_close(usbmod->proxy_pcm_record_handle); + usbmod->proxy_pcm_record_handle = NULL; + } + pthread_mutex_unlock(&usbmod->usb_record_lock); + + ALOGD("%s: exiting",__func__); +} + +bool audio_extn_usb_is_proxy_inuse() +{ + if( usbmod->is_record_running || usbmod->is_playback_running) + return true; + else + return false; +} +#endif /*USB_HEADSET_ENABLED end*/ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index e80f88f6d..7a65925bc 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -186,6 +186,15 @@ static int enable_snd_device(struct audio_device *adev, return 0; } + /* start usb playback thread */ + if(SND_DEVICE_OUT_USB_HEADSET == snd_device || + SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device) + audio_extn_usb_start_playback(adev); + + /* start usb capture thread */ + if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) + audio_extn_usb_start_capture(adev); + if (platform_send_audio_calibration(adev->platform, snd_device) < 0) { adev->snd_dev_ref_cnt[snd_device]--; return -EINVAL; @@ -214,6 +223,16 @@ int disable_snd_device(struct audio_device *adev, return -EINVAL; } adev->snd_dev_ref_cnt[snd_device]--; + + /* exit usb play back thread */ + if(SND_DEVICE_OUT_USB_HEADSET == snd_device || + SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device) + audio_extn_usb_stop_playback(); + + /* exit usb capture thread */ + if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) + audio_extn_usb_stop_capture(adev); + if (adev->snd_dev_ref_cnt[snd_device] == 0) { ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, platform_get_snd_device_name(snd_device)); diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 02940b4c2..310a04868 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -115,6 +115,9 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy", + [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones", + [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones", [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm", [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones", [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones", @@ -144,6 +147,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef", [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", + [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic", [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm", [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic", }; @@ -166,6 +170,9 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + [SND_DEVICE_OUT_AFE_PROXY] = 0, + [SND_DEVICE_OUT_USB_HEADSET] = 0, + [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14, [SND_DEVICE_OUT_TRANSMISSION_FM] = 0, [SND_DEVICE_OUT_ANC_HEADSET] = 26, [SND_DEVICE_OUT_ANC_FB_HEADSET] = 26, @@ -192,6 +199,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_REC_MIC] = 62, + [SND_DEVICE_IN_USB_HEADSET_MIC] = 44, [SND_DEVICE_IN_CAPTURE_FM] = 0, [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, /* TODO: Update with proper acdb ids */ @@ -263,7 +271,7 @@ void *platform_init(struct audio_device *adev) { char value[PROPERTY_VALUE_MAX]; struct platform_data *my_data; - int retry_num = 0; + int retry_num = 0, ret; adev->mixer = mixer_open(MIXER_CARD); @@ -340,12 +348,17 @@ void *platform_init(struct audio_device *adev) my_data->acdb_init(); } + /* init usb */ + audio_extn_usb_init(adev); + return my_data; } void platform_deinit(void *platform) { free(platform); + /* deinit usb */ + audio_extn_usb_deinit(); } const char *platform_get_snd_device_name(snd_device_t snd_device) @@ -366,6 +379,15 @@ void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) strcat(mixer_path, " hdmi"); else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) strcat(mixer_path, " speaker-and-hdmi"); + else if (snd_device == SND_DEVICE_OUT_AFE_PROXY) + strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_USB_HEADSET) + strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET) + strlcat(mixer_path, " speaker-and-usb-headphones", + MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC) + strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_IN_CAPTURE_FM) strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM) @@ -528,11 +550,6 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi goto exit; } - if(devices & AUDIO_DEVICE_OUT_PROXY) { - ALOGD("%s: setting sink capability for Proxy", __func__); - audio_extn_set_afe_proxy_channel_mixer(adev); - } - if (mode == AUDIO_MODE_IN_CALL) { if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { @@ -554,6 +571,9 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || + devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_OUT_USB_HEADSET; } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { @@ -582,6 +602,9 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_DEVICE_OUT_SPEAKER)) { snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; + } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET; } else { ALOGE("%s: Invalid combo device(%#x)", __func__, devices); goto exit; @@ -616,10 +639,17 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_BT_SCO; } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { snd_device = SND_DEVICE_OUT_HDMI ; + } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || + devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_OUT_USB_HEADSET; } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { snd_device = SND_DEVICE_OUT_HANDSET; + } else if (devices & AUDIO_DEVICE_OUT_PROXY) { + ALOGD("%s: setting sink capability for Proxy", __func__); + audio_extn_set_afe_proxy_channel_mixer(adev); + snd_device = SND_DEVICE_OUT_AFE_PROXY; } else { ALOGE("%s: Unknown device(s) %#x", __func__, devices); } @@ -763,6 +793,9 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_BT_SCO_MIC ; } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { snd_device = SND_DEVICE_IN_HDMI_MIC; + } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET || + in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_IN_USB_HEADSET_MIC; } else if (in_device & AUDIO_DEVICE_IN_FM_RX) { snd_device = SND_DEVICE_IN_CAPTURE_FM; } else { @@ -783,6 +816,9 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_BT_SCO_MIC; } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { snd_device = SND_DEVICE_IN_HDMI_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || + out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_IN_USB_HEADSET_MIC; } else { ALOGE("%s: Unknown output device(s) %#x", __func__, out_device); ALOGW("%s: Using default handset-mic", __func__); diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 1bc4fc42f..65d815048 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -60,6 +60,9 @@ enum { SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_AFE_PROXY, + SND_DEVICE_OUT_USB_HEADSET, + SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET, SND_DEVICE_OUT_TRANSMISSION_FM, SND_DEVICE_OUT_ANC_HEADSET, SND_DEVICE_OUT_ANC_FB_HEADSET, @@ -96,6 +99,7 @@ enum { SND_DEVICE_IN_VOICE_REC_MIC, SND_DEVICE_IN_VOICE_REC_DMIC, SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_USB_HEADSET_MIC, SND_DEVICE_IN_CAPTURE_FM, SND_DEVICE_IN_AANC_HANDSET_MIC, SND_DEVICE_IN_END, -- GitLab From da107648031548e599e59b8654c9cb2d4dbaf6f7 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Thu, 17 Oct 2013 11:16:13 -0700 Subject: [PATCH 051/298] audio_hal: add incall recording feature The uplink, downlink and the combination of both can be recorded using sound recorder app. Add support for incall recording feature in audio HAL. Change-Id: Ia828ab5b3af8044d82b6ef8eb989ae0ba9bbba16 --- hal/audio_hw.c | 11 ++++++++ hal/audio_hw.h | 4 +++ hal/msm8960/platform.c | 6 +++++ hal/msm8974/platform.c | 38 +++++++++++++++++++++++++- hal/msm8974/platform.h | 1 + hal/platform_api.h | 2 +- hal/voice.c | 54 ++++++++++++++++++++++++++++++++++--- hal/voice.h | 3 +++ hal/voice_extn/voice_extn.c | 18 +++++++++++++ hal/voice_extn/voice_extn.h | 7 +++++ 10 files changed, 139 insertions(+), 5 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 3155ab652..0411b34c5 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -90,6 +90,9 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_VOICE2_CALL] = "voice2-call", [USECASE_VOLTE_CALL] = "volte-call", [USECASE_QCHAT_CALL] = "qchat-call", + [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", + [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", }; @@ -619,6 +622,14 @@ int start_input_stream(struct stream_in *in) struct audio_device *adev = in->dev; ALOGV("%s: enter: usecase(%d)", __func__, in->usecase); + + /* Check if source matches incall recording usecase criteria */ + ret = voice_check_and_set_incall_rec_usecase(adev, in); + if (ret) + goto error_config; + else + ALOGV("%s: usecase(%d)", __func__, in->usecase); + in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); if (in->pcm_device_id < 0) { ALOGE("%s: Could not find PCM device id for the usecase(%d)", diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 2eb161620..9b397b44b 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -68,6 +68,10 @@ typedef enum { USECASE_VOLTE_CALL, USECASE_QCHAT_CALL, + USECASE_INCALL_REC_UPLINK, + USECASE_INCALL_REC_DOWNLINK, + USECASE_INCALL_REC_UPLINK_AND_DOWNLINK, + AUDIO_USECASE_MAX } audio_usecase_t; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index a2eefdd07..78d06c538 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -883,3 +883,9 @@ int platform_set_parameters(void *platform, struct str_parms *parms) LOGE("%s: Not implemented", __func__); return -ENOSYS; } + +int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id) +{ + LOGE("%s: Not implemented", __func__); + return -ENOSYS; +} diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index ee069d77d..44d9b42fe 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -99,7 +99,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { LOWLATENCY_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTI_CHANNEL_PCM_DEVICE, MULTI_CHANNEL_PCM_DEVICE}, - [USECASE_AUDIO_RECORD] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE}, + [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, @@ -107,6 +107,12 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE}, + [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE}, }; /* Array to store sound devices */ @@ -947,6 +953,36 @@ int platform_set_parameters(void *platform, struct str_parms *parms) return ret; } +int platform_set_incall_recoding_session_id(void *platform, + uint32_t session_id) +{ + int ret = 0; + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voc VSID"; + int num_ctl_values; + int i; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + ret = -EINVAL; + } else { + num_ctl_values = mixer_ctl_get_num_values(ctl); + for (i = 0; i < num_ctl_values; i++) { + if (mixer_ctl_set_value(ctl, i, session_id)) { + ALOGV("Error: invalid session_id: %x", session_id); + ret = -EINVAL; + break; + } + } + } + + return ret; +} + void platform_get_parameters(void *platform, struct str_parms *query, struct str_parms *reply) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index dd8dfda9f..9d0ff2462 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -138,6 +138,7 @@ enum { #define AUDIO_CAPTURE_PERIOD_COUNT 2 #define DEEP_BUFFER_PCM_DEVICE 0 +#define AUDIO_RECORD_PCM_DEVICE 0 #define MULTI_CHANNEL_PCM_DEVICE 1 #define VOICE_CALL_PCM_DEVICE 2 #define FM_PLAYBACK_PCM_DEVICE 5 diff --git a/hal/platform_api.h b/hal/platform_api.h index b1d0420e0..39c94e82d 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -41,6 +41,6 @@ int platform_edid_get_max_channels(void *platform); void platform_get_parameters(void *platform, struct str_parms *query, struct str_parms *reply); int platform_set_parameters(void *platform, struct str_parms *parms); - +int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id); #endif // QCOM_AUDIO_PLATFORM_API_H diff --git a/hal/voice.c b/hal/voice.c index 2b1ac87cb..7b40d1a2a 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -119,7 +119,7 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) struct audio_usecase *uc_info; int pcm_dev_rx_id, pcm_dev_tx_id; struct voice_session *session = NULL; - + struct pcm_config voice_config = pcm_config_voice_call; ALOGD("%s: enter", __func__); session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); @@ -150,7 +150,7 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) __func__, SOUND_CARD, pcm_dev_rx_id); session->pcm_rx = pcm_open(SOUND_CARD, pcm_dev_rx_id, - PCM_OUT, &pcm_config_voice_call); + PCM_OUT, &voice_config); if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) { ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx)); ret = -EIO; @@ -161,7 +161,7 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) __func__, SOUND_CARD, pcm_dev_tx_id); session->pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id, - PCM_IN, &pcm_config_voice_call); + PCM_IN, &voice_config); if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) { ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx)); ret = -EIO; @@ -199,6 +199,54 @@ bool voice_is_in_call(struct audio_device *adev) return in_call; } +uint32_t voice_get_active_session_id(struct audio_device *adev) +{ + int ret = 0; + uint32_t session_id; + + ret = voice_extn_get_active_session_id(adev, &session_id); + if (ret == -ENOSYS) { + session_id = VOICE_VSID; + } + return session_id; +} + +int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, + struct stream_in *in) +{ + int ret = 0; + uint32_t session_id; + int usecase_id; + + if (voice_is_in_call(adev)) { + switch (in->source) { + case AUDIO_SOURCE_VOICE_UPLINK: + in->usecase = USECASE_INCALL_REC_UPLINK; + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + in->usecase = USECASE_INCALL_REC_DOWNLINK; + break; + case AUDIO_SOURCE_VOICE_CALL: + in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK; + break; + default: + ALOGV("%s: Source type %d doesnt match incall recording criteria", + __func__, in->source); + return ret; + } + + in->config = pcm_config_voice_call; + session_id = voice_get_active_session_id(adev); + ret = platform_set_incall_recoding_session_id(adev->platform, + session_id); + ALOGV("%s: Update usecase to %d",__func__, in->usecase); + } else { + ALOGV("%s: voice call not active", __func__); + } + + return ret; +} + int voice_set_mic_mute(struct audio_device *adev, bool state) { int err = 0; diff --git a/hal/voice.h b/hal/voice.h index 22c359d55..d5e5a8d16 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -37,6 +37,7 @@ struct audio_device; struct str_parms; +struct stream_in; struct call_state { int current; @@ -65,4 +66,6 @@ bool voice_is_in_call(struct audio_device *adev); int voice_set_mic_mute(struct audio_device *dev, bool state); bool voice_get_mic_mute(struct audio_device *dev); int voice_set_volume(struct audio_device *adev, float volume); +int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, + struct stream_in *in); #endif //VOICE_H diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index ac3d9f2bb..29f12d41d 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -103,6 +103,24 @@ static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index) return usecase_id; } +int voice_extn_get_active_session_id(struct audio_device *adev, + uint32_t *session_id) +{ + struct voice_session *session = NULL; + int i = 0; + *session_id = 0; + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + session = &adev->voice.session[i]; + if(session->state.current == CALL_ACTIVE){ + *session_id = session->vsid; + break; + } + } + + return 0; +} + int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) { struct voice_session *session = NULL; diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index ae983e1c0..568f71680 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -28,6 +28,8 @@ int voice_extn_init(struct audio_device *adev); int voice_extn_set_parameters(struct audio_device *adev, struct str_parms *parms); int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); +int voice_extn_get_active_session_id(struct audio_device *adev, + uint32_t *session_id); #ifndef MULTI_VOICE_SESSION_ENABLED int voice_extn_update_calls(struct audio_device *adev) @@ -57,6 +59,11 @@ int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) { return -ENOSYS; } +int voice_extn_get_active_session_id(struct audio_device *adev, + uint32_t *session_id) +{ + return -ENOSYS; +} #endif #endif //VOICE_EXTN_H -- GitLab From 6178a3f6183329587ecaf6501d254379eb9845b2 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Sat, 19 Oct 2013 12:38:54 -0700 Subject: [PATCH 052/298] hal: Add support for ssr audio feature Update audio HAL to support surround sound recording (5.1 channels) Change-Id: I5b24340251b55ad5c602f2de0a0b4c7672ba729b --- hal/Android.mk | 7 +- hal/audio_extn/audio_extn.c | 12 +- hal/audio_extn/audio_extn.h | 16 + hal/audio_extn/ssr.c | 619 ++++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 28 +- hal/msm8974/platform.c | 10 +- hal/msm8974/platform.h | 1 + 7 files changed, 682 insertions(+), 11 deletions(-) create mode 100644 hal/audio_extn/ssr.c diff --git a/hal/Android.mk b/hal/Android.mk index cfd41dec6..7d681ce73 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -53,6 +53,12 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_USBAUDIO)),true) LOCAL_SRC_FILES += audio_extn/usb.c endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_SSR)),true) + LOCAL_CFLAGS += -DSSR_ENABLED + LOCAL_SRC_FILES += audio_extn/ssr.c + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/surround_sound/ +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ @@ -60,7 +66,6 @@ LOCAL_SHARED_LIBRARIES := \ libaudioroute \ libdl - LOCAL_C_INCLUDES += \ external/tinyalsa/include \ $(call include-path-for, audio-route) \ diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 6f094c0d0..2389f00be 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -51,6 +51,14 @@ void audio_extn_fm_set_parameters(struct audio_device *adev, struct str_parms *parms); #endif +#ifndef SSR_ENABLED +#define audio_extn_ssr_get_parameters(query, reply) (0) +#else +void audio_extn_ssr_get_parameters(struct str_parms *query, + + struct str_parms *reply); +#endif + #ifndef ANC_HEADSET_ENABLED #define audio_extn_set_anc_parameters(parms) (0) #else @@ -195,5 +203,7 @@ void audio_extn_get_parameters(const struct audio_device *adev, struct str_parms *reply) { audio_extn_get_afe_proxy_parameters(query, reply); - ALOGD("%s: exit: returns %s", __func__, str_parms_to_str(reply)); + audio_extn_ssr_get_parameters(query, reply); + + ALOGD("%s: returns %s", __func__, str_parms_to_str(reply)); } diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 858faaf2c..ee03f5a7d 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -65,4 +65,20 @@ void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx); bool audio_extn_usb_is_proxy_inuse(); #endif +#ifndef SSR_ENABLED +#define audio_extn_ssr_init(adev, in) (0) +#define audio_extn_ssr_deinit() (0) +#define audio_extn_ssr_update_enabled(adev) (0) +#define audio_extn_ssr_get_enabled() (0) +#define audio_extn_ssr_read(stream, buffer, bytes) (0) +#else +int32_t audio_extn_ssr_init(struct audio_device *adev, + struct stream_in *in); +int32_t audio_extn_ssr_deinit(); +int32_t audio_extn_ssr_update_enabled(struct audio_device *adev); +bool audio_extn_ssr_get_enabled(); +int32_t audio_extn_ssr_read(struct audio_stream_in *stream, + void *buffer, size_t bytes); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c new file mode 100644 index 000000000..efd92ea38 --- /dev/null +++ b/hal/audio_extn/ssr.c @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_ssr" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include + +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" +#include "surround_filters_interface.h" + +#ifdef SSR_ENABLED +#define COEFF_ARRAY_SIZE 4 +#define FILT_SIZE ((512+1)* 6) /* # ((FFT bins)/2+1)*numOutputs */ +#define SSR_FRAME_SIZE 512 +#define SSR_INPUT_FRAME_SIZE (SSR_FRAME_SIZE * 4) +#define SSR_OUTPUT_FRAME_SIZE (SSR_FRAME_SIZE * 6) +#define SSR_CHANNEL_COUNT 4 +#define SSR_PERIOD_SIZE 256 +#define SSR_PERIOD_COUNT 8 + +#define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm" +#define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm" +#define SURROUND_FILE_3R "/system/etc/surround_sound/filter3r.pcm" +#define SURROUND_FILE_4R "/system/etc/surround_sound/filter4r.pcm" + +#define SURROUND_FILE_1I "/system/etc/surround_sound/filter1i.pcm" +#define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm" +#define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm" +#define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm" +#define AUDIO_PARAMETER_KEY_SSR "ssr" +#define LIB_SURROUND_PROC "libsurround_proc.so" + +typedef int (*surround_filters_init_t)(void *, int, int, Word16 **, + Word16 **, int, int, int, Profiler *); +typedef void (*surround_filters_release_t)(void *); +typedef int (*surround_filters_set_channel_map_t)(void *, const int *); +typedef void (*surround_filters_intl_process_t)(void *, Word16 *, Word16 *); + +struct ssr_module { + FILE *fp_4ch; + FILE *fp_6ch; + int16_t **real_coeffs; + int16_t **imag_coeffs; + void *surround_obj; + + int16_t *surround_input_buffer; + int16_t *surround_output_buffer; + int surround_input_bufferIdx; + int surround_output_bufferIdx; + bool is_ssr_enabled; + + void *surround_filters_handle; + surround_filters_init_t surround_filters_init; + surround_filters_release_t surround_filters_release; + surround_filters_set_channel_map_t surround_filters_set_channel_map; + surround_filters_intl_process_t surround_filters_intl_process; +}; + +static int32_t ssr_init_surround_sound_lib(unsigned long buffersize); +static int32_t ssr_read_coeffs_from_file(); + +static struct ssr_module ssrmod = { + .fp_4ch = NULL, + .fp_6ch= NULL, + .real_coeffs = NULL, + .imag_coeffs = NULL, + .surround_obj = NULL, + .surround_output_buffer = NULL, + .surround_input_buffer = NULL, + .surround_output_bufferIdx = 0, + .surround_input_bufferIdx= 0, + .is_ssr_enabled = 0, + + .surround_filters_handle = NULL, + .surround_filters_init = NULL, + .surround_filters_release = NULL, + .surround_filters_set_channel_map = NULL, + .surround_filters_intl_process = NULL, +}; + +/* Use AAC/DTS channel mapping as default channel mapping: C,FL,FR,Ls,Rs,LFE */ +static const int chan_map[] = { 1, 2, 4, 3, 0, 5}; + +/* Rotine to read coeffs from File and updates real and imaginary + coeff array member variable */ +static int32_t ssr_read_coeffs_from_file() +{ + FILE *flt1r; + FILE *flt2r; + FILE *flt3r; + FILE *flt4r; + FILE *flt1i; + FILE *flt2i; + FILE *flt3i; + FILE *flt4i; + int i; + + if ( (flt1r = fopen(SURROUND_FILE_1R, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter co-efficient " + "file %s", __func__, SURROUND_FILE_1R); + return -EINVAL; + } + + if ( (flt2r = fopen(SURROUND_FILE_2R, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_2R); + return -EINVAL; + } + + if ( (flt3r = fopen(SURROUND_FILE_3R, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_3R); + return -EINVAL; + } + + if ( (flt4r = fopen(SURROUND_FILE_4R, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_4R); + return -EINVAL; + } + + if ( (flt1i = fopen(SURROUND_FILE_1I, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_1I); + return -EINVAL; + } + + if ( (flt2i = fopen(SURROUND_FILE_2I, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_2I); + return -EINVAL; + } + + if ( (flt3i = fopen(SURROUND_FILE_3I, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_3I); + return -EINVAL; + } + + if ( (flt4i = fopen(SURROUND_FILE_4I, "rb")) == NULL ) { + ALOGE("%s: Cannot open filter " + "co-efficient file %s", __func__, SURROUND_FILE_4I); + return -EINVAL; + } + ALOGV("%s: readCoeffsFromFile all filter " + "files opened", __func__); + + for (i=0; i 0 ) { + ALOGV("%s: Allocating surroundObj size is %d", __func__, ret); + ssrmod.surround_obj = (void *)malloc(ret); + memset(ssrmod.surround_obj,0,ret); + if (NULL != ssrmod.surround_obj) { + /* initialize after allocating the memory for surround_obj */ + ret = ssrmod.surround_filters_init(ssrmod.surround_obj, + 6, + 4, + ssrmod.real_coeffs, + ssrmod.imag_coeffs, + sub_woofer, + low_freq, + high_freq, + NULL); + if (0 != ret) { + ALOGE("%s: surround_filters_init failed with ret:%d",__func__, ret); + ssrmod.surround_filters_release(ssrmod.surround_obj); + goto init_fail; + } + } else { + ALOGE("%s: Allocationg surround_obj failed", __func__); + goto init_fail; + } + } else { + ALOGE("%s: surround_filters_init(surround_obj=Null) " + "failed with ret: %d", __func__, ret); + goto init_fail; + } + + (void) ssrmod.surround_filters_set_channel_map(ssrmod.surround_obj, chan_map); + + return 0; + +init_fail: + if (ssrmod.surround_obj) { + free(ssrmod.surround_obj); + ssrmod.surround_obj = NULL; + } + if (ssrmod.surround_output_buffer) { + free(ssrmod.surround_output_buffer); + ssrmod.surround_output_buffer = NULL; + } + if (ssrmod.surround_input_buffer) { + free(ssrmod.surround_input_buffer); + ssrmod.surround_input_buffer = NULL; + } + if (ssrmod.real_coeffs){ + for (i =0; iconfig.channels = SSR_CHANNEL_COUNT; + in->config.period_size = SSR_PERIOD_SIZE; + in->config.period_count = SSR_PERIOD_COUNT; + + buffer_size = (SSR_PERIOD_SIZE)*(SSR_PERIOD_COUNT); + ALOGD("%s: buffer_size: %d", __func__, buffer_size); + + ret = ssr_init_surround_sound_lib(buffer_size); + if (0 != ret) { + ALOGE("%s: initSurroundSoundLibrary failed: %d " + "handle->bufferSize:%d", __func__, ret, buffer_size); + return ret; + } + + property_get("ssr.pcmdump",c_multi_ch_dump,"0"); + if (0 == strncmp("true",c_multi_ch_dump, sizeof("ssr.dump-pcm"))) { + /* Remember to change file system permission of data(e.g. chmod 777 data/), + otherwise, fopen may fail */ + if ( !ssrmod.fp_4ch) + ssrmod.fp_4ch = fopen("/data/media/0/4ch_ssr.pcm", "wb"); + if ( !ssrmod.fp_6ch) + ssrmod.fp_6ch = fopen("/data/media/0/6ch_ssr.pcm", "wb"); + if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch)) + ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p", + __func__, ssrmod.fp_4ch, ssrmod.fp_6ch); + } + + return 0; +} + +int32_t audio_extn_ssr_deinit() +{ + int i; + + if (ssrmod.surround_obj) { + ALOGD("%s: entry", __func__); + ssrmod.surround_filters_release(ssrmod.surround_obj); + if (ssrmod.surround_obj) + free(ssrmod.surround_obj); + ssrmod.surround_obj = NULL; + if (ssrmod.real_coeffs){ + for (i =0; i> 1; + + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + + period_bytes = in->config.period_size; + ALOGD("%s: period_size: %d", __func__, in->config.period_size); + period_samples = period_bytes >> 1; + + if (!ssrmod.surround_obj) + return -ENOMEM; + + do { + if (ssrmod.surround_output_bufferIdx > 0) { + ALOGV("%s: copy processed output " + "to buffer, surround_output_bufferIdx = %d", + __func__, ssrmod.surround_output_bufferIdx); + /* Copy processed output to buffer */ + processed_pending = ssrmod.surround_output_bufferIdx; + if (processed_pending > (samples - processed)) { + processed_pending = (samples - processed); + } + memcpy(buffer, ssrmod.surround_output_buffer, processed_pending * sizeof(Word16)); + buffer = (char*)buffer + processed_pending * sizeof(Word16); + processed += processed_pending; + if (ssrmod.surround_output_bufferIdx > processed_pending) { + /* Shift leftover samples to beginning of the buffer */ + memcpy(&ssrmod.surround_output_buffer[0], + &ssrmod.surround_output_buffer[processed_pending], + (ssrmod.surround_output_bufferIdx - processed_pending) * sizeof(Word16)); + } + ssrmod.surround_output_bufferIdx -= processed_pending; + } + + if (processed >= samples) { + ALOGV("%s: done processing buffer, " + "processed = %d", __func__, processed); + /* Done processing this buffer */ + break; + } + + /* Fill input buffer until there is enough to process */ + read_pending = SSR_INPUT_FRAME_SIZE - ssrmod.surround_input_bufferIdx; + read_bytes = ssrmod.surround_input_bufferIdx; + while (in->pcm && read_pending > 0) { + n = pcm_read(in->pcm, &ssrmod.surround_input_buffer[read_bytes], + period_bytes); + ALOGV("%s: pcm_read() returned n = %d buffer:%p size:%d", __func__, + n, &ssrmod.surround_input_buffer[read_bytes], period_bytes); + if (n && n != -EAGAIN) { + /* Recovery part of pcm_read. TODO:split recovery */ + return (ssize_t)n; + } + else if (n < 0) { + /* Recovery is part of pcm_write. TODO split is later */ + return (ssize_t)n; + } + else { + read_pending -= period_samples; + read_bytes += period_samples; + } + } + + + if (ssrmod.fp_4ch) { + fwrite( ssrmod.surround_input_buffer, 1, + SSR_INPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_4ch); + } + + /* apply ssr libs to conver 4ch to 6ch */ + ssrmod.surround_filters_intl_process(ssrmod.surround_obj, + &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx], + (Word16 *)ssrmod.surround_input_buffer); + + /* Shift leftover samples to beginning of input buffer */ + if (read_pending < 0) { + memcpy(&ssrmod.surround_input_buffer[0], + &ssrmod.surround_input_buffer[SSR_INPUT_FRAME_SIZE], + (-read_pending) * sizeof(Word16)); + } + ssrmod.surround_input_bufferIdx = -read_pending; + + if (ssrmod.fp_6ch) { + fwrite( &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx], + 1, SSR_OUTPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_6ch); + } + + ssrmod.surround_output_bufferIdx += SSR_OUTPUT_FRAME_SIZE; + ALOGV("%s: do_while loop: processed=%d, samples=%d\n", __func__, processed, samples); + } while (in->pcm && processed < samples); + read_bytes = processed * sizeof(Word16); + buffer = buffer_start; + + return 0; +} + +void audio_extn_ssr_get_parameters(struct str_parms *query, + struct str_parms *reply) +{ + int ret, val; + char value[32]={0}; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SSR, value, sizeof(value)); + + if (ret >= 0) { + memcpy(value, "true", 4); + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SSR, value); + } +} +#endif /* SSR_ENABLED */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index a101cfb4b..abda10c78 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -774,7 +774,7 @@ static int check_input_parameters(uint32_t sample_rate, { if (format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; - if ((channel_count < 1) || (channel_count > 2)) return -EINVAL; + if ((channel_count < 1) || (channel_count > 6)) return -EINVAL; switch (sample_rate) { case 8000: @@ -1223,7 +1223,10 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, } if (in->pcm) { - ret = pcm_read(in->pcm, buffer, bytes); + if (audio_extn_ssr_get_enabled() && popcount(in->channel_mask) == 6) + ret = audio_extn_ssr_read(stream, buffer, bytes); + else + ret = pcm_read(in->pcm, buffer, bytes); } /* @@ -1610,14 +1613,19 @@ static int adev_open_input_stream(struct audio_hw_device *dev, /* Update config params with the requested sample rate and channels */ in->usecase = USECASE_AUDIO_RECORD; in->config = pcm_config_audio_capture; - in->config.channels = channel_count; in->config.rate = config->sample_rate; - frame_size = audio_stream_frame_size((struct audio_stream *)in); - buffer_size = get_input_buffer_size(config->sample_rate, - config->format, - channel_count); - in->config.period_size = buffer_size / frame_size; + if (audio_extn_ssr_get_enabled()&& channel_count == 6) { + if(audio_extn_ssr_init(adev, in)) + ALOGE("%s: audio_extn_ssr_init failed", __func__); + } else { + in->config.channels = channel_count; + frame_size = audio_stream_frame_size((struct audio_stream *)in); + buffer_size = get_input_buffer_size(config->sample_rate, + config->format, + channel_count); + in->config.period_size = buffer_size / frame_size; + } *stream_in = &in->stream; ALOGV("%s: exit", __func__); @@ -1632,9 +1640,13 @@ err_open: static void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) { + struct stream_in *in = (struct stream_in *)stream; ALOGV("%s", __func__); in_standby(&stream->common); + if (audio_extn_ssr_get_enabled() && (popcount(in->channel_mask) == 6)) { + audio_extn_ssr_deinit(); + } free(stream); return; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index bb732f60e..dc3857bc7 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -171,6 +171,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic", [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm", [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic", + [SND_DEVICE_IN_QUAD_MIC] = "quad-mic", }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ @@ -225,6 +226,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_USB_HEADSET_MIC] = 44, [SND_DEVICE_IN_CAPTURE_FM] = 0, [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, + [SND_DEVICE_IN_QUAD_MIC] = 46, /* TODO: Update with proper acdb ids */ [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, @@ -357,6 +359,9 @@ void *platform_init(struct audio_device *adev) /* init usb */ audio_extn_usb_init(adev); + /* Read one time ssr property */ + audio_extn_ssr_update_enabled(adev); + return my_data; } @@ -792,7 +797,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) && !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - snd_device = SND_DEVICE_IN_HANDSET_MIC; + if (audio_extn_ssr_get_enabled() && channel_count == 6) + snd_device = SND_DEVICE_IN_QUAD_MIC; + else + snd_device = SND_DEVICE_IN_HANDSET_MIC; } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { snd_device = SND_DEVICE_IN_SPEAKER_MIC; } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index d34aa413c..bc1e78488 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -104,6 +104,7 @@ enum { SND_DEVICE_IN_USB_HEADSET_MIC, SND_DEVICE_IN_CAPTURE_FM, SND_DEVICE_IN_AANC_HANDSET_MIC, + SND_DEVICE_IN_QUAD_MIC, SND_DEVICE_IN_END, SND_DEVICE_MAX = SND_DEVICE_IN_END, -- GitLab From 6bd8dbf4003de4df0747c972443339f648001084 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Sat, 19 Oct 2013 18:37:52 -0700 Subject: [PATCH 053/298] hal: Support for stereo recording audio feature Add support for stereo recording audio feature Change-Id: I0616bd0292be62d5d6520eb13e3664b15a95bc29 --- hal/msm8974/platform.c | 11 ++++++++++- hal/msm8974/platform.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index dc3857bc7..d2626afda 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -172,6 +172,8 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm", [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic", [SND_DEVICE_IN_QUAD_MIC] = "quad-mic", + [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef", + [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef", }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ @@ -227,6 +229,8 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_CAPTURE_FM] = 0, [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, [SND_DEVICE_IN_QUAD_MIC] = 46, + [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34, + [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35, /* TODO: Update with proper acdb ids */ [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, @@ -799,6 +803,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { if (audio_extn_ssr_get_enabled() && channel_count == 6) snd_device = SND_DEVICE_IN_QUAD_MIC; + else if (channel_count > 1) + snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC; else snd_device = SND_DEVICE_IN_HANDSET_MIC; } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { @@ -828,7 +834,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC; } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { - snd_device = SND_DEVICE_IN_SPEAKER_MIC; + if (channel_count > 1) + snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC; + else + snd_device = SND_DEVICE_IN_SPEAKER_MIC; } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index bc1e78488..fe55f1bad 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -105,6 +105,8 @@ enum { SND_DEVICE_IN_CAPTURE_FM, SND_DEVICE_IN_AANC_HANDSET_MIC, SND_DEVICE_IN_QUAD_MIC, + SND_DEVICE_IN_HANDSET_STEREO_DMIC, + SND_DEVICE_IN_SPEAKER_STEREO_DMIC, SND_DEVICE_IN_END, SND_DEVICE_MAX = SND_DEVICE_IN_END, -- GitLab From 866d5ff1463591e276b7f138c42466d9832c47d4 Mon Sep 17 00:00:00 2001 From: "sangwon.jeon" Date: Thu, 17 Oct 2013 21:42:50 +0900 Subject: [PATCH 054/298] hal: Fix for Audio Route issue when sound path changes - if you make an outgoing call as mp3 playback is runnign with headset, Right side of headset is not functional when keep changing sound path from headset to speaker - Fix the issue by separating loop related of disable/enable_snd_device Bug: 11232052 Change-Id: Id02a6d7221c77cf4003d97749d75a062d8575d02 --- hal/audio_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 08d9c32c1..d8e8ca87d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -311,6 +311,12 @@ static void check_usecases_codec_backend(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { disable_snd_device(adev, usecase->out_snd_device, false); + } + } + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { enable_snd_device(adev, snd_device, false); } } -- GitLab From f3b9a42020a389b5c2619844841a9b7fb5e973be Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Tue, 22 Oct 2013 16:38:08 -0700 Subject: [PATCH 055/298] hal: add incall music delivery feature In multisim scenarios, local call hold tone has to be played to the uplink on the sub on local call hold. Add incall music delivery feature so that call hold tones can be played to the uplink. Change-Id: I8cecf0139926a4bfee603c02542bbedc67720bf4 --- hal/Android.mk | 4 ++ hal/audio_hw.c | 10 +++++ hal/audio_hw.h | 3 ++ hal/msm8974/platform.c | 4 ++ hal/msm8974/platform.h | 2 + hal/voice.c | 14 +++++++ hal/voice.h | 5 ++- hal/voice_extn/voice_extn.c | 77 ++++++++++++++++++++++++++++--------- hal/voice_extn/voice_extn.h | 34 ++++++++++------ 9 files changed, 122 insertions(+), 31 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index cc6b62e72..be67ba018 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -43,6 +43,10 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAFE_PROXY_ENABLED endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) +LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED +endif + ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) LOCAL_CFLAGS += -DFM_ENABLED LOCAL_SRC_FILES += audio_extn/fm.c diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1bcb25aca..aa7e6a6bf 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -114,6 +114,8 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", + [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink", + [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", }; @@ -1925,6 +1927,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); + } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { + ret = voice_check_and_set_incall_music_usecase(adev, out); + if (ret != 0) { + ALOGE("%s: Incall music delivery usecase cannot be set error:%d", + __func__, ret); + goto error_open; + } } else { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; @@ -2146,6 +2155,7 @@ static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) struct audio_device *adev = (struct audio_device *)dev; pthread_mutex_lock(&adev->lock); if (adev->mode != mode) { + ALOGD("%s mode %d\n", __func__, mode); adev->mode = mode; } pthread_mutex_unlock(&adev->lock); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index c43b557d5..965ac62c9 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -78,6 +78,9 @@ typedef enum { USECASE_INCALL_REC_DOWNLINK, USECASE_INCALL_REC_UPLINK_AND_DOWNLINK, + USECASE_INCALL_MUSIC_UPLINK, + USECASE_INCALL_MUSIC_UPLINK2, + AUDIO_USECASE_MAX } audio_usecase_t; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 134fdbb28..1734cedca 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -113,6 +113,10 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { AUDIO_RECORD_PCM_DEVICE}, [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE, + INCALL_MUSIC_UPLINK_PCM_DEVICE}, + [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE, + INCALL_MUSIC_UPLINK2_PCM_DEVICE}, }; /* Array to store sound devices */ diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index fe55f1bad..921230762 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -150,6 +150,8 @@ enum { #define VOICE_CALL_PCM_DEVICE 2 #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 +#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 #ifdef PLATFORM_MSM8x26 #define VOICE2_CALL_PCM_DEVICE 14 diff --git a/hal/voice.c b/hal/voice.c index 190df7c94..39e2dd961 100755 --- a/hal/voice.c +++ b/hal/voice.c @@ -249,6 +249,20 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, return ret; } +int voice_check_and_set_incall_music_usecase(struct audio_device *adev, + struct stream_out *out) +{ + int ret = 0; + + ret = voice_extn_check_and_set_incall_music_usecase(adev, out); + if (ret == -ENOSYS) { + /* Incall music delivery is used only for LCH call state */ + ret = -EINVAL; + } + + return ret; +} + int voice_set_mic_mute(struct audio_device *adev, bool state) { int err = 0; diff --git a/hal/voice.h b/hal/voice.h index d5e5a8d16..7f8b25baa 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -38,6 +38,7 @@ struct audio_device; struct str_parms; struct stream_in; +struct stream_out; struct call_state { int current; @@ -67,5 +68,7 @@ int voice_set_mic_mute(struct audio_device *dev, bool state); bool voice_get_mic_mute(struct audio_device *dev); int voice_set_volume(struct audio_device *adev, float volume); int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, - struct stream_in *in); + struct stream_in *in); +int voice_check_and_set_incall_music_usecase(struct audio_device *adev, + struct stream_out *out); #endif //VOICE_H diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 29f12d41d..903d2aa8c 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -17,8 +17,6 @@ * limitations under the License. */ -#ifdef MULTI_VOICE_SESSION_ENABLED - #define LOG_TAG "voice_extn" /*#define LOG_NDEBUG 0*/ #define LOG_NDDEBUG 0 @@ -52,6 +50,17 @@ #define CALL_HOLD (BASE_CALL_STATE + 2) #define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3) +struct pcm_config pcm_config_incall_music = { + .channels = 1, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, + .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, +}; + extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id); extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id); int voice_extn_update_calls(struct audio_device *adev); @@ -103,21 +112,28 @@ static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index) return usecase_id; } -int voice_extn_get_active_session_id(struct audio_device *adev, - uint32_t *session_id) +static uint32_t get_session_id_with_state(struct audio_device *adev, + int call_state) { struct voice_session *session = NULL; int i = 0; - *session_id = 0; + uint32_t session_id = 0; for (i = 0; i < MAX_VOICE_SESSIONS; i++) { session = &adev->voice.session[i]; - if(session->state.current == CALL_ACTIVE){ - *session_id = session->vsid; + if(session->state.current == call_state){ + session_id = session->vsid; break; } } + return session_id; +} + +int voice_extn_get_active_session_id(struct audio_device *adev, + uint32_t *session_id) +{ + *session_id = get_session_id_with_state(adev, CALL_ACTIVE); return 0; } @@ -155,6 +171,7 @@ static int voice_extn_update_call_states(struct audio_device *adev, if (session) { session->state.new = call_state; voice_extn_is_in_call(adev, &is_in_call); + ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode); if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) { /* Device routing is not triggered for voice calls on the subsequent * subs, Hence update the call states if voice call is already @@ -224,7 +241,7 @@ int voice_extn_update_calls(struct audio_device *adev) for (i = 0; i < MAX_VOICE_SESSIONS; i++) { usecase_id = voice_extn_get_usecase_for_session_idx(i); session = &adev->voice.session[i]; - ALOGV("%s: cur_state=%d new_state=%d vsid=%x", + ALOGD("%s: cur_state=%d new_state=%d vsid=%x", __func__, session->state.current, session->state.new, session->vsid); switch(session->state.new) @@ -233,7 +250,7 @@ int voice_extn_update_calls(struct audio_device *adev) switch(session->state.current) { case CALL_INACTIVE: - ALOGD("%s: INACTIVE ->ACTIVE vsid:%x", __func__, session->vsid); + ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid); ret = start_call(adev, usecase_id); if(ret < 0) { ALOGE("%s: voice_start_call() failed for usecase: %d\n", @@ -243,15 +260,15 @@ int voice_extn_update_calls(struct audio_device *adev) break; case CALL_HOLD: - ALOGD("%s: HOLD ->ACTIVE vsid:%x", __func__, session->vsid); + ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid); session->state.current = session->state.new; break; case CALL_LOCAL_HOLD: - ALOGD("%s: LOCAL_HOLD ->ACTIVE vsid:%x", __func__, session->vsid); + ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid); lch_mode = VOICE_LCH_STOP; if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { - ALOGE("LOCAL_HOLD ->ACTIVE failed"); + ALOGE("LOCAL_HOLD -> ACTIVE failed"); } else { session->state.current = session->state.new; } @@ -270,7 +287,7 @@ int voice_extn_update_calls(struct audio_device *adev) case CALL_ACTIVE: case CALL_HOLD: case CALL_LOCAL_HOLD: - ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD ->INACTIVE vsid:%x", __func__, session->vsid); + ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid); ret = stop_call(adev, usecase_id); if(ret < 0) { ALOGE("%s: voice_end_call() failed for usecase: %d\n", @@ -290,15 +307,15 @@ int voice_extn_update_calls(struct audio_device *adev) switch(session->state.current) { case CALL_ACTIVE: - ALOGD("%s: CALL_ACTIVE ->HOLD vsid:%x", __func__, session->vsid); + ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid); session->state.current = session->state.new; break; case CALL_LOCAL_HOLD: - ALOGD("%s: CALL_LOCAL_HOLD ->HOLD vsid:%x", __func__, session->vsid); + ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid); lch_mode = VOICE_LCH_STOP; if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { - ALOGE("LOCAL_HOLD ->HOLD failed"); + ALOGE("LOCAL_HOLD -> HOLD failed"); } else { session->state.current = session->state.new; } @@ -316,10 +333,11 @@ int voice_extn_update_calls(struct audio_device *adev) { case CALL_ACTIVE: case CALL_HOLD: - ALOGD("%s: ACTIVE/CALL_HOLD ->LOCAL_HOLD vsid:%x", __func__, session->vsid); + ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__, + session->vsid); lch_mode = VOICE_LCH_START; if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { - ALOGE("LOCAL_HOLD ->HOLD failed"); + ALOGE("LOCAL_HOLD -> HOLD failed"); } else { session->state.current = session->state.new; } @@ -382,4 +400,25 @@ done: return ret; } -#endif +int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, + struct stream_out *out) +{ + uint32_t session_id = 0; + + session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD); + if (session_id == VOICE_VSID) { + out->usecase = USECASE_INCALL_MUSIC_UPLINK; + } else if (session_id == VOICE2_VSID) { + out->usecase = USECASE_INCALL_MUSIC_UPLINK2; + } else { + ALOGE("%s: Invalid session id %x", __func__, session_id); + return -EINVAL; + } + + out->config = pcm_config_incall_music; + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO; + out->channel_mask = AUDIO_CHANNEL_OUT_MONO; + + return 0; +} + diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index 568f71680..a8efef152 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -20,6 +20,7 @@ #ifndef VOICE_EXTN_H #define VOICE_EXTN_H +#ifdef MULTI_VOICE_SESSION_ENABLED int voice_extn_update_calls(struct audio_device *adev); int voice_extn_get_session_from_use_case(struct audio_device *adev, const audio_usecase_t usecase_id, @@ -30,37 +31,48 @@ int voice_extn_set_parameters(struct audio_device *adev, int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id); +#else +static int voice_extn_update_calls(struct audio_device *adev) +{ + return -ENOSYS; +} -#ifndef MULTI_VOICE_SESSION_ENABLED -int voice_extn_update_calls(struct audio_device *adev) +static int voice_extn_get_session_from_use_case(struct audio_device *adev, + const audio_usecase_t usecase_id, + struct voice_session **session) { return -ENOSYS; } -int voice_extn_get_session_from_use_case(struct audio_device *adev, - const audio_usecase_t usecase_id, - struct voice_session **session) +static int voice_extn_init(struct audio_device *adev) { return -ENOSYS; } -int voice_extn_init(struct audio_device *adev) +static int voice_extn_set_parameters(struct audio_device *adev, + struct str_parms *parms) { return -ENOSYS; } -int voice_extn_set_parameters(struct audio_device *adev, - struct str_parms *parms) +static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) { return -ENOSYS; } -int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) +static int voice_extn_get_active_session_id(struct audio_device *adev, + uint32_t *session_id) { return -ENOSYS; } -int voice_extn_get_active_session_id(struct audio_device *adev, - uint32_t *session_id) +#endif + +#if defined INCALL_MUSIC_ENABLED && defined MULTI_VOICE_SESSION_ENABLED +int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, + struct stream_out *out); +#else +static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, + struct stream_out *out) { return -ENOSYS; } -- GitLab From 303f51dd95debe951d820e2bd70c32fd4e64e720 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Fri, 25 Oct 2013 16:24:27 -0700 Subject: [PATCH 056/298] hal: compile voice extensions based on board config flag Compile voice extensions based on the flag AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS defined in BoardConfigVendor.mk. Change-Id: I06c42bf4b79294fed2077c1d2771ed155f68de00 --- hal/Android.mk | 30 ++++++++++++------------------ hal/voice_extn/voice_extn.h | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index be67ba018..9e9be9e00 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -6,12 +6,6 @@ include $(CLEAR_VARS) LOCAL_ARM_MODE := arm -#MULTI_VOICE_SESSION_ENABLED := true - -ifdef MULTI_VOICE_SESSION_ENABLED -LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED -endif - AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) ifneq ($(filter msm8974 msm8226 msm8610 apq8084,$(TARGET_BOARD_PLATFORM)),) # B-family platform uses msm8974 code base @@ -29,10 +23,6 @@ LOCAL_SRC_FILES := \ voice.c \ $(AUDIO_PLATFORM)/platform.c -ifdef MULTI_VOICE_SESSION_ENABLED -LOCAL_SRC_FILES += voice_extn/voice_extn.c -endif - LOCAL_SRC_FILES += audio_extn/audio_extn.c ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true) @@ -43,10 +33,6 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAFE_PROXY_ENABLED endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) -LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED -endif - ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) LOCAL_CFLAGS += -DFM_ENABLED LOCAL_SRC_FILES += audio_extn/fm.c @@ -63,6 +49,18 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_SSR)),true) LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/surround_sound/ endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS)),true) + LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED + LOCAL_SRC_FILES += voice_extn/voice_extn.c + LOCAL_C_INCLUDES += $(LOCAL_PATH)/voice_extn + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) + LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED +endif + +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ @@ -79,10 +77,6 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \ $(LOCAL_PATH)/audio_extn -ifdef MULTI_VOICE_SESSION_ENABLED -LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include -endif - LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index a8efef152..dd2dfd861 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -67,7 +67,7 @@ static int voice_extn_get_active_session_id(struct audio_device *adev, } #endif -#if defined INCALL_MUSIC_ENABLED && defined MULTI_VOICE_SESSION_ENABLED +#ifdef INCALL_MUSIC_ENABLED int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, struct stream_out *out); #else -- GitLab From e0b186f934e4acb8e51b5495b0b0ca7caf5803ba Mon Sep 17 00:00:00 2001 From: Helen Zeng Date: Wed, 23 Oct 2013 14:00:59 -0700 Subject: [PATCH 057/298] hal: Fix for no audio recorded during voice downlink record with mic muted If mic is muted, the recording buffer is reset, then there is no audio recorded during voice downlink recording. Don't reset the buffer if voice call is active. Change-Id: I59d0543febcccf4a70dfbe713e0921e7bb9f2092 --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index aa7e6a6bf..e9c3b56b9 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1763,7 +1763,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, * Instead of writing zeroes here, we could trust the hardware * to always provide zeroes when muted. */ - if (ret == 0 && voice_get_mic_mute(adev)) + if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call(adev)) memset(buffer, 0, bytes); exit: -- GitLab From 8f715d94926ee51baf766800f4e9c3ceec435e4c Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Fri, 1 Nov 2013 20:37:38 -0700 Subject: [PATCH 058/298] hal: Use deep buffer output as primary - The audio content in video clips, YouTube content, etc are being rendered through low latency path as it was set as default output profile. This results more power consumption for video playback. - Fix this using deep buffer path as default one and use low latency path only for those audio tracks that request with AUDIO_OUTPUT_FLAG_FAST. Change-Id: I52fafa0ec2a312bc4383c813497830e6ded071bc CRs-Fixed: 570389 --- hal/audio_hw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index aa7e6a6bf..68c977713 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1873,10 +1873,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config.rate = config->sample_rate; out->config.channels = popcount(out->channel_mask); out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); - } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { - out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; - out->config = pcm_config_deep_buffer; - out->sample_rate = out->config.rate; } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { @@ -1934,10 +1930,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, __func__, ret); goto error_open; } - } else { + } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; out->sample_rate = out->config.rate; + } else { + out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; + out->config = pcm_config_deep_buffer; + out->sample_rate = out->config.rate; } if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { -- GitLab From 48c921d4e8763cd5b92d0b8afa90a42c5d1255f7 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Tue, 29 Oct 2013 06:07:44 -0700 Subject: [PATCH 059/298] hal: Add support for multiple hardware variants - Most of the targets supports multiple hardware variants such as MTP, CDP, Fluid, Liquid etc. The mixer paths for certain devices may vary on some of the variants. For example, the mixer controls for speaker device are different on msm8974 MTP and Fluid variants. - Update audio HAL to select corresponding entry in the mixer_paths.xml file based on HW information. Change-Id: I060f2e6c331344dd41417c19fb688ff27a129308 Conflicts: hal/Android.mk --- hal/Android.mk | 7 + hal/audio_extn/audio_extn.h | 12 ++ hal/audio_hw.c | 26 +++- hal/msm8960/platform.c | 30 +++- hal/msm8974/hw_info.c | 290 ++++++++++++++++++++++++++++++++++++ hal/msm8974/platform.c | 36 ++++- hal/msm8974/platform.h | 2 + hal/platform_api.h | 2 + hal/voice.c | 0 9 files changed, 395 insertions(+), 10 deletions(-) create mode 100644 hal/msm8974/hw_info.c mode change 100755 => 100644 hal/voice.c diff --git a/hal/Android.mk b/hal/Android.mk index 9e9be9e00..6a8da100f 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -7,9 +7,11 @@ include $(CLEAR_VARS) LOCAL_ARM_MODE := arm AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) + ifneq ($(filter msm8974 msm8226 msm8610 apq8084,$(TARGET_BOARD_PLATFORM)),) # B-family platform uses msm8974 code base AUDIO_PLATFORM = msm8974 + MULTIPLE_HW_VARIANTS_ENABLED := true ifneq ($(filter msm8610,$(TARGET_BOARD_PLATFORM)),) LOCAL_CFLAGS := -DPLATFORM_MSM8610 endif @@ -61,6 +63,11 @@ endif endif +ifdef MULTIPLE_HW_VARIANTS_ENABLED + LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED + LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index ee03f5a7d..3676c0876 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -81,4 +81,16 @@ int32_t audio_extn_ssr_read(struct audio_stream_in *stream, void *buffer, size_t bytes); #endif +#ifndef HW_VARIANTS_ENABLED +#define hw_info_init(snd_card_name) (0) +#define hw_info_deinit(hw_info) (0) +#define hw_info_append_hw_type(hw_info,\ + snd_device, device_name) (0) +#else +void *hw_info_init(const char *snd_card_name); +void hw_info_deinit(void *hw_info); +void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, + char *device_name); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index aa7e6a6bf..28035d3c7 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -222,6 +222,8 @@ static int enable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool update_mixer) { + char device_name[DEVICE_NAME_MAX_SIZE] = {0}; + if (snd_device < SND_DEVICE_MIN || snd_device >= SND_DEVICE_MAX) { ALOGE("%s: Invalid sound device %d", __func__, snd_device); @@ -229,9 +231,14 @@ static int enable_snd_device(struct audio_device *adev, } adev->snd_dev_ref_cnt[snd_device]++; + + if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) { + ALOGE("%s: Invalid sound device returned", __func__); + return -EINVAL; + } if (adev->snd_dev_ref_cnt[snd_device] > 1) { ALOGV("%s: snd_device(%d: %s) is already active", - __func__, snd_device, platform_get_snd_device_name(snd_device)); + __func__, snd_device, device_name); return 0; } @@ -250,8 +257,8 @@ static int enable_snd_device(struct audio_device *adev, } ALOGV("%s: snd_device(%d: %s)", __func__, - snd_device, platform_get_snd_device_name(snd_device)); - audio_route_apply_path(adev->audio_route, platform_get_snd_device_name(snd_device)); + snd_device, device_name); + audio_route_apply_path(adev->audio_route, device_name); if (update_mixer) audio_route_update_mixer(adev->audio_route); @@ -262,6 +269,8 @@ int disable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool update_mixer) { + char device_name[DEVICE_NAME_MAX_SIZE] = {0}; + if (snd_device < SND_DEVICE_MIN || snd_device >= SND_DEVICE_MAX) { ALOGE("%s: Invalid sound device %d", __func__, snd_device); @@ -271,6 +280,7 @@ int disable_snd_device(struct audio_device *adev, ALOGE("%s: device ref cnt is already 0", __func__); return -EINVAL; } + adev->snd_dev_ref_cnt[snd_device]--; /* exit usb play back thread */ @@ -282,13 +292,19 @@ int disable_snd_device(struct audio_device *adev, if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) audio_extn_usb_stop_capture(adev); + if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) { + ALOGE("%s: Invalid sound device returned", __func__); + return -EINVAL; + } + if (adev->snd_dev_ref_cnt[snd_device] == 0) { ALOGV("%s: snd_device(%d: %s)", __func__, - snd_device, platform_get_snd_device_name(snd_device)); - audio_route_reset_path(adev->audio_route, platform_get_snd_device_name(snd_device)); + snd_device, device_name); + audio_route_reset_path(adev->audio_route, device_name); if (update_mixer) audio_route_update_mixer(adev->audio_route); } + return 0; } diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index ac36f8758..e80aa270f 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -73,7 +73,6 @@ typedef int (*csd_start_voice_t)(); typedef int (*csd_stop_voice_t)(); -/* Audio calibration related functions */ struct platform_data { struct audio_device *adev; bool fluence_in_spkr_mode; @@ -82,6 +81,9 @@ struct platform_data { int fluence_type; int dualmic_config; + void *hw_info; + + /* Audio calibration related functions */ void *acdb_handle; acdb_init_t acdb_init; acdb_deallocate_t acdb_deallocate; @@ -243,6 +245,7 @@ void *platform_init(struct audio_device *adev) char baseband[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX]; struct platform_data *my_data; + const char *snd_card_name; adev->mixer = mixer_open(MIXER_CARD); @@ -259,6 +262,12 @@ void *platform_init(struct audio_device *adev) my_data = calloc(1, sizeof(struct platform_data)); + snd_card_name = mixer_get_name(adev->mixer); + my_data->hw_info = hw_info_init(snd_card_name); + if (!my_data->hw_info) { + ALOGE("%s: Failed to init hardware info", __func__); + } + my_data->adev = adev; my_data->fluence_in_spkr_mode = false; my_data->fluence_in_voice_call = false; @@ -356,6 +365,9 @@ void *platform_init(struct audio_device *adev) void platform_deinit(void *platform) { + struct platform_data *my_data = (struct platform_data *)platform; + + hw_info_deinit(my_data->hw_info); free(platform); } @@ -367,6 +379,22 @@ const char *platform_get_snd_device_name(snd_device_t snd_device) return ""; } +int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device, + char *device_name) +{ + struct platform_data *my_data = (struct platform_data *)platform; + + if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) { + strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE); + hw_info_append_hw_type(my_data->hw_info, snd_device, device_name); + } else { + strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE); + return -EINVAL; + } + + return 0; +} + void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) { if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c new file mode 100644 index 000000000..02eb148ac --- /dev/null +++ b/hal/msm8974/hw_info.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "hardware_info" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" + + +struct hardware_info { + char name[HW_INFO_ARRAY_MAX_SIZE]; + char type[HW_INFO_ARRAY_MAX_SIZE]; + /* variables for handling target variants */ + uint32_t num_snd_devices; + char dev_extn[HW_INFO_ARRAY_MAX_SIZE]; + snd_device_t *snd_devices; +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define LITERAL_TO_STRING(x) #x +#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\ + __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ + " ASSERT_FATAL(" #condition ") failed.") + +static const snd_device_t taiko_fluid_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static const snd_device_t taiko_CDP_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static const snd_device_t taiko_liquid_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_HEADSET_MIC, +}; + +static const snd_device_t taiko_DB_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_SPEAKER_MIC, +}; + +static const snd_device_t tapan_lite_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static const snd_device_t tapan_skuf_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static const snd_device_t tapan_lite_skuf_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_ANC_HANDSET, + SND_DEVICE_OUT_ANC_HEADSET, + SND_DEVICE_OUT_ANC_FB_HEADSET, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_AANC_HANDSET_MIC, +}; + +static const snd_device_t helicon_skuab_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static void update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card")) { + strlcpy(hw_info->type, "mtp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "apq8084-taiko-cdp-snd-card")) { + strlcpy(hw_info->type, " cdp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices); + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) { + strlcpy(hw_info->type , " liquid", sizeof(hw_info->type)); + strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type)); + hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices); + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8084 device", __func__); + } +} + +static void update_hardware_info_8974(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "msm8974-taiko-mtp-snd-card")) { + strlcpy(hw_info->type, " mtp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8974-taiko-cdp-snd-card")) { + strlcpy(hw_info->type, " cdp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices); + strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8974-taiko-fluid-snd-card")) { + strlcpy(hw_info->type, " fluid", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *) taiko_fluid_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_fluid_variant_devices); + strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8974-taiko-liquid-snd-card")) { + strlcpy(hw_info->type, " liquid", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices); + strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "apq8074-taiko-db-snd-card")) { + strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_DB_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_DB_variant_devices); + strlcpy(hw_info->dev_extn, "-DB", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8974 device", __func__); + } +} + +static void update_hardware_info_8610(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "msm8x10-snd-card")) { + strlcpy(hw_info->type, "", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8x10-skuab-snd-card")) { + strlcpy(hw_info->type, "skuab", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)helicon_skuab_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(helicon_skuab_variant_devices); + strlcpy(hw_info->dev_extn, "-skuab", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8x10-skuaa-snd-card")) { + strlcpy(hw_info->type, " skuaa", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8x10 device", __func__); + } +} + +static void update_hardware_info_8226(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "msm8226-tapan-snd-card")) { + strlcpy(hw_info->type, "", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8226-tapan9302-snd-card")) { + strlcpy(hw_info->type, "tapan_lite", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)tapan_lite_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_variant_devices); + strlcpy(hw_info->dev_extn, "-lite", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8226-tapan-skuf-snd-card")) { + strlcpy(hw_info->type, " skuf", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *) tapan_skuf_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(tapan_skuf_variant_devices); + strlcpy(hw_info->dev_extn, "-skuf", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8226-tapan9302-skuf-snd-card")) { + strlcpy(hw_info->type, " tapan9302-skuf", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)tapan_lite_skuf_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_skuf_variant_devices); + strlcpy(hw_info->dev_extn, "-skuf-lite", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8x26 device", __func__); + } +} + +void *hw_info_init(const char *snd_card_name) +{ + struct hardware_info *hw_info; + + hw_info = malloc(sizeof(struct hardware_info)); + + if(strstr(snd_card_name, "msm8974") || + strstr(snd_card_name, "apq8074")) { + ALOGV("8974 - variant soundcard"); + update_hardware_info_8974(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "msm8226")) { + ALOGV("8x26 - variant soundcard"); + update_hardware_info_8226(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "msm8x10")) { + ALOGV("8x10 - variant soundcard"); + update_hardware_info_8610(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "apq8084")) { + ALOGV("8084 - variant soundcard"); + update_hardware_info_8084(hw_info, snd_card_name); + } else { + ALOGE("%s: Unupported target %s:",__func__, snd_card_name); + CHECK(0); + free(hw_info); + hw_info = NULL; + } + + return hw_info; +} + +void hw_info_deinit(void *hw_info) +{ + struct hardware_info *my_data = (struct hardware_info*) hw_info; + + if(!my_data) + free(my_data); +} + +void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, + char *device_name) +{ + struct hardware_info *my_data = (struct hardware_info*) hw_info; + uint32_t i = 0; + + snd_device_t *snd_devices = + (snd_device_t *) my_data->snd_devices; + + if(snd_devices != NULL) { + for (i = 0; i < my_data->num_snd_devices; i++) { + if (snd_device == (snd_device_t)snd_devices[i]) { + ALOGV("extract dev_extn device %d, extn = %s", + (snd_device_t)snd_devices[i], my_data->dev_extn); + CHECK(strlcat(device_name, my_data->dev_extn, + DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE); + break; + } + } + } + ALOGD("%s : device_name = %s", __func__,device_name); +} diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1734cedca..188825358 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -75,7 +75,6 @@ typedef int (*acdb_init_t)(); typedef void (*acdb_send_audio_cal_t)(int, int); typedef void (*acdb_send_voice_cal_t)(int, int); -/* Audio calibration related functions */ struct platform_data { struct audio_device *adev; bool fluence_in_spkr_mode; @@ -85,11 +84,14 @@ struct platform_data { int btsco_sample_rate; bool slowtalk; + /* Audio calibration related functions */ void *acdb_handle; acdb_init_t acdb_init; acdb_deallocate_t acdb_deallocate; acdb_send_audio_cal_t acdb_send_audio_cal; acdb_send_voice_cal_t acdb_send_voice_cal; + + void *hw_info; }; static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { @@ -204,9 +206,9 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14, [SND_DEVICE_OUT_TRANSMISSION_FM] = 0, [SND_DEVICE_OUT_ANC_HEADSET] = 26, - [SND_DEVICE_OUT_ANC_FB_HEADSET] = 26, + [SND_DEVICE_OUT_ANC_FB_HEADSET] = 27, [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26, - [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 26, + [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27, [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26, [SND_DEVICE_OUT_ANC_HANDSET] = 103, @@ -302,7 +304,8 @@ void *platform_init(struct audio_device *adev) { char value[PROPERTY_VALUE_MAX]; struct platform_data *my_data; - int retry_num = 0, ret; + int retry_num = 0; + const char *snd_card_name; adev->mixer = mixer_open(MIXER_CARD); @@ -325,6 +328,12 @@ void *platform_init(struct audio_device *adev) my_data = calloc(1, sizeof(struct platform_data)); + snd_card_name = mixer_get_name(adev->mixer); + my_data->hw_info = hw_info_init(snd_card_name); + if (!my_data->hw_info) { + ALOGE("%s: Failed to init hardware info", __func__); + } + my_data->adev = adev; my_data->btsco_sample_rate = SAMPLE_RATE_8KHZ; my_data->fluence_in_spkr_mode = false; @@ -391,6 +400,9 @@ void *platform_init(struct audio_device *adev) void platform_deinit(void *platform) { + struct platform_data *my_data = (struct platform_data *)platform; + + hw_info_deinit(my_data->hw_info); free(platform); /* deinit usb */ audio_extn_usb_deinit(); @@ -404,6 +416,22 @@ const char *platform_get_snd_device_name(snd_device_t snd_device) return ""; } +int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device, + char *device_name) +{ + struct platform_data *my_data = (struct platform_data *)platform; + + if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) { + strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE); + hw_info_append_hw_type(my_data->hw_info, snd_device, device_name); + } else { + strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE); + return -EINVAL; + } + + return 0; +} + void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) { if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 921230762..86dbe1be9 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -169,4 +169,6 @@ enum { #define LOWLATENCY_PCM_DEVICE 15 #endif +#define DEVICE_NAME_MAX_SIZE 128 +#define HW_INFO_ARRAY_MAX_SIZE 32 #endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal/platform_api.h b/hal/platform_api.h index 04049f4ff..256bb760e 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -23,6 +23,8 @@ void *platform_init(struct audio_device *adev); void platform_deinit(void *platform); const char *platform_get_snd_device_name(snd_device_t snd_device); +int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device, + char *device_name); void platform_add_backend_name(char *mixer_path, snd_device_t snd_device); int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type); int platform_send_audio_calibration(void *platform, snd_device_t snd_device); diff --git a/hal/voice.c b/hal/voice.c old mode 100755 new mode 100644 -- GitLab From a43f96ec77a3ca0d92e23e7737193889cf5c980e Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Fri, 1 Nov 2013 12:17:53 -0700 Subject: [PATCH 060/298] hal: Add missing offload changes. Compressed offload device number and entry from the device table is missing due to merge issue. Add the device number to fix offload playback issues. Change-Id: Ia3eb0e3aaef1e1a73eda5d70bb8f16711ddd182f --- hal/msm8974/platform.c | 2 ++ hal/msm8974/platform.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 188825358..44842b5c6 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -101,6 +101,8 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { LOWLATENCY_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTI_CHANNEL_PCM_DEVICE, MULTI_CHANNEL_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_OFFLOAD] = + {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE}, [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 86dbe1be9..444832fc8 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -163,6 +163,8 @@ enum { #define QCHAT_CALL_PCM_DEVICE 20 #endif +#define PLAYBACK_OFFLOAD_DEVICE 9 + #ifdef PLATFORM_MSM8610 #define LOWLATENCY_PCM_DEVICE 12 #else -- GitLab From de84f1a7fc14705b5da0567f5b1b4aae3fca634a Mon Sep 17 00:00:00 2001 From: Preetam Singh Ranawat Date: Fri, 1 Nov 2013 14:58:16 -0700 Subject: [PATCH 061/298] hal : Support for another instance of fm recording -Added support for one more instance of fm recording to play fm over a2dp. Change-Id: I0c796c5acdc045327a8d43754e7530aab10097d9 --- hal/audio_hw.c | 2 ++ hal/audio_hw.h | 1 + hal/msm8974/platform.c | 23 ++++++++++++++++------- hal/msm8974/platform.h | 2 +- hal/platform_api.h | 1 + policy_hal/AudioPolicyManager.cpp | 16 ++++++++++++++-- policy_hal/AudioPolicyManager.h | 2 ++ 7 files changed, 37 insertions(+), 10 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c00b067d2..b53892fad 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -105,6 +105,7 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", + [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", [USECASE_VOICE_CALL] = "voice-call", @@ -707,6 +708,7 @@ int start_input_stream(struct stream_in *in) struct audio_usecase *uc_info; struct audio_device *adev = in->dev; + in->usecase = platform_get_usecase_from_source(in->source); ALOGV("%s: enter: usecase(%d)", __func__, in->usecase); /* Check if source matches incall recording usecase criteria */ diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 965ac62c9..07fd027cc 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -65,6 +65,7 @@ typedef enum { /* Capture usecases */ USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_LOW_LATENCY, + USECASE_AUDIO_RECORD_FM_VIRTUAL, /* Voice usecase */ USECASE_VOICE_CALL, diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 44842b5c6..691a83374 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -98,14 +98,16 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, - LOWLATENCY_PCM_DEVICE}, - [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTI_CHANNEL_PCM_DEVICE, - MULTI_CHANNEL_PCM_DEVICE}, + LOWLATENCY_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE, + MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE}, [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, + [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE, + MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, @@ -834,10 +836,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else set_echo_reference(adev->mixer, "NONE"); } - } else if (source == AUDIO_SOURCE_FM_RX) { - if (in_device & AUDIO_DEVICE_IN_FM_RX) { - snd_device = SND_DEVICE_IN_CAPTURE_FM; - } + } else if (source == AUDIO_SOURCE_FM_RX || AUDIO_SOURCE_FM_RX_A2DP) { + snd_device = SND_DEVICE_IN_CAPTURE_FM; } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; } @@ -1127,3 +1127,12 @@ int64_t platform_render_latency(audio_usecase_t usecase) return 0; } } + +int platform_get_usecase_from_source(int source) +{ + ALOGV("%s: input source ", __func__, source); + if(AUDIO_SOURCE_FM_RX_A2DP) + return USECASE_AUDIO_RECORD_FM_VIRTUAL; + else + return USECASE_AUDIO_RECORD; +} diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 444832fc8..6ad392b52 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -146,7 +146,7 @@ enum { #define DEEP_BUFFER_PCM_DEVICE 0 #define AUDIO_RECORD_PCM_DEVICE 0 -#define MULTI_CHANNEL_PCM_DEVICE 1 +#define MULTIMEDIA2_PCM_DEVICE 1 #define VOICE_CALL_PCM_DEVICE 2 #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 diff --git a/hal/platform_api.h b/hal/platform_api.h index 256bb760e..856444de5 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -47,5 +47,6 @@ int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id) /* returns the latency for a usecase in Us */ int64_t platform_render_latency(audio_usecase_t usecase); +int platform_get_usecase_from_source(int source); #endif // QCOM_AUDIO_PLATFORM_API_H diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 5992c876b..07166569b 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -29,7 +29,7 @@ // A device mask for all audio input devices that are considered "virtual" when evaluating // active inputs in getActiveInput() -#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX +#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX | AUDIO_DEVICE_IN_FM_RX_A2DP // A device mask for all audio output devices that are considered "remote" when evaluating // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX @@ -725,9 +725,11 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource) break; #ifdef AUDIO_EXTN_FM_ENABLED case AUDIO_SOURCE_FM_RX: - case AUDIO_SOURCE_FM_RX_A2DP: device = AUDIO_DEVICE_IN_FM_RX; break; + case AUDIO_SOURCE_FM_RX_A2DP: + device = AUDIO_DEVICE_IN_FM_RX_A2DP; + break; #endif default: ALOGW("getDeviceForInputSource() invalid input source %d", inputSource); @@ -737,6 +739,16 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource) return device; } +bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device) +{ + if ((device & AUDIO_DEVICE_BIT_IN) != 0) { + device &= ~AUDIO_DEVICE_BIT_IN; + if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0)) + return true; + } + return false; +} + AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device) { switch(getDeviceForVolume(device)) { diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 7a8cfa911..2e0c6fb14 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -68,6 +68,8 @@ protected: // select input device corresponding to requested audio source virtual audio_devices_t getDeviceForInputSource(int inputSource); + static bool isVirtualInputDevice(audio_devices_t device); + // compute the actual volume for a given stream according to the requested index and a particular // device virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device); -- GitLab From 910e186c70ff7bd158800af9ebc5800db976c0de Mon Sep 17 00:00:00 2001 From: Kiran Kandi Date: Tue, 29 Oct 2013 13:29:42 -0700 Subject: [PATCH 062/298] hal: Enable support for Listen voice wakeup feature enable the support for Listen voice wakeup feature by loading listen hal library dynamically. Change-Id: Ife8e71589620342e21b4c52751466edaccc536ef --- hal/Android.mk | 6 ++ hal/audio_extn/audio_extn.c | 1 + hal/audio_extn/audio_extn.h | 24 +++++ hal/audio_extn/listen.c | 185 ++++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 35 +++++-- hal/voice.c | 7 ++ 6 files changed, 250 insertions(+), 8 deletions(-) create mode 100644 hal/audio_extn/listen.c diff --git a/hal/Android.mk b/hal/Android.mk index 6a8da100f..44e686276 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -84,6 +84,12 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \ $(LOCAL_PATH)/audio_extn +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true) + LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-listen + LOCAL_SRC_FILES += audio_extn/listen.c +endif + LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 2389f00be..98765c404 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -196,6 +196,7 @@ void audio_extn_set_parameters(struct audio_device *adev, audio_extn_set_anc_parameters(parms); audio_extn_set_afe_proxy_parameters(parms); audio_extn_fm_set_parameters(adev, parms); + audio_extn_listen_set_parameters(adev, parms); } void audio_extn_get_parameters(const struct audio_device *adev, diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 3676c0876..71b486392 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -93,4 +93,28 @@ void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, char *device_name); #endif +#ifndef AUDIO_LISTEN_ENABLED + +#define audio_extn_listen_init(adev) (0) +#define audio_extn_listen_deinit(adev) (0) +#define audio_extn_listen_update_status(uc_info, event) (0) +#define audio_extn_listen_set_parameters(adev, parms) (0) + +#else + +enum listen_event_type { + LISTEN_EVENT_AUDIO_CAPTURE_INACTIVE, + LISTEN_EVENT_AUDIO_CAPTURE_ACTIVE, +}; +typedef enum listen_event_type listen_event_type_t; + +int audio_extn_listen_init(struct audio_device *adev); +void audio_extn_listen_deinit(struct audio_device *adev); +void audio_extn_listen_update_status(struct audio_usecase *uc_info, + listen_event_type_t event); +void audio_extn_listen_set_parameters(struct audio_device *adev, + struct str_parms *parms); + +#endif /* AUDIO_LISTEN_ENABLED */ + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c new file mode 100644 index 000000000..14a427b1f --- /dev/null +++ b/hal/audio_extn/listen.c @@ -0,0 +1,185 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define LOG_TAG "listen_hal_loader" +#define LOG_NDEBUG 0 +/* #define LOG_NDDEBUG 0 */ +#include +#include +#include +#include +#ifdef AUDIO_LISTEN_ENABLED +#include +#endif +#include "audio_hw.h" +#include "audio_extn.h" +#include "platform.h" +#include "platform_api.h" + + +#ifdef AUDIO_LISTEN_ENABLED + +#define LIB_LISTEN_LOADER "/vendor/lib/liblistenhardware.so" + +#define LISTEN_LOAD_SYMBOLS(dev, func_p, func_type, symbol) \ +{\ + dev->func_p = (func_type)dlsym(dev->lib_handle,#symbol);\ + if (dev->func_p == NULL) {\ + ALOGE("%s: dlsym error %s for %s",\ + __func__, dlerror(), #symbol);\ + free(dev);\ + dev = NULL;\ + return -EINVAL;\ + }\ +} + + +typedef int (*create_listen_hw_t)(); +typedef void (*destroy_listen_hw_t)(); + +typedef int (*open_listen_session_t)(struct audio_hw_device *, + struct listen_session**); + +typedef int (*close_listen_session_t)(struct audio_hw_device *dev, + struct listen_session* handle); + +typedef int (*set_mad_observer_t)(struct audio_hw_device *dev, + listen_callback_t cb_func); + +typedef int (*listen_set_parameters_t)(struct audio_hw_device *dev, + const char *kv_pairs); +typedef char* (*get_parameters_t)(const struct audio_hw_device *dev, + const char *keys); +typedef void (*listen_notify_event_t)(event_type_t event_type); + +struct listen_audio_device { + void *lib_handle; + struct audio_device *adev; + + create_listen_hw_t create_listen_hw; + destroy_listen_hw_t destroy_listen_hw; + open_listen_session_t open_listen_session; + close_listen_session_t close_listen_session; + set_mad_observer_t set_mad_observer; + listen_set_parameters_t listen_set_parameters; + get_parameters_t get_parameters; + listen_notify_event_t notify_event; +}; + +static struct listen_audio_device *listen_dev; + +void audio_extn_listen_update_status(struct audio_usecase *uc_info, + listen_event_type_t event) +{ + if (listen_dev) { + ALOGI("%s(): current active device = %s. Event = %u", __func__, + platform_get_snd_device_name(uc_info->in_snd_device), + event); + if (uc_info->in_snd_device != SND_DEVICE_IN_CAPTURE_FM) + listen_dev->notify_event(event); + } +} + +void audio_extn_listen_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + return; +} + +int audio_extn_listen_init(struct audio_device *adev) +{ + int ret; + void *lib_handle; + + ALOGI("%s: Enter", __func__); + + lib_handle = dlopen(LIB_LISTEN_LOADER, RTLD_NOW); + + if (lib_handle == NULL) { + ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, LIB_LISTEN_LOADER, + dlerror()); + return -EINVAL; + } else { + ALOGI("%s: DLOPEN successful for %s", __func__, LIB_LISTEN_LOADER); + + listen_dev = (struct listen_audio_device*) + calloc(1, sizeof(struct listen_audio_device)); + + listen_dev->lib_handle = lib_handle; + listen_dev->adev = adev; + + LISTEN_LOAD_SYMBOLS(listen_dev, create_listen_hw, + create_listen_hw_t, create_listen_hw); + + LISTEN_LOAD_SYMBOLS(listen_dev, destroy_listen_hw, + destroy_listen_hw_t, destroy_listen_hw); + + LISTEN_LOAD_SYMBOLS(listen_dev, open_listen_session, + open_listen_session_t, open_listen_session); + + adev->device.open_listen_session = listen_dev->open_listen_session; + + LISTEN_LOAD_SYMBOLS(listen_dev, close_listen_session, + close_listen_session_t, close_listen_session); + + adev->device.close_listen_session = listen_dev->close_listen_session; + + LISTEN_LOAD_SYMBOLS(listen_dev, set_mad_observer, + set_mad_observer_t, set_mad_observer); + + adev->device.set_mad_observer = listen_dev->set_mad_observer; + + LISTEN_LOAD_SYMBOLS(listen_dev, listen_set_parameters, + listen_set_parameters_t, listen_hw_set_parameters); + + adev->device.listen_set_parameters = listen_dev->listen_set_parameters; + + LISTEN_LOAD_SYMBOLS(listen_dev, get_parameters, + get_parameters_t, listen_hw_get_parameters); + + LISTEN_LOAD_SYMBOLS(listen_dev, notify_event, + listen_notify_event_t, listen_hw_notify_event); + + listen_dev->create_listen_hw(); + } + return 0; +} + +void audio_extn_listen_deinit(struct audio_device *adev) +{ + ALOGI("%s: Enter", __func__); + + if (listen_dev && (listen_dev->adev == adev) && listen_dev->lib_handle) { + listen_dev->destroy_listen_hw(); + dlclose(listen_dev->lib_handle); + free(listen_dev); + listen_dev = NULL; + } +} + +#endif /* AUDIO_LISTEN_ENABLED */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c00b067d2..f7e742823 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -134,7 +134,8 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = { static struct audio_device *adev = NULL; static pthread_mutex_t adev_init_lock; -static bool is_adev_initialised = false; +static unsigned int audio_device_ref_count; + static int set_voice_volume_l(struct audio_device *adev, float volume); static bool is_supported_format(audio_format_t format) @@ -693,6 +694,9 @@ static int stop_input_stream(struct stream_in *in) /* 2. Disable the tx device */ disable_snd_device(adev, uc_info->in_snd_device, true); + audio_extn_listen_update_status(uc_info, + LISTEN_EVENT_AUDIO_CAPTURE_INACTIVE); + list_remove(&uc_info->list); free(uc_info); @@ -736,6 +740,9 @@ int start_input_stream(struct stream_in *in) list_add_tail(&adev->usecase_list, &uc_info->list); select_devices(adev, in->usecase); + audio_extn_listen_update_status(uc_info, + LISTEN_EVENT_AUDIO_CAPTURE_ACTIVE); + ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, SOUND_CARD, in->pcm_device_id, in->config.channels); in->pcm = pcm_open(SOUND_CARD, in->pcm_device_id, @@ -2287,10 +2294,21 @@ static int adev_dump(const audio_hw_device_t *device, int fd) static int adev_close(hw_device_t *device) { struct audio_device *adev = (struct audio_device *)device; - audio_route_free(adev->audio_route); - free(adev->snd_dev_ref_cnt); - platform_deinit(adev->platform); - free(device); + + if (!adev) + return 0; + + pthread_mutex_lock(&adev_init_lock); + + if ((--audio_device_ref_count) == 0) { + audio_route_free(adev->audio_route); + free(adev->snd_dev_ref_cnt); + platform_deinit(adev->platform); + audio_extn_listen_deinit(adev); + free(device); + adev = NULL; + } + pthread_mutex_unlock(&adev_init_lock); return 0; } @@ -2303,8 +2321,9 @@ static int adev_open(const hw_module_t *module, const char *name, if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL; pthread_mutex_lock(&adev_init_lock); - if (is_adev_initialised == true){ + if (audio_device_ref_count != 0){ *device = &adev->device.common; + audio_device_ref_count++; ALOGD("%s: returning existing instance of adev", __func__); ALOGD("%s: exit", __func__); pthread_mutex_unlock(&adev_init_lock); @@ -2372,11 +2391,11 @@ static int adev_open(const hw_module_t *module, const char *name, "visualizer_hal_stop_output"); } } + audio_extn_listen_init(adev); *device = &adev->device.common; - /* update init flag*/ - is_adev_initialised = true; + audio_device_ref_count++; pthread_mutex_unlock(&adev_init_lock); ALOGV("%s: exit", __func__); diff --git a/hal/voice.c b/hal/voice.c index 39e2dd961..907ebc911 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -31,6 +31,7 @@ #include "voice_extn/voice_extn.h" #include "platform.h" #include "platform_api.h" +#include "audio_extn.h" struct pcm_config pcm_config_voice_call = { .channels = 1, @@ -106,6 +107,9 @@ int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) disable_snd_device(adev, uc_info->out_snd_device, false); disable_snd_device(adev, uc_info->in_snd_device, true); + audio_extn_listen_update_status(uc_info, + LISTEN_EVENT_AUDIO_CAPTURE_INACTIVE); + list_remove(&uc_info->list); free(uc_info); @@ -136,6 +140,9 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) select_devices(adev, usecase_id); + audio_extn_listen_update_status(uc_info, + LISTEN_EVENT_AUDIO_CAPTURE_ACTIVE); + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); -- GitLab From ab42978617dda567a7c61ad6b4ce23d2a954c037 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Thu, 7 Nov 2013 11:16:55 -0800 Subject: [PATCH 063/298] hal: fix for audio record failures - Audio record fails because FM usecase and device are always selected for normal record. - Fix this issue by updating if condition checks for FM usecase and device. Change-Id: I9aa5cfc29bc686c351cac177b41139d138b9835a --- hal/msm8974/platform.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 691a83374..02f79fbb2 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -836,7 +836,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else set_echo_reference(adev->mixer, "NONE"); } - } else if (source == AUDIO_SOURCE_FM_RX || AUDIO_SOURCE_FM_RX_A2DP) { + } else if (source == AUDIO_SOURCE_FM_RX || + source == AUDIO_SOURCE_FM_RX_A2DP) { snd_device = SND_DEVICE_IN_CAPTURE_FM; } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; @@ -1130,8 +1131,8 @@ int64_t platform_render_latency(audio_usecase_t usecase) int platform_get_usecase_from_source(int source) { - ALOGV("%s: input source ", __func__, source); - if(AUDIO_SOURCE_FM_RX_A2DP) + ALOGV("%s: input source :%d", __func__, source); + if(source == AUDIO_SOURCE_FM_RX_A2DP) return USECASE_AUDIO_RECORD_FM_VIRTUAL; else return USECASE_AUDIO_RECORD; -- GitLab From f1d46c784a412cbf8ce6b82c4e00d4888cdd5c73 Mon Sep 17 00:00:00 2001 From: Damir Didjusto Date: Wed, 6 Nov 2013 17:59:04 -0800 Subject: [PATCH 064/298] hal: Add support for AUXPCM BT Atheros BT chip uses AUXPCM instead of slimbus. Audio HAL has to use different mixer paths file depending on whether it's internal or external BT chip Change-Id: I78ae70462fed42d4260ae37070ba23e81779c866 --- hal/Android.mk | 4 ++++ hal/audio_extn/audio_extn.c | 31 +++++++++++++++++++++++++++++++ hal/audio_extn/audio_extn.h | 8 ++++++++ hal/msm8974/platform.c | 6 +++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/hal/Android.mk b/hal/Android.mk index 44e686276..f20105c56 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -90,6 +90,10 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true) LOCAL_SRC_FILES += audio_extn/listen.c endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true) + LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED +endif + LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 98765c404..47d7c3343 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -29,6 +29,9 @@ #include "audio_hw.h" #include "audio_extn.h" +#define MAX_SLEEP_RETRY 100 +#define WIFI_INIT_WAIT_SLEEP 50 + struct audio_extn_module { bool anc_enabled; bool aanc_enabled; @@ -208,3 +211,31 @@ void audio_extn_get_parameters(const struct audio_device *adev, ALOGD("%s: returns %s", __func__, str_parms_to_str(reply)); } + +#ifdef AUXPCM_BT_ENABLED +int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card, + const char* mixer_xml_path, + const char* mixer_xml_path_auxpcm) +{ + char bt_soc[128]; + bool wifi_init_complete = false; + int sleep_retry = 0; + + while (!wifi_init_complete && sleep_retry < MAX_SLEEP_RETRY) { + property_get("qcom.bluetooth.soc", bt_soc, NULL); + if (strncmp(bt_soc, "unknown", sizeof("unknown"))) { + wifi_init_complete = true; + } else { + usleep(WIFI_INIT_WAIT_SLEEP*1000); + sleep_retry++; + } + } + + if (!strncmp(bt_soc, "ath3k", sizeof("ath3k"))) + adev->audio_route = audio_route_init(mixer_card, mixer_xml_path_auxpcm); + else + adev->audio_route = audio_route_init(mixer_card, mixer_xml_path); + + return 0; +} +#endif /* AUXPCM_BT_ENABLED */ diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 71b486392..62fbd8d90 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -117,4 +117,12 @@ void audio_extn_listen_set_parameters(struct audio_device *adev, #endif /* AUDIO_LISTEN_ENABLED */ +#ifndef AUXPCM_BT_ENABLED +#define audio_extn_read_xml(adev, MIXER_CARD, MIXER_XML_PATH, \ + MIXER_XML_PATH_AUXPCM) (-ENOSYS) +#else +int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card, + const char* mixer_xml_path, + const char* mixer_xml_path_auxpcm); +#endif /* AUXPCM_BT_ENABLED */ #endif /* AUDIO_EXTN_H */ diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 691a83374..359e56c1c 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -32,6 +32,7 @@ #include "audio_extn.h" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" +#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" #define LIB_ACDB_LOADER "libacdbloader.so" #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" @@ -324,7 +325,10 @@ void *platform_init(struct audio_device *adev) return NULL; } - adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); + if (audio_extn_read_xml(adev, MIXER_CARD, MIXER_XML_PATH, + MIXER_XML_PATH_AUXPCM) == -ENOSYS) + adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); + if (!adev->audio_route) { ALOGE("%s: Failed to init audio route controls, aborting.", __func__); return NULL; -- GitLab From fae4211e4faffcca50ce7cd6a0ab6d76f67ef5e9 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Thu, 7 Nov 2013 23:31:54 -0800 Subject: [PATCH 065/298] hal: Fix audio playback issue on USB headset - Start music playback on USB headset. The playback is stopped after 3sec. - A touch tone is played through low latency output path, while selecting the song in the music app. This output goes to standy after 3sec. So the disable_snd_device() is called to reduce the ref count on usb headset device by 1. At this point the music playback (deep-buffer path) is still active. But the current implementation has uncondtionally calls usb_stop_playback() which results music playback to stop. - Fix by ensuring the usb_stop_playback is called only when the device ref count goes to 0. - Fix related minor stabilty issues Change-Id: I979423458738e68da45973751cd918d4c1a924ea CRs-Fixed: 572048 --- hal/audio_extn/usb.c | 5 +++- hal/audio_hw.c | 54 ++++++++++++++++++++++++++++-------------- hal/msm8974/platform.c | 2 +- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c index 5b045ea73..88af9bef2 100644 --- a/hal/audio_extn/usb.c +++ b/hal/audio_extn/usb.c @@ -127,7 +127,7 @@ static int usb_get_capability(char *type, int32_t *channels, char *read_buf, *str_start, *channel_start, *rates_str, *rates_str_for_val, *rates_str_start, *next_sr_str, *test, *next_sr_string, *temp_ptr; struct stat st; - int rates_supported[size]; + int *rates_supported; char path[128]; memset(&st, 0x0, sizeof(struct stat)); @@ -246,12 +246,14 @@ static int usb_get_capability(char *type, int32_t *channels, return -EINVAL; } + rates_supported = (int *)malloc(sizeof(int) * size); next_sr_string = strtok_r(rates_str_for_val, " ,", &temp_ptr); if (next_sr_string == NULL) { ALOGE("%s: error could not get first rate val", __func__); close(fd); free(rates_str_for_val); free(rates_str); + free(rates_supported); free(read_buf); return -EINVAL; } @@ -282,6 +284,7 @@ static int usb_get_capability(char *type, int32_t *channels, close(fd); free(rates_str_for_val); free(rates_str); + free(rates_supported); free(read_buf); return 0; } diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 59e7c8622..74217b75f 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -285,15 +285,6 @@ int disable_snd_device(struct audio_device *adev, adev->snd_dev_ref_cnt[snd_device]--; - /* exit usb play back thread */ - if(SND_DEVICE_OUT_USB_HEADSET == snd_device || - SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device) - audio_extn_usb_stop_playback(); - - /* exit usb capture thread */ - if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) - audio_extn_usb_stop_capture(adev); - if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) { ALOGE("%s: Invalid sound device returned", __func__); return -EINVAL; @@ -302,7 +293,17 @@ int disable_snd_device(struct audio_device *adev, if (adev->snd_dev_ref_cnt[snd_device] == 0) { ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, device_name); + /* exit usb play back thread */ + if(SND_DEVICE_OUT_USB_HEADSET == snd_device || + SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device) + audio_extn_usb_stop_playback(); + + /* exit usb capture thread */ + if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) + audio_extn_usb_stop_capture(adev); + audio_route_reset_path(adev->audio_route, device_name); + if (update_mixer) audio_route_update_mixer(adev->audio_route); } @@ -1094,9 +1095,18 @@ static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count) { - if (format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; + int ret = 0; - if ((channel_count < 1) || (channel_count > 6)) return -EINVAL; + if (format != AUDIO_FORMAT_PCM_16_BIT) ret = -EINVAL; + + switch (channel_count) { + case 1: + case 2: + case 6: + break; + default: + ret = -EINVAL; + } switch (sample_rate) { case 8000: @@ -1110,10 +1120,10 @@ static int check_input_parameters(uint32_t sample_rate, case 48000: break; default: - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } static size_t get_input_buffer_size(uint32_t sample_rate, @@ -2214,7 +2224,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, { struct audio_device *adev = (struct audio_device *)dev; struct stream_in *in; - int ret, buffer_size, frame_size; + int ret = 0, buffer_size, frame_size; int channel_count = popcount(config->channel_mask); ALOGV("%s: enter", __func__); @@ -2251,9 +2261,17 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->config = pcm_config_audio_capture; in->config.rate = config->sample_rate; - if (audio_extn_ssr_get_enabled()&& channel_count == 6) { - if(audio_extn_ssr_init(adev, in)) - ALOGE("%s: audio_extn_ssr_init failed", __func__); + if (channel_count == 6) { + if(audio_extn_ssr_get_enabled()) { + if(audio_extn_ssr_init(adev, in)) { + ALOGE("%s: audio_extn_ssr_init failed", __func__); + ret = -EINVAL; + goto err_open; + } + } else { + ret = -EINVAL; + goto err_open; + } } else { in->config.channels = channel_count; frame_size = audio_stream_frame_size((struct audio_stream *)in); @@ -2265,7 +2283,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, *stream_in = &in->stream; ALOGV("%s: exit", __func__); - return 0; + return ret; err_open: free(in); diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 800ac76ae..47f14e6bc 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -858,7 +858,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { if (audio_extn_ssr_get_enabled() && channel_count == 6) snd_device = SND_DEVICE_IN_QUAD_MIC; - else if (channel_count > 1) + else if (channel_count == 2) snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC; else snd_device = SND_DEVICE_IN_HANDSET_MIC; -- GitLab From f538cefc0747e6bc2cff296ad295f6a37e17f7a5 Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Mon, 28 Oct 2013 14:06:03 -0700 Subject: [PATCH 066/298] hal: Add support for speaker protection - Speaker protection feature protects the speaker from overheating. Change-Id: Ida4899534124eba203025915beba662e88a0f403 --- hal/Android.mk | 7 + hal/audio_extn/audio_extn.h | 12 + hal/audio_extn/spkr_protection.c | 677 +++++++++++++++++++++++++++++++ hal/audio_hw.c | 33 +- hal/audio_hw.h | 8 + hal/msm8974/platform.c | 9 +- hal/msm8974/platform.h | 4 + 7 files changed, 738 insertions(+), 12 deletions(-) create mode 100644 hal/audio_extn/spkr_protection.c diff --git a/hal/Android.mk b/hal/Android.mk index f20105c56..8bbfa6992 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -60,7 +60,14 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS)),true) ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED endif +endif +ifneq ($(strip, $(AUDIO_FEATURE_DISABLED_SPKR_PROTECTION)),true) +ifneq ($(filter msm8974,$(TARGET_BOARD_PLATFORM)),) + LOCAL_CFLAGS += -DSPKR_PROT_ENABLED + LOCAL_SRC_FILES += audio_extn/spkr_protection.c + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +endif endif ifdef MULTIPLE_HW_VARIANTS_ENABLED diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 62fbd8d90..a54e5e7e1 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -125,4 +125,16 @@ int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card, const char* mixer_xml_path, const char* mixer_xml_path_auxpcm); #endif /* AUXPCM_BT_ENABLED */ +#ifndef SPKR_PROT_ENABLED +#define audio_extn_spkr_prot_init(adev) (0) +#define audio_extn_spkr_prot_start_processing(snd_device) (-EINVAL) +#define audio_extn_spkr_prot_stop_processing() (0) +#define audio_extn_spkr_prot_is_enabled() (false) +#else +void audio_extn_spkr_prot_init(void *adev); +int audio_extn_spkr_prot_start_processing(snd_device_t snd_device); +void audio_extn_spkr_prot_stop_processing(); +bool audio_extn_spkr_prot_is_enabled(); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c new file mode 100644 index 000000000..0fc790aa0 --- /dev/null +++ b/hal/audio_extn/spkr_protection.c @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "audio_hw_spkr_prot" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" +#include +#include +#include +#include +#include +#include "audio_extn.h" +#include + +#ifdef SPKR_PROT_ENABLED + +/*Range of spkr temparatures -30C to 80C*/ +#define MIN_SPKR_TEMP_Q6 (-30 * (1 << 6)) +#define MAX_SPKR_TEMP_Q6 (80 * (1 << 6)) + +/*Set safe temp value to 40C*/ +#define SAFE_SPKR_TEMP 40 +#define SAFE_SPKR_TEMP_Q6 (SAFE_SPKR_TEMP * (1 << 6)) + +/*Range of resistance values 2ohms to 40 ohms*/ +#define MIN_RESISTANCE_SPKR_Q24 (2 * (1 << 24)) +#define MAX_RESISTANCE_SPKR_Q24 (40 * (1 << 24)) + +/*Path where the calibration file will be stored*/ +#define CALIB_FILE "/data/misc/audio/audio.cal" + +/*Time between retries for calibartion or intial wait time + after boot up*/ +#define WAIT_TIME_SPKR_CALIB (60 * 1000 * 1000) + +#define MIN_SPKR_IDLE_SEC (60 * 30) + +/*Once calibration is started sleep for 1 sec to allow + the calibration to kick off*/ +#define SLEEP_AFTER_CALIB_START (3000) + +/*If calibration is in progress wait for 200 msec before querying + for status again*/ +#define WAIT_FOR_GET_CALIB_STATUS (200 * 1000) + +/*Speaker states*/ +#define SPKR_NOT_CALIBRATED -1 +#define SPKR_CALIBRATED 1 + +/*Speaker processing state*/ +#define SPKR_PROCESSING_IN_PROGRESS 1 +#define SPKR_PROCESSING_IN_IDLE 0 + +/*Modes of Speaker Protection*/ +enum speaker_protection_mode { + SPKR_PROTECTION_DISABLED = -1, + SPKR_PROTECTION_MODE_PROCESSING = 0, + SPKR_PROTECTION_MODE_CALIBRATE = 1, +}; + +struct speaker_prot_session { + int spkr_prot_mode; + int spkr_processing_state; + int thermal_client_handle; + pthread_mutex_t mutex_spkr_prot; + pthread_t spkr_calibration_thread; + pthread_mutex_t spkr_prot_thermalsync_mutex; + pthread_cond_t spkr_prot_thermalsync; + int cancel_spkr_calib; + pthread_cond_t spkr_calib_cancel; + pthread_mutex_t spkr_calib_cancelack_mutex; + pthread_cond_t spkr_calibcancel_ack; + pthread_t speaker_prot_threadid; + void *thermal_handle; + void *adev_handle; + int spkr_prot_t0; + struct pcm *pcm_rx; + struct pcm *pcm_tx; + int (*client_register_callback) + (char *client_name, int (*callback)(int, void *, void *), void *data); + void (*thermal_client_unregister_callback)(int handle); + int (*thermal_client_request)(char *client_name, int req_data); + bool spkr_prot_enable; + bool spkr_in_use; + struct timespec spkr_last_time_used; +}; + +static struct pcm_config pcm_config_skr_prot = { + .channels = 2, + .rate = 48000, + .period_size = 256, + .period_count = 4, + .format = PCM_FORMAT_S16_LE, + .start_threshold = 0, + .stop_threshold = INT_MAX, + .avail_min = 0, +}; + +static struct speaker_prot_session handle; + +static void spkr_prot_set_spkrstatus(bool enable) +{ + struct timespec ts; + if (enable) + handle.spkr_in_use = true; + else { + handle.spkr_in_use = false; + clock_gettime(CLOCK_MONOTONIC, &handle.spkr_last_time_used); + } +} + +static void spkr_prot_calib_cancel(void *adev) +{ + pthread_t threadid; + struct audio_usecase *uc_info; + int count = 0; + threadid = pthread_self(); + ALOGV("%s: Entry", __func__); + if (pthread_equal(handle.speaker_prot_threadid, threadid) || !adev) { + ALOGE("%s: Invalid params", __func__); + return; + } + uc_info = get_usecase_from_list(adev, USECASE_AUDIO_SPKR_CALIB_RX); + if (uc_info) { + pthread_mutex_lock(&handle.mutex_spkr_prot); + pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex); + handle.cancel_spkr_calib = 1; + pthread_cond_signal(&handle.spkr_calib_cancel); + pthread_mutex_unlock(&handle.mutex_spkr_prot); + pthread_cond_wait(&handle.spkr_calibcancel_ack, + &handle.spkr_calib_cancelack_mutex); + pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex); + pthread_mutex_unlock(&handle.mutex_spkr_prot); + } + ALOGV("%s: Exit", __func__); +} + +static bool is_speaker_in_use(unsigned long *sec) +{ + struct timespec temp; + if (!sec) { + ALOGE("%s: Invalid params", __func__); + return true; + } + if (handle.spkr_in_use) { + *sec = 0; + return true; + } else { + clock_gettime(CLOCK_MONOTONIC, &temp); + *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec; + return false; + } +} + + +static int spkr_calibrate(int t0) +{ + struct audio_device *adev = handle.adev_handle; + struct msm_spk_prot_cfg protCfg; + struct msm_spk_prot_status status; + bool cleanup = false, disable_rx = false, disable_tx = false; + int acdb_fd = -1; + struct audio_usecase *uc_info_rx = NULL, *uc_info_tx = NULL; + int32_t pcm_dev_rx_id = -1, pcm_dev_tx_id = -1; + struct timespec ts; + + if (!adev) { + ALOGE("%s: Invalid params", __func__); + return -EINVAL; + } + if (!list_empty(&adev->usecase_list)) { + ALOGD("%s: Usecase present retry speaker protection", __func__); + return -EAGAIN; + } + acdb_fd = open("/dev/msm_acdb",O_RDWR | O_NONBLOCK); + if (acdb_fd < 0) { + ALOGE("%s: spkr_prot_thread open msm_acdb failed", __func__); + return -ENODEV; + } else { + protCfg.mode = MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS; + protCfg.t0 = t0; + if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) { + ALOGE("%s: spkr_prot_thread set failed AUDIO_SET_SPEAKER_PROT", + __func__); + status.status = -ENODEV; + goto exit; + } + } + uc_info_rx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info_rx->id = USECASE_AUDIO_SPKR_CALIB_RX; + uc_info_rx->type = PCM_PLAYBACK; + uc_info_rx->in_snd_device = SND_DEVICE_NONE; + uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED; + pthread_mutex_lock(&adev->lock); + disable_rx = true; + enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED, true); + enable_audio_route(adev, uc_info_rx, true); + pthread_mutex_unlock(&adev->lock); + + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info_rx->id, PCM_PLAYBACK); + ALOGV("%s: pcm device id %d", __func__, pcm_dev_rx_id); + if (pcm_dev_rx_id < 0) { + ALOGE("%s: Invalid pcm device for usecase (%d)", + __func__, uc_info_rx->id); + status.status = -ENODEV; + goto exit; + } + handle.pcm_rx = handle.pcm_tx = NULL; + handle.pcm_rx = pcm_open(SOUND_CARD, pcm_dev_rx_id, + PCM_OUT, &pcm_config_skr_prot); + if (handle.pcm_rx && !pcm_is_ready(handle.pcm_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_rx)); + status.status = -EIO; + goto exit; + } + uc_info_tx = (struct audio_usecase *) + calloc(1, sizeof(struct audio_usecase)); + uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX; + uc_info_tx->type = PCM_CAPTURE; + uc_info_tx->in_snd_device = SND_DEVICE_NONE; + uc_info_tx->out_snd_device = SND_DEVICE_NONE; + + pthread_mutex_lock(&adev->lock); + disable_tx = true; + enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); + enable_audio_route(adev, uc_info_tx, true); + pthread_mutex_unlock(&adev->lock); + + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE); + if (pcm_dev_tx_id < 0) { + ALOGE("%s: Invalid pcm device for usecase (%d)", + __func__, uc_info_tx->id); + status.status = -ENODEV; + goto exit; + } + handle.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id, + PCM_IN, &pcm_config_skr_prot); + if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx)); + status.status = -EIO; + goto exit; + } + if (pcm_start(handle.pcm_rx) < 0) { + ALOGE("%s: pcm start for RX failed", __func__); + status.status = -EINVAL; + goto exit; + } + if (pcm_start(handle.pcm_tx) < 0) { + ALOGE("%s: pcm start for TX failed", __func__); + status.status = -EINVAL; + goto exit; + } + cleanup = true; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (SLEEP_AFTER_CALIB_START/1000); + ts.tv_nsec = 0; + (void)pthread_cond_timedwait(&handle.spkr_calib_cancel, + &handle.mutex_spkr_prot, &ts); + ALOGD("%s: Speaker calibration done", __func__); + cleanup = true; + pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex); + if (handle.cancel_spkr_calib) { + status.status = -EAGAIN; + goto exit; + } + if (acdb_fd > 0) { + status.status = -EINVAL; + while (!ioctl(acdb_fd, AUDIO_GET_SPEAKER_PROT,&status)) { + /*sleep for 200 ms to check for status check*/ + if (!status.status) { + ALOGD("%s: spkr_prot_thread calib Success R0 %d", + __func__, status.r0); + FILE *fp; + fp = fopen(CALIB_FILE,"wb"); + if (!fp) { + ALOGE("%s: spkr_prot_thread File open failed %s", + __func__, strerror(errno)); + status.status = -ENODEV; + } else { + fwrite(&status.r0, sizeof(status.r0),1,fp); + fwrite(&protCfg.t0, sizeof(protCfg.t0),1,fp); + fclose(fp); + } + break; + } else if (status.status == -EAGAIN) { + ALOGD("%s: spkr_prot_thread try again", __func__); + usleep(WAIT_FOR_GET_CALIB_STATUS); + } else { + ALOGE("%s: spkr_prot_thread get failed status %d", + __func__, status.status); + break; + } + } +exit: + if (handle.pcm_rx) + pcm_close(handle.pcm_rx); + handle.pcm_rx = NULL; + if (handle.pcm_tx) + pcm_close(handle.pcm_tx); + handle.pcm_tx = NULL; + pthread_mutex_lock(&adev->lock); + if (disable_rx) { + disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED, true); + disable_audio_route(adev, uc_info_rx, true); + } + if (disable_tx) { + disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); + disable_audio_route(adev, uc_info_tx, true); + } + pthread_mutex_unlock(&adev->lock); + + if (!status.status) { + protCfg.mode = MSM_SPKR_PROT_CALIBRATED; + protCfg.r0 = status.r0; + if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) + ALOGE("%s: spkr_prot_thread disable calib mode", __func__); + else + handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED; + } else { + protCfg.mode = MSM_SPKR_PROT_NOT_CALIBRATED; + handle.spkr_prot_mode = MSM_SPKR_PROT_NOT_CALIBRATED; + if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) + ALOGE("%s: spkr_prot_thread disable calib mode failed", __func__); + } + if (acdb_fd > 0) + close(acdb_fd); + if (uc_info_rx) free(uc_info_rx); + if (uc_info_tx) free(uc_info_tx); + if (cleanup) { + if (handle.cancel_spkr_calib) + pthread_cond_signal(&handle.spkr_calibcancel_ack); + handle.cancel_spkr_calib = 0; + pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex); + } + } + return status.status; +} + +static void* spkr_calibration_thread(void *context) +{ + unsigned long sec = 0; + int t0; + bool goahead = false; + struct msm_spk_prot_cfg protCfg; + FILE *fp; + int acdb_fd; + struct audio_device *adev = handle.adev_handle; + + handle.speaker_prot_threadid = pthread_self(); + ALOGD("spkr_prot_thread enable prot Entry"); + acdb_fd = open("/dev/msm_acdb",O_RDWR | O_NONBLOCK); + if (acdb_fd > 0) { + /*Set processing mode with t0/r0*/ + protCfg.mode = MSM_SPKR_PROT_NOT_CALIBRATED; + if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) { + ALOGE("%s: spkr_prot_thread enable prot failed", __func__); + handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED; + close(acdb_fd); + } else + handle.spkr_prot_mode = MSM_SPKR_PROT_NOT_CALIBRATED; + } else { + handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED; + ALOGE("%s: Failed to open acdb node", __func__); + } + if (handle.spkr_prot_mode == MSM_SPKR_PROT_DISABLED) { + ALOGD("%s: Speaker protection disabled", __func__); + pthread_exit(0); + return NULL; + } + + fp = fopen(CALIB_FILE,"rb"); + if (fp) { + fread(&protCfg.r0,sizeof(protCfg.r0),1,fp); + ALOGD("%s: spkr_prot_thread r0 value %d", __func__, protCfg.r0); + fread(&protCfg.t0, sizeof(protCfg.t0), 1, fp); + ALOGD("%s: spkr_prot_thread t0 value %d", __func__, protCfg.t0); + fclose(fp); + /*Valid tempature range: -30C to 80C(in q6 format) + Valid Resistance range: 2 ohms to 40 ohms(in q24 format)*/ + if (protCfg.t0 > MIN_SPKR_TEMP_Q6 && + protCfg.t0 < MAX_SPKR_TEMP_Q6 && + protCfg.r0 >= MIN_RESISTANCE_SPKR_Q24 + && protCfg.r0 < MAX_RESISTANCE_SPKR_Q24) { + ALOGD("%s: Spkr calibrated", __func__); + protCfg.mode = MSM_SPKR_PROT_CALIBRATED; + if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) { + ALOGE("%s: enable prot failed", __func__); + handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED; + } else + handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED; + close(acdb_fd); + pthread_exit(0); + return NULL; + } + close(acdb_fd); + } + + while (1) { + ALOGV("%s: start calibration", __func__); + if (!handle.thermal_client_request("spkr",1)) { + ALOGD("%s: wait for callback from thermal daemon", __func__); + pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex); + pthread_cond_wait(&handle.spkr_prot_thermalsync, + &handle.spkr_prot_thermalsync_mutex); + /*Convert temp into q6 format*/ + t0 = (handle.spkr_prot_t0 * (1 << 6)); + pthread_mutex_unlock(&handle.spkr_prot_thermalsync_mutex); + if (t0 < MIN_SPKR_TEMP_Q6 || t0 > MAX_SPKR_TEMP_Q6) { + ALOGE("%s: Calibration temparature error %d", __func__, + handle.spkr_prot_t0); + continue; + } + ALOGD("%s: Request t0 success value %d", __func__, + handle.spkr_prot_t0); + } else { + ALOGE("%s: Request t0 failed", __func__); + /*Assume safe value for temparature*/ + t0 = SAFE_SPKR_TEMP_Q6; + } + goahead = false; + pthread_mutex_lock(&handle.mutex_spkr_prot); + if (is_speaker_in_use(&sec)) { + ALOGD("%s: Speaker in use retry calibration", __func__); + pthread_mutex_unlock(&handle.mutex_spkr_prot); + continue; + } else { + ALOGD("%s: speaker idle %ld", __func__, sec); + if (sec < MIN_SPKR_IDLE_SEC) { + ALOGD("%s: speaker idle is less retry", __func__); + pthread_mutex_unlock(&handle.mutex_spkr_prot); + continue; + } + goahead = true; + } + if (!list_empty(&adev->usecase_list)) + goahead = false; + if (goahead) { + int status; + status = spkr_calibrate(t0); + if (status == -EAGAIN) { + ALOGE("%s: failed to calibrate try again %s", + __func__, strerror(status)); + pthread_mutex_unlock(&handle.mutex_spkr_prot); + continue; + } else { + ALOGE("%s: calibrate status %s", __func__, strerror(status)); + } + ALOGD("%s: spkr_prot_thread end calibration", __func__); + pthread_mutex_unlock(&handle.mutex_spkr_prot); + break; + } + } + if (handle.thermal_client_handle) + handle.thermal_client_unregister_callback(handle.thermal_client_handle); + handle.thermal_client_handle = 0; + if (handle.thermal_handle) + dlclose(handle.thermal_handle); + handle.thermal_handle = NULL; + pthread_exit(0); + return NULL; +} + +static int thermal_client_callback(int temp, void *user_data, void *reserved) +{ + pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex); + ALOGD("%s: spkr_prot set t0 %d and signal", __func__, temp); + if (handle.spkr_prot_mode == MSM_SPKR_PROT_NOT_CALIBRATED) + handle.spkr_prot_t0 = temp; + pthread_cond_signal(&handle.spkr_prot_thermalsync); + pthread_mutex_unlock(&handle.spkr_prot_thermalsync_mutex); + return 0; +} + +void audio_extn_spkr_prot_init(void *adev) +{ + char value[PROPERTY_VALUE_MAX]; + ALOGD("%s: Initialize speaker protection module", __func__); + memset(&handle, 0, sizeof(handle)); + if (!adev) { + ALOGE("%s: Invalid params", __func__); + return; + } + property_get("persist.speaker.prot.enable", value, ""); + handle.spkr_prot_enable = false; + if (!strncmp("true", value, 4)) + handle.spkr_prot_enable = true; + if (!handle.spkr_prot_enable) { + ALOGD("%s: Speaker protection disabled", __func__); + return; + } + handle.adev_handle = adev; + handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED; + handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE; + handle.spkr_prot_t0 = -1; + pthread_cond_init(&handle.spkr_prot_thermalsync, NULL); + pthread_cond_init(&handle.spkr_calib_cancel, NULL); + pthread_cond_init(&handle.spkr_calibcancel_ack, NULL); + pthread_mutex_init(&handle.mutex_spkr_prot, NULL); + pthread_mutex_init(&handle.spkr_calib_cancelack_mutex, NULL); + pthread_mutex_init(&handle.spkr_prot_thermalsync_mutex, NULL); + handle.thermal_handle = dlopen("/vendor/lib/libthermalclient.so", + RTLD_NOW); + if (!handle.thermal_handle) { + ALOGE("%s: DLOPEN for thermal client failed", __func__); + } else { + /*Query callback function symbol*/ + handle.client_register_callback = + (int (*)(char *, int (*)(int, void *, void *),void *)) + dlsym(handle.thermal_handle, "thermal_client_register_callback"); + handle.thermal_client_unregister_callback = + (void (*)(int) ) + dlsym(handle.thermal_handle, "thermal_client_unregister_callback"); + if (!handle.client_register_callback || + !handle.thermal_client_unregister_callback) { + ALOGE("%s: DLSYM thermal_client_register_callback failed", __func__); + } else { + /*Register callback function*/ + handle.thermal_client_handle = + handle.client_register_callback("spkr", thermal_client_callback, NULL); + if (!handle.thermal_client_handle) { + ALOGE("%s: client_register_callback failed", __func__); + } else { + ALOGD("%s: spkr_prot client_register_callback success", __func__); + handle.thermal_client_request = (int (*)(char *, int)) + dlsym(handle.thermal_handle, "thermal_client_request"); + } + } + } + if (handle.thermal_client_request) { + ALOGD("%s: Create calibration thread", __func__); + (void)pthread_create(&handle.spkr_calibration_thread, + (const pthread_attr_t *) NULL, spkr_calibration_thread, &handle); + } else { + ALOGE("%s: thermal_client_request failed", __func__); + if (handle.thermal_client_handle) + handle.thermal_client_unregister_callback(handle.thermal_client_handle); + if (handle.thermal_handle) + dlclose(handle.thermal_handle); + handle.thermal_handle = NULL; + handle.spkr_prot_enable = false; + } +} + +int audio_extn_spkr_prot_start_processing(snd_device_t snd_device) +{ + struct audio_usecase uc_info_tx; + struct audio_device *adev = handle.adev_handle; + int32_t pcm_dev_tx_id = -1, ret = 0; + + ALOGV("%s: Entry", __func__); + /* cancel speaker calibration */ + if (!adev) { + ALOGE("%s: Invalid params", __func__); + return -EINVAL; + } + spkr_prot_calib_cancel(adev); + spkr_prot_set_spkrstatus(true); + if (platform_send_audio_calibration(adev->platform, + SND_DEVICE_OUT_SPEAKER_PROTECTED) < 0) { + adev->snd_dev_ref_cnt[snd_device]--; + return -EINVAL; + } + ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, + platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED)); + audio_route_apply_path(adev->audio_route, + platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED)); + + pthread_mutex_lock(&handle.mutex_spkr_prot); + if (handle.spkr_processing_state == SPKR_PROCESSING_IN_IDLE) { + memset(&uc_info_tx, 0 , sizeof(uc_info_tx)); + uc_info_tx.id = USECASE_AUDIO_SPKR_CALIB_TX; + uc_info_tx.type = PCM_CAPTURE; + uc_info_tx.in_snd_device = SND_DEVICE_NONE; + uc_info_tx.out_snd_device = SND_DEVICE_NONE; + handle.pcm_tx = NULL; + + enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); + enable_audio_route(adev, &uc_info_tx, true); + + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx.id, PCM_CAPTURE); + if (pcm_dev_tx_id < 0) { + ALOGE("%s: Invalid pcm device for usecase (%d)", + __func__, uc_info_tx.id); + ret = -ENODEV; + goto exit; + } + handle.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id, + PCM_IN, &pcm_config_skr_prot); + if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx)); + ret = -EIO; + goto exit; + } + if (pcm_start(handle.pcm_tx) < 0) { + ALOGE("%s: pcm start for TX failed", __func__); + ret = -EINVAL; + } + } +exit: + if (ret) { + if (handle.pcm_tx) + pcm_close(handle.pcm_tx); + handle.pcm_tx = NULL; + disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); + disable_audio_route(adev, &uc_info_tx, true); + } else + handle.spkr_processing_state = SPKR_PROCESSING_IN_PROGRESS; + pthread_mutex_unlock(&handle.mutex_spkr_prot); + ALOGV("%s: Exit", __func__); + return ret; +} + +void audio_extn_spkr_prot_stop_processing() +{ + struct audio_usecase uc_info_tx; + struct audio_device *adev = handle.adev_handle; + ALOGV("%s: Entry", __func__); + spkr_prot_set_spkrstatus(false); + pthread_mutex_lock(&handle.mutex_spkr_prot); + if (adev && handle.spkr_processing_state == SPKR_PROCESSING_IN_PROGRESS) { + memset(&uc_info_tx, 0 , sizeof(uc_info_tx)); + uc_info_tx.id = USECASE_AUDIO_SPKR_CALIB_TX; + uc_info_tx.type = PCM_CAPTURE; + uc_info_tx.in_snd_device = SND_DEVICE_NONE; + uc_info_tx.out_snd_device = SND_DEVICE_NONE; + if (handle.pcm_tx) + pcm_close(handle.pcm_tx); + handle.pcm_tx = NULL; + disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); + disable_audio_route(adev, &uc_info_tx, true); + } + handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE; + pthread_mutex_unlock(&handle.mutex_spkr_prot); + audio_route_reset_path(adev->audio_route, + platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED)); + ALOGV("%s: Exit", __func__); +} + +bool audio_extn_spkr_prot_is_enabled() +{ + return handle.spkr_prot_enable; +} +#endif /*SPKR_PROT_ENABLED*/ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 74217b75f..a90caa4ad 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -117,6 +117,8 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink", [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", + [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib", + [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record", }; @@ -166,7 +168,7 @@ static int get_snd_codec_id(audio_format_t format) return id; } -static int enable_audio_route(struct audio_device *adev, +int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, bool update_mixer) { @@ -220,7 +222,7 @@ int disable_audio_route(struct audio_device *adev, return 0; } -static int enable_snd_device(struct audio_device *adev, +int enable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool update_mixer) { @@ -253,14 +255,21 @@ static int enable_snd_device(struct audio_device *adev, if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) audio_extn_usb_start_capture(adev); - if (platform_send_audio_calibration(adev->platform, snd_device) < 0) { - adev->snd_dev_ref_cnt[snd_device]--; - return -EINVAL; + if (snd_device == SND_DEVICE_OUT_SPEAKER && + audio_extn_spkr_prot_is_enabled()) { + if (audio_extn_spkr_prot_start_processing(snd_device)) { + ALOGE("%s: spkr_start_processing failed", __func__); + return -EINVAL; + } + } else { + ALOGV("%s: snd_device(%d: %s)", __func__, + snd_device, device_name); + if (platform_send_audio_calibration(adev->platform, snd_device) < 0) { + adev->snd_dev_ref_cnt[snd_device]--; + return -EINVAL; + } + audio_route_apply_path(adev->audio_route, device_name); } - - ALOGV("%s: snd_device(%d: %s)", __func__, - snd_device, device_name); - audio_route_apply_path(adev->audio_route, device_name); if (update_mixer) audio_route_update_mixer(adev->audio_route); @@ -302,7 +311,11 @@ int disable_snd_device(struct audio_device *adev, if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) audio_extn_usb_stop_capture(adev); - audio_route_reset_path(adev->audio_route, device_name); + if (snd_device == SND_DEVICE_OUT_SPEAKER && + audio_extn_spkr_prot_is_enabled()) { + audio_extn_spkr_prot_stop_processing(); + } else + audio_route_reset_path(adev->audio_route, device_name); if (update_mixer) audio_route_update_mixer(adev->audio_route); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 07fd027cc..68e40ce4b 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -82,6 +82,8 @@ typedef enum { USECASE_INCALL_MUSIC_UPLINK, USECASE_INCALL_MUSIC_UPLINK2, + USECASE_AUDIO_SPKR_CALIB_RX, + USECASE_AUDIO_SPKR_CALIB_TX, AUDIO_USECASE_MAX } audio_usecase_t; @@ -223,6 +225,12 @@ int disable_audio_route(struct audio_device *adev, int disable_snd_device(struct audio_device *adev, snd_device_t snd_device, bool update_mixer); +int enable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer); +int enable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer); struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id); /* diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 47f14e6bc..5229f9a2b 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -84,7 +84,6 @@ struct platform_data { int fluence_type; int btsco_sample_rate; bool slowtalk; - /* Audio calibration related functions */ void *acdb_handle; acdb_init_t acdb_init; @@ -124,6 +123,8 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { INCALL_MUSIC_UPLINK_PCM_DEVICE}, [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE, INCALL_MUSIC_UPLINK2_PCM_DEVICE}, + [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1}, + [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE}, }; /* Array to store sound devices */ @@ -156,6 +157,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones", [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones", [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset", + [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected", /* Capture sound devices */ [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", @@ -185,6 +187,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_QUAD_MIC] = "quad-mic", [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef", [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef", + [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback", }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ @@ -216,6 +219,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27, [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26, [SND_DEVICE_OUT_ANC_HANDSET] = 103, + [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101, [SND_DEVICE_IN_HANDSET_MIC] = 4, [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */ @@ -245,6 +249,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { /* TODO: Update with proper acdb ids */ [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, + [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102, }; #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) @@ -402,7 +407,7 @@ void *platform_init(struct audio_device *adev) /* Read one time ssr property */ audio_extn_ssr_update_enabled(adev); - + audio_extn_spkr_prot_init(adev); return my_data; } diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 6ad392b52..93dafa59c 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -71,6 +71,7 @@ enum { SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET, SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, SND_DEVICE_OUT_ANC_HANDSET, + SND_DEVICE_OUT_SPEAKER_PROTECTED, SND_DEVICE_OUT_END, /* @@ -107,6 +108,7 @@ enum { SND_DEVICE_IN_QUAD_MIC, SND_DEVICE_IN_HANDSET_STEREO_DMIC, SND_DEVICE_IN_SPEAKER_STEREO_DMIC, + SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, SND_DEVICE_IN_END, SND_DEVICE_MAX = SND_DEVICE_IN_END, @@ -152,6 +154,8 @@ enum { #define FM_CAPTURE_PCM_DEVICE 6 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 +#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 +#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22 #ifdef PLATFORM_MSM8x26 #define VOICE2_CALL_PCM_DEVICE 14 -- GitLab From ceb408232dd9328e84ed07c808c9025194786f5d Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 6 Nov 2013 11:01:47 -0800 Subject: [PATCH 067/298] hal: Remove mobile carrier specific ACDB devices - There is no specific ACDB existing for T-Mobile on all A/B-family targets. - The T-mobile specific implementation is from Nexus5 audio HAL - Remove the related implementation which is not applicable Change-Id: I0732dd174b8b61792fbc60905c191ac4ec1bbae0 --- hal/msm8960/platform.c | 40 ++------------------------------ hal/msm8960/platform.h | 2 -- hal/msm8974/platform.c | 52 ++---------------------------------------- hal/msm8974/platform.h | 2 -- 4 files changed, 4 insertions(+), 92 deletions(-) diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index e80aa270f..089b2ec2d 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -125,7 +125,6 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_HDMI] = "hdmi", [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus", [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", @@ -143,7 +142,6 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", - [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus", [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", @@ -166,7 +164,6 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_HDMI] = 18, [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14, [SND_DEVICE_OUT_BT_SCO] = 22, - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81, [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, @@ -183,7 +180,6 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_BT_SCO_MIC] = 21, [SND_DEVICE_IN_CAMCORDER_MIC] = 61, [SND_DEVICE_IN_VOICE_DMIC] = 6, - [SND_DEVICE_IN_VOICE_DMIC_TMUS] = 91, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 13, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, @@ -197,32 +193,6 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) -static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; -static bool is_tmus = false; - -static void check_operator() -{ - char value[PROPERTY_VALUE_MAX]; - int mccmnc; - property_get("gsm.sim.operator.numeric",value,"0"); - mccmnc = atoi(value); - ALOGD("%s: tmus mccmnc %d", __func__, mccmnc); - switch(mccmnc) { - /* TMUS MCC(310), MNC(490, 260, 026) */ - case 310490: - case 310260: - case 310026: - is_tmus = true; - break; - } -} - -bool is_operator_tmus() -{ - pthread_once(&check_op_once_ctl, check_operator); - return is_tmus; -} - static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -611,10 +581,7 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { - if (is_operator_tmus()) - snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; - else - snd_device = SND_DEVICE_OUT_HANDSET; + snd_device = SND_DEVICE_OUT_HANDSET; } if (snd_device != SND_DEVICE_NONE) { goto exit; @@ -714,10 +681,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else { - if (is_operator_tmus()) - snd_device = SND_DEVICE_IN_VOICE_DMIC_TMUS; - else - snd_device = SND_DEVICE_IN_VOICE_DMIC; + snd_device = SND_DEVICE_IN_VOICE_DMIC; adev->acdb_settings |= DMIC_FLAG; } } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h index d58356081..e38d801de 100644 --- a/hal/msm8960/platform.h +++ b/hal/msm8960/platform.h @@ -55,7 +55,6 @@ enum { SND_DEVICE_OUT_HDMI, SND_DEVICE_OUT_SPEAKER_AND_HDMI, SND_DEVICE_OUT_BT_SCO, - SND_DEVICE_OUT_VOICE_HANDSET_TMUS, SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, @@ -79,7 +78,6 @@ enum { SND_DEVICE_IN_BT_SCO_MIC, SND_DEVICE_IN_CAMCORDER_MIC, SND_DEVICE_IN_VOICE_DMIC, - SND_DEVICE_IN_VOICE_DMIC_TMUS, SND_DEVICE_IN_VOICE_SPEAKER_DMIC, SND_DEVICE_IN_VOICE_SPEAKER_QMIC, SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 5229f9a2b..0c87b84cd 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -143,7 +143,6 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb", - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus", [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", @@ -173,7 +172,6 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb", [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", - [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus", [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", @@ -205,7 +203,6 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, [SND_DEVICE_OUT_BT_SCO] = 22, [SND_DEVICE_OUT_BT_SCO_WB] = 39, - [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88, [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, @@ -234,7 +231,6 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38, [SND_DEVICE_IN_CAMCORDER_MIC] = 61, [SND_DEVICE_IN_VOICE_DMIC] = 41, - [SND_DEVICE_IN_VOICE_DMIC_TMUS] = 89, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, @@ -255,45 +251,6 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) -static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; -static bool is_tmus = false; - -static void check_operator() -{ - char value[PROPERTY_VALUE_MAX]; - int mccmnc; - property_get("gsm.sim.operator.numeric",value,"0"); - mccmnc = atoi(value); - ALOGD("%s: tmus mccmnc %d", __func__, mccmnc); - switch(mccmnc) { - /* TMUS MCC(310), MNC(490, 260, 026) */ - case 310490: - case 310260: - case 310026: - /* Add new TMUS MNC(800, 660, 580, 310, 270, 250, 240, 230, 220, 210, 200, 160) */ - case 310800: - case 310660: - case 310580: - case 310310: - case 310270: - case 310250: - case 310240: - case 310230: - case 310220: - case 310210: - case 310200: - case 310160: - is_tmus = true; - break; - } -} - -bool is_operator_tmus() -{ - pthread_once(&check_op_once_ctl, check_operator); - return is_tmus; -} - static int set_echo_reference(struct mixer *mixer, const char* ec_ref) { struct mixer_ctl *ctl; @@ -648,9 +605,7 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { - if (is_operator_tmus()) - snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS; - else if (audio_extn_should_use_handset_anc(channel_count)) + if (audio_extn_should_use_handset_anc(channel_count)) snd_device = SND_DEVICE_OUT_ANC_HANDSET; else snd_device = SND_DEVICE_OUT_VOICE_HANDSET; @@ -784,10 +739,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; } else { - if (is_operator_tmus()) - snd_device = SND_DEVICE_IN_VOICE_DMIC_TMUS; - else - snd_device = SND_DEVICE_IN_VOICE_DMIC; + snd_device = SND_DEVICE_IN_VOICE_DMIC; adev->acdb_settings |= DMIC_FLAG; } } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 93dafa59c..43d796ae3 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -57,7 +57,6 @@ enum { SND_DEVICE_OUT_SPEAKER_AND_HDMI, SND_DEVICE_OUT_BT_SCO, SND_DEVICE_OUT_BT_SCO_WB, - SND_DEVICE_OUT_VOICE_HANDSET_TMUS, SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, @@ -93,7 +92,6 @@ enum { SND_DEVICE_IN_BT_SCO_MIC_WB, SND_DEVICE_IN_CAMCORDER_MIC, SND_DEVICE_IN_VOICE_DMIC, - SND_DEVICE_IN_VOICE_DMIC_TMUS, SND_DEVICE_IN_VOICE_SPEAKER_DMIC, SND_DEVICE_IN_VOICE_SPEAKER_QMIC, SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, -- GitLab From b034ddb716697b2382ce6573e0bff39927a11112 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 6 Nov 2013 15:52:18 -0800 Subject: [PATCH 068/298] hal: Add support for fluence in regular audio recording - Add support to enable dualmic fluence on regular audio capture - Correct the ACDB ids for camcorder and voice recognition devices CRs-Fixed: 568507 Change-Id: I5d24907db0bd8222a65827659bf5425015c7bd50 --- hal/msm8974/platform.c | 70 +++++++++++++++++++++++++++++++----------- hal/msm8974/platform.h | 10 ++++-- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 0c87b84cd..c9c59d798 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -81,6 +81,7 @@ struct platform_data { bool fluence_in_spkr_mode; bool fluence_in_voice_call; bool fluence_in_voice_rec; + bool fluence_in_audio_rec; int fluence_type; int btsco_sample_rate; bool slowtalk; @@ -160,10 +161,14 @@ static const char * const device_table[SND_DEVICE_MAX] = { /* Capture sound devices */ [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", + [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire", [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire", [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic", - [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "voice-speaker-mic", + [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire", + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire", [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic", [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", @@ -177,7 +182,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", - [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef", + [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef", [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic", [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm", @@ -219,32 +224,35 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101, [SND_DEVICE_IN_HANDSET_MIC] = 4, - [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */ + [SND_DEVICE_IN_HANDSET_DMIC] = 41, + [SND_DEVICE_IN_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_SPEAKER_DMIC] = 43, [SND_DEVICE_IN_HEADSET_MIC] = 8, [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40, + [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 41, [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42, + [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 43, [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47, [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, [SND_DEVICE_IN_HDMI_MIC] = 4, [SND_DEVICE_IN_BT_SCO_MIC] = 21, [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38, - [SND_DEVICE_IN_CAMCORDER_MIC] = 61, + [SND_DEVICE_IN_CAMCORDER_MIC] = 4, [SND_DEVICE_IN_VOICE_DMIC] = 41, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, - [SND_DEVICE_IN_VOICE_REC_MIC] = 62, + [SND_DEVICE_IN_VOICE_REC_MIC] = 4, + [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34, + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41, [SND_DEVICE_IN_USB_HEADSET_MIC] = 44, [SND_DEVICE_IN_CAPTURE_FM] = 0, [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, [SND_DEVICE_IN_QUAD_MIC] = 46, [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34, [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35, - /* TODO: Update with proper acdb ids */ - [SND_DEVICE_IN_VOICE_REC_DMIC] = 62, - [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6, [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102, }; @@ -309,11 +317,12 @@ void *platform_init(struct audio_device *adev) my_data->fluence_in_spkr_mode = false; my_data->fluence_in_voice_call = false; my_data->fluence_in_voice_rec = false; + my_data->fluence_in_audio_rec = false; my_data->fluence_type = FLUENCE_NONE; property_get("ro.qc.sdk.audio.fluencetype", value, ""); if (!strncmp("fluencepro", value, sizeof("fluencepro"))) { - my_data->fluence_type = FLUENCE_QUAD_MIC; + my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC; } else if (!strncmp("fluence", value, sizeof("fluence"))) { my_data->fluence_type = FLUENCE_DUAL_MIC; } else { @@ -331,6 +340,11 @@ void *platform_init(struct audio_device *adev) my_data->fluence_in_voice_rec = true; } + property_get("persist.audio.fluence.audiorec",value,""); + if (!strncmp("true", value, sizeof("true"))) { + my_data->fluence_in_audio_rec = true; + } + property_get("persist.audio.fluence.speaker",value,""); if (!strncmp("true", value, sizeof("true"))) { my_data->fluence_in_spkr_mode = true; @@ -753,12 +767,12 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if (my_data->fluence_type != FLUENCE_NONE && my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode) { - if(my_data->fluence_type == FLUENCE_DUAL_MIC) { - adev->acdb_settings |= DMIC_FLAG; - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC; - } else { + if(my_data->fluence_type & FLUENCE_QUAD_MIC) { adev->acdb_settings |= QMIC_FLAG; snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC; + } else { + adev->acdb_settings |= DMIC_FLAG; + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC; } } else { snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; @@ -772,7 +786,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) - snd_device = SND_DEVICE_IN_VOICE_REC_DMIC; + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO; else if (my_data->fluence_in_voice_rec) snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE; @@ -787,9 +801,15 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if (adev->active_input) { if (adev->active_input->enable_aec) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { - snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; + if(my_data->fluence_type & FLUENCE_DUAL_MIC) + snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC; + else + snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; + if(my_data->fluence_type & FLUENCE_DUAL_MIC) + snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC; + else + snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC; } @@ -797,6 +817,20 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else set_echo_reference(adev->mixer, "NONE"); } + } else if (source == AUDIO_SOURCE_MIC) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + if(my_data->fluence_type & FLUENCE_DUAL_MIC && + my_data->fluence_in_audio_rec) + snd_device = SND_DEVICE_IN_SPEAKER_DMIC; + else + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if(my_data->fluence_type & FLUENCE_DUAL_MIC && + my_data->fluence_in_audio_rec) + snd_device = SND_DEVICE_IN_HANDSET_DMIC; + else + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } } else if (source == AUDIO_SOURCE_FM_RX || source == AUDIO_SOURCE_FM_RX_A2DP) { snd_device = SND_DEVICE_IN_CAPTURE_FM; @@ -1062,9 +1096,9 @@ void platform_get_parameters(void *platform, value, sizeof(value)); if (ret >= 0) { pthread_mutex_lock(&my_data->adev->lock); - if (my_data->fluence_type == FLUENCE_QUAD_MIC) { + if (my_data->fluence_type & FLUENCE_QUAD_MIC) { strlcpy(value, "fluencepro", sizeof(value)); - } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) { + } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) { strlcpy(value, "fluence", sizeof(value)); } else { strlcpy(value, "none", sizeof(value)); diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 43d796ae3..795c9f9bc 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -22,8 +22,8 @@ enum { FLUENCE_NONE, - FLUENCE_DUAL_MIC, - FLUENCE_QUAD_MIC + FLUENCE_DUAL_MIC = 0x1, + FLUENCE_QUAD_MIC = 0x2, }; /* @@ -80,10 +80,14 @@ enum { /* Capture devices */ SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END, SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN, + SND_DEVICE_IN_HANDSET_DMIC, SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_SPEAKER_DMIC, SND_DEVICE_IN_HEADSET_MIC, SND_DEVICE_IN_HANDSET_MIC_AEC, + SND_DEVICE_IN_HANDSET_DMIC_AEC, SND_DEVICE_IN_SPEAKER_MIC_AEC, + SND_DEVICE_IN_SPEAKER_DMIC_AEC, SND_DEVICE_IN_HEADSET_MIC_AEC, SND_DEVICE_IN_VOICE_SPEAKER_MIC, SND_DEVICE_IN_VOICE_HEADSET_MIC, @@ -98,7 +102,7 @@ enum { SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, SND_DEVICE_IN_VOICE_REC_MIC, - SND_DEVICE_IN_VOICE_REC_DMIC, + SND_DEVICE_IN_VOICE_REC_DMIC_STEREO, SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, SND_DEVICE_IN_USB_HEADSET_MIC, SND_DEVICE_IN_CAPTURE_FM, -- GitLab From dc4f757fac69d81e1692d068ad17a307a0dcacd5 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Fri, 1 Nov 2013 20:07:13 -0700 Subject: [PATCH 069/298] hal : Fix for stability offload issues. -Disable and enable the device seperately from check_usecases_codec_backend function. -Acquire device lock for pcm close. This prevents crash during headset device switch and fast forward. -hw free is getting called from compress framework while runtime update is going on. The front end list could be cleared during runtime update and concurrent access of front end list could result a crash. CRs-Fixed: 568710 Change-Id: Iccc2b9d3c175a5421cfc4d070b0af3906d9080c5 --- hal/audio_hw.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 74217b75f..29997fec4 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -358,10 +358,15 @@ static void check_usecases_codec_backend(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { disable_snd_device(adev, usecase->out_snd_device, false); - enable_snd_device(adev, snd_device, false); } } + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { + enable_snd_device(adev, snd_device, false); + } + } /* Make sure new snd device is enabled before re-routing the streams */ audio_route_update_mixer(adev->audio_route); @@ -1198,6 +1203,7 @@ static int out_standby(struct audio_stream *stream) out->usecase, use_case_table[out->usecase]); pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->lock); if (!out->standby) { out->standby = true; if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { @@ -1214,10 +1220,9 @@ static int out_standby(struct audio_stream *stream) out->compr = NULL; } } - pthread_mutex_lock(&adev->lock); stop_output_stream(out); - pthread_mutex_unlock(&adev->lock); } + pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&out->lock); ALOGV("%s: exit", __func__); return 0; -- GitLab From d801ae34b5ad8f24088903eac9a40f1e1a68253f Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Sun, 3 Nov 2013 15:48:42 -0800 Subject: [PATCH 070/298] hal: Update devices that are different across variants. -Update devices that are different across 8974/8x26 variants. -Use extension as cdp for 8974 cdp device instead of liquid. Change-Id: Ic0844577743303dc6bd1508a40beeb616abb76d3 --- hal/msm8974/hw_info.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index 02eb148ac..673b6e292 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -66,6 +66,7 @@ static const snd_device_t taiko_CDP_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_QUAD_MIC, }; static const snd_device_t taiko_liquid_variant_devices[] = { @@ -74,6 +75,13 @@ static const snd_device_t taiko_liquid_variant_devices[] = { SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, SND_DEVICE_IN_SPEAKER_MIC, SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_VOICE_DMIC, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC, + SND_DEVICE_IN_VOICE_REC_DMIC_STEREO, + SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_QUAD_MIC, + SND_DEVICE_IN_HANDSET_STEREO_DMIC, + SND_DEVICE_IN_SPEAKER_STEREO_DMIC, }; static const snd_device_t taiko_DB_variant_devices[] = { @@ -81,28 +89,33 @@ static const snd_device_t taiko_DB_variant_devices[] = { SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_QUAD_MIC, }; static const snd_device_t tapan_lite_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, - SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, }; static const snd_device_t tapan_skuf_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + /*SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,*/ }; static const snd_device_t tapan_lite_skuf_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, - SND_DEVICE_OUT_ANC_HANDSET, - SND_DEVICE_OUT_ANC_HEADSET, - SND_DEVICE_OUT_ANC_FB_HEADSET, + SND_DEVICE_OUT_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, - SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, - SND_DEVICE_IN_AANC_HANDSET_MIC, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, }; static const snd_device_t helicon_skuab_variant_devices[] = { @@ -149,7 +162,7 @@ static void update_hardware_info_8974(struct hardware_info *hw_info, const char strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices; hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices); - strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn)); + strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn)); } else if (!strcmp(snd_card_name, "msm8974-taiko-fluid-snd-card")) { strlcpy(hw_info->type, " fluid", sizeof(hw_info->type)); strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); -- GitLab From 198185e9942d963d947a1922374572a27c3f7046 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Thu, 7 Nov 2013 15:42:19 -0800 Subject: [PATCH 071/298] hal: Add support for AEC and NS audio effects - Add sound devices needed to enable/disable AEC and NS audio effects on voice communication and voice recognition usecases. Change-Id: I53ef3fc84e9ad43852cb22786731594f3e598390 --- hal/audio_hw.c | 6 +++ hal/audio_hw.h | 1 + hal/msm8974/platform.c | 105 ++++++++++++++++++++++++++++++++--------- hal/msm8974/platform.h | 19 ++++++-- 4 files changed, 103 insertions(+), 28 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 64db646e8..b661dd194 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1857,6 +1857,12 @@ static int add_remove_audio_effect(const struct audio_stream *stream, if (!in->standby) select_devices(in->dev, in->usecase); } + if (in->enable_ns != enable && + (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) { + in->enable_ns = enable; + if (!in->standby) + select_devices(in->dev, in->usecase); + } pthread_mutex_unlock(&in->dev->lock); pthread_mutex_unlock(&in->lock); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 68e40ce4b..d68236686 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -167,6 +167,7 @@ struct stream_in { audio_channel_mask_t channel_mask; audio_usecase_t usecase; bool enable_aec; + bool enable_ns; struct audio_device *dev; }; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c9c59d798..e9cb493b7 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -161,15 +161,23 @@ static const char * const device_table[SND_DEVICE_MAX] = { /* Capture sound devices */ [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", - [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire", - [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", - [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire", - [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic", + [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic", + [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic", + [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire", [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire", + [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire", + [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire", + [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire", [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire", - [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic", + [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire", + [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire", + [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", + [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = "headset-mic", [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", @@ -182,6 +190,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", + [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic", [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef", [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic", @@ -224,15 +233,23 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101, [SND_DEVICE_IN_HANDSET_MIC] = 4, + [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106, + [SND_DEVICE_IN_HANDSET_MIC_NS] = 107, + [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108, [SND_DEVICE_IN_HANDSET_DMIC] = 41, + [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109, + [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110, + [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111, [SND_DEVICE_IN_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112, + [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113, + [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114, [SND_DEVICE_IN_SPEAKER_DMIC] = 43, + [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115, + [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116, + [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117, [SND_DEVICE_IN_HEADSET_MIC] = 8, - [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40, - [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 41, - [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42, - [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 43, - [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47, + [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = 47, [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, [SND_DEVICE_IN_HDMI_MIC] = 4, @@ -245,6 +262,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_REC_MIC] = 4, + [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107, [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34, [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41, [SND_DEVICE_IN_USB_HEADSET_MIC] = 44, @@ -785,35 +803,76 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) + if (channel_count == 2) { snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO; - else if (my_data->fluence_in_voice_rec) + adev->acdb_settings |= DMIC_FLAG; + } else if (adev->active_input->enable_ns) + snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS; + else if (my_data->fluence_type != FLUENCE_NONE && + my_data->fluence_in_voice_rec) { snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE; - - if (snd_device == SND_DEVICE_NONE) - snd_device = SND_DEVICE_IN_VOICE_REC_MIC; - else adev->acdb_settings |= DMIC_FLAG; + } else { + snd_device = SND_DEVICE_IN_VOICE_REC_MIC; + } } } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { if (out_device & AUDIO_DEVICE_OUT_SPEAKER) in_device = AUDIO_DEVICE_IN_BACK_MIC; if (adev->active_input) { - if (adev->active_input->enable_aec) { + if (adev->active_input->enable_aec && + adev->active_input->enable_ns) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC && + my_data->fluence_in_spkr_mode) { + snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; + } + set_echo_reference(adev->mixer, "SLIM_RX"); + } else if (adev->active_input->enable_aec) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { - if(my_data->fluence_type & FLUENCE_DUAL_MIC) + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC; - else + adev->acdb_settings |= DMIC_FLAG; + } else snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { - if(my_data->fluence_type & FLUENCE_DUAL_MIC) + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC; - else + adev->acdb_settings |= DMIC_FLAG; + } else snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { - snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC; + snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; } set_echo_reference(adev->mixer, "SLIM_RX"); + } else if (adev->active_input->enable_ns) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_HANDSET_MIC_NS; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; + } + set_echo_reference(adev->mixer, "NONE"); } else set_echo_reference(adev->mixer, "NONE"); } @@ -832,7 +891,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_HANDSET_MIC; } } else if (source == AUDIO_SOURCE_FM_RX || - source == AUDIO_SOURCE_FM_RX_A2DP) { + source == AUDIO_SOURCE_FM_RX_A2DP) { snd_device = SND_DEVICE_IN_CAPTURE_FM; } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 795c9f9bc..00b5515dc 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -80,15 +80,23 @@ enum { /* Capture devices */ SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END, SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN, - SND_DEVICE_IN_HANDSET_DMIC, - SND_DEVICE_IN_SPEAKER_MIC, - SND_DEVICE_IN_SPEAKER_DMIC, - SND_DEVICE_IN_HEADSET_MIC, SND_DEVICE_IN_HANDSET_MIC_AEC, + SND_DEVICE_IN_HANDSET_MIC_NS, + SND_DEVICE_IN_HANDSET_MIC_AEC_NS, + SND_DEVICE_IN_HANDSET_DMIC, SND_DEVICE_IN_HANDSET_DMIC_AEC, + SND_DEVICE_IN_HANDSET_DMIC_NS, + SND_DEVICE_IN_HANDSET_DMIC_AEC_NS, + SND_DEVICE_IN_SPEAKER_MIC, SND_DEVICE_IN_SPEAKER_MIC_AEC, + SND_DEVICE_IN_SPEAKER_MIC_NS, + SND_DEVICE_IN_SPEAKER_MIC_AEC_NS, + SND_DEVICE_IN_SPEAKER_DMIC, SND_DEVICE_IN_SPEAKER_DMIC_AEC, - SND_DEVICE_IN_HEADSET_MIC_AEC, + SND_DEVICE_IN_SPEAKER_DMIC_NS, + SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_HEADSET_MIC_FLUENCE, SND_DEVICE_IN_VOICE_SPEAKER_MIC, SND_DEVICE_IN_VOICE_HEADSET_MIC, SND_DEVICE_IN_HDMI_MIC, @@ -102,6 +110,7 @@ enum { SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, SND_DEVICE_IN_VOICE_REC_MIC, + SND_DEVICE_IN_VOICE_REC_MIC_NS, SND_DEVICE_IN_VOICE_REC_DMIC_STEREO, SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, SND_DEVICE_IN_USB_HEADSET_MIC, -- GitLab From 3bb7358558eec93501c926b0077f28187a43c7b1 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Tue, 5 Nov 2013 12:49:15 -0800 Subject: [PATCH 072/298] hal: end all calls when setmode(AUDIO_MODE_NORMAL) is called Telephony will call set_mode(AUDIO_MODE_NORMAL) when a call is ended which will trigger audio policy manager setting routing with audio usecase compatible device. Voice calls can still be active if RIL has not yet called setparameters(vsid,callstate). This would result in routing voice call usecases with incompatible device for voice calls. Fix this by ending all voice calls when set_mode(MODE_NORMAL) is called. Change-Id: Id2c9f2ff9ed46969e5cbd27b525b81735c1d49d8 --- hal/audio_hw.c | 21 +++- hal/msm8974/platform.c | 6 - hal/voice.c | 30 +---- hal/voice_extn/voice_extn.c | 245 ++++++++++++++++++++---------------- hal/voice_extn/voice_extn.h | 15 ++- 5 files changed, 171 insertions(+), 146 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 64db646e8..7d438ba2a 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -98,7 +98,7 @@ struct pcm_config pcm_config_audio_capture = { .format = PCM_FORMAT_S16_LE, }; -static const char * const use_case_table[AUDIO_USECASE_MAX] = { +const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback", [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", @@ -2083,7 +2083,9 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) int val; int ret; - ALOGV("%s: enter: %s", __func__, kvpairs); + ALOGD("%s: enter: %s", __func__, kvpairs); + + pthread_mutex_lock(&adev->lock); parms = str_parms_create_str(kvpairs); voice_set_parameters(adev, parms); @@ -2125,7 +2127,6 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) default: ALOGE("%s: unexpected rotation of %d", __func__, val); } - pthread_mutex_lock(&adev->lock); if (adev->speaker_lr_swap != reverse_speakers) { adev->speaker_lr_swap = reverse_speakers; // only update the selected device if there is active pcm playback @@ -2139,11 +2140,12 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) } } } - pthread_mutex_unlock(&adev->lock); } audio_extn_set_parameters(adev, parms); str_parms_destroy(parms); + + pthread_mutex_unlock(&adev->lock); ALOGV("%s: exit with code(%d)", __func__, ret); return ret; } @@ -2156,12 +2158,15 @@ static char* adev_get_parameters(const struct audio_hw_device *dev, struct str_parms *query = str_parms_create_str(keys); char *str; + pthread_mutex_lock(&adev->lock); + audio_extn_get_parameters(adev, query, reply); platform_get_parameters(adev->platform, query, reply); str = str_parms_to_str(reply); str_parms_destroy(query); str_parms_destroy(reply); + pthread_mutex_unlock(&adev->lock); ALOGV("%s: exit: returns - %s", __func__, str); return str; } @@ -2217,7 +2222,13 @@ static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) { - return voice_set_mic_mute((struct audio_device *)dev, state); + int ret; + + pthread_mutex_lock(&adev->lock); + ret = voice_set_mic_mute((struct audio_device *)dev, state); + pthread_mutex_unlock(&adev->lock); + + return ret; } static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c9c59d798..4443f402d 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1033,19 +1033,15 @@ int platform_set_parameters(void *platform, struct str_parms *parms) ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val); if (ret >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO); - pthread_mutex_lock(&my_data->adev->lock); my_data->btsco_sample_rate = val; - pthread_mutex_unlock(&my_data->adev->lock); } ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val); if (ret >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK); - pthread_mutex_lock(&my_data->adev->lock); ret = platform_set_slowtalk(my_data, val); if (ret) ALOGE("%s: Failed to set slow talk err: %d", __func__, ret); - pthread_mutex_unlock(&my_data->adev->lock); } ALOGV("%s: exit with code(%d)", __func__, ret); @@ -1095,7 +1091,6 @@ void platform_get_parameters(void *platform, ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value, sizeof(value)); if (ret >= 0) { - pthread_mutex_lock(&my_data->adev->lock); if (my_data->fluence_type & FLUENCE_QUAD_MIC) { strlcpy(value, "fluencepro", sizeof(value)); } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) { @@ -1103,7 +1098,6 @@ void platform_get_parameters(void *platform, } else { strlcpy(value, "none", sizeof(value)); } - pthread_mutex_unlock(&my_data->adev->lock); str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value); } diff --git a/hal/voice.c b/hal/voice.c index 907ebc911..c85fcd4e5 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -41,20 +41,7 @@ struct pcm_config pcm_config_voice_call = { .format = PCM_FORMAT_S16_LE, }; -extern struct audio_usecase *get_usecase_from_list(struct audio_device *adev, - audio_usecase_t uc_id); -extern int disable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool update_mixer); -extern int disable_audio_route(struct audio_device *adev, - struct audio_usecase *usecase, - bool update_mixer); - -extern int disable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool update_mixer); -extern int select_devices(struct audio_device *adev, - audio_usecase_t uc_id); +extern const char * const use_case_table[AUDIO_USECASE_MAX]; static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev, audio_usecase_t usecase_id) @@ -76,7 +63,7 @@ int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) struct audio_usecase *uc_info; struct voice_session *session = NULL; - ALOGD("%s: enter", __func__); + ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]); session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); session->state.current = CALL_INACTIVE; @@ -124,10 +111,10 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) int pcm_dev_rx_id, pcm_dev_tx_id; struct voice_session *session = NULL; struct pcm_config voice_config = pcm_config_voice_call; - ALOGD("%s: enter", __func__); - session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); + ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]); + session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); uc_info->id = usecase_id; uc_info->type = VOICE_CALL; @@ -274,14 +261,11 @@ int voice_set_mic_mute(struct audio_device *adev, bool state) { int err = 0; - pthread_mutex_lock(&adev->lock); - err = platform_set_mic_mute(adev->platform, state); if (!err) { adev->voice.mic_mute = state; } - pthread_mutex_unlock(&adev->lock); return err; } @@ -319,7 +303,7 @@ int voice_start_call(struct audio_device *adev) { int ret = 0; - ret = voice_extn_update_calls(adev); + ret = voice_extn_start_call(adev); if (ret == -ENOSYS) { ret = start_call(adev, USECASE_VOICE_CALL); } @@ -331,7 +315,7 @@ int voice_stop_call(struct audio_device *adev) { int ret = 0; - ret = voice_extn_update_calls(adev); + ret = voice_extn_stop_call(adev); if (ret == -ENOSYS) { ret = stop_call(adev, USECASE_VOICE_CALL); } @@ -367,7 +351,6 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) goto done; } - pthread_mutex_lock(&adev->lock); if (tty_mode != adev->voice.tty_mode) { adev->voice.tty_mode = tty_mode; adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode; @@ -375,7 +358,6 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) //todo: what about voice2, volte and qchat usecases? select_devices(adev, USECASE_VOICE_CALL); } - pthread_mutex_unlock(&adev->lock); } done: diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 903d2aa8c..87a97e2c3 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -63,7 +63,7 @@ struct pcm_config pcm_config_incall_music = { extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id); extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id); -int voice_extn_update_calls(struct audio_device *adev); +int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); static bool is_valid_call_state(int call_state) { @@ -130,104 +130,7 @@ static uint32_t get_session_id_with_state(struct audio_device *adev, return session_id; } -int voice_extn_get_active_session_id(struct audio_device *adev, - uint32_t *session_id) -{ - *session_id = get_session_id_with_state(adev, CALL_ACTIVE); - return 0; -} - -int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) -{ - struct voice_session *session = NULL; - int i = 0; - *in_call = false; - - for (i = 0; i < MAX_VOICE_SESSIONS; i++) { - session = &adev->voice.session[i]; - if(session->state.current != CALL_INACTIVE){ - *in_call = true; - break; - } - } - - return 0; -} - -static int voice_extn_update_call_states(struct audio_device *adev, - const uint32_t vsid, const int call_state) -{ - struct voice_session *session = NULL; - int i = 0; - bool is_in_call; - - for (i = 0; i < MAX_VOICE_SESSIONS; i++) { - if (vsid == adev->voice.session[i].vsid) { - session = &adev->voice.session[i]; - break; - } - } - - if (session) { - session->state.new = call_state; - voice_extn_is_in_call(adev, &is_in_call); - ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode); - if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) { - /* Device routing is not triggered for voice calls on the subsequent - * subs, Hence update the call states if voice call is already - * active on other sub. - */ - voice_extn_update_calls(adev); - } - } else { - return -EINVAL; - } - - return 0; - -} - -void voice_extn_init(struct audio_device *adev) -{ - adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID; - adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID; - adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID; - adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID; -} - -int voice_extn_get_session_from_use_case(struct audio_device *adev, - const audio_usecase_t usecase_id, - struct voice_session **session) -{ - - switch(usecase_id) - { - case USECASE_VOICE_CALL: - *session = &adev->voice.session[VOICE_SESS_IDX]; - break; - - case USECASE_VOICE2_CALL: - *session = &adev->voice.session[VOICE2_SESS_IDX]; - break; - - case USECASE_VOLTE_CALL: - *session = &adev->voice.session[VOLTE_SESS_IDX]; - break; - - case USECASE_QCHAT_CALL: - *session = &adev->voice.session[QCHAT_SESS_IDX]; - break; - - default: - ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id); - *session = NULL; - return -EINVAL; - } - - return 0; -} - -int voice_extn_update_calls(struct audio_device *adev) +static int update_calls(struct audio_device *adev) { int i = 0; audio_usecase_t usecase_id = 0; @@ -255,8 +158,9 @@ int voice_extn_update_calls(struct audio_device *adev) if(ret < 0) { ALOGE("%s: voice_start_call() failed for usecase: %d\n", __func__, usecase_id); + } else { + session->state.current = session->state.new; } - session->state.current = session->state.new; break; case CALL_HOLD: @@ -292,8 +196,9 @@ int voice_extn_update_calls(struct audio_device *adev) if(ret < 0) { ALOGE("%s: voice_end_call() failed for usecase: %d\n", __func__, usecase_id); + } else { + session->state.current = session->state.new; } - session->state.current = session->state.new; break; default: @@ -358,6 +263,136 @@ int voice_extn_update_calls(struct audio_device *adev) return ret; } +static int update_call_states(struct audio_device *adev, + const uint32_t vsid, const int call_state) +{ + struct voice_session *session = NULL; + int i = 0; + bool is_in_call; + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + if (vsid == adev->voice.session[i].vsid) { + session = &adev->voice.session[i]; + break; + } + } + + if (session) { + session->state.new = call_state; + voice_extn_is_in_call(adev, &is_in_call); + ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode); + if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) { + /* Device routing is not triggered for voice calls on the subsequent + * subs, Hence update the call states if voice call is already + * active on other sub. + */ + update_calls(adev); + } + } else { + return -EINVAL; + } + + return 0; + +} + +int voice_extn_get_active_session_id(struct audio_device *adev, + uint32_t *session_id) +{ + *session_id = get_session_id_with_state(adev, CALL_ACTIVE); + return 0; +} + +int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) +{ + struct voice_session *session = NULL; + int i = 0; + *in_call = false; + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + session = &adev->voice.session[i]; + if(session->state.current != CALL_INACTIVE){ + *in_call = true; + break; + } + } + + return 0; +} + +void voice_extn_init(struct audio_device *adev) +{ + adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID; + adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID; + adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID; + adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID; +} + +int voice_extn_get_session_from_use_case(struct audio_device *adev, + const audio_usecase_t usecase_id, + struct voice_session **session) +{ + + switch(usecase_id) + { + case USECASE_VOICE_CALL: + *session = &adev->voice.session[VOICE_SESS_IDX]; + break; + + case USECASE_VOICE2_CALL: + *session = &adev->voice.session[VOICE2_SESS_IDX]; + break; + + case USECASE_VOLTE_CALL: + *session = &adev->voice.session[VOLTE_SESS_IDX]; + break; + + case USECASE_QCHAT_CALL: + *session = &adev->voice.session[QCHAT_SESS_IDX]; + break; + + default: + ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id); + *session = NULL; + return -EINVAL; + } + + return 0; +} + +int voice_extn_start_call(struct audio_device *adev) +{ + /* Start voice calls on sessions whose call state has been + * udpated. + */ + ALOGV("%s: enter:", __func__); + return update_calls(adev); +} + +int voice_extn_stop_call(struct audio_device *adev) +{ + int i; + int ret = 0; + + ALOGV("%s: enter:", __func__); + + /* If BT device is enabled and voice calls are ended, telephony will call + * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to + * set routing with device BT A2DP profile. Hence end all voice calls when + * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected. + */ + if (adev->mode == AUDIO_MODE_NORMAL) { + ALOGD("%s: end all calls", __func__); + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + adev->voice.session[i].state.new = CALL_INACTIVE; + } + + ret = update_calls(adev); + } + + return ret; +} + int voice_extn_set_parameters(struct audio_device *adev, struct str_parms *parms) { @@ -375,7 +410,6 @@ int voice_extn_set_parameters(struct audio_device *adev, ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value); if (ret >= 0) { call_state = value; - //validate callstate } else { ALOGE("%s: call_state key not found", __func__); ret = -EINVAL; @@ -383,11 +417,10 @@ int voice_extn_set_parameters(struct audio_device *adev, } if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) { - pthread_mutex_lock(&adev->lock); - voice_extn_update_call_states(adev, vsid, call_state); - pthread_mutex_unlock(&adev->lock); + ret = update_call_states(adev, vsid, call_state); } else { - ALOGE("%s: invalid vsid or call_state", __func__); + ALOGE("%s: invalid vsid:%x or call_state:%d", + __func__, vsid, call_state); ret = -EINVAL; goto done; } diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index dd2dfd861..c4e213112 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -21,18 +21,24 @@ #define VOICE_EXTN_H #ifdef MULTI_VOICE_SESSION_ENABLED -int voice_extn_update_calls(struct audio_device *adev); +int voice_extn_start_call(struct audio_device *adev); +int voice_extn_stop_call(struct audio_device *adev); int voice_extn_get_session_from_use_case(struct audio_device *adev, const audio_usecase_t usecase_id, struct voice_session **session); -int voice_extn_init(struct audio_device *adev); +void voice_extn_init(struct audio_device *adev); int voice_extn_set_parameters(struct audio_device *adev, struct str_parms *parms); int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id); #else -static int voice_extn_update_calls(struct audio_device *adev) +static int voice_extn_start_call(struct audio_device *adev) +{ + return -ENOSYS; +} + +static int voice_extn_stop_call(struct audio_device *adev) { return -ENOSYS; } @@ -44,9 +50,8 @@ static int voice_extn_get_session_from_use_case(struct audio_device *adev, return -ENOSYS; } -static int voice_extn_init(struct audio_device *adev) +static void voice_extn_init(struct audio_device *adev) { - return -ENOSYS; } static int voice_extn_set_parameters(struct audio_device *adev, -- GitLab From 7a2545c8b31d890baf79c02736ea62d3489361ef Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Fri, 8 Nov 2013 18:26:33 -0800 Subject: [PATCH 073/298] hal: Fix voice calls starting on speaker unintendedly If setParameters(vsid, callstate) call is processed before setparameter(routing), voice calls will be started on speaker. Fix by not starting voice calls by checking if the primary output device is speaker. Change-Id: If3ecb83bbcb02d5da40d66340276263413adabc9 --- hal/voice_extn/voice_extn.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 87a97e2c3..2b26f3f0e 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -281,7 +281,13 @@ static int update_call_states(struct audio_device *adev, session->state.new = call_state; voice_extn_is_in_call(adev, &is_in_call); ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode); - if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) { + /* Dont start voice call before device routing for voice usescases has + * occured, otherwise voice calls will be started unintendedly on + * speaker. + */ + if (is_in_call || + (adev->mode == AUDIO_MODE_IN_CALL && + adev->primary_output->devices != AUDIO_DEVICE_OUT_SPEAKER)) { /* Device routing is not triggered for voice calls on the subsequent * subs, Hence update the call states if voice call is already * active on other sub. -- GitLab From 8bba9e957f56100d4e1464d576121273ffa434eb Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Mon, 11 Nov 2013 21:09:07 -0800 Subject: [PATCH 074/298] hal: Fix the audio loss issue on codec back end - Start music playback, plug in and plug out headset and press 'Next' button in the Music app immediately. Repeating these steps result complete loss of audio on HW codec. - When headset is pluged out and Next is pressed immediately, the audio HAL triggers audio routing change from Headset to Speaker, and closure of compress playback driver. The later is not lock protected which result un protected access of back end information in the ALSA framework. This leads to incorrect routing and hence loss of audio. It is also observed that sometimes it could lead to crash in kernel and phone reboots. - Fix by ensuring that the kernel driver close is also lock protected along with other routing events. Bug: 11088400 Change-Id: I785effb09e5cef7ba20ee43e0ef91dc296d4e58a --- hal/audio_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 0b603d7df..48c426da3 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1184,6 +1184,7 @@ static int out_standby(struct audio_stream *stream) pthread_mutex_lock(&out->lock); if (!out->standby) { + pthread_mutex_lock(&adev->lock); out->standby = true; if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { if (out->pcm) { @@ -1199,7 +1200,6 @@ static int out_standby(struct audio_stream *stream) out->compr = NULL; } } - pthread_mutex_lock(&adev->lock); stop_output_stream(out); pthread_mutex_unlock(&adev->lock); } @@ -1673,12 +1673,12 @@ static int in_standby(struct audio_stream *stream) ALOGV("%s: enter", __func__); pthread_mutex_lock(&in->lock); if (!in->standby) { + pthread_mutex_lock(&adev->lock); in->standby = true; if (in->pcm) { pcm_close(in->pcm); in->pcm = NULL; } - pthread_mutex_lock(&adev->lock); status = stop_input_stream(in); pthread_mutex_unlock(&adev->lock); } -- GitLab From d9d9ff34fa946f8151422b1b083f9967b6a7dc53 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Wed, 13 Nov 2013 11:46:52 -0800 Subject: [PATCH 075/298] hal: add voice call support on apq8084 APQ8084 uses external modem to make voice calls. APQ uses CSD QMI interface to communicate with external modem. Add csd client apis to support voice calls Change-Id: I11fe0cc614ee38c42e95b40d5cd5e2d8b3afd43a --- hal/Android.mk | 3 + hal/msm8974/platform.c | 229 ++++++++++++++++++++++++++++++++++++++--- hal/msm8974/platform.h | 59 +++++++++-- hal/platform_api.h | 4 +- hal/voice.c | 4 +- 5 files changed, 272 insertions(+), 27 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index 8bbfa6992..58cf1c659 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -18,6 +18,9 @@ endif ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),) LOCAL_CFLAGS := -DPLATFORM_MSM8x26 endif +ifneq ($(filter apq8084,$(TARGET_BOARD_PLATFORM)),) + LOCAL_CFLAGS := -DPLATFORM_APQ8084 +endif endif LOCAL_SRC_FILES := \ diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c9c59d798..532075cd7 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -71,6 +71,7 @@ struct audio_block_header int length; }; +/* Audio calibration related functions */ typedef void (*acdb_deallocate_t)(); typedef int (*acdb_init_t)(); typedef void (*acdb_send_audio_cal_t)(int, int); @@ -93,6 +94,7 @@ struct platform_data { acdb_send_voice_cal_t acdb_send_voice_cal; void *hw_info; + struct csd_data *csd; }; static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { @@ -275,8 +277,133 @@ static int set_echo_reference(struct mixer *mixer, const char* ec_ref) return 0; } +static struct csd_data *open_csd_client() +{ + struct csd_data *csd = calloc(1, sizeof(struct csd_data)); + + csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW); + if (csd->csd_client == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT); + goto error; + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT); + + csd->deinit = (deinit_t)dlsym(csd->csd_client, + "csd_client_deinit"); + if (csd->deinit == NULL) { + ALOGE("%s: dlsym error %s for csd_client_deinit", __func__, + dlerror()); + goto error; + } + csd->disable_device = (disable_device_t)dlsym(csd->csd_client, + "csd_client_disable_device"); + if (csd->disable_device == NULL) { + ALOGE("%s: dlsym error %s for csd_client_disable_device", + __func__, dlerror()); + goto error; + } + csd->enable_device = (enable_device_t)dlsym(csd->csd_client, + "csd_client_enable_device"); + if (csd->enable_device == NULL) { + ALOGE("%s: dlsym error %s for csd_client_enable_device", + __func__, dlerror()); + goto error; + } + csd->start_voice = (start_voice_t)dlsym(csd->csd_client, + "csd_client_start_voice"); + if (csd->start_voice == NULL) { + ALOGE("%s: dlsym error %s for csd_client_start_voice", + __func__, dlerror()); + goto error; + } + csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client, + "csd_client_stop_voice"); + if (csd->stop_voice == NULL) { + ALOGE("%s: dlsym error %s for csd_client_stop_voice", + __func__, dlerror()); + goto error; + } + csd->volume = (volume_t)dlsym(csd->csd_client, + "csd_client_volume"); + if (csd->volume == NULL) { + ALOGE("%s: dlsym error %s for csd_client_volume", + __func__, dlerror()); + goto error; + } + csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client, + "csd_client_mic_mute"); + if (csd->mic_mute == NULL) { + ALOGE("%s: dlsym error %s for csd_client_mic_mute", + __func__, dlerror()); + goto error; + } + csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client, + "csd_client_slow_talk"); + if (csd->slow_talk == NULL) { + ALOGE("%s: dlsym error %s for csd_client_slow_talk", + __func__, dlerror()); + goto error; + } + csd->start_playback = (start_playback_t)dlsym(csd->csd_client, + "csd_client_start_playback"); + if (csd->start_playback == NULL) { + ALOGE("%s: dlsym error %s for csd_client_start_playback", + __func__, dlerror()); + goto error; + } + csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client, + "csd_client_stop_playback"); + if (csd->stop_playback == NULL) { + ALOGE("%s: dlsym error %s for csd_client_stop_playback", + __func__, dlerror()); + goto error; + } + csd->start_record = (start_record_t)dlsym(csd->csd_client, + "csd_client_start_record"); + if (csd->start_record == NULL) { + ALOGE("%s: dlsym error %s for csd_client_start_record", + __func__, dlerror()); + goto error; + } + csd->stop_record = (stop_record_t)dlsym(csd->csd_client, + "csd_client_stop_record"); + if (csd->stop_record == NULL) { + ALOGE("%s: dlsym error %s for csd_client_stop_record", + __func__, dlerror()); + goto error; + } + csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init"); + + if (csd->init == NULL) { + ALOGE("%s: dlsym error %s for csd_client_init", + __func__, dlerror()); + goto error; + } else { + csd->init(); + } + } + return csd; + +error: + free(csd); + csd = NULL; + return csd; +} + +void close_csd_client(struct csd_data *csd) +{ + if (csd != NULL) { + csd->deinit(); + dlclose(csd->csd_client); + free(csd); + csd = NULL; + } +} + void *platform_init(struct audio_device *adev) { + char platform[PROPERTY_VALUE_MAX]; + char baseband[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX]; struct platform_data *my_data; int retry_num = 0; @@ -373,6 +500,17 @@ void *platform_init(struct audio_device *adev) my_data->acdb_init(); } + /* If platform is apq8084 and baseband is MDM, load CSD Client specific + * symbols. Voice call is handled by MDM and apps processor talks to + * MDM through CSD Client + */ + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strncmp("apq8084", platform, sizeof("apq8084")) && + !strncmp("mdm", baseband, sizeof("mdm"))) { + my_data->csd = open_csd_client(); + } + /* init usb */ audio_extn_usb_init(adev); @@ -387,6 +525,8 @@ void platform_deinit(void *platform) struct platform_data *my_data = (struct platform_data *)platform; hw_info_deinit(my_data->hw_info); + close_csd_client(my_data->csd); + free(platform); /* deinit usb */ audio_extn_usb_deinit(); @@ -481,7 +621,18 @@ int platform_send_audio_calibration(void *platform, snd_device_t snd_device) int platform_switch_voice_call_device_pre(void *platform) { - return 0; + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd != NULL) { + /* This must be called before disabling mixer controls on APQ side */ + ret = my_data->csd->disable_device(); + if (ret < 0) { + ALOGE("%s: csd_client_disable_device, failed, error %d", + __func__, ret); + } + } + return ret; } int platform_switch_voice_call_device_post(void *platform, @@ -490,13 +641,14 @@ int platform_switch_voice_call_device_post(void *platform, { struct platform_data *my_data = (struct platform_data *)platform; int acdb_rx_id, acdb_tx_id; + int ret = 0; + + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; if (my_data->acdb_send_voice_cal == NULL) { ALOGE("%s: dlsym error for acdb_send_voice_call", __func__); } else { - acdb_rx_id = acdb_device_table[out_snd_device]; - acdb_tx_id = acdb_device_table[in_snd_device]; - if (acdb_rx_id > 0 && acdb_tx_id > 0) my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id); else @@ -504,17 +656,48 @@ int platform_switch_voice_call_device_post(void *platform, acdb_rx_id, acdb_tx_id); } - return 0; + if (my_data->csd != NULL) { + if (acdb_rx_id > 0 || acdb_tx_id > 0) { + ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id, + my_data->adev->acdb_settings); + if (ret < 0) { + ALOGE("%s: csd_enable_device, failed, error %d", + __func__, ret); + } + } else { + ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, + acdb_rx_id, acdb_tx_id); + } + } + return ret; } -int platform_start_voice_call(void *platform) +int platform_start_voice_call(void *platform, uint32_t vsid) { - return 0; + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd != NULL) { + ret = my_data->csd->start_voice(vsid); + if (ret < 0) { + ALOGE("%s: csd_start_voice error %d\n", __func__, ret); + } + } + return ret; } -int platform_stop_voice_call(void *platform) +int platform_stop_voice_call(void *platform, uint32_t vsid) { - return 0; + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd != NULL) { + ret = my_data->csd->stop_voice(vsid); + if (ret < 0) { + ALOGE("%s: csd_stop_voice error %d\n", __func__, ret); + } + } + return ret; } int platform_set_voice_volume(void *platform, int volume) @@ -523,7 +706,7 @@ int platform_set_voice_volume(void *platform, int volume) struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Rx Gain"; - int vol_index = 0; + int vol_index = 0, ret = 0; uint32_t set_values[ ] = {0, ALL_SESSION_VSID, DEFAULT_VOLUME_RAMP_DURATION_MS}; @@ -543,7 +726,13 @@ int platform_set_voice_volume(void *platform, int volume) ALOGV("Setting voice volume index: %d", set_values[0]); mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); - return 0; + if (my_data->csd != NULL) { + ret = my_data->csd->volume(ALL_SESSION_VSID, volume); + if (ret < 0) { + ALOGE("%s: csd_volume error %d", __func__, ret); + } + } + return ret; } int platform_set_mic_mute(void *platform, bool state) @@ -552,6 +741,7 @@ int platform_set_mic_mute(void *platform, bool state) struct audio_device *adev = my_data->adev; struct mixer_ctl *ctl; const char *mixer_ctl_name = "Voice Tx Mute"; + int ret = 0; uint32_t set_values[ ] = {0, ALL_SESSION_VSID, DEFAULT_VOLUME_RAMP_DURATION_MS}; @@ -566,9 +756,15 @@ int platform_set_mic_mute(void *platform, bool state) } ALOGV("Setting voice mute state: %d", state); mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); - } - return 0; + if (my_data->csd != NULL) { + ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state); + if (ret < 0) { + ALOGE("%s: csd_mic_mute error %d", __func__, ret); + } + } + } + return ret; } snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices) @@ -1017,6 +1213,13 @@ static int platform_set_slowtalk(struct platform_data *my_data, bool state) my_data->slowtalk = state; } + if (my_data->csd != NULL) { + ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state); + if (ret < 0) { + ALOGE("%s: csd_client_disable_device, failed, error %d", + __func__, ret); + } + } return ret; } diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 795c9f9bc..4cff95978 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -148,35 +148,74 @@ enum { #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20 #define AUDIO_CAPTURE_PERIOD_COUNT 2 +#define DEVICE_NAME_MAX_SIZE 128 +#define HW_INFO_ARRAY_MAX_SIZE 32 + #define DEEP_BUFFER_PCM_DEVICE 0 #define AUDIO_RECORD_PCM_DEVICE 0 #define MULTIMEDIA2_PCM_DEVICE 1 -#define VOICE_CALL_PCM_DEVICE 2 #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 22 +#define PLAYBACK_OFFLOAD_DEVICE 9 + +#ifdef PLATFORM_MSM8610 +#define LOWLATENCY_PCM_DEVICE 12 +#else +#define LOWLATENCY_PCM_DEVICE 15 +#endif #ifdef PLATFORM_MSM8x26 +#define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 14 #define VOLTE_CALL_PCM_DEVICE 17 #define QCHAT_CALL_PCM_DEVICE 18 +#elif PLATFORM_APQ8084 +#define VOICE_CALL_PCM_DEVICE 20 +#define VOICE2_CALL_PCM_DEVICE 13 +#define VOLTE_CALL_PCM_DEVICE 21 +#define QCHAT_CALL_PCM_DEVICE 06 #else +#define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 13 #define VOLTE_CALL_PCM_DEVICE 14 #define QCHAT_CALL_PCM_DEVICE 20 #endif -#define PLAYBACK_OFFLOAD_DEVICE 9 - -#ifdef PLATFORM_MSM8610 -#define LOWLATENCY_PCM_DEVICE 12 -#else -#define LOWLATENCY_PCM_DEVICE 15 -#endif +#define LIB_CSD_CLIENT "libcsd-client.so" +/* CSD-CLIENT related functions */ +typedef int (*init_t)(); +typedef int (*deinit_t)(); +typedef int (*disable_device_t)(); +typedef int (*enable_device_t)(int, int, uint32_t); +typedef int (*volume_t)(uint32_t, int); +typedef int (*mic_mute_t)(uint32_t, int); +typedef int (*slow_talk_t)(uint32_t, uint8_t); +typedef int (*start_voice_t)(uint32_t); +typedef int (*stop_voice_t)(uint32_t); +typedef int (*start_playback_t)(uint32_t); +typedef int (*stop_playback_t)(uint32_t); +typedef int (*start_record_t)(uint32_t, int); +typedef int (*stop_record_t)(uint32_t, int); +/* CSD Client structure */ +struct csd_data { + void *csd_client; + init_t init; + deinit_t deinit; + disable_device_t disable_device; + enable_device_t enable_device; + volume_t volume; + mic_mute_t mic_mute; + slow_talk_t slow_talk; + start_voice_t start_voice; + stop_voice_t stop_voice; + start_playback_t start_playback; + stop_playback_t stop_playback; + start_record_t start_record; + stop_record_t stop_record; +}; -#define DEVICE_NAME_MAX_SIZE 128 -#define HW_INFO_ARRAY_MAX_SIZE 32 #endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal/platform_api.h b/hal/platform_api.h index 856444de5..b9919ae31 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -32,8 +32,8 @@ int platform_switch_voice_call_device_pre(void *platform); int platform_switch_voice_call_device_post(void *platform, snd_device_t out_snd_device, snd_device_t in_snd_device); -int platform_start_voice_call(void *platform); -int platform_stop_voice_call(void *platform); +int platform_start_voice_call(void *platform, uint32_t vsid); +int platform_stop_voice_call(void *platform, uint32_t vsid); int platform_set_voice_volume(void *platform, int volume); int platform_set_mic_mute(void *platform, bool state); snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices); diff --git a/hal/voice.c b/hal/voice.c index 907ebc911..90b7a7e75 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -81,7 +81,7 @@ int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id); session->state.current = CALL_INACTIVE; - ret = platform_stop_voice_call(adev->platform); + ret = platform_stop_voice_call(adev->platform, session->vsid); /* 1. Close the PCM devices */ if (session->pcm_rx) { @@ -179,7 +179,7 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) voice_set_volume(adev, adev->voice.volume); - ret = platform_start_voice_call(adev->platform); + ret = platform_start_voice_call(adev->platform, session->vsid); if (ret < 0) { ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret); goto error_start_voice; -- GitLab From c30f96d2b630380fa2e350e894eb99b731303095 Mon Sep 17 00:00:00 2001 From: Banajit Goswami Date: Thu, 14 Nov 2013 12:46:39 -0800 Subject: [PATCH 076/298] hal: Add audio support for APQ8084 - Add support for OMX audio encoder components for apq8084. Change-Id: I0cf2bba74fe9a90b2dd9c9b96f0f8f3cf28de743 --- mm-audio/aenc-aac/Android.mk | 3 +++ mm-audio/aenc-amrnb/Android.mk | 3 +++ mm-audio/aenc-evrc/Android.mk | 3 +++ mm-audio/aenc-qcelp13/Android.mk | 3 +++ 4 files changed, 12 insertions(+) diff --git a/mm-audio/aenc-aac/Android.mk b/mm-audio/aenc-aac/Android.mk index b81257259..86984368b 100644 --- a/mm-audio/aenc-aac/Android.mk +++ b/mm-audio/aenc-aac/Android.mk @@ -18,6 +18,9 @@ endif ifeq ($(call is-board-platform,msm8610),true) include $(AENC_AAC_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,apq8084),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif endif diff --git a/mm-audio/aenc-amrnb/Android.mk b/mm-audio/aenc-amrnb/Android.mk index 673c5cb36..6c2f45836 100644 --- a/mm-audio/aenc-amrnb/Android.mk +++ b/mm-audio/aenc-amrnb/Android.mk @@ -18,6 +18,9 @@ endif ifeq ($(call is-board-platform,msm8610),true) include $(AENC_AMR_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,apq8084),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif endif diff --git a/mm-audio/aenc-evrc/Android.mk b/mm-audio/aenc-evrc/Android.mk index 0e2ea3827..c8ee1edae 100644 --- a/mm-audio/aenc-evrc/Android.mk +++ b/mm-audio/aenc-evrc/Android.mk @@ -18,6 +18,9 @@ endif ifeq ($(call is-board-platform,msm8610),true) include $(AENC_EVRC_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,apq8084),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif endif diff --git a/mm-audio/aenc-qcelp13/Android.mk b/mm-audio/aenc-qcelp13/Android.mk index d8b589c96..8f6985c52 100644 --- a/mm-audio/aenc-qcelp13/Android.mk +++ b/mm-audio/aenc-qcelp13/Android.mk @@ -18,6 +18,9 @@ endif ifeq ($(call is-board-platform,msm8610),true) include $(AENC_QCELP13_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,apq8084),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif endif -- GitLab From c29d4abe511532255fd79de409be060a242085ee Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Thu, 14 Nov 2013 16:58:02 -0800 Subject: [PATCH 077/298] hal: Update speaker ACDB ID value Currently stereo ACDB ID is used for speaker device but 8974 and 8084 has mono speaker so update correct ACDB ID Change-Id: Id9a18f698456a2cdcf75619c6e28648317f58fef --- hal/msm8974/platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 2aaaf4ab6..16adbb570 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -206,15 +206,15 @@ static const char * const device_table[SND_DEVICE_MAX] = { static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_NONE] = -1, [SND_DEVICE_OUT_HANDSET] = 7, - [SND_DEVICE_OUT_SPEAKER] = 15, - [SND_DEVICE_OUT_SPEAKER_REVERSE] = 15, + [SND_DEVICE_OUT_SPEAKER] = 14, + [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14, [SND_DEVICE_OUT_HEADPHONES] = 10, [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, [SND_DEVICE_OUT_VOICE_HANDSET] = 7, - [SND_DEVICE_OUT_VOICE_SPEAKER] = 15, + [SND_DEVICE_OUT_VOICE_SPEAKER] = 14, [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10, [SND_DEVICE_OUT_HDMI] = 18, - [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15, + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14, [SND_DEVICE_OUT_BT_SCO] = 22, [SND_DEVICE_OUT_BT_SCO_WB] = 39, [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, -- GitLab From c053654496be535138ae82c1ecb39087e2c0aa81 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Thu, 14 Nov 2013 16:25:59 -0800 Subject: [PATCH 078/298] hal: Fix android music app crash when turning ANC OFF - Music app crashes when turning ANC OFF during audio playback - Fix by adding device switch logic on set param request for ANC enable - Fix for broken AAC recording due to missing fluence channel count check Change-Id: I8035d7efd47d4aec278f6ee8c366234982b14222 CRs-fixed: 570800 --- hal/audio_extn/audio_extn.c | 23 ++++++++++++++++++++--- hal/msm8974/platform.c | 11 ++--------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 47d7c3343..0c8918aab 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -63,7 +63,7 @@ void audio_extn_ssr_get_parameters(struct str_parms *query, #endif #ifndef ANC_HEADSET_ENABLED -#define audio_extn_set_anc_parameters(parms) (0) +#define audio_extn_set_anc_parameters(adev, parms) (0) #else bool audio_extn_get_anc_enabled(void) { @@ -97,10 +97,13 @@ bool audio_extn_should_use_fb_anc(void) return false; } -void audio_extn_set_anc_parameters(struct str_parms *parms) +void audio_extn_set_anc_parameters(struct audio_device *adev, + struct str_parms *parms) { int ret; char value[32] ={0}; + struct listnode *node; + struct audio_usecase *usecase; ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ANC, value, sizeof(value)); @@ -111,6 +114,20 @@ void audio_extn_set_anc_parameters(struct str_parms *parms) aextnmod.anc_enabled = false; } + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK) { + if (usecase->stream.out->devices == \ + AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + usecase->stream.out->devices == \ + AUDIO_DEVICE_OUT_WIRED_HEADSET) { + select_devices(adev, usecase->id); + ALOGV("%s: switching device", __func__); + break; + } + } + } + ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled); } #endif /* ANC_HEADSET_ENABLED */ @@ -196,7 +213,7 @@ int audio_extn_get_afe_proxy_parameters(struct str_parms *query, void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms) { - audio_extn_set_anc_parameters(parms); + audio_extn_set_anc_parameters(adev, parms); audio_extn_set_afe_proxy_parameters(parms); audio_extn_fm_set_parameters(adev, parms); audio_extn_listen_set_parameters(adev, parms); diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 2aaaf4ab6..717521607 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -877,18 +877,11 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d set_echo_reference(adev->mixer, "NONE"); } } else if (source == AUDIO_SOURCE_MIC) { - if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { - if(my_data->fluence_type & FLUENCE_DUAL_MIC && - my_data->fluence_in_audio_rec) - snd_device = SND_DEVICE_IN_SPEAKER_DMIC; - else - snd_device = SND_DEVICE_IN_SPEAKER_MIC; - } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC && + channel_count == 1 ) { if(my_data->fluence_type & FLUENCE_DUAL_MIC && my_data->fluence_in_audio_rec) snd_device = SND_DEVICE_IN_HANDSET_DMIC; - else - snd_device = SND_DEVICE_IN_HANDSET_MIC; } } else if (source == AUDIO_SOURCE_FM_RX || source == AUDIO_SOURCE_FM_RX_A2DP) { -- GitLab From 05573b74bf85342b0ca58800126d7f438272b331 Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Fri, 15 Nov 2013 15:21:40 -0800 Subject: [PATCH 079/298] hal: Add support for compressed voip Add support to enable voip calls using compressed audio formats. Change-Id: If20493b75befbcc56945e4309c8f01384948a7b5 --- hal/Android.mk | 9 +- hal/audio_hw.c | 128 ++++++- hal/audio_hw.h | 5 +- hal/msm8974/platform.c | 66 ++-- hal/msm8974/platform.h | 6 + hal/voice.c | 13 +- hal/voice_extn/compress_voip.c | 676 +++++++++++++++++++++++++++++++++ hal/voice_extn/voice_extn.c | 15 + hal/voice_extn/voice_extn.h | 155 ++++++++ 9 files changed, 1021 insertions(+), 52 deletions(-) create mode 100644 hal/voice_extn/compress_voip.c diff --git a/hal/Android.mk b/hal/Android.mk index 58cf1c659..21dc8a051 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -57,12 +57,16 @@ endif ifneq ($(strip $(AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS)),true) LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED LOCAL_SRC_FILES += voice_extn/voice_extn.c - LOCAL_C_INCLUDES += $(LOCAL_PATH)/voice_extn LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED endif + +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_VOIP)),true) + LOCAL_CFLAGS += -DCOMPRESS_VOIP_ENABLED + LOCAL_SRC_FILES += voice_extn/compress_voip.c +endif endif ifneq ($(strip, $(AUDIO_FEATURE_DISABLED_SPKR_PROTECTION)),true) @@ -92,7 +96,8 @@ LOCAL_C_INCLUDES += \ $(call include-path-for, audio-route) \ $(call include-path-for, audio-effects) \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \ - $(LOCAL_PATH)/audio_extn + $(LOCAL_PATH)/audio_extn \ + $(LOCAL_PATH)/voice_extn ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true) LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 209c13e5c..9b59e4a9d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -50,6 +50,7 @@ #include "platform_api.h" #include #include "audio_extn.h" +#include "voice_extn.h" #include "sound/compress_params.h" @@ -112,6 +113,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_VOICE2_CALL] = "voice2-call", [USECASE_VOLTE_CALL] = "volte-call", [USECASE_QCHAT_CALL] = "qchat-call", + [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call", [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", @@ -573,6 +575,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) snd_device_t in_snd_device = SND_DEVICE_NONE; struct audio_usecase *usecase = NULL; struct audio_usecase *vc_usecase = NULL; + struct audio_usecase *voip_usecase = NULL; struct listnode *node; int status = 0; @@ -582,7 +585,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) return -EINVAL; } - if (usecase->type == VOICE_CALL) { + if ((usecase->type == VOICE_CALL) || + (usecase->type == VOIP_CALL)) { out_snd_device = platform_get_output_snd_device(adev->platform, usecase->stream.out->devices); in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices); @@ -602,6 +606,12 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) in_snd_device = vc_usecase->in_snd_device; out_snd_device = vc_usecase->out_snd_device; } + } else if (voice_extn_compress_voip_is_active(adev)) { + voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + if (voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + in_snd_device = voip_usecase->in_snd_device; + out_snd_device = voip_usecase->out_snd_device; + } } if (usecase->type == PCM_PLAYBACK) { usecase->devices = usecase->stream.out->devices; @@ -645,8 +655,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) * and enable both RX and TX devices though one of them is same as current * device. */ - if (usecase->type == VOICE_CALL) { - disable_all_usecases_of_type(adev, VOICE_CALL, true); + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) { + disable_all_usecases_of_type(adev, usecase->type, true); status = platform_switch_voice_call_device_pre(adev->platform); } @@ -673,7 +683,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) enable_snd_device(adev, in_snd_device, false); } - if (usecase->type == VOICE_CALL) + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) status = platform_switch_voice_call_device_post(adev->platform, out_snd_device, in_snd_device); @@ -683,8 +693,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) usecase->in_snd_device = in_snd_device; usecase->out_snd_device = out_snd_device; - if (usecase->type == VOICE_CALL) - enable_all_usecases_of_type(adev, VOICE_CALL, true); + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) + enable_all_usecases_of_type(adev, usecase->type, true); else enable_audio_route(adev, usecase, true); @@ -1115,7 +1125,8 @@ static int check_input_parameters(uint32_t sample_rate, { int ret = 0; - if (format != AUDIO_FORMAT_PCM_16_BIT) ret = -EINVAL; + if ((format != AUDIO_FORMAT_PCM_16_BIT) && + !voice_extn_compress_voip_is_format_supported(format)) ret = -EINVAL; switch (channel_count) { case 1: @@ -1181,9 +1192,10 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) return out->compr_config.fragment_size; - } + else if(out->usecase == USECASE_COMPRESS_VOIP_CALL) + return voice_extn_compress_voip_out_get_buffer_size(out); return out->config.period_size * audio_stream_frame_size(stream); } @@ -1214,6 +1226,13 @@ static int out_standby(struct audio_stream *stream) ALOGV("%s: enter: usecase(%d: %s)", __func__, out->usecase, use_case_table[out->usecase]); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + /* Ignore standby in case of voip call because the voip output + * stream is closed in adev_close_output_stream() + */ + ALOGV("%s: Ignore Standby in VOIP call", __func__); + return 0; + } pthread_mutex_lock(&out->lock); pthread_mutex_lock(&adev->lock); @@ -1401,7 +1420,11 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); str = str_parms_to_str(reply); } else { - str = strdup(keys); + voice_extn_out_get_parameters(out, query, reply); + str = str_parms_to_str(reply); + if (!strncmp(str, "", sizeof(""))) { + str = strdup(keys); + } } str_parms_destroy(query); str_parms_destroy(reply); @@ -1461,7 +1484,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, if (out->standby) { out->standby = false; pthread_mutex_lock(&adev->lock); - ret = start_output_stream(out); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) + ret = voice_extn_compress_voip_start_output_stream(out); + else + ret = start_output_stream(out); pthread_mutex_unlock(&adev->lock); /* ToDo: If use case is compress offload should return 0 */ if (ret != 0) { @@ -1686,6 +1712,9 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) { struct stream_in *in = (struct stream_in *)stream; + if(in->usecase == USECASE_COMPRESS_VOIP_CALL) + return voice_extn_compress_voip_in_get_buffer_size(in); + return in->config.period_size * audio_stream_frame_size(stream); } @@ -1698,7 +1727,9 @@ static uint32_t in_get_channels(const struct audio_stream *stream) static audio_format_t in_get_format(const struct audio_stream *stream) { - return AUDIO_FORMAT_PCM_16_BIT; + struct stream_in *in = (struct stream_in *)stream; + + return in->format; } static int in_set_format(struct audio_stream *stream, audio_format_t format) @@ -1712,6 +1743,15 @@ static int in_standby(struct audio_stream *stream) struct audio_device *adev = in->dev; int status = 0; ALOGV("%s: enter", __func__); + + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + /* Ignore standby in case of voip call because the voip input + * stream is closed in adev_close_input_stream() + */ + ALOGV("%s: Ignore Standby in VOIP call", __func__); + return status; + } + pthread_mutex_lock(&in->lock); if (!in->standby) { in->standby = true; @@ -1779,7 +1819,21 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) static char* in_get_parameters(const struct audio_stream *stream, const char *keys) { - return strdup(""); + struct stream_in *in = (struct stream_in *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + ALOGV("%s: enter: keys - %s", __func__, keys); + + voice_extn_in_get_parameters(in, query, reply); + + str = str_parms_to_str(reply); + str_parms_destroy(query); + str_parms_destroy(reply); + + ALOGV("%s: exit: returns - %s", __func__, str); + return str; } static int in_set_gain(struct audio_stream_in *stream, float gain) @@ -1797,7 +1851,10 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, pthread_mutex_lock(&in->lock); if (in->standby) { pthread_mutex_lock(&adev->lock); - ret = start_input_stream(in); + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) + ret = voice_extn_compress_voip_start_input_stream(in); + else + ret = start_input_stream(in); pthread_mutex_unlock(&adev->lock); if (ret != 0) { goto exit; @@ -1932,6 +1989,17 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config.rate = config->sample_rate; out->config.channels = popcount(out->channel_mask); out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); + } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && + (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) && + (voice_extn_compress_voip_is_format_supported(out->format))) { + ret = voice_extn_compress_voip_open_output_stream(out); + if (ret != 0) { + ALOGE("%s: Compress voip output cannot be opened, error:%d", + __func__, ret); + goto error_open; + } + out->config.rate = config->sample_rate; + out->sample_rate = config->sample_rate; } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { @@ -2065,9 +2133,18 @@ static void adev_close_output_stream(struct audio_hw_device *dev, { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; + int ret = 0; ALOGV("%s: enter", __func__); - out_standby(&stream->common); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + ret = voice_extn_compress_voip_close_output_stream(&stream->common); + if(ret != 0) + ALOGE("%s: Compress voip output cannot be closed, error:%d", + __func__, ret); + } + else + out_standby(&stream->common); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { destroy_offload_callback_thread(out); @@ -2295,7 +2372,18 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->usecase = USECASE_AUDIO_RECORD; in->config = pcm_config_audio_capture; in->config.rate = config->sample_rate; + in->format = config->format; + if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && + (voice_extn_compress_voip_is_format_supported(in->format))) { + ret = voice_extn_compress_voip_open_input_stream(in); + if (ret != 0) + { + ALOGE("%s: Compress voip input cannot be opened, error:%d", + __func__, ret); + goto err_open; + } + } if (channel_count == 6) { if(audio_extn_ssr_get_enabled()) { if(audio_extn_ssr_init(adev, in)) { @@ -2329,10 +2417,18 @@ err_open: static void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) { + int ret; struct stream_in *in = (struct stream_in *)stream; ALOGV("%s", __func__); - in_standby(&stream->common); + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + ret = voice_extn_compress_voip_close_input_stream(&stream->common); + if (ret != 0) + ALOGE("%s: Compress voip input cannot be closed, error:%d", + __func__, ret); + } else + in_standby(&stream->common); + if (audio_extn_ssr_get_enabled() && (popcount(in->channel_mask) == 6)) { audio_extn_ssr_deinit(); } diff --git a/hal/audio_hw.h b/hal/audio_hw.h index d68236686..9dca5c1df 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -74,6 +74,7 @@ typedef enum { USECASE_VOICE2_CALL, USECASE_VOLTE_CALL, USECASE_QCHAT_CALL, + USECASE_COMPRESS_VOIP_CALL, USECASE_INCALL_REC_UPLINK, USECASE_INCALL_REC_DOWNLINK, @@ -168,6 +169,7 @@ struct stream_in { audio_usecase_t usecase; bool enable_aec; bool enable_ns; + audio_format_t format; struct audio_device *dev; }; @@ -175,7 +177,8 @@ struct stream_in { typedef enum { PCM_PLAYBACK, PCM_CAPTURE, - VOICE_CALL + VOICE_CALL, + VOIP_CALL } usecase_type_t; union stream_ptr { diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index b8e8bb5f4..4a5bbc6e7 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -30,6 +30,7 @@ #include #include "platform.h" #include "audio_extn.h" +#include "voice_extn.h" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" @@ -56,11 +57,6 @@ #define SAMPLE_RATE_8KHZ 8000 #define SAMPLE_RATE_16KHZ 16000 -#define MAX_VOL_INDEX 5 -#define MIN_VOL_INDEX 0 -#define percent_to_index(val, min, max) \ - ((val) * ((max) - (min)) * 0.01 + (min) + .5) - #define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence" #define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate" #define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable" @@ -116,6 +112,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE}, + [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE}, [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, @@ -764,22 +761,20 @@ int platform_set_mic_mute(void *platform, bool state) ALL_SESSION_VSID, DEFAULT_VOLUME_RAMP_DURATION_MS}; - if (adev->mode == AUDIO_MODE_IN_CALL) { - set_values[0] = state; - ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("Setting voice mute state: %d", state); - mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting voice mute state: %d", state); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); - if (my_data->csd != NULL) { - ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state); - if (ret < 0) { - ALOGE("%s: csd_mic_mute error %d", __func__, ret); - } + if (my_data->csd != NULL) { + ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state); + if (ret < 0) { + ALOGE("%s: csd_mic_mute error %d", __func__, ret); } } return ret; @@ -803,15 +798,26 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi goto exit; } - if (mode == AUDIO_MODE_IN_CALL) { + if ((mode == AUDIO_MODE_IN_CALL) || + voice_extn_compress_voip_is_active(adev)) { if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { - if (adev->voice.tty_mode == TTY_MODE_FULL) { - snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES; - } else if (adev->voice.tty_mode == TTY_MODE_VCO) { - snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; - } else if (adev->voice.tty_mode == TTY_MODE_HCO) { - snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; + if ((adev->voice.tty_mode != TTY_MODE_OFF) && + !voice_extn_compress_voip_is_active(adev)) { + switch (adev->voice.tty_mode) { + case TTY_MODE_FULL: + snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES; + break; + case TTY_MODE_VCO: + snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES; + break; + case TTY_MODE_HCO: + snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET; + break; + default: + ALOGE("%s: Invalid TTY mode (%#x)", + __func__, adev->voice.tty_mode); + } } else if (audio_extn_get_anc_enabled()) { if (audio_extn_should_use_fb_anc()) snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET; @@ -933,12 +939,14 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d ALOGV("%s: enter: out_device(%#x) in_device(%#x)", __func__, out_device, in_device); - if (mode == AUDIO_MODE_IN_CALL) { + if ((mode == AUDIO_MODE_IN_CALL) || + voice_extn_compress_voip_is_active(adev)) { if (out_device == AUDIO_DEVICE_NONE) { ALOGE("%s: No output device set for voice call", __func__); goto exit; } - if (adev->voice.tty_mode != TTY_MODE_OFF) { + if ((adev->voice.tty_mode != TTY_MODE_OFF) && + !voice_extn_compress_voip_is_active(adev)) { if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { switch (adev->voice.tty_mode) { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 18cd4a21b..9d4378d4c 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -136,6 +136,11 @@ enum { #define DEFAULT_VOLUME_RAMP_DURATION_MS 20 #define MIXER_PATH_MAX_LENGTH 100 +#define MAX_VOL_INDEX 5 +#define MIN_VOL_INDEX 0 +#define percent_to_index(val, min, max) \ + ((val) * ((max) - (min)) * 0.01 + (min) + .5) + /* * tinyAlsa library interprets period size as number of frames * one frame = channel_count * sizeof (pcm sample) @@ -170,6 +175,7 @@ enum { #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 22 #define PLAYBACK_OFFLOAD_DEVICE 9 +#define COMPRESS_VOIP_CALL_PCM_DEVICE 3 #ifdef PLATFORM_MSM8610 #define LOWLATENCY_PCM_DEVICE 12 diff --git a/hal/voice.c b/hal/voice.c index ff497c7a8..62449d232 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -261,10 +261,11 @@ int voice_set_mic_mute(struct audio_device *adev, bool state) { int err = 0; - err = platform_set_mic_mute(adev->platform, state); - if (!err) { - adev->voice.mic_mute = state; - } + adev->voice.mic_mute = state; + if (adev->mode == AUDIO_MODE_IN_CALL) + err = platform_set_mic_mute(adev->platform, state); + if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) + err = voice_extn_compress_voip_set_mic_mute(adev, state); return err; } @@ -295,6 +296,9 @@ int voice_set_volume(struct audio_device *adev, float volume) err = platform_set_voice_volume(adev->platform, vol); } + if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) + err = voice_extn_compress_voip_set_volume(adev, volume); + return err; } @@ -333,6 +337,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); voice_extn_set_parameters(adev, parms); + voice_extn_compress_voip_set_parameters(adev, parms); ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); if (ret >= 0) { diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c new file mode 100644 index 000000000..25668cc4f --- /dev/null +++ b/hal/voice_extn/compress_voip.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "compress_voip" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audio_hw.h" +#include "platform_api.h" +#include "platform.h" +#include "voice_extn.h" + +#define COMPRESS_VOIP_IO_BUF_SIZE 320 + +struct pcm_config pcm_config_voip = { + .channels = 1, + .rate = 8000, /* changed when the stream is opened */ + .period_size = COMPRESS_VOIP_IO_BUF_SIZE/2, + .period_count = 10, + .format = PCM_FORMAT_S16_LE, +}; + +struct voip_data { + struct pcm *pcm_rx; + struct pcm *pcm_tx; + struct stream_out *out_stream; + int ref_count; +}; + +#define MODE_IS127 0x2 +#define MODE_4GV_NB 0x3 +#define MODE_4GV_WB 0x4 +#define MODE_AMR 0x5 +#define MODE_AMR_WB 0xD +#define MODE_PCM 0xC +#define MODE_4GV_NW 0xE + +#define AUDIO_PARAMETER_KEY_VOIP_RATE "voip_rate" +#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN "evrc_rate_min" +#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX "evrc_rate_max" +#define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE "dtx_on" +#define AUDIO_PARAMETER_VALUE_VOIP_TRUE "true" +#define AUDIO_PARAMETER_KEY_VOIP_CHECK "voip_flag" + +static struct voip_data voip_data = { + .pcm_rx = NULL, + .pcm_tx = NULL, + .out_stream = NULL, + .ref_count = 0 +}; + +static int voip_set_volume(struct audio_device *adev, int volume); +static int voip_set_mic_mute(struct audio_device *adev, bool state); +static int voip_set_mode(struct audio_device *adev, int format); +static int voip_set_rate(struct audio_device *adev, int rate); +static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate, + int max_rate); +static int voip_set_dtx(struct audio_device *adev, bool enable); +static int voip_stop_call(struct audio_device *adev); +static int voip_start_call(struct audio_device *adev); + +static int audio_format_to_voip_mode(int format) +{ + int mode; + + switch(format) { + case AUDIO_FORMAT_PCM_16_BIT: + mode = MODE_PCM; + break; + case AUDIO_FORMAT_AMR_NB: + mode = MODE_AMR; + break; + case AUDIO_FORMAT_AMR_WB: + mode = MODE_AMR_WB; + break; + case AUDIO_FORMAT_EVRC: + mode = MODE_IS127; + break; + case AUDIO_FORMAT_EVRCB: + mode = MODE_4GV_NB; + break; + case AUDIO_FORMAT_EVRCWB: + mode = MODE_4GV_WB; + break; + case AUDIO_FORMAT_EVRCNW: + mode = MODE_4GV_NW; + break; + default: + mode = MODE_PCM; + } + return mode; +} + +static int voip_set_volume(struct audio_device *adev, int volume) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Rx Gain"; + int vol_index = 0; + uint32_t set_values[ ] = {0, + DEFAULT_VOLUME_RAMP_DURATION_MS}; + + ALOGV("%s: enter", __func__); + + /* Voice volume levels are mapped to adsp volume levels as follows. + * 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 + * But this values don't changed in kernel. So, below change is need. + */ + vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); + set_values[0] = vol_index; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("%s: Setting voip volume index: %d", __func__, set_values[0]); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_mic_mute(struct audio_device *adev, bool state) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Tx Mute"; + uint32_t set_values[ ] = {0, + DEFAULT_VOLUME_RAMP_DURATION_MS}; + + ALOGV("%s: enter, state=%d", __func__, state); + + if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) { + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + } + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_mode(struct audio_device *adev, int format) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Mode Config"; + uint32_t set_values[ ] = {0}; + int mode; + + ALOGD("%s: enter, format=%d", __func__, format); + + mode = audio_format_to_voip_mode(format); + ALOGD("%s: Derived mode = %d", __func__, mode); + + set_values[0] = mode; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_rate(struct audio_device *adev, int rate) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Rate Config"; + uint32_t set_values[ ] = {0}; + + ALOGD("%s: enter, rate=%d", __func__, rate); + + set_values[0] = rate; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate, + int max_rate) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Evrc Min Max Rate Config"; + uint32_t set_values[ ] = {0, 0}; + + ALOGD("%s: enter, min_rate=%d, max_rate=%d", + __func__, min_rate, max_rate); + + set_values[0] = min_rate; + set_values[1] = max_rate; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_set_dtx(struct audio_device *adev, bool enable) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voip Dtx Mode"; + uint32_t set_values[ ] = {0}; + + ALOGD("%s: enter, enable=%d", __func__, enable); + + set_values[0] = enable; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + ALOGV("%s: exit", __func__); + return 0; +} + +static int voip_stop_call(struct audio_device *adev) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + + ALOGD("%s: enter, ref_count=%d", __func__, voip_data.ref_count); + voip_data.ref_count--; + + if (!voip_data.ref_count) { + uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, USECASE_COMPRESS_VOIP_CALL); + return -EINVAL; + } + + /* 1. Close the PCM devices */ + if (voip_data.pcm_rx) { + pcm_close(voip_data.pcm_rx); + voip_data.pcm_rx = NULL; + } + if (voip_data.pcm_tx) { + pcm_close(voip_data.pcm_tx); + voip_data.pcm_tx = NULL; + } + + /* 2. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 3. Disable the rx and tx devices */ + disable_snd_device(adev, uc_info->out_snd_device, false); + disable_snd_device(adev, uc_info->in_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + } else + ALOGV("%s: NO-OP because ref_count=%d", __func__, voip_data.ref_count); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +static int voip_start_call(struct audio_device *adev) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + int pcm_dev_rx_id, pcm_dev_tx_id; + struct pcm_config voip_config = pcm_config_voip; + + ALOGD("%s: enter", __func__); + + uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + if ((uc_info == NULL) && (voip_data.out_stream)) { + ALOGV("%s: voip usecase is added to the list", __func__); + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = USECASE_COMPRESS_VOIP_CALL; + uc_info->type = VOIP_CALL; + uc_info->stream.out = voip_data.out_stream; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, USECASE_COMPRESS_VOIP_CALL); + + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); + + if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) { + ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); + ret = -EIO; + goto error_start_voip; + } + + ALOGD("%s: Opening PCM playback device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_rx_id); + voip_data.pcm_rx = pcm_open(SOUND_CARD, + pcm_dev_rx_id, + PCM_OUT, &voip_config); + if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx)); + pcm_close(voip_data.pcm_rx); + voip_data.pcm_rx = NULL; + ret = -EIO; + goto error_start_voip; + } + + ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_tx_id); + voip_data.pcm_tx = pcm_open(SOUND_CARD, + pcm_dev_tx_id, + PCM_IN, &voip_config); + if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx)); + pcm_close(voip_data.pcm_rx); + voip_data.pcm_tx = NULL; + if (voip_data.pcm_rx) { + pcm_close(voip_data.pcm_rx); + voip_data.pcm_rx = NULL; + } + ret = -EIO; + goto error_start_voip; + } + pcm_start(voip_data.pcm_rx); + pcm_start(voip_data.pcm_tx); + + voice_extn_compress_voip_set_volume(adev, adev->voice.volume); + + if (ret < 0) { + ALOGE("%s: error %d\n", __func__, ret); + goto error_start_voip; + } + voip_data.ref_count = 0; + } + else + ALOGV("%s: voip usecase is already enabled", __func__); + + voip_data.ref_count++; + return 0; + +error_start_voip: + voip_stop_call(adev); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +void voice_extn_compress_voip_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + char *str; + char value[32]={0}; + int ret, rate; + int min_rate, max_rate; + bool flag; + + ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE, + value, sizeof(value)); + if (ret >= 0) { + rate = atoi(value); + voip_set_rate(adev, rate); + voip_set_evrc_min_max_rate(adev, rate, rate); + } + + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN, + value, sizeof(value)); + if (ret >= 0) { + min_rate = atoi(value); + str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN); + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX, + value, sizeof(value)); + if (ret >= 0) { + max_rate = atoi(value); + voip_set_evrc_min_max_rate(adev, min_rate, max_rate); + } + else + ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__); + } + + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE, + value, sizeof(value)); + if (ret >= 0) { + flag = false; + if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0) + flag = true; + voip_set_dtx(adev, flag); + } + + ALOGV("%s: exit", __func__); +} + +void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply) +{ + int ret, val; + char value[32]={0}; + + ALOGD("%s: enter", __func__); + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value)); + + if (ret >= 0) { + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true); + else + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false); + } + + ALOGV("%s: exit", __func__); +} + +void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply) +{ + int ret, val; + char value[32]={0}; + + ALOGV("%s: enter", __func__); + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value)); + + if (ret >= 0) { + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true); + else + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false); + } + + ALOGD("%s: exit: return - %s", __func__, str_parms_to_str(reply)); +} + +int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out) +{ + return COMPRESS_VOIP_IO_BUF_SIZE; +} + +int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in) +{ + return COMPRESS_VOIP_IO_BUF_SIZE; +} + +int voice_extn_compress_voip_start_output_stream(struct stream_out *out) +{ + int ret = 0; + struct audio_device *adev = out->dev; + struct audio_usecase *uc_info; + + ALOGD("%s: enter", __func__); + + ret = voip_start_call(adev); + out->pcm = voip_data.pcm_rx; + uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + uc_info->stream.out = out; + uc_info->devices = out->devices; + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_start_input_stream(struct stream_in *in) +{ + int ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = in->dev; + + ALOGD("%s: enter", __func__); + + ret = voip_start_call(adev); + in->pcm = voip_data.pcm_tx; + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + int ret = 0; + + ALOGD("%s: enter", __func__); + + ret = voip_stop_call(adev); + voip_data.out_stream = NULL; + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int voice_extn_compress_voip_open_output_stream(struct stream_out *out) +{ + int mode, ret; + + ALOGD("%s: enter", __func__); + + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO; + out->channel_mask = AUDIO_CHANNEL_OUT_MONO; + out->usecase = USECASE_COMPRESS_VOIP_CALL; + out->config = pcm_config_voip; + voip_data.out_stream = out; + + ret = voip_set_mode(out->dev, out->format); + + ALOGV("%s: exit", __func__); + return ret; +} + +int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + int status = 0; + + ALOGD("%s: enter", __func__); + + status = voip_stop_call(adev); + + ALOGV("%s: exit: status(%d)", __func__, status); + return status; + +} + +int voice_extn_compress_voip_open_input_stream(struct stream_in *in) +{ + int sample_rate; + int buffer_size,frame_size; + int mode, ret; + + ALOGD("%s: enter", __func__); + + in->usecase = USECASE_COMPRESS_VOIP_CALL; + sample_rate = in->config.rate; + in->config = pcm_config_voip; + in->config.rate = sample_rate; + + ret = voip_set_mode(in->dev, in->format); + + ALOGV("%s: exit", __func__); + return ret; +} + +int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume) +{ + int vol, err = 0; + + ALOGV("%s: enter", __func__); + + if (volume < 0.0) { + volume = 0.0; + } else if (volume > 1.0) { + volume = 1.0; + } + + vol = lrint(volume * 100.0); + + /* Voice volume levels from android are mapped to driver volume levels as follows. + * 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0 + * So adjust the volume to get the correct volume index in driver + */ + vol = 100 - vol; + + err = voip_set_volume(adev, vol); + + ALOGV("%s: exit: status(%d)", __func__, err); + + return err; +} + +int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state) +{ + int err = 0; + + ALOGV("%s: enter", __func__); + + err = voip_set_mic_mute(adev, state); + + ALOGV("%s: exit: status(%d)", __func__, err); + return err; +} + +bool voice_extn_compress_voip_pcm_prop_check() +{ + char prop_value[PROPERTY_VALUE_MAX] = {0}; + + property_get("use.voice.path.for.pcm.voip", prop_value, "0"); + if (!strncmp("true", prop_value, sizeof("true"))) + { + ALOGD("%s: VoIP PCM property is enabled", __func__); + return true; + } + else + return false; +} + +bool voice_extn_compress_voip_is_active(struct audio_device *adev) +{ + struct audio_usecase *voip_usecase = NULL; + voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); + + if (voip_usecase != NULL) + return true; + else + return false; +} + +bool voice_extn_compress_voip_is_format_supported(audio_format_t format) +{ + switch (format) { + case AUDIO_FORMAT_PCM_16_BIT: + if (voice_extn_compress_voip_pcm_prop_check()) + return true; + else + return false; + case AUDIO_FORMAT_AMR_NB: + case AUDIO_FORMAT_AMR_WB: + case AUDIO_FORMAT_EVRC: + case AUDIO_FORMAT_EVRCB: + case AUDIO_FORMAT_EVRCWB: + case AUDIO_FORMAT_EVRCNW: + return true; + default: + return false; + } +} diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 87a97e2c3..c12fcb3bf 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -32,6 +32,7 @@ #include "voice.h" #include "platform.h" #include "platform_api.h" +#include "voice_extn.h" #define AUDIO_PARAMETER_KEY_VSID "vsid" #define AUDIO_PARAMETER_KEY_CALL_STATE "call_state" @@ -433,6 +434,20 @@ done: return ret; } +void voice_extn_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply) +{ + voice_extn_compress_voip_out_get_parameters(out, query, reply); +} + +void voice_extn_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply) +{ + voice_extn_compress_voip_in_get_parameters(in, query, reply); +} + int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, struct stream_out *out) { diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index c4e213112..b3643f908 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -32,6 +32,12 @@ int voice_extn_set_parameters(struct audio_device *adev, int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id); +void voice_extn_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply); +void voice_extn_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply); #else static int voice_extn_start_call(struct audio_device *adev) { @@ -70,6 +76,18 @@ static int voice_extn_get_active_session_id(struct audio_device *adev, { return -ENOSYS; } + +static void voice_extn_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply) +{ +} + +static void voice_extn_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply) +{ +} #endif #ifdef INCALL_MUSIC_ENABLED @@ -83,4 +101,141 @@ static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *ad } #endif +#ifdef COMPRESS_VOIP_ENABLED +int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream); +int voice_extn_compress_voip_open_output_stream(struct stream_out *out); + +int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream); +int voice_extn_compress_voip_open_input_stream(struct stream_in *in); + +int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out); +int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in); + +int voice_extn_compress_voip_start_input_stream(struct stream_in *in); +int voice_extn_compress_voip_start_output_stream(struct stream_out *out); + +int voice_extn_compress_voip_set_mic_mute(struct audio_device *dev, bool state); +int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume); +int voice_extn_compress_voip_select_devices(struct audio_device *adev, + snd_device_t *out_snd_device, + snd_device_t *in_snd_device); +void voice_extn_compress_voip_set_parameters(struct audio_device *adev, + struct str_parms *parms); + +void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply); +void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply); +bool voice_extn_compress_voip_pcm_prop_check(); +bool voice_extn_compress_voip_is_active(struct audio_device *adev); +bool voice_extn_compress_voip_is_format_supported(audio_format_t format); +#else +static int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_open_output_stream(struct stream_out *out) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_open_input_stream(struct stream_in *in) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_out_get_buffer_size(struct audio_stream *stream) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_start_input_stream(struct stream_in *in) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_start_output_stream(struct stream_out *out) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return 0; +} + +static int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return 0; +} + +static int voice_extn_compress_voip_select_devices(struct audio_device *adev, + snd_device_t *out_snd_device, + snd_device_t *in_snd_device) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; +} + +static void voice_extn_compress_voip_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); +} + +static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, + struct str_parms *query, + struct str_parms *reply) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); +} + +static void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, + struct str_parms *query, + struct str_parms *reply) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); +} + +static bool voice_extn_compress_voip_pcm_prop_check() +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return false; +} + +static bool voice_extn_compress_voip_is_active(struct audio_device *adev) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return false; +} +static bool voice_extn_compress_voip_is_format_supported(audio_format_t format) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return true; +} +#endif + #endif //VOICE_EXTN_H -- GitLab From e62d784d2d0520c4c7780d764c659cd161a5b1b6 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Fri, 25 Oct 2013 16:26:03 -0700 Subject: [PATCH 080/298] hal: Add support for compressed capture - Add support for AMR-WB compressed capture. Change-Id: Ief591c5d1ccc6f8afb408abfff447787ee7bd7aa --- hal/Android.mk | 5 + hal/audio_extn/audio_extn.h | 20 ++++ hal/audio_extn/compress_capture.c | 153 ++++++++++++++++++++++++++++++ hal/audio_hw.c | 19 +++- hal/audio_hw.h | 1 + hal/msm8960/platform.c | 6 ++ hal/msm8974/platform.c | 8 +- hal/msm8974/platform.h | 1 + hal/platform_api.h | 2 +- 9 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 hal/audio_extn/compress_capture.c diff --git a/hal/Android.mk b/hal/Android.mk index 21dc8a051..abafb85c3 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -82,6 +82,11 @@ ifdef MULTIPLE_HW_VARIANTS_ENABLED LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_CAPTURE)),true) + LOCAL_CFLAGS += -DCOMPRESS_CAPTURE_ENABLED + LOCAL_SRC_FILES += audio_extn/compress_capture.c +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index a54e5e7e1..7d04c6d6b 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -137,4 +137,24 @@ void audio_extn_spkr_prot_stop_processing(); bool audio_extn_spkr_prot_is_enabled(); #endif +#ifndef COMPRESS_CAPTURE_ENABLED +#define audio_extn_compr_cap_init(adev,in) (0) +#define audio_extn_compr_cap_enabled() (0) +#define audio_extn_compr_cap_format_supported(format) (0) +#define audio_extn_compr_cap_usecase_supported(usecase) (0) +#define audio_extn_compr_cap_get_buffer_size(format) (0) +#define audio_extn_compr_cap_read(in, buffer, bytes) (0) +#define audio_extn_compr_cap_deinit() (0) +#else +void audio_extn_compr_cap_init(struct audio_device *adev, + struct stream_in *in); +bool audio_extn_compr_cap_enabled(); +bool audio_extn_compr_cap_format_supported(audio_format_t format); +bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase); +size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format); +size_t audio_extn_compr_cap_read(struct stream_in *in, + void *buffer, size_t bytes); +void audio_extn_compr_cap_deinit(); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_extn/compress_capture.c b/hal/audio_extn/compress_capture.c new file mode 100644 index 000000000..f3db41926 --- /dev/null +++ b/hal/audio_extn/compress_capture.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_compress" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include + +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" + +#include "sound/compress_params.h" +#include "sound/compress_offload.h" + +#ifdef COMPRESS_CAPTURE_ENABLED + +#define COMPRESS_IN_CONFIG_CHANNELS 1 +#define COMPRESS_IN_CONFIG_PERIOD_SIZE 2048 +#define COMPRESS_IN_CONFIG_PERIOD_COUNT 16 + + +struct compress_in_module { + uint8_t *in_buf; +}; + +static struct compress_in_module c_in_mod = { + .in_buf = NULL, +}; + + +void audio_extn_compr_cap_init(struct audio_device *adev, + struct stream_in *in) +{ + in->usecase = USECASE_AUDIO_RECORD_COMPRESS; + in->config.channels = COMPRESS_IN_CONFIG_CHANNELS; + in->config.period_size = COMPRESS_IN_CONFIG_PERIOD_SIZE; + in->config.period_count= COMPRESS_IN_CONFIG_PERIOD_COUNT; + in->config.format = AUDIO_FORMAT_AMR_WB; + c_in_mod.in_buf = (uint8_t*)calloc(1, in->config.period_size*2); +} + +void audio_extn_compr_cap_deinit() +{ + if (c_in_mod.in_buf) { + free(c_in_mod.in_buf); + c_in_mod.in_buf = NULL; + } +} + +bool audio_extn_compr_cap_enabled() +{ + char prop_value[PROPERTY_VALUE_MAX] = {0}; + bool tunnel_encode = false; + + property_get("tunnel.audio.encode",prop_value,"0"); + if (!strncmp("true", prop_value, sizeof("true"))) + return true; + else + return false; +} + +bool audio_extn_compr_cap_format_supported(audio_format_t format) +{ + if (format == AUDIO_FORMAT_AMR_WB) + return true; + else + return false; +} + + +bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase) +{ + if (usecase == USECASE_AUDIO_RECORD_COMPRESS) + return true; + else + return false; +} + + +size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format) +{ + if (format == AUDIO_FORMAT_AMR_WB) + /*One AMR WB frame is 61 bytes. Return that to the caller. + The buffer size is not altered, that is still period size.*/ + return AMR_WB_FRAMESIZE; + else + return 0; +} + +size_t audio_extn_compr_cap_read(struct stream_in * in, + void *buffer, size_t bytes) +{ + int ret; + struct snd_compr_audio_info *header; + uint32_t c_in_header; + uint32_t c_in_buf_size; + + c_in_buf_size = in->config.period_size*2; + + if (in->pcm) { + ret = pcm_read(in->pcm, c_in_mod.in_buf, c_in_buf_size); + if (ret < 0) { + ALOGE("pcm_read() returned failure: %d", ret); + return ret; + } else { + header = (struct snd_compr_audio_info *) c_in_mod.in_buf; + c_in_header = sizeof(*header) + header->reserved[0]; + if (header->frame_size > 0) { + if (c_in_header + header->frame_size > c_in_buf_size) { + ALOGW("AMR WB read buffer overflow."); + header->frame_size = + bytes - sizeof(*header) - header->reserved[0]; + } + ALOGV("c_in_buf: %p, data offset: %p, header size: %u," + "reserved[0]: %u frame_size: %d", c_in_mod.in_buf, + c_in_mod.in_buf + c_in_header, + sizeof(*header), header->reserved[0], + header->frame_size); + memcpy(buffer, c_in_mod.in_buf + c_in_header, header->frame_size); + } else { + ALOGE("pcm_read() with zero frame size"); + ret = -EINVAL; + } + } + } + + return 0; +} + +#endif /* COMPRESS_CAPTURE_ENABLED end */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 9b59e4a9d..873e5e2fc 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -105,6 +105,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", [USECASE_AUDIO_RECORD] = "audio-record", + [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", @@ -741,7 +742,7 @@ int start_input_stream(struct stream_in *in) struct audio_usecase *uc_info; struct audio_device *adev = in->dev; - in->usecase = platform_get_usecase_from_source(in->source); + in->usecase = platform_update_usecase_from_source(in->source,in->usecase); ALOGV("%s: enter: usecase(%d)", __func__, in->usecase); /* Check if source matches incall recording usecase criteria */ @@ -1126,7 +1127,8 @@ static int check_input_parameters(uint32_t sample_rate, int ret = 0; if ((format != AUDIO_FORMAT_PCM_16_BIT) && - !voice_extn_compress_voip_is_format_supported(format)) ret = -EINVAL; + !voice_extn_compress_voip_is_format_supported(format) && + !audio_extn_compr_cap_format_supported(format)) ret = -EINVAL; switch (channel_count) { case 1: @@ -1714,6 +1716,8 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) if(in->usecase == USECASE_COMPRESS_VOIP_CALL) return voice_extn_compress_voip_in_get_buffer_size(in); + else if(audio_extn_compr_cap_usecase_supported(in->usecase)) + return audio_extn_compr_cap_get_buffer_size(in->config.format); return in->config.period_size * audio_stream_frame_size(stream); } @@ -1865,6 +1869,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, if (in->pcm) { if (audio_extn_ssr_get_enabled() && popcount(in->channel_mask) == 6) ret = audio_extn_ssr_read(stream, buffer, bytes); + else if (audio_extn_compr_cap_usecase_supported(in->usecase)) + ret = audio_extn_compr_cap_read(in, buffer, bytes); else ret = pcm_read(in->pcm, buffer, bytes); } @@ -2383,8 +2389,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, __func__, ret); goto err_open; } - } - if (channel_count == 6) { + } else if (channel_count == 6) { if(audio_extn_ssr_get_enabled()) { if(audio_extn_ssr_init(adev, in)) { ALOGE("%s: audio_extn_ssr_init failed", __func__); @@ -2395,6 +2400,9 @@ static int adev_open_input_stream(struct audio_hw_device *dev, ret = -EINVAL; goto err_open; } + } else if (audio_extn_compr_cap_enabled() && + audio_extn_compr_cap_format_supported(config->format)) { + audio_extn_compr_cap_init(adev, in); } else { in->config.channels = channel_count; frame_size = audio_stream_frame_size((struct audio_stream *)in); @@ -2434,6 +2442,9 @@ static void adev_close_input_stream(struct audio_hw_device *dev, } free(stream); + if(audio_extn_compr_cap_enabled() && + audio_extn_compr_cap_format_supported(in->config.format)) + audio_extn_compr_cap_deinit(); return; } diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 9dca5c1df..6ff6f40be 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -64,6 +64,7 @@ typedef enum { /* Capture usecases */ USECASE_AUDIO_RECORD, + USECASE_AUDIO_RECORD_COMPRESS, USECASE_AUDIO_RECORD_LOW_LATENCY, USECASE_AUDIO_RECORD_FM_VIRTUAL, diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 089b2ec2d..43bef8146 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -897,3 +897,9 @@ int64_t platform_render_latency(audio_usecase_t usecase) return 0; } } + +int platform_update_usecase_from_source(int source, int usecase) +{ + ALOGV("%s: input source :%d", __func__, source); + return usecase; +} diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 4a5bbc6e7..352c4d8e6 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -103,6 +103,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE}, [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, + [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE, @@ -1381,11 +1382,10 @@ int64_t platform_render_latency(audio_usecase_t usecase) } } -int platform_get_usecase_from_source(int source) +int platform_update_usecase_from_source(int source, int usecase) { ALOGV("%s: input source :%d", __func__, source); if(source == AUDIO_SOURCE_FM_RX_A2DP) - return USECASE_AUDIO_RECORD_FM_VIRTUAL; - else - return USECASE_AUDIO_RECORD; + usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL; + return usecase; } diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 9d4378d4c..7d80906a0 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -182,6 +182,7 @@ enum { #else #define LOWLATENCY_PCM_DEVICE 15 #endif +#define COMPRESS_CAPTURE_DEVICE 19 #ifdef PLATFORM_MSM8x26 #define VOICE_CALL_PCM_DEVICE 2 diff --git a/hal/platform_api.h b/hal/platform_api.h index b9919ae31..dac3fd992 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -47,6 +47,6 @@ int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id) /* returns the latency for a usecase in Us */ int64_t platform_render_latency(audio_usecase_t usecase); -int platform_get_usecase_from_source(int source); +int platform_update_usecase_from_source(int source, audio_usecase_t usecase); #endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From 1fd2179b5f7cb896195bc5f9a233808f6877575a Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Fri, 15 Nov 2013 14:50:57 -0800 Subject: [PATCH 081/298] hal: change voice call sequence on APQ targets Send device disable command to external modem before voice call mixer controls are disabled on APQ side. Enable device command also should be sent only after enabling mixer controls on APQ side. Change-Id: I2e4dc321b16f695564460771b3656cd2c4a089a9 --- hal/audio_hw.c | 11 ++++++++++- hal/msm8974/platform.c | 26 ++++++++++++++++++++------ hal/platform_api.h | 3 +++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 873e5e2fc..58f9132cb 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -657,8 +657,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) * device. */ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) { - disable_all_usecases_of_type(adev, usecase->type, true); status = platform_switch_voice_call_device_pre(adev->platform); + disable_all_usecases_of_type(adev, VOICE_CALL, true); } /* Disable current sound devices */ @@ -699,6 +699,15 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) else enable_audio_route(adev, usecase, true); + /* Applicable only on the targets that has external modem. + * Enable device command should be sent to modem only after + * enabling voice call mixer controls + */ + if (usecase->type == VOICE_CALL) + status = platform_switch_voice_call_usecase_route_post(adev->platform, + out_snd_device, + in_snd_device); + return status; } diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 352c4d8e6..1a53f32f2 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -640,7 +640,8 @@ int platform_switch_voice_call_device_pre(void *platform) struct platform_data *my_data = (struct platform_data *)platform; int ret = 0; - if (my_data->csd != NULL) { + if (my_data->csd != NULL && + my_data->adev->mode == AUDIO_MODE_IN_CALL) { /* This must be called before disabling mixer controls on APQ side */ ret = my_data->csd->disable_device(); if (ret < 0) { @@ -657,14 +658,13 @@ int platform_switch_voice_call_device_post(void *platform, { struct platform_data *my_data = (struct platform_data *)platform; int acdb_rx_id, acdb_tx_id; - int ret = 0; - - acdb_rx_id = acdb_device_table[out_snd_device]; - acdb_tx_id = acdb_device_table[in_snd_device]; if (my_data->acdb_send_voice_cal == NULL) { ALOGE("%s: dlsym error for acdb_send_voice_call", __func__); } else { + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; + if (acdb_rx_id > 0 && acdb_tx_id > 0) my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id); else @@ -672,8 +672,22 @@ int platform_switch_voice_call_device_post(void *platform, acdb_rx_id, acdb_tx_id); } + return 0; +} + +int platform_switch_voice_call_usecase_route_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_rx_id, acdb_tx_id; + int ret = 0; + + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; + if (my_data->csd != NULL) { - if (acdb_rx_id > 0 || acdb_tx_id > 0) { + if (acdb_rx_id > 0 && acdb_tx_id > 0) { ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id, my_data->adev->acdb_settings); if (ret < 0) { diff --git a/hal/platform_api.h b/hal/platform_api.h index dac3fd992..44ad7905d 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -32,6 +32,9 @@ int platform_switch_voice_call_device_pre(void *platform); int platform_switch_voice_call_device_post(void *platform, snd_device_t out_snd_device, snd_device_t in_snd_device); +int platform_switch_voice_call_usecase_route_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device); int platform_start_voice_call(void *platform, uint32_t vsid); int platform_stop_voice_call(void *platform, uint32_t vsid); int platform_set_voice_volume(void *platform, int volume); -- GitLab From 144d87459c4f3e620fc6f0f8cf20786ed152a62c Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Mon, 11 Nov 2013 14:26:21 -0800 Subject: [PATCH 082/298] audio: Add new Audio daemon process - Add new audio daemon process. - Pupose of this daemon is to monitor and report changes ADSP processor state to audio framework/Audio flinger. - Specific sysfs node file on device indicates ADSP processor state as ONLINE or OFFLINE Change-Id: Ibad54ea93cbb4fbc59ba599c76541c1f255d4c48 --- Android.mk | 1 + audiod/Android.mk | 24 ++++ audiod/AudioDaemon.cpp | 242 +++++++++++++++++++++++++++++++++++++++++ audiod/AudioDaemon.h | 67 ++++++++++++ audiod/audiod_main.cpp | 60 ++++++++++ 5 files changed, 394 insertions(+) create mode 100644 audiod/Android.mk create mode 100644 audiod/AudioDaemon.cpp create mode 100644 audiod/AudioDaemon.h create mode 100644 audiod/audiod_main.cpp diff --git a/Android.mk b/Android.mk index db74eaf4d..0e94762bc 100644 --- a/Android.mk +++ b/Android.mk @@ -10,6 +10,7 @@ include $(MY_LOCAL_PATH)/voice_processing/Android.mk include $(MY_LOCAL_PATH)/mm-audio/Android.mk include $(MY_LOCAL_PATH)/policy_hal/Android.mk include $(MY_LOCAL_PATH)/visualizer/Android.mk +include $(MY_LOCAL_PATH)/audiod/Android.mk endif endif diff --git a/audiod/Android.mk b/audiod/Android.mk new file mode 100644 index 000000000..8f25125ed --- /dev/null +++ b/audiod/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +include external/stlport/libstlport.mk + +LOCAL_SRC_FILES:= \ + audiod_main.cpp \ + AudioDaemon.cpp \ + +LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libmedia \ + libstlport + +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +LOCAL_MODULE:= audiod +LOCAL_MODULE_TAGS:= debug + +include $(BUILD_EXECUTABLE) diff --git a/audiod/AudioDaemon.cpp b/audiod/AudioDaemon.cpp new file mode 100644 index 000000000..6c8d99128 --- /dev/null +++ b/audiod/AudioDaemon.cpp @@ -0,0 +1,242 @@ +/* AudioDaemon.cpp +Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ + +#define LOG_TAG "AudioDaemon" +#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 + +#include +#include + +#include "AudioDaemon.h" + +int bootup_complete = 0; + +namespace android { + + AudioDaemon::AudioDaemon() : Thread(false) { + } + + AudioDaemon::~AudioDaemon() { + putStateFDs(mSndCardFd); + } + + void AudioDaemon::onFirstRef() { + ALOGV("Start audiod daemon"); + run("AudioDaemon", PRIORITY_AUDIO); + } + + void AudioDaemon::binderDied(const wp& who) + { + requestExit(); + } + + bool AudioDaemon::getStateFDs(std::vector > &sndcardFdPair) + { + FILE *fp; + int fd; + char *ptr, *saveptr; + char buffer[128]; + int line = 0; + String8 path; + int sndcard; + const char* cards = "/proc/asound/cards"; + + if ((fp = fopen(cards, "r")) == NULL) { + ALOGE("Cannot open %s file to get list of sound cars", cards); + return false; + } + + sndcardFdPair.clear(); + memset(buffer, 0x0, sizeof(buffer)); + while ((fgets(buffer, sizeof(buffer), fp) != NULL)) { + if (line % 2) + continue; + ptr = strtok_r(buffer, " [", &saveptr); + if (ptr) { + path = "/proc/asound/card"; + path += ptr; + path += "/state"; + ALOGD("Opening sound card state : %s", path.string()); + fd = open(path.string(), O_RDONLY); + if (fd == -1) { + ALOGE("Open %s failed : %s", path.string(), strerror(errno)); + } else { + /* returns vector of pair */ + sndcard = atoi(ptr); + sndcardFdPair.push_back(std::make_pair(sndcard, fd)); + } + } + line++; + } + + ALOGV("%s: %d sound cards detected", __func__, sndcardFdPair.size()); + fclose(fp); + + return sndcardFdPair.size() > 0 ? true : false; + } + + void AudioDaemon::putStateFDs(std::vector > &sndcardFdPair) + { + unsigned int i; + for (i = 0; i < sndcardFdPair.size(); i++) + close(sndcardFdPair[i].second); + sndcardFdPair.clear(); + } + + status_t AudioDaemon::readyToRun() { + + ALOGV("readyToRun: open snd card state node files"); + return NO_ERROR; + } + +#define MAX_SLEEP_RETRY 100 +#define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */ + + bool AudioDaemon::threadLoop() + { + int max = -1; + unsigned int i; + bool ret = true; + snd_card_status cur_state = snd_card_offline; + struct pollfd *pfd = NULL; + char rd_buf[9]; + unsigned int sleepRetry = 0; + bool audioInitDone = false; + + ALOGV("Start threadLoop()"); + while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) { + if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) { + ALOGE("Sleeping for 100 ms"); + usleep(AUDIO_INIT_SLEEP_WAIT*1000); + sleepRetry++; + } else { + audioInitDone = true; + } + } + + if (audioInitDone == false) + ALOGE("Sound Card is empty!!!"); + + pfd = new pollfd[mSndCardFd.size()]; + bzero(pfd, sizeof(*pfd) * mSndCardFd.size()); + for (i = 0; i < mSndCardFd.size(); i++) { + pfd[i].fd = mSndCardFd[i].second; + pfd[i].events = POLLPRI; + } + + ALOGD("read for sound card state change before while"); + for (i = 0; i < mSndCardFd.size(); i++) { + if (!read(pfd[i].fd, (void *)rd_buf, 8)) { + ALOGE("Error receiving sound card state event (%s)", strerror(errno)); + ret = false; + } else { + rd_buf[8] = '\0'; + ALOGD("sound card state file content: %s before while",rd_buf); + lseek(pfd[i].fd, 0, SEEK_SET); + + if (strstr(rd_buf, "OFFLINE")) { + ALOGE("put cur_state to offline"); + cur_state = snd_card_offline; + } else if (strstr(rd_buf, "ONLINE")){ + ALOGE("put cur_state to online"); + cur_state = snd_card_online; + } else { + ALOGE("ERROR rd_buf %s", rd_buf); + } + + ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state ); + if (cur_state == snd_card_online && !bootup_complete) { + bootup_complete = 1; + ALOGE("sound card up is deteced before while"); + ALOGE("bootup_complete set to 1"); + } + } + } + + while (1) { + ALOGD("poll() for sound card state change "); + if (poll(pfd, mSndCardFd.size(), -1) < 0) { + ALOGE("poll() failed (%s)", strerror(errno)); + ret = false; + break; + } + + ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size()); + for (i = 0; i < mSndCardFd.size(); i++) { + if (pfd[i].revents & POLLPRI) { + if (!read(pfd[i].fd, (void *)rd_buf, 8)) { + ALOGE("Error receiving sound card state event (%s)", strerror(errno)); + ret = false; + } else { + rd_buf[8] = '\0'; + ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete); + lseek(pfd[i].fd, 0, SEEK_SET); + + if (strstr(rd_buf, "OFFLINE")) { + cur_state = snd_card_offline; + } else if (strstr(rd_buf, "ONLINE")){ + cur_state = snd_card_online; + } + + if (bootup_complete) { + ALOGV("bootup_complete, so NofityAudioSystem"); + notifyAudioSystem(mSndCardFd[i].first, cur_state); + } + + if (cur_state == snd_card_online && !bootup_complete) { + bootup_complete = 1; + } + } + } + } + } + + putStateFDs(mSndCardFd); + delete [] pfd; + + ALOGV("Exiting Poll ThreadLoop"); + return ret; + } + + void AudioDaemon::notifyAudioSystem(int snd_card, snd_card_status status) { + + String8 str; + char buf[4] = {0,}; + + str = "SND_CARD_STATUS="; + snprintf(buf, sizeof(buf), "%d", snd_card); + str += buf; + if (status == snd_card_online) + str += ",ONLINE"; + else + str += ",OFFLINE"; + ALOGV("%s: notifyAudioSystem : %s", __func__, str.string()); + AudioSystem::setParameters(0, str); + } +} diff --git a/audiod/AudioDaemon.h b/audiod/AudioDaemon.h new file mode 100644 index 000000000..15c0cf1a0 --- /dev/null +++ b/audiod/AudioDaemon.h @@ -0,0 +1,67 @@ +/* AudioDaemon.h + +Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace android { + +enum snd_card_status { snd_card_online, snd_card_offline}; + +class AudioDaemon:public Thread, public IBinder :: DeathRecipient +{ + /*Overrides*/ + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual void onFirstRef(); + virtual void binderDied(const wp < IBinder > &who); + + bool processUeventMessage(); + void notifyAudioSystem(int snd_card, snd_card_status status); + int mUeventSock; + bool getStateFDs(std::vector > &sndcardFdPair); + void putStateFDs(std::vector > &sndcardFdPair); + +public: + AudioDaemon(); + virtual ~AudioDaemon(); + +private: + std::vector > mSndCardFd; +}; + +} diff --git a/audiod/audiod_main.cpp b/audiod/audiod_main.cpp new file mode 100644 index 000000000..50691fd5c --- /dev/null +++ b/audiod/audiod_main.cpp @@ -0,0 +1,60 @@ +/* Copyright (C) 2007 The Android Open Source Project + +Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + +Not a Contribution, Apache license notifications and license are retained +for attribution purposes only. + +* 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. +*/ + +#define LOG_TAG "AudioDaemonMain" +#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 + +#include + +#include +#include +#include + +#include +#include + +#if defined(HAVE_PTHREADS) +# include +# include +#endif + +#include "AudioDaemon.h" + +using namespace android; + +// --------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ +#if defined(HAVE_PTHREADS) + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); +#endif + + + ALOGV("Audio daemon starting sequence.."); + sp proc(ProcessState::self()); + ProcessState::self()->startThreadPool(); + + sp audioService = new AudioDaemon(); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} -- GitLab From 11806dbf229cd7c3dbf346f958a885f3789a9f4b Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Wed, 20 Nov 2013 10:39:32 -0800 Subject: [PATCH 083/298] hal: Add the correct pcm device for compress capture. The dai-link id is 20 for compress capture on 8x26. Add the correct id for 8x26. Change-Id: Ie41b2c039816a6014ac32af4f191c2e3aaad37a1 --- hal/msm8974/platform.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 7d80906a0..bea78e925 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -182,7 +182,11 @@ enum { #else #define LOWLATENCY_PCM_DEVICE 15 #endif +#ifdef PLATFORM_MSM8x26 +#define COMPRESS_CAPTURE_DEVICE 20 +#else #define COMPRESS_CAPTURE_DEVICE 19 +#endif #ifdef PLATFORM_MSM8x26 #define VOICE_CALL_PCM_DEVICE 2 -- GitLab From fe095b41c822ffec909af7e00d97838cca565e74 Mon Sep 17 00:00:00 2001 From: Helen Zeng Date: Wed, 20 Nov 2013 11:28:25 -0800 Subject: [PATCH 084/298] hal: Fix incall recording with AMR-WB format Select AMR-WB and start incall recording, the audio quality is bad. The root cause is that the sample rate is set to 8k not 16k for AMR-WB. Use audio record configure instead of voice configure for incall recording. Change-Id: Ib71e0e8d1f2c5eb72db3260110e55179e415fa26 CRs-Fixed: 576412 --- hal/voice.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hal/voice.c b/hal/voice.c index ff497c7a8..ce8a77a62 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -231,7 +231,6 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, return ret; } - in->config = pcm_config_voice_call; session_id = voice_get_active_session_id(adev); ret = platform_set_incall_recoding_session_id(adev->platform, session_id); -- GitLab From 86b0e2b6ff6dd71ea5ef99f9ca97c9d21717ebad Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 20 Nov 2013 14:52:30 -0800 Subject: [PATCH 085/298] hal: Correct the multi-channel output usecase selection Both Multi-channel output on HDMI and Compress offload playback on HDMI use cases request for a stream with AUDIO_OUTPUT_FLAG_DIRECT. The current logic would then result selection MULTI_CH usecase. Fix this by checking for complete match of flags to select the use case. Change-Id: I66df94af6c3b837a6c8054282364e1acf78e6e0f --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 873e5e2fc..00bb65dd2 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1975,7 +1975,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->handle = handle; /* Init use case and pcm_config */ - if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && + if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT && out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { pthread_mutex_lock(&adev->lock); ret = read_hdmi_channel_masks(out); -- GitLab From 9d8992981c31e84d75059b7604ac606b6055375f Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Wed, 20 Nov 2013 14:43:01 -0800 Subject: [PATCH 086/298] hal: add get_parameter support slowtalk Add support for get_parameter so that slow talk value can be retrieved by apps. CRs-Fixed: 579154 Change-Id: Ia91e1ec1ac2e5b71041332529ef3d871e04800c3 --- hal/msm8974/platform.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 352c4d8e6..486943cef 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1366,6 +1366,14 @@ void platform_get_parameters(void *platform, str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value); } + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK, + value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SLOWTALK, + my_data->slowtalk); + } + ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply)); } -- GitLab From cb065748f9d12b74c7849800866d51400e34c45d Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Wed, 20 Nov 2013 18:31:58 -0800 Subject: [PATCH 087/298] hal: Fix incorrect FM volume after reboot Reboot the phone, start FM playback and it plays back at max volume regardless of previous Media volume. The audio HAL is caching the volume that is being sent to driver after conversion. Fix the issue by caching the value set by the policy manager. Change-Id: I2c416fc72d354b368890afcdd51b83e662b0ce6e CRs-Fixed: 579377 --- hal/audio_extn/fm.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c index 53499b9b1..eeba404a7 100644 --- a/hal/audio_extn/fm.c +++ b/hal/audio_extn/fm.c @@ -50,7 +50,7 @@ struct fm_module { struct pcm *fm_pcm_rx; struct pcm *fm_pcm_tx; bool is_fm_running; - int fm_volume; + float fm_volume; }; static struct fm_module fmmod = { @@ -66,7 +66,7 @@ static int32_t fm_set_volume(struct audio_device *adev, float value) struct mixer_ctl *ctl; const char *mixer_ctl_name = "Internal FM RX Volume"; - ALOGD("%s: entry", __func__); + ALOGV("%s: entry", __func__); ALOGD("%s: (%f)\n", __func__, value); if (value < 0.0) { @@ -77,8 +77,7 @@ static int32_t fm_set_volume(struct audio_device *adev, float value) value = 1.0; } vol = lrint((value * 0x2000) + 0.5); - - fmmod.fm_volume = vol; + fmmod.fm_volume = value; if (!fmmod.is_fm_running) { ALOGV("%s: FM not active, ignoring set_fm_volume call", __func__); @@ -92,9 +91,9 @@ static int32_t fm_set_volume(struct audio_device *adev, float value) __func__, mixer_ctl_name); return -EINVAL; } - mixer_ctl_set_value(ctl, 0, fmmod.fm_volume); + mixer_ctl_set_value(ctl, 0, vol); - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return ret; } -- GitLab From de144c8495a831bd08b982a4bfd9a283107af9d8 Mon Sep 17 00:00:00 2001 From: Kiran Kandi Date: Wed, 20 Nov 2013 15:58:32 -0800 Subject: [PATCH 088/298] hal: notify listen while enabling/disabling snd device Listen needs be stopped when audio capture is active. Also Listen needs to be started again after audio capture becomes inactive. Stop and start listen based on audio capture device. Change-Id: I05ca7cccd59b43a163604881bd9c6ee10cc8fba3 Depends-on: 510494 --- hal/audio_extn/audio_extn.h | 14 +++++++------- hal/audio_extn/listen.c | 31 +++++++++++++++++++++---------- hal/audio_hw.c | 16 ++++++++-------- hal/msm8960/platform.c | 5 +++++ hal/msm8974/platform.c | 11 +++++++++++ hal/platform_api.h | 2 ++ hal/voice.c | 6 ------ 7 files changed, 54 insertions(+), 31 deletions(-) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 7d04c6d6b..904152f7e 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -95,7 +95,7 @@ void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, #ifndef AUDIO_LISTEN_ENABLED -#define audio_extn_listen_init(adev) (0) +#define audio_extn_listen_init(adev, snd_card) (0) #define audio_extn_listen_deinit(adev) (0) #define audio_extn_listen_update_status(uc_info, event) (0) #define audio_extn_listen_set_parameters(adev, parms) (0) @@ -103,17 +103,17 @@ void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, #else enum listen_event_type { - LISTEN_EVENT_AUDIO_CAPTURE_INACTIVE, - LISTEN_EVENT_AUDIO_CAPTURE_ACTIVE, + LISTEN_EVENT_SND_DEVICE_FREE, + LISTEN_EVENT_SND_DEVICE_BUSY }; typedef enum listen_event_type listen_event_type_t; -int audio_extn_listen_init(struct audio_device *adev); +int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card); void audio_extn_listen_deinit(struct audio_device *adev); -void audio_extn_listen_update_status(struct audio_usecase *uc_info, - listen_event_type_t event); +void audio_extn_listen_update_status(snd_device_t snd_device, + listen_event_type_t event); void audio_extn_listen_set_parameters(struct audio_device *adev, - struct str_parms *parms); + struct str_parms *parms); #endif /* AUDIO_LISTEN_ENABLED */ diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c index 14a427b1f..65c0ae68f 100644 --- a/hal/audio_extn/listen.c +++ b/hal/audio_extn/listen.c @@ -27,7 +27,7 @@ * */ #define LOG_TAG "listen_hal_loader" -#define LOG_NDEBUG 0 +/* #define LOG_NDEBUG 0 */ /* #define LOG_NDDEBUG 0 */ #include #include @@ -59,7 +59,8 @@ } -typedef int (*create_listen_hw_t)(); +typedef int (*create_listen_hw_t)(unsigned int snd_card, + struct audio_route *audio_route); typedef void (*destroy_listen_hw_t)(); typedef int (*open_listen_session_t)(struct audio_hw_device *, @@ -93,15 +94,25 @@ struct listen_audio_device { static struct listen_audio_device *listen_dev; -void audio_extn_listen_update_status(struct audio_usecase *uc_info, +void audio_extn_listen_update_status(snd_device_t snd_device, listen_event_type_t event) { + if (!platform_listen_update_status(snd_device)) { + ALOGV("%s(): no need to notify listen. device = %s. Event = %u", + __func__, platform_get_snd_device_name(snd_device), event); + return; + } + if (listen_dev) { - ALOGI("%s(): current active device = %s. Event = %u", __func__, - platform_get_snd_device_name(uc_info->in_snd_device), - event); - if (uc_info->in_snd_device != SND_DEVICE_IN_CAPTURE_FM) - listen_dev->notify_event(event); + ALOGI("%s(): %s listen. current active device = %s. Event = %u", + __func__, + (event == LISTEN_EVENT_SND_DEVICE_BUSY) ? "stop" : "start", + platform_get_snd_device_name(snd_device), event); + + if (event == LISTEN_EVENT_SND_DEVICE_FREE) + listen_dev->notify_event(AUDIO_CAPTURE_INACTIVE); + else if (event == LISTEN_EVENT_SND_DEVICE_BUSY) + listen_dev->notify_event(AUDIO_CAPTURE_ACTIVE); } } @@ -111,7 +122,7 @@ void audio_extn_listen_set_parameters(struct audio_device *adev, return; } -int audio_extn_listen_init(struct audio_device *adev) +int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card) { int ret; void *lib_handle; @@ -165,7 +176,7 @@ int audio_extn_listen_init(struct audio_device *adev) LISTEN_LOAD_SYMBOLS(listen_dev, notify_event, listen_notify_event_t, listen_hw_notify_event); - listen_dev->create_listen_hw(); + listen_dev->create_listen_hw(snd_card, adev->audio_route); } return 0; } diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 5537115f3..df040e20c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -271,6 +271,9 @@ int enable_snd_device(struct audio_device *adev, adev->snd_dev_ref_cnt[snd_device]--; return -EINVAL; } + audio_extn_listen_update_status(snd_device, + LISTEN_EVENT_SND_DEVICE_BUSY); + audio_route_apply_path(adev->audio_route, device_name); } if (update_mixer) @@ -322,6 +325,9 @@ int disable_snd_device(struct audio_device *adev, if (update_mixer) audio_route_update_mixer(adev->audio_route); + + audio_extn_listen_update_status(snd_device, + LISTEN_EVENT_SND_DEVICE_FREE); } return 0; @@ -734,9 +740,6 @@ static int stop_input_stream(struct stream_in *in) /* 2. Disable the tx device */ disable_snd_device(adev, uc_info->in_snd_device, true); - audio_extn_listen_update_status(uc_info, - LISTEN_EVENT_AUDIO_CAPTURE_INACTIVE); - list_remove(&uc_info->list); free(uc_info); @@ -781,9 +784,6 @@ int start_input_stream(struct stream_in *in) list_add_tail(&adev->usecase_list, &uc_info->list); select_devices(adev, in->usecase); - audio_extn_listen_update_status(uc_info, - LISTEN_EVENT_AUDIO_CAPTURE_ACTIVE); - ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, SOUND_CARD, in->pcm_device_id, in->config.channels); in->pcm = pcm_open(SOUND_CARD, in->pcm_device_id, @@ -2472,10 +2472,10 @@ static int adev_close(hw_device_t *device) pthread_mutex_lock(&adev_init_lock); if ((--audio_device_ref_count) == 0) { + audio_extn_listen_deinit(adev); audio_route_free(adev->audio_route); free(adev->snd_dev_ref_cnt); platform_deinit(adev->platform); - audio_extn_listen_deinit(adev); free(device); adev = NULL; } @@ -2562,7 +2562,7 @@ static int adev_open(const hw_module_t *module, const char *name, "visualizer_hal_stop_output"); } } - audio_extn_listen_init(adev); + audio_extn_listen_init(adev, SOUND_CARD); *device = &adev->device.common; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 43bef8146..298c60d8f 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -903,3 +903,8 @@ int platform_update_usecase_from_source(int source, int usecase) ALOGV("%s: input source :%d", __func__, source); return usecase; } + +bool platform_listen_update_status(snd_device_t snd_device) +{ + return false; +} diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1a53f32f2..af93782fe 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1403,3 +1403,14 @@ int platform_update_usecase_from_source(int source, int usecase) usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL; return usecase; } + +bool platform_listen_update_status(snd_device_t snd_device) +{ + if ((snd_device >= SND_DEVICE_IN_BEGIN) && + (snd_device < SND_DEVICE_IN_END) && + (snd_device != SND_DEVICE_IN_CAPTURE_FM) && + (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)) + return true; + else + return false; +} diff --git a/hal/platform_api.h b/hal/platform_api.h index 44ad7905d..a829365a4 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -52,4 +52,6 @@ int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id) int64_t platform_render_latency(audio_usecase_t usecase); int platform_update_usecase_from_source(int source, audio_usecase_t usecase); +bool platform_listen_update_status(snd_device_t snd_device); + #endif // QCOM_AUDIO_PLATFORM_API_H diff --git a/hal/voice.c b/hal/voice.c index dc5c41779..c6c513a83 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -94,9 +94,6 @@ int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) disable_snd_device(adev, uc_info->out_snd_device, false); disable_snd_device(adev, uc_info->in_snd_device, true); - audio_extn_listen_update_status(uc_info, - LISTEN_EVENT_AUDIO_CAPTURE_INACTIVE); - list_remove(&uc_info->list); free(uc_info); @@ -127,9 +124,6 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) select_devices(adev, usecase_id); - audio_extn_listen_update_status(uc_info, - LISTEN_EVENT_AUDIO_CAPTURE_ACTIVE); - pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); -- GitLab From d21e5832996d91b814893f8d975045924dbe5467 Mon Sep 17 00:00:00 2001 From: Aviral Gupta Date: Wed, 20 Nov 2013 17:32:46 +0530 Subject: [PATCH 089/298] hal: Add audio support for 8092 - Add support for OMX audio encoder components for mpq8092. Change-Id: I7a652581fd48fc22c025193d2c825b6e747edcfe --- mm-audio/aenc-aac/Android.mk | 3 +++ mm-audio/aenc-amrnb/Android.mk | 3 +++ mm-audio/aenc-evrc/Android.mk | 3 +++ mm-audio/aenc-qcelp13/Android.mk | 4 +++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mm-audio/aenc-aac/Android.mk b/mm-audio/aenc-aac/Android.mk index 86984368b..8ab45b3a0 100644 --- a/mm-audio/aenc-aac/Android.mk +++ b/mm-audio/aenc-aac/Android.mk @@ -21,6 +21,9 @@ endif ifeq ($(call is-board-platform,apq8084),true) include $(AENC_AAC_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,mpq8092),true) +include $(AENC_AAC_PATH)/qdsp6/Android.mk +endif endif diff --git a/mm-audio/aenc-amrnb/Android.mk b/mm-audio/aenc-amrnb/Android.mk index 6c2f45836..2601edebc 100644 --- a/mm-audio/aenc-amrnb/Android.mk +++ b/mm-audio/aenc-amrnb/Android.mk @@ -21,6 +21,9 @@ endif ifeq ($(call is-board-platform,apq8084),true) include $(AENC_AMR_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,mpq8092),true) +include $(AENC_AMR_PATH)/qdsp6/Android.mk +endif endif diff --git a/mm-audio/aenc-evrc/Android.mk b/mm-audio/aenc-evrc/Android.mk index c8ee1edae..2f42d6ba0 100644 --- a/mm-audio/aenc-evrc/Android.mk +++ b/mm-audio/aenc-evrc/Android.mk @@ -21,6 +21,9 @@ endif ifeq ($(call is-board-platform,apq8084),true) include $(AENC_EVRC_PATH)/qdsp6/Android.mk endif +ifeq ($(call is-board-platform,mpq8092),true) +include $(AENC_EVRC_PATH)/qdsp6/Android.mk +endif endif diff --git a/mm-audio/aenc-qcelp13/Android.mk b/mm-audio/aenc-qcelp13/Android.mk index 8f6985c52..fe18efc59 100644 --- a/mm-audio/aenc-qcelp13/Android.mk +++ b/mm-audio/aenc-qcelp13/Android.mk @@ -21,6 +21,8 @@ endif ifeq ($(call is-board-platform,apq8084),true) include $(AENC_QCELP13_PATH)/qdsp6/Android.mk endif - +ifeq ($(call is-board-platform,mpq8092),true) +include $(AENC_QCELP13_PATH)/qdsp6/Android.mk +endif endif -- GitLab From 2850d5327dc2760a8220086da38b216f4fca0c9b Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Tue, 19 Nov 2013 16:02:12 -0800 Subject: [PATCH 090/298] hal: In-call recording and In-call music support on APQ targets -In-call recording feature support is added in APQ. -In-call music delivery support is added in APQ. Change-Id: Id473eac87da33f1f566b6910ec1feadcd3f08317 --- hal/audio_hw.c | 4 +++ hal/msm8974/platform.c | 60 ++++++++++++++++++++++++++++++++++++++++-- hal/msm8974/platform.h | 2 +- hal/platform_api.h | 7 +++-- hal/voice.c | 35 +++++++++++++++++++++--- hal/voice.h | 12 +++++++++ 6 files changed, 112 insertions(+), 8 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index df040e20c..a35fc4374 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -734,6 +734,9 @@ static int stop_input_stream(struct stream_in *in) return -EINVAL; } + /* Close in-call recording streams */ + voice_check_and_stop_incall_rec_usecase(adev, in); + /* 1. Disable stream specific mixer controls */ disable_audio_route(adev, uc_info, true); @@ -2323,6 +2326,7 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) int ret; pthread_mutex_lock(&adev->lock); + ALOGD("%s state %d\n", __func__, state); ret = voice_set_mic_mute((struct audio_device *)dev, state); pthread_mutex_unlock(&adev->lock); diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index a207c2f8d..3b736f0a5 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1326,8 +1326,8 @@ int platform_set_parameters(void *platform, struct str_parms *parms) return ret; } -int platform_set_incall_recoding_session_id(void *platform, - uint32_t session_id) +int platform_set_incall_recording_session_id(void *platform, + uint32_t session_id, int rec_mode) { int ret = 0; struct platform_data *my_data = (struct platform_data *)platform; @@ -1353,6 +1353,62 @@ int platform_set_incall_recoding_session_id(void *platform, } } + if (my_data->csd != NULL) { + ret = my_data->csd->start_record(ALL_SESSION_VSID, rec_mode); + if (ret < 0) { + ALOGE("%s: csd_client_start_record failed, error %d", + __func__, ret); + } + } + + return ret; +} + +int platform_stop_incall_recording_usecase(void *platform) +{ + int ret = 0; + struct platform_data *my_data = (struct platform_data *)platform; + + if (my_data->csd != NULL) { + ret = my_data->csd->stop_record(ALL_SESSION_VSID); + if (ret < 0) { + ALOGE("%s: csd_client_stop_record failed, error %d", + __func__, ret); + } + } + + return ret; +} + +int platform_start_incall_music_usecase(void *platform) +{ + int ret = 0; + struct platform_data *my_data = (struct platform_data *)platform; + + if (my_data->csd != NULL) { + ret = my_data->csd->start_playback(ALL_SESSION_VSID); + if (ret < 0) { + ALOGE("%s: csd_client_start_playback failed, error %d", + __func__, ret); + } + } + + return ret; +} + +int platform_stop_incall_music_usecase(void *platform) +{ + int ret = 0; + struct platform_data *my_data = (struct platform_data *)platform; + + if (my_data->csd != NULL) { + ret = my_data->csd->stop_playback(ALL_SESSION_VSID); + if (ret < 0) { + ALOGE("%s: csd_client_stop_playback failed, error %d", + __func__, ret); + } + } + return ret; } diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 7d80906a0..bc054cf74 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -215,7 +215,7 @@ typedef int (*stop_voice_t)(uint32_t); typedef int (*start_playback_t)(uint32_t); typedef int (*stop_playback_t)(uint32_t); typedef int (*start_record_t)(uint32_t, int); -typedef int (*stop_record_t)(uint32_t, int); +typedef int (*stop_record_t)(uint32_t); /* CSD Client structure */ struct csd_data { void *csd_client; diff --git a/hal/platform_api.h b/hal/platform_api.h index a829365a4..4096ef02f 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -46,8 +46,11 @@ int platform_edid_get_max_channels(void *platform); void platform_get_parameters(void *platform, struct str_parms *query, struct str_parms *reply); int platform_set_parameters(void *platform, struct str_parms *parms); -int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id); - +int platform_set_incall_recording_session_id(void *platform, uint32_t session_id, + int rec_mode); +int platform_stop_incall_recording_usecase(void *platform); +int platform_start_incall_music_usecase(void *platform); +int platform_stop_incall_music_usecase(void *platform); /* returns the latency for a usecase in Us */ int64_t platform_render_latency(audio_usecase_t usecase); int platform_update_usecase_from_source(int source, audio_usecase_t usecase); diff --git a/hal/voice.c b/hal/voice.c index c6c513a83..25b53d4cd 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -202,22 +202,26 @@ uint32_t voice_get_active_session_id(struct audio_device *adev) } int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, - struct stream_in *in) + struct stream_in *in) { int ret = 0; uint32_t session_id; int usecase_id; + int rec_mode = INCALL_REC_NONE; if (voice_is_in_call(adev)) { switch (in->source) { case AUDIO_SOURCE_VOICE_UPLINK: in->usecase = USECASE_INCALL_REC_UPLINK; + rec_mode = INCALL_REC_UPLINK; break; case AUDIO_SOURCE_VOICE_DOWNLINK: in->usecase = USECASE_INCALL_REC_DOWNLINK; + rec_mode = INCALL_REC_DOWNLINK; break; case AUDIO_SOURCE_VOICE_CALL: in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK; + rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK; break; default: ALOGV("%s: Source type %d doesnt match incall recording criteria", @@ -226,8 +230,8 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, } session_id = voice_get_active_session_id(adev); - ret = platform_set_incall_recoding_session_id(adev->platform, - session_id); + ret = platform_set_incall_recording_session_id(adev->platform, + session_id, rec_mode); ALOGV("%s: Update usecase to %d",__func__, in->usecase); } else { ALOGV("%s: voice call not active", __func__); @@ -236,6 +240,21 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, return ret; } +int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev, + struct stream_in *in) +{ + int ret = 0; + + if (in->source == AUDIO_SOURCE_VOICE_UPLINK || + in->source == AUDIO_SOURCE_VOICE_DOWNLINK || + in->source == AUDIO_SOURCE_VOICE_CALL) { + ret = platform_stop_incall_recording_usecase(adev->platform); + ALOGV("%s: Stop In-call recording", __func__); + } + + return ret; +} + int voice_check_and_set_incall_music_usecase(struct audio_device *adev, struct stream_out *out) { @@ -358,6 +377,16 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) } } + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC, + value, sizeof(value)); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC); + if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0) + platform_start_incall_music_usecase(adev->platform); + else + platform_stop_incall_music_usecase(adev->platform); + } + done: ALOGV("%s: exit with code(%d)", __func__, ret); return ret; diff --git a/hal/voice.h b/hal/voice.h index 7f8b25baa..eeb65dc1c 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -35,6 +35,9 @@ #define VOICE_VSID 0x10C01000 +#define AUDIO_PARAMETER_KEY_INCALLMUSIC "incall_music_enabled" +#define AUDIO_PARAMETER_VALUE_TRUE "true" + struct audio_device; struct str_parms; struct stream_in; @@ -59,6 +62,13 @@ struct voice { float volume; }; +enum { + INCALL_REC_NONE = -1, + INCALL_REC_UPLINK, + INCALL_REC_DOWNLINK, + INCALL_REC_UPLINK_AND_DOWNLINK, +}; + int voice_start_call(struct audio_device *adev); int voice_stop_call(struct audio_device *adev); int voice_set_parameters(struct audio_device *adev, struct str_parms *parms); @@ -71,4 +81,6 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, struct stream_in *in); int voice_check_and_set_incall_music_usecase(struct audio_device *adev, struct stream_out *out); +int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev, + struct stream_in *in); #endif //VOICE_H -- GitLab From 903101056462308418250912c7e4a302bfbc16b2 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Wed, 13 Nov 2013 16:57:00 -0800 Subject: [PATCH 091/298] hal: add Dolby DD+ support for AC3/EAC3 - Enhance offload formats to support AC3/EAC3. - update HMDI profile check to make sure that Dolby playback goes through compress offload path. Change-Id: Id8d1738305c117ccdf01c61bb5f4dd17e106b40b --- hal/Android.mk | 5 ++++ hal/audio_extn/audio_extn.c | 56 +++++++++++++++++++++++++++++++++++++ hal/audio_extn/audio_extn.h | 10 +++++++ hal/audio_hw.c | 21 ++++++++++++-- 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index abafb85c3..86f92d979 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -87,6 +87,11 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_CAPTURE)),true) LOCAL_SRC_FILES += audio_extn/compress_capture.c endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true) + LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +endif + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 0c8918aab..2c7fbcabf 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -29,6 +29,8 @@ #include "audio_hw.h" #include "audio_extn.h" +#include "sound/compress_params.h" + #define MAX_SLEEP_RETRY 100 #define WIFI_INIT_WAIT_SLEEP 50 @@ -256,3 +258,57 @@ int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card, return 0; } #endif /* AUXPCM_BT_ENABLED */ + + +#ifdef DS1_DOLBY_DDP_ENABLED + +bool audio_extn_dolby_is_supported_format(audio_format_t format) +{ + if (format == AUDIO_FORMAT_AC3 || + format == AUDIO_FORMAT_EAC3) + return true; + else + return false; +} + +int audio_extn_dolby_get_snd_codec_id(audio_format_t format) +{ + int id = 0; + + switch (format) { + case AUDIO_FORMAT_AC3: + id = SND_AUDIOCODEC_AC3; + break; + case AUDIO_FORMAT_EAC3: + id = SND_AUDIOCODEC_EAC3; + break; + default: + ALOGE("%s: Unsupported audio format :%x", __func__, format); + } + + return id; +} + +int audio_extn_dolby_set_DMID(struct audio_device *adev) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "DS1 Security"; + char c_dmid[128] = {0}; + int i_dmid, ret; + + property_get("dmid",c_dmid,"0"); + i_dmid = atoi(c_dmid); + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid); + ret = mixer_ctl_set_value(ctl, 0, i_dmid); + + return ret; +} +#endif /* DS1_DOLBY_DDP_ENABLED */ + diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 7d04c6d6b..23b165f70 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -157,4 +157,14 @@ size_t audio_extn_compr_cap_read(struct stream_in *in, void audio_extn_compr_cap_deinit(); #endif +#ifndef DS1_DOLBY_DDP_ENABLED +#define audio_extn_dolby_is_supported_format(format) (0) +#define audio_extn_dolby_get_snd_codec_id(format) (0) +#define audio_extn_dolby_set_DMID(adev) (0) +#else +bool audio_extn_dolby_is_supported_format(audio_format_t format); +int audio_extn_dolby_get_snd_codec_id(audio_format_t format); +int audio_extn_dolby_set_DMID(struct audio_device *adev); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 5537115f3..de567594f 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -165,7 +165,7 @@ static int get_snd_codec_id(audio_format_t format) id = SND_AUDIOCODEC_AAC; break; default: - ALOGE("%s: Unsupported audio format", __func__); + ALOGE("%s: Unsupported audio format :%x", __func__, format); } return id; @@ -2022,7 +2022,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ret = -EINVAL; goto error_open; } - if (!is_supported_format(config->offload_info.format)) { + if (!is_supported_format(config->offload_info.format) && + !audio_extn_dolby_is_supported_format(config->offload_info.format)) { ALOGE("%s: Unsupported audio format", __func__); ret = -EINVAL; goto error_open; @@ -2045,7 +2046,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.drain = out_drain; out->stream.flush = out_flush; - out->compr_config.codec->id = + if (audio_extn_dolby_is_supported_format(config->offload_info.format)) + out->compr_config.codec->id = + audio_extn_dolby_get_snd_codec_id(config->offload_info.format); + else + out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; @@ -2065,6 +2070,16 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); + + if (audio_extn_dolby_is_supported_format(out->format)) { + ret = audio_extn_dolby_set_DMID(adev); + if (ret != 0) { + ALOGE("%s: Dolby DMID cannot be set error:%d", + __func__, ret); + goto error_open; + } + } + } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { ret = voice_check_and_set_incall_music_usecase(adev, out); if (ret != 0) { -- GitLab From fae19629526916faab4079ffde00fb463672d85b Mon Sep 17 00:00:00 2001 From: Duy Truong Date: Sun, 24 Nov 2013 02:17:54 -0800 Subject: [PATCH 092/298] Update copyright to The Linux Foundation Change-Id: Ibaced495ccbe2ef8b53e7d5101dfe59855b5476b --- hal/audio_hw.c | 2 +- legacy/alsa_sound/ALSAControl.cpp | 2 +- legacy/alsa_sound/ALSAStreamOps.cpp | 2 +- legacy/alsa_sound/AudioHardwareALSA.cpp | 2 +- legacy/alsa_sound/AudioHardwareALSA.h | 2 +- legacy/alsa_sound/AudioPolicyManagerALSA.cpp | 2 +- legacy/alsa_sound/AudioPolicyManagerALSA.h | 2 +- legacy/alsa_sound/AudioStreamInALSA.cpp | 2 +- legacy/alsa_sound/AudioStreamOutALSA.cpp | 2 +- legacy/alsa_sound/AudioUsbALSA.cpp | 4 ++-- legacy/alsa_sound/AudioUsbALSA.h | 4 ++-- legacy/alsa_sound/alsa_default.cpp | 2 +- legacy/alsa_sound/audio_hw_hal.cpp | 4 ++-- legacy/alsa_sound/audio_policy_hal.cpp | 2 +- legacy/libalsa-intf/alsa_audio.h | 2 +- legacy/libalsa-intf/alsa_mixer.c | 2 +- legacy/libalsa-intf/alsa_pcm.c | 2 +- legacy/libalsa-intf/alsa_ucm.c | 4 ++-- legacy/libalsa-intf/alsaucm_test.c | 4 ++-- legacy/libalsa-intf/amix.c | 2 +- legacy/libalsa-intf/aplay.c | 2 +- legacy/libalsa-intf/arec.c | 2 +- legacy/libalsa-intf/msm8960_use_cases.h | 4 ++-- 23 files changed, 29 insertions(+), 29 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ee6770396..d81712e60 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2599,7 +2599,7 @@ struct audio_module HAL_MODULE_INFO_SYM = { .hal_api_version = HARDWARE_HAL_API_VERSION, .id = AUDIO_HARDWARE_MODULE_ID, .name = "QCOM Audio HAL", - .author = "Code Aurora Forum", + .author = "The Linux Foundation", .methods = &hal_module_methods, }, }; diff --git a/legacy/alsa_sound/ALSAControl.cpp b/legacy/alsa_sound/ALSAControl.cpp index 2d610a15f..5b2cf3141 100644 --- a/legacy/alsa_sound/ALSAControl.cpp +++ b/legacy/alsa_sound/ALSAControl.cpp @@ -1,7 +1,7 @@ /* ALSAControl.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/ALSAStreamOps.cpp b/legacy/alsa_sound/ALSAStreamOps.cpp index c7c0ca171..ad9a117bc 100644 --- a/legacy/alsa_sound/ALSAStreamOps.cpp +++ b/legacy/alsa_sound/ALSAStreamOps.cpp @@ -1,7 +1,7 @@ /* ALSAStreamOps.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioHardwareALSA.cpp b/legacy/alsa_sound/AudioHardwareALSA.cpp index 508418ccd..c61a3e837 100644 --- a/legacy/alsa_sound/AudioHardwareALSA.cpp +++ b/legacy/alsa_sound/AudioHardwareALSA.cpp @@ -1,7 +1,7 @@ /* AudioHardwareALSA.cpp ** ** Copyright 2008-2010 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioHardwareALSA.h b/legacy/alsa_sound/AudioHardwareALSA.h index 4ef878b55..b65773aca 100644 --- a/legacy/alsa_sound/AudioHardwareALSA.h +++ b/legacy/alsa_sound/AudioHardwareALSA.h @@ -1,7 +1,7 @@ /* AudioHardwareALSA.h ** ** Copyright 2008-2010, Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioPolicyManagerALSA.cpp b/legacy/alsa_sound/AudioPolicyManagerALSA.cpp index 93c9b01a3..36ae4d3db 100644 --- a/legacy/alsa_sound/AudioPolicyManagerALSA.cpp +++ b/legacy/alsa_sound/AudioPolicyManagerALSA.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioPolicyManagerALSA.h b/legacy/alsa_sound/AudioPolicyManagerALSA.h index 91b7e1392..a343cffe1 100644 --- a/legacy/alsa_sound/AudioPolicyManagerALSA.h +++ b/legacy/alsa_sound/AudioPolicyManagerALSA.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (C) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioStreamInALSA.cpp b/legacy/alsa_sound/AudioStreamInALSA.cpp index 4771d429c..7887f55d0 100644 --- a/legacy/alsa_sound/AudioStreamInALSA.cpp +++ b/legacy/alsa_sound/AudioStreamInALSA.cpp @@ -1,7 +1,7 @@ /* AudioStreamInALSA.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioStreamOutALSA.cpp b/legacy/alsa_sound/AudioStreamOutALSA.cpp index 2adb5d817..bbb8d3d03 100644 --- a/legacy/alsa_sound/AudioStreamOutALSA.cpp +++ b/legacy/alsa_sound/AudioStreamOutALSA.cpp @@ -1,7 +1,7 @@ /* AudioStreamOutALSA.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/AudioUsbALSA.cpp b/legacy/alsa_sound/AudioUsbALSA.cpp index 3316e3e26..93e07544a 100644 --- a/legacy/alsa_sound/AudioUsbALSA.cpp +++ b/legacy/alsa_sound/AudioUsbALSA.cpp @@ -1,5 +1,5 @@ /* AudioUsbALSA.cpp -Copyright (c) 2012, Code Aurora Forum. All rights reserved. +Copyright (c) 2012, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Code Aurora Forum, Inc. nor the names of its + * Neither the name of The Linux Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/legacy/alsa_sound/AudioUsbALSA.h b/legacy/alsa_sound/AudioUsbALSA.h index 4204eb011..d06bbb75f 100644 --- a/legacy/alsa_sound/AudioUsbALSA.h +++ b/legacy/alsa_sound/AudioUsbALSA.h @@ -1,6 +1,6 @@ /* AudioUsbALSA.h -Copyright (c) 2012, Code Aurora Forum. All rights reserved. +Copyright (c) 2012, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +11,7 @@ met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Code Aurora Forum, Inc. nor the names of its + * Neither the name of The Linux Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/legacy/alsa_sound/alsa_default.cpp b/legacy/alsa_sound/alsa_default.cpp index 2f043bb57..5be2958cd 100644 --- a/legacy/alsa_sound/alsa_default.cpp +++ b/legacy/alsa_sound/alsa_default.cpp @@ -1,7 +1,7 @@ /* alsa_default.cpp ** ** Copyright 2009 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/alsa_sound/audio_hw_hal.cpp b/legacy/alsa_sound/audio_hw_hal.cpp index ab15e2744..24e50d325 100644 --- a/legacy/alsa_sound/audio_hw_hal.cpp +++ b/legacy/alsa_sound/audio_hw_hal.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 The Android Open Source Project - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. 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. @@ -770,7 +770,7 @@ struct qcom_audio_module HAL_MODULE_INFO_SYM = { hal_api_version: HARDWARE_HAL_API_VERSION, id: AUDIO_HARDWARE_MODULE_ID, name: "QCOM Audio HW HAL", - author: "Code Aurora Forum", + author: "The Linux Foundation", methods: &qcom_audio_module_methods, dso : NULL, reserved : {0}, diff --git a/legacy/alsa_sound/audio_policy_hal.cpp b/legacy/alsa_sound/audio_policy_hal.cpp index 5363e2824..a1687f770 100644 --- a/legacy/alsa_sound/audio_policy_hal.cpp +++ b/legacy/alsa_sound/audio_policy_hal.cpp @@ -455,7 +455,7 @@ struct qcom_ap_module HAL_MODULE_INFO_SYM = { version_minor: 0, id: AUDIO_POLICY_HARDWARE_MODULE_ID, name: "QCOM Audio Policy HAL", - author: "Code Aurora Forum", + author: "The Linux Foundation", methods: &qcom_ap_module_methods, dso : NULL, reserved : {0}, diff --git a/legacy/libalsa-intf/alsa_audio.h b/legacy/libalsa-intf/alsa_audio.h index 7f2acf0d2..90fbe56ca 100644 --- a/legacy/libalsa-intf/alsa_audio.h +++ b/legacy/libalsa-intf/alsa_audio.h @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/libalsa-intf/alsa_mixer.c b/legacy/libalsa-intf/alsa_mixer.c index cdcdcea25..c3738f0bb 100644 --- a/legacy/libalsa-intf/alsa_mixer.c +++ b/legacy/libalsa-intf/alsa_mixer.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/libalsa-intf/alsa_pcm.c b/legacy/libalsa-intf/alsa_pcm.c index a814ae809..51c5691d4 100644 --- a/legacy/libalsa-intf/alsa_pcm.c +++ b/legacy/libalsa-intf/alsa_pcm.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/libalsa-intf/alsa_ucm.c b/legacy/libalsa-intf/alsa_ucm.c index e53211f98..fac8498de 100644 --- a/legacy/libalsa-intf/alsa_ucm.c +++ b/legacy/libalsa-intf/alsa_ucm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/legacy/libalsa-intf/alsaucm_test.c b/legacy/libalsa-intf/alsaucm_test.c index e01cf59c1..aaed38e25 100644 --- a/legacy/libalsa-intf/alsaucm_test.c +++ b/legacy/libalsa-intf/alsaucm_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2012, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/legacy/libalsa-intf/amix.c b/legacy/libalsa-intf/amix.c index 40f38077a..b425ed572 100644 --- a/legacy/libalsa-intf/amix.c +++ b/legacy/libalsa-intf/amix.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011, The Linux Foundation. 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. diff --git a/legacy/libalsa-intf/aplay.c b/legacy/libalsa-intf/aplay.c index c0602775c..120febd02 100644 --- a/legacy/libalsa-intf/aplay.c +++ b/legacy/libalsa-intf/aplay.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/libalsa-intf/arec.c b/legacy/libalsa-intf/arec.c index cab88f119..30e710c36 100644 --- a/legacy/libalsa-intf/arec.c +++ b/legacy/libalsa-intf/arec.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. 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. diff --git a/legacy/libalsa-intf/msm8960_use_cases.h b/legacy/libalsa-intf/msm8960_use_cases.h index 4c37cd077..7f98df140 100644 --- a/legacy/libalsa-intf/msm8960_use_cases.h +++ b/legacy/libalsa-intf/msm8960_use_cases.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * -- GitLab From d60ca7f2378cd6240b37c512d7e784158b84e07c Mon Sep 17 00:00:00 2001 From: Banajit Goswami Date: Sat, 16 Nov 2013 20:55:49 -0800 Subject: [PATCH 093/298] hal: update devices for APQ8084 cdp and liquid APQ8084 CDP and Liquid might use a different set of devices compared to MTP device for the same use case. Update device list to use the right set of mixer controls for use cases for APQ8084 CDP and Liquid Change-Id: Ia40c31bc6cd94155d2b6dcc966bf4524906ea687 --- hal/msm8974/hw_info.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index 673b6e292..58ca4dc54 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -69,6 +69,10 @@ static const snd_device_t taiko_CDP_variant_devices[] = { SND_DEVICE_IN_QUAD_MIC, }; +static const snd_device_t taiko_apq8084_CDP_variant_devices[] = { + SND_DEVICE_IN_HANDSET_MIC, +}; + static const snd_device_t taiko_liquid_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, @@ -135,15 +139,15 @@ static void update_hardware_info_8084(struct hardware_info *hw_info, const char } else if (!strcmp(snd_card_name, "apq8084-taiko-cdp-snd-card")) { strlcpy(hw_info->type, " cdp", sizeof(hw_info->type)); strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name)); - hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices; - hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices); - strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + hw_info->snd_devices = (snd_device_t *)taiko_apq8084_CDP_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_apq8084_CDP_variant_devices); + strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn)); } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) { strlcpy(hw_info->type , " liquid", sizeof(hw_info->type)); strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type)); hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices; hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices); - strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn)); } else { ALOGW("%s: Not an 8084 device", __func__); } -- GitLab From 5b4d3f10ea822ea6139294872ee06d2fa4bbd702 Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Tue, 5 Nov 2013 15:57:39 -0800 Subject: [PATCH 094/298] hal: Added support for HFP - Added setparameter to be set from hfp app to enable and disable hfp session. - Implemeted start and stop hfp session which takes care of switching device and setting the session Change-Id: Ie8697328ccbfee09d0d162f6fad01ddb552e4f83 --- hal/Android.mk | 4 + hal/audio_extn/audio_extn.c | 8 +- hal/audio_extn/hfp.c | 231 ++++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 4 +- hal/audio_hw.h | 6 +- hal/msm8974/platform.c | 2 + hal/msm8974/platform.h | 4 + 7 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 hal/audio_extn/hfp.c diff --git a/hal/Android.mk b/hal/Android.mk index 86f92d979..d8a4733f7 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -47,6 +47,10 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_USBAUDIO)),true) LOCAL_CFLAGS += -DUSB_HEADSET_ENABLED LOCAL_SRC_FILES += audio_extn/usb.c endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_HFP)),true) + LOCAL_CFLAGS += -DHFP_ENABLED + LOCAL_SRC_FILES += audio_extn/hfp.c +endif ifneq ($(strip $(AUDIO_FEATURE_DISABLED_SSR)),true) LOCAL_CFLAGS += -DSSR_ENABLED diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 2c7fbcabf..72e2f9c13 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -55,7 +55,12 @@ static struct audio_extn_module aextnmod = { void audio_extn_fm_set_parameters(struct audio_device *adev, struct str_parms *parms); #endif - +#ifndef HFP_ENABLED +void audio_extn_hfp_set_parameters(adev, parms) (0) +#else +void audio_extn_hfp_set_parameters(struct audio_device *adev, + struct str_parms *parms); +#endif #ifndef SSR_ENABLED #define audio_extn_ssr_get_parameters(query, reply) (0) #else @@ -219,6 +224,7 @@ void audio_extn_set_parameters(struct audio_device *adev, audio_extn_set_afe_proxy_parameters(parms); audio_extn_fm_set_parameters(adev, parms); audio_extn_listen_set_parameters(adev, parms); + audio_extn_hfp_set_parameters(adev, parms); } void audio_extn_get_parameters(const struct audio_device *adev, diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c new file mode 100644 index 000000000..73824bdff --- /dev/null +++ b/hal/audio_extn/hfp.c @@ -0,0 +1,231 @@ +/* hfp.c +Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ + +#define LOG_TAG "audio_hw_hfp" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include + +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" +#include +#include + +#ifdef HFP_ENABLED +#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable" + +static int32_t audio_extn_start_hfp(struct audio_device *adev, + struct str_parms *parms); + +static int32_t audio_extn_stop_hfp(struct audio_device *adev); + +struct hfp_module { + struct pcm *hfp_sco_rx; + struct pcm *hfp_sco_tx; + struct pcm *hfp_pcm_rx; + struct pcm *hfp_pcm_tx; + bool is_hfp_running; + int hfp_volume; +}; + +static struct hfp_module hfpmod = { + .hfp_sco_rx = NULL, + .hfp_sco_tx = NULL, + .hfp_pcm_rx = NULL, + .hfp_pcm_tx = NULL, + .hfp_volume = 0, + .is_hfp_running = 0, +}; +static struct pcm_config pcm_config_hfp = { + .channels = 1, + .rate = 8000, + .period_size = 240, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, + .start_threshold = 0, + .stop_threshold = INT_MAX, + .avail_min = 0, +}; + +void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) +{ + int ret; + char value[32]={0}; + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, + sizeof(value)); + if (ret >= 0) { + if(!strncmp(value,"true",sizeof(value))) + ret = audio_extn_start_hfp(adev,parms); + else + audio_extn_stop_hfp(adev); + } +} + +static int32_t audio_extn_start_hfp(struct audio_device *adev, + struct str_parms *parms) +{ + int32_t i, ret = 0; + struct audio_usecase *uc_info; + int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id; + + ALOGD("%s: enter", __func__); + + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = USECASE_AUDIO_HFP_SCO; + uc_info->type = PCM_HFP_CALL; + uc_info->stream.out = adev->primary_output; + uc_info->devices = adev->primary_output->devices; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, USECASE_AUDIO_HFP_SCO); + + pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); + pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); + pcm_dev_asm_rx_id = HFP_ASM_RX_TX; + pcm_dev_asm_tx_id = HFP_ASM_RX_TX; + if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 || + pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) { + ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id); + ret = -EIO; + goto exit; + } + + ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)", + __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); + + ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_rx_id); + hfpmod.hfp_sco_rx = pcm_open(SOUND_CARD, + pcm_dev_asm_rx_id, + PCM_OUT, &pcm_config_hfp); + if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx)); + ret = -EIO; + goto exit; + } + ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_tx_id); + hfpmod.hfp_pcm_rx = pcm_open(SOUND_CARD, + pcm_dev_rx_id, + PCM_OUT, &pcm_config_hfp); + if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) { + ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx)); + ret = -EIO; + goto exit; + } + hfpmod.hfp_sco_tx = pcm_open(SOUND_CARD, + pcm_dev_asm_tx_id, + PCM_IN, &pcm_config_hfp); + if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx)); + ret = -EIO; + goto exit; + } + ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", + __func__, SOUND_CARD, pcm_dev_tx_id); + hfpmod.hfp_pcm_tx = pcm_open(SOUND_CARD, + pcm_dev_tx_id, + PCM_IN, &pcm_config_hfp); + if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) { + ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx)); + ret = -EIO; + goto exit; + } + pcm_start(hfpmod.hfp_sco_rx); + pcm_start(hfpmod.hfp_sco_tx); + pcm_start(hfpmod.hfp_pcm_rx); + pcm_start(hfpmod.hfp_pcm_tx); + + + hfpmod.is_hfp_running = true; + + ALOGD("%s: exit: status(%d)", __func__, ret); + return 0; + +exit: + audio_extn_stop_hfp(adev); + ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret); + return ret; +} + +static int32_t audio_extn_stop_hfp(struct audio_device *adev) +{ + int32_t i, ret = 0; + struct audio_usecase *uc_info; + + ALOGD("%s: enter", __func__); + hfpmod.is_hfp_running = false; + + /* 1. Close the PCM devices */ + if (hfpmod.hfp_sco_rx) { + pcm_close(hfpmod.hfp_sco_rx); + hfpmod.hfp_sco_rx = NULL; + } + if (hfpmod.hfp_sco_tx) { + pcm_close(hfpmod.hfp_sco_tx); + hfpmod.hfp_sco_tx = NULL; + } + if (hfpmod.hfp_pcm_rx) { + pcm_close(hfpmod.hfp_pcm_rx); + hfpmod.hfp_pcm_rx = NULL; + } + if (hfpmod.hfp_pcm_tx) { + pcm_close(hfpmod.hfp_pcm_tx); + hfpmod.hfp_pcm_tx = NULL; + } + + uc_info = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, USECASE_AUDIO_HFP_SCO); + return -EINVAL; + } + + /* 2. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 3. Disable the rx and tx devices */ + disable_snd_device(adev, uc_info->out_snd_device, false); + disable_snd_device(adev, uc_info->in_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + + ALOGD("%s: exit: status(%d)", __func__, ret); + return ret; +} +#endif /*HFP_ENABLED*/ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ee6770396..920dbc2ef 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -109,6 +109,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", + [USECASE_AUDIO_HFP_SCO] = "hfp-sco", [USECASE_VOICE_CALL] = "voice-call", [USECASE_VOICE2_CALL] = "voice2-call", @@ -593,7 +594,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) } if ((usecase->type == VOICE_CALL) || - (usecase->type == VOIP_CALL)) { + (usecase->type == VOIP_CALL) || + (usecase->type == PCM_HFP_CALL)) { out_snd_device = platform_get_output_snd_device(adev->platform, usecase->stream.out->devices); in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 6ff6f40be..639032f9e 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -62,6 +62,9 @@ typedef enum { /* FM usecase */ USECASE_AUDIO_PLAYBACK_FM, + /* HFP Use case*/ + USECASE_AUDIO_HFP_SCO, + /* Capture usecases */ USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_COMPRESS, @@ -179,7 +182,8 @@ typedef enum { PCM_PLAYBACK, PCM_CAPTURE, VOICE_CALL, - VOIP_CALL + VOIP_CALL, + PCM_HFP_CALL } usecase_type_t; union stream_ptr { diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index a207c2f8d..da671450d 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -109,6 +109,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE, MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, + [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, @@ -989,6 +990,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (my_data->fluence_type == FLUENCE_NONE || my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; + set_echo_reference(adev->mixer, "SLIM_RX"); } else { snd_device = SND_DEVICE_IN_VOICE_DMIC; adev->acdb_settings |= DMIC_FLAG; diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 7d80906a0..e1ae77b53 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -170,6 +170,10 @@ enum { #define MULTIMEDIA2_PCM_DEVICE 1 #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 +#define HFP_PCM_RX 5 +#define HFP_SCO_RX 35 +#define HFP_ASM_RX_TX 36 + #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 -- GitLab From 10fef6a82ed13bacba0df47a1ae4c9967b2b2d6c Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Tue, 26 Nov 2013 17:17:01 -0800 Subject: [PATCH 095/298] hal: fix channel mask for m-ch offload playback - Update channel mask with compress parameters for compress offload playback on HDMI device Change-Id: I89263f56923588fcb906facfd4ae9ebf95203743 --- hal/audio_hw.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ee6770396..1a83b6356 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -989,7 +989,7 @@ static int check_and_set_hdmi_channels(struct audio_device *adev, return 0; if (channels == adev->cur_hdmi_channels) { - ALOGD("%s: Requested channels are same as current", __func__); + ALOGD("%s: Requested channels are same as current channels(%d)", __func__, channels); return 0; } @@ -1085,8 +1085,12 @@ int start_output_stream(struct stream_out *out) uc_info->out_snd_device = SND_DEVICE_NONE; /* This must be called before adding this usecase to the list */ - if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) - check_and_set_hdmi_channels(adev, out->config.channels); + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in); + else + check_and_set_hdmi_channels(adev, out->config.channels); + } list_add_tail(&adev->usecase_list, &uc_info->list); -- GitLab From daf6ebbc06c530d29551e2d106699a6abb4729a9 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Mon, 7 Oct 2013 11:38:46 -0700 Subject: [PATCH 096/298] Initial mpq8092 HAL upload Initial mpq8092 HAL upload Depends-on: 531569 531557 Change-Id: Ic130ab0a5ae2ffee09d98b7ca2c3ee4374965466 --- Android.mk | 6 +- hal_mpq/Android.mk | 57 + hal_mpq/audio_hw.c | 2400 ++++++++++++++++++++++++++++++++++++ hal_mpq/audio_hw.h | 244 ++++ hal_mpq/mpq8092/hw_info.c | 326 +++++ hal_mpq/mpq8092/platform.c | 1272 +++++++++++++++++++ hal_mpq/mpq8092/platform.h | 242 ++++ hal_mpq/platform_api.h | 55 + 8 files changed, 4601 insertions(+), 1 deletion(-) create mode 100644 hal_mpq/Android.mk create mode 100644 hal_mpq/audio_hw.c create mode 100644 hal_mpq/audio_hw.h create mode 100644 hal_mpq/mpq8092/hw_info.c create mode 100644 hal_mpq/mpq8092/platform.c create mode 100644 hal_mpq/mpq8092/platform.h create mode 100644 hal_mpq/platform_api.h diff --git a/Android.mk b/Android.mk index 0e94762bc..e293fd6e5 100644 --- a/Android.mk +++ b/Android.mk @@ -1,11 +1,15 @@ -ifneq ($(filter msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084,$(TARGET_BOARD_PLATFORM)),) +ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084,$(TARGET_BOARD_PLATFORM)),) MY_LOCAL_PATH := $(call my-dir) ifeq ($(BOARD_USES_LEGACY_ALSA_AUDIO),true) include $(MY_LOCAL_PATH)/legacy/Android.mk else +ifneq ($(filter mpq8092,$(TARGET_BOARD_PLATFORM)),) +include $(MY_LOCAL_PATH)/hal_mpq/Android.mk +else include $(MY_LOCAL_PATH)/hal/Android.mk +endif include $(MY_LOCAL_PATH)/voice_processing/Android.mk include $(MY_LOCAL_PATH)/mm-audio/Android.mk include $(MY_LOCAL_PATH)/policy_hal/Android.mk diff --git a/hal_mpq/Android.mk b/hal_mpq/Android.mk new file mode 100644 index 000000000..338ee401b --- /dev/null +++ b/hal_mpq/Android.mk @@ -0,0 +1,57 @@ +ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_ARM_MODE := arm + +AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) + +LOCAL_SRC_FILES := \ + audio_hw.c \ + $(AUDIO_PLATFORM)/hw_info.c \ + $(AUDIO_PLATFORM)/platform.c + +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true) + LOCAL_CFLAGS += -DANC_HEADSET_ENABLED +endif + +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) + LOCAL_CFLAGS += -DAFE_PROXY_ENABLED +endif + + +ifdef MULTIPLE_HW_VARIANTS_ENABLED + LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED + LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c +endif + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libtinyalsa \ + libtinycompress \ + libaudioroute \ + libdl + +LOCAL_C_INCLUDES := \ + external/tinyalsa/include \ + external/tinycompress/include \ + $(call include-path-for, audio-route) \ + $(call include-path-for, audio-effects) \ + $(LOCAL_PATH)/$(AUDIO_PLATFORM) + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true) + LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED +endif + +LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/hal_mpq/audio_hw.c b/hal_mpq/audio_hw.c new file mode 100644 index 000000000..8df46be83 --- /dev/null +++ b/hal_mpq/audio_hw.c @@ -0,0 +1,2400 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_primary" +/*#define LOG_NDEBUG 0*/ +/*#define VERY_VERY_VERBOSE_LOGGING*/ +#ifdef VERY_VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "audio_hw.h" +#include "platform_api.h" +#include + +#include "sound/compress_params.h" + +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) +#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 +/* ToDo: Check and update a proper value in msec */ +#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 +#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 + +struct pcm_config pcm_config_deep_buffer = { + .channels = 2, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, + .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, +}; + +struct pcm_config pcm_config_low_latency = { + .channels = 2, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, + .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, +}; + +struct pcm_config pcm_config_hdmi_multi = { + .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */ + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */ + .period_size = HDMI_MULTI_PERIOD_SIZE, + .period_count = HDMI_MULTI_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = 0, + .stop_threshold = INT_MAX, + .avail_min = 0, +}; + +struct pcm_config pcm_config_audio_capture = { + .channels = 2, + .period_count = AUDIO_CAPTURE_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, +}; + +const char * const use_case_table[AUDIO_USECASE_MAX] = { + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback", + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", + [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", + [USECASE_AUDIO_RECORD] = "audio-record", + [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", + [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", + [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", + [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", + [USECASE_VOICE_CALL] = "voice-call", + + [USECASE_VOICE2_CALL] = "voice2-call", + [USECASE_VOLTE_CALL] = "volte-call", + [USECASE_QCHAT_CALL] = "qchat-call", + [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call", + [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", + [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", + [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink", + [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", + [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib", + [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record", +}; + + +#define STRING_TO_ENUM(string) { #string, string } + +struct string_to_enum { + const char *name; + uint32_t value; +}; + +static const struct string_to_enum out_channels_name_to_enum_table[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; + +static struct audio_device *adev = NULL; +static pthread_mutex_t adev_init_lock; +static unsigned int audio_device_ref_count; + +static int set_voice_volume_l(struct audio_device *adev, float volume); + +static bool is_supported_format(audio_format_t format) +{ + if (format == AUDIO_FORMAT_MP3 || + format == AUDIO_FORMAT_AAC) + return true; + + return false; +} + +static int get_snd_codec_id(audio_format_t format) +{ + int id = 0; + + switch (format) { + case AUDIO_FORMAT_MP3: + id = SND_AUDIOCODEC_MP3; + break; + case AUDIO_FORMAT_AAC: + id = SND_AUDIOCODEC_AAC; + break; + default: + ALOGE("%s: Unsupported audio format", __func__); + } + + return id; +} + +int enable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer) +{ + snd_device_t snd_device; + char mixer_path[MIXER_PATH_MAX_LENGTH]; + + if (usecase == NULL) + return -EINVAL; + + ALOGV("%s: enter: usecase(%d)", __func__, usecase->id); + + if (usecase->type == PCM_CAPTURE) + snd_device = usecase->in_snd_device; + else + snd_device = usecase->out_snd_device; + + strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path)); + platform_add_backend_name(mixer_path, snd_device); + ALOGV("%s: apply mixer path: %s", __func__, mixer_path); + audio_route_apply_path(adev->audio_route, mixer_path); + if (update_mixer) + audio_route_update_mixer(adev->audio_route); + + ALOGV("%s: exit", __func__); + return 0; +} + +int disable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer) +{ + snd_device_t snd_device; + char mixer_path[MIXER_PATH_MAX_LENGTH]; + + if (usecase == NULL) + return -EINVAL; + + ALOGV("%s: enter: usecase(%d)", __func__, usecase->id); + if (usecase->type == PCM_CAPTURE) + snd_device = usecase->in_snd_device; + else + snd_device = usecase->out_snd_device; + strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path)); + platform_add_backend_name(mixer_path, snd_device); + ALOGV("%s: reset mixer path: %s", __func__, mixer_path); + audio_route_reset_path(adev->audio_route, mixer_path); + if (update_mixer) + audio_route_update_mixer(adev->audio_route); + + ALOGV("%s: exit", __func__); + return 0; +} + +int enable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer) +{ + char device_name[DEVICE_NAME_MAX_SIZE] = {0}; + + if (snd_device < SND_DEVICE_MIN || + snd_device >= SND_DEVICE_MAX) { + ALOGE("%s: Invalid sound device %d", __func__, snd_device); + return -EINVAL; + } + + adev->snd_dev_ref_cnt[snd_device]++; + + if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) { + ALOGE("%s: Invalid sound device returned", __func__); + return -EINVAL; + } + if (adev->snd_dev_ref_cnt[snd_device] > 1) { + ALOGV("%s: snd_device(%d: %s) is already active", + __func__, snd_device, device_name); + return 0; + } + + { + ALOGV("%s: snd_device(%d: %s)", __func__, + snd_device, device_name); + if (platform_send_audio_calibration(adev->platform, snd_device) < 0) { + adev->snd_dev_ref_cnt[snd_device]--; + return -EINVAL; + } + audio_route_apply_path(adev->audio_route, device_name); + } + if (update_mixer) + audio_route_update_mixer(adev->audio_route); + + return 0; +} + +int disable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer) +{ + char device_name[DEVICE_NAME_MAX_SIZE] = {0}; + + if (snd_device < SND_DEVICE_MIN || + snd_device >= SND_DEVICE_MAX) { + ALOGE("%s: Invalid sound device %d", __func__, snd_device); + return -EINVAL; + } + if (adev->snd_dev_ref_cnt[snd_device] <= 0) { + ALOGE("%s: device ref cnt is already 0", __func__); + return -EINVAL; + } + + adev->snd_dev_ref_cnt[snd_device]--; + + if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) { + ALOGE("%s: Invalid sound device returned", __func__); + return -EINVAL; + } + + if (adev->snd_dev_ref_cnt[snd_device] == 0) { + ALOGV("%s: snd_device(%d: %s)", __func__, + snd_device, device_name); + audio_route_reset_path(adev->audio_route, device_name); + + if (update_mixer) + audio_route_update_mixer(adev->audio_route); + } + + return 0; +} + +static void check_usecases_codec_backend(struct audio_device *adev, + struct audio_usecase *uc_info, + snd_device_t snd_device) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool switch_device[AUDIO_USECASE_MAX]; + int i, num_uc_to_switch = 0; + + /* + * This function is to make sure that all the usecases that are active on + * the hardware codec backend are always routed to any one device that is + * handled by the hardware codec. + * For example, if low-latency and deep-buffer usecases are currently active + * on speaker and out_set_parameters(headset) is received on low-latency + * output, then we have to make sure deep-buffer is also switched to headset, + * because of the limitation that both the devices cannot be enabled + * at the same time as they share the same backend. + */ + /* Disable all the usecases on the shared backend other than the + specified usecase */ + for (i = 0; i < AUDIO_USECASE_MAX; i++) + switch_device[i] = false; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase != uc_info && + usecase->out_snd_device != snd_device && + usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", + __func__, use_case_table[usecase->id], + platform_get_snd_device_name(usecase->out_snd_device)); + disable_audio_route(adev, usecase, false); + switch_device[usecase->id] = true; + num_uc_to_switch++; + } + } + + if (num_uc_to_switch) { + /* Make sure all the streams are de-routed before disabling the device */ + audio_route_update_mixer(adev->audio_route); + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { + disable_snd_device(adev, usecase->out_snd_device, false); + } + } + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { + enable_snd_device(adev, snd_device, false); + } + } + /* Make sure new snd device is enabled before re-routing the streams */ + audio_route_update_mixer(adev->audio_route); + + /* Re-route all the usecases on the shared backend other than the + specified usecase to new snd devices */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + /* Update the out_snd_device only before enabling the audio route */ + if (switch_device[usecase->id] ) { + usecase->out_snd_device = snd_device; + enable_audio_route(adev, usecase, false); + } + } + + audio_route_update_mixer(adev->audio_route); + } +} + +static void check_and_route_capture_usecases(struct audio_device *adev, + struct audio_usecase *uc_info, + snd_device_t snd_device) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool switch_device[AUDIO_USECASE_MAX]; + int i, num_uc_to_switch = 0; + + /* + * This function is to make sure that all the active capture usecases + * are always routed to the same input sound device. + * For example, if audio-record and voice-call usecases are currently + * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece) + * is received for voice call then we have to make sure that audio-record + * usecase is also switched to earpiece i.e. voice-dmic-ef, + * because of the limitation that two devices cannot be enabled + * at the same time if they share the same backend. + */ + for (i = 0; i < AUDIO_USECASE_MAX; i++) + switch_device[i] = false; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_CAPTURE && + usecase != uc_info && + usecase->in_snd_device != snd_device) { + ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", + __func__, use_case_table[usecase->id], + platform_get_snd_device_name(usecase->in_snd_device)); + disable_audio_route(adev, usecase, false); + switch_device[usecase->id] = true; + num_uc_to_switch++; + } + } + + if (num_uc_to_switch) { + /* Make sure all the streams are de-routed before disabling the device */ + audio_route_update_mixer(adev->audio_route); + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { + disable_snd_device(adev, usecase->in_snd_device, false); + enable_snd_device(adev, snd_device, false); + } + } + + /* Make sure new snd device is enabled before re-routing the streams */ + audio_route_update_mixer(adev->audio_route); + + /* Re-route all the usecases on the shared backend other than the + specified usecase to new snd devices */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + /* Update the in_snd_device only before enabling the audio route */ + if (switch_device[usecase->id] ) { + usecase->in_snd_device = snd_device; + enable_audio_route(adev, usecase, false); + } + } + + audio_route_update_mixer(adev->audio_route); + } +} + +static int disable_all_usecases_of_type(struct audio_device *adev, + usecase_type_t usecase_type, + bool update_mixer) +{ + struct audio_usecase *usecase; + struct listnode *node; + int ret = 0; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == usecase_type) { + ALOGV("%s: usecase id %d", __func__, usecase->id); + ret = disable_audio_route(adev, usecase, update_mixer); + if (ret) { + ALOGE("%s: Failed to disable usecase id %d", + __func__, usecase->id); + } + } + } + + return ret; +} + +static int enable_all_usecases_of_type(struct audio_device *adev, + usecase_type_t usecase_type, + bool update_mixer) +{ + struct audio_usecase *usecase; + struct listnode *node; + int ret = 0; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == usecase_type) { + ALOGV("%s: usecase id %d", __func__, usecase->id); + ret = enable_audio_route(adev, usecase, update_mixer); + if (ret) { + ALOGE("%s: Failed to enable usecase id %d", + __func__, usecase->id); + } + } + } + + return ret; +} + +/* must be called with hw device mutex locked */ +static int read_hdmi_channel_masks(struct stream_out *out) +{ + int ret = 0; + int channels = platform_edid_get_max_channels(out->dev->platform); + + switch (channels) { + /* + * Do not handle stereo output in Multi-channel cases + * Stereo case is handled in normal playback path + */ + case 6: + ALOGV("%s: HDMI supports 5.1", __func__); + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; + break; + case 8: + ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__); + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; + out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1; + break; + default: + ALOGE("HDMI does not support multi channel playback"); + ret = -ENOSYS; + break; + } + return ret; +} + +static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev) +{ + struct audio_usecase *usecase; + struct listnode *node; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == VOICE_CALL) { + ALOGV("%s: usecase id %d", __func__, usecase->id); + return usecase->id; + } + } + return USECASE_INVALID; +} + +struct audio_usecase *get_usecase_from_list(struct audio_device *adev, + audio_usecase_t uc_id) +{ + struct audio_usecase *usecase; + struct listnode *node; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->id == uc_id) + return usecase; + } + return NULL; +} + +int select_devices(struct audio_device *adev, audio_usecase_t uc_id) +{ + snd_device_t out_snd_device = SND_DEVICE_NONE; + snd_device_t in_snd_device = SND_DEVICE_NONE; + struct audio_usecase *usecase = NULL; + struct audio_usecase *vc_usecase = NULL; + struct audio_usecase *voip_usecase = NULL; + struct listnode *node; + int status = 0; + + usecase = get_usecase_from_list(adev, uc_id); + if (usecase == NULL) { + ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id); + return -EINVAL; + } + + if ((usecase->type == VOICE_CALL) || + (usecase->type == VOIP_CALL)) { + out_snd_device = platform_get_output_snd_device(adev->platform, + usecase->stream.out->devices); + in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices); + usecase->devices = usecase->stream.out->devices; + } else { + /* + * If the voice call is active, use the sound devices of voice call usecase + * so that it would not result any device switch. All the usecases will + * be switched to new device when select_devices() is called for voice call + * usecase. This is to avoid switching devices for voice call when + * check_usecases_codec_backend() is called below. + */ + if (usecase->type == PCM_PLAYBACK) { + usecase->devices = usecase->stream.out->devices; + in_snd_device = SND_DEVICE_NONE; + if (out_snd_device == SND_DEVICE_NONE) { + out_snd_device = platform_get_output_snd_device(adev->platform, + usecase->stream.out->devices); + if (usecase->stream.out == adev->primary_output && + adev->active_input && + adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) { + select_devices(adev, adev->active_input->usecase); + } + } + } else if (usecase->type == PCM_CAPTURE) { + usecase->devices = usecase->stream.in->device; + out_snd_device = SND_DEVICE_NONE; + if (in_snd_device == SND_DEVICE_NONE) { + if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION && + adev->primary_output && !adev->primary_output->standby) { + in_snd_device = platform_get_input_snd_device(adev->platform, + adev->primary_output->devices); + } else { + in_snd_device = platform_get_input_snd_device(adev->platform, + AUDIO_DEVICE_NONE); + } + } + } + } + + if (out_snd_device == usecase->out_snd_device && + in_snd_device == usecase->in_snd_device) { + return 0; + } + + ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__, + out_snd_device, platform_get_snd_device_name(out_snd_device), + in_snd_device, platform_get_snd_device_name(in_snd_device)); + + /* + * Limitation: While in call, to do a device switch we need to disable + * and enable both RX and TX devices though one of them is same as current + * device. + */ + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) { + status = platform_switch_voice_call_device_pre(adev->platform); + disable_all_usecases_of_type(adev, VOICE_CALL, true); + } + + /* Disable current sound devices */ + if (usecase->out_snd_device != SND_DEVICE_NONE) { + disable_audio_route(adev, usecase, true); + disable_snd_device(adev, usecase->out_snd_device, false); + } + + if (usecase->in_snd_device != SND_DEVICE_NONE) { + disable_audio_route(adev, usecase, true); + disable_snd_device(adev, usecase->in_snd_device, false); + } + + /* Enable new sound devices */ + if (out_snd_device != SND_DEVICE_NONE) { + if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) + check_usecases_codec_backend(adev, usecase, out_snd_device); + enable_snd_device(adev, out_snd_device, false); + } + + if (in_snd_device != SND_DEVICE_NONE) { + check_and_route_capture_usecases(adev, usecase, in_snd_device); + enable_snd_device(adev, in_snd_device, false); + } + + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) + status = platform_switch_voice_call_device_post(adev->platform, + out_snd_device, + in_snd_device); + + audio_route_update_mixer(adev->audio_route); + + usecase->in_snd_device = in_snd_device; + usecase->out_snd_device = out_snd_device; + + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) + enable_all_usecases_of_type(adev, usecase->type, true); + else + enable_audio_route(adev, usecase, true); + + /* Applicable only on the targets that has external modem. + * Enable device command should be sent to modem only after + * enabling voice call mixer controls + */ + if (usecase->type == VOICE_CALL) + status = platform_switch_voice_call_usecase_route_post(adev->platform, + out_snd_device, + in_snd_device); + + return status; +} + +static int stop_input_stream(struct stream_in *in) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = in->dev; + + adev->active_input = NULL; + + ALOGV("%s: enter: usecase(%d: %s)", __func__, + in->usecase, use_case_table[in->usecase]); + uc_info = get_usecase_from_list(adev, in->usecase); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, in->usecase); + return -EINVAL; + } + + /* 1. Disable stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 2. Disable the tx device */ + disable_snd_device(adev, uc_info->in_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int start_input_stream(struct stream_in *in) +{ + /* 1. Enable output device and stream routing controls */ + int ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = in->dev; + + in->usecase = platform_update_usecase_from_source(in->source,in->usecase); + ALOGV("%s: enter: usecase(%d)", __func__, in->usecase); + + in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); + if (in->pcm_device_id < 0) { + ALOGE("%s: Could not find PCM device id for the usecase(%d)", + __func__, in->usecase); + ret = -EINVAL; + goto error_config; + } + + adev->active_input = in; + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = in->usecase; + uc_info->type = PCM_CAPTURE; + uc_info->stream.in = in; + uc_info->devices = in->device; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + list_add_tail(&adev->usecase_list, &uc_info->list); + select_devices(adev, in->usecase); + + ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", + __func__, SOUND_CARD, in->pcm_device_id, in->config.channels); + in->pcm = pcm_open(SOUND_CARD, in->pcm_device_id, + PCM_IN, &in->config); + if (in->pcm && !pcm_is_ready(in->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); + pcm_close(in->pcm); + in->pcm = NULL; + ret = -EIO; + goto error_open; + } + ALOGV("%s: exit", __func__); + return ret; + +error_open: + stop_input_stream(in); + +error_config: + adev->active_input = NULL; + ALOGD("%s: exit: status(%d)", __func__, ret); + + return ret; +} + +/* must be called with out->lock locked */ +static int send_offload_cmd_l(struct stream_out* out, int command) +{ + struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd)); + + ALOGVV("%s %d", __func__, command); + + cmd->cmd = command; + list_add_tail(&out->offload_cmd_list, &cmd->node); + pthread_cond_signal(&out->offload_cond); + return 0; +} + +/* must be called iwth out->lock locked */ +static void stop_compressed_output_l(struct stream_out *out) +{ + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + out->send_new_metadata = 1; + if (out->compr != NULL) { + compress_stop(out->compr); + while (out->offload_thread_blocked) { + pthread_cond_wait(&out->cond, &out->lock); + } + } +} + +static void *offload_thread_loop(void *context) +{ + struct stream_out *out = (struct stream_out *) context; + struct listnode *item; + + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); + set_sched_policy(0, SP_FOREGROUND); + prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0); + + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + for (;;) { + struct offload_cmd *cmd = NULL; + stream_callback_event_t event; + bool send_callback = false; + + ALOGVV("%s offload_cmd_list %d out->offload_state %d", + __func__, list_empty(&out->offload_cmd_list), + out->offload_state); + if (list_empty(&out->offload_cmd_list)) { + ALOGV("%s SLEEPING", __func__); + pthread_cond_wait(&out->offload_cond, &out->lock); + ALOGV("%s RUNNING", __func__); + continue; + } + + item = list_head(&out->offload_cmd_list); + cmd = node_to_item(item, struct offload_cmd, node); + list_remove(item); + + ALOGVV("%s STATE %d CMD %d out->compr %p", + __func__, out->offload_state, cmd->cmd, out->compr); + + if (cmd->cmd == OFFLOAD_CMD_EXIT) { + free(cmd); + break; + } + + if (out->compr == NULL) { + ALOGE("%s: Compress handle is NULL", __func__); + pthread_cond_signal(&out->cond); + continue; + } + out->offload_thread_blocked = true; + pthread_mutex_unlock(&out->lock); + send_callback = false; + switch(cmd->cmd) { + case OFFLOAD_CMD_WAIT_FOR_BUFFER: + compress_wait(out->compr, -1); + send_callback = true; + event = STREAM_CBK_EVENT_WRITE_READY; + break; + case OFFLOAD_CMD_PARTIAL_DRAIN: + compress_next_track(out->compr); + compress_partial_drain(out->compr); + send_callback = true; + event = STREAM_CBK_EVENT_DRAIN_READY; + break; + case OFFLOAD_CMD_DRAIN: + compress_drain(out->compr); + send_callback = true; + event = STREAM_CBK_EVENT_DRAIN_READY; + break; + default: + ALOGE("%s unknown command received: %d", __func__, cmd->cmd); + break; + } + pthread_mutex_lock(&out->lock); + out->offload_thread_blocked = false; + pthread_cond_signal(&out->cond); + if (send_callback) { + out->offload_callback(event, NULL, out->offload_cookie); + } + free(cmd); + } + + pthread_cond_signal(&out->cond); + while (!list_empty(&out->offload_cmd_list)) { + item = list_head(&out->offload_cmd_list); + list_remove(item); + free(node_to_item(item, struct offload_cmd, node)); + } + pthread_mutex_unlock(&out->lock); + + return NULL; +} + +static int create_offload_callback_thread(struct stream_out *out) +{ + pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL); + list_init(&out->offload_cmd_list); + pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL, + offload_thread_loop, out); + return 0; +} + +static int destroy_offload_callback_thread(struct stream_out *out) +{ + pthread_mutex_lock(&out->lock); + stop_compressed_output_l(out); + send_offload_cmd_l(out, OFFLOAD_CMD_EXIT); + + pthread_mutex_unlock(&out->lock); + pthread_join(out->offload_thread, (void **) NULL); + pthread_cond_destroy(&out->offload_cond); + + return 0; +} + +static bool allow_hdmi_channel_config(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool ret = true; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + /* + * If voice call is already existing, do not proceed further to avoid + * disabling/enabling both RX and TX devices, CSD calls, etc. + * Once the voice call done, the HDMI channels can be configured to + * max channels of remaining use cases. + */ + if (usecase->id == USECASE_VOICE_CALL) { + ALOGD("%s: voice call is active, no change in HDMI channels", + __func__); + ret = false; + break; + } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) { + ALOGD("%s: multi channel playback is active, " + "no change in HDMI channels", __func__); + ret = false; + break; + } + } + } + return ret; +} + +static int check_and_set_hdmi_channels(struct audio_device *adev, + unsigned int channels) +{ + struct listnode *node; + struct audio_usecase *usecase; + + /* Check if change in HDMI channel config is allowed */ + if (!allow_hdmi_channel_config(adev)) + return 0; + + if (channels == adev->cur_hdmi_channels) { + ALOGD("%s: Requested channels are same as current", __func__); + return 0; + } + + platform_set_hdmi_channels(adev->platform, channels); + adev->cur_hdmi_channels = channels; + + /* + * Deroute all the playback streams routed to HDMI so that + * the back end is deactivated. Note that backend will not + * be deactivated if any one stream is connected to it. + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + disable_audio_route(adev, usecase, true); + } + } + + /* + * Enable all the streams disabled above. Now the HDMI backend + * will be activated with new channel configuration + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + enable_audio_route(adev, usecase, true); + } + } + + return 0; +} + +static int stop_output_stream(struct stream_out *out) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = out->dev; + + ALOGV("%s: enter: usecase(%d: %s)", __func__, + out->usecase, use_case_table[out->usecase]); + uc_info = get_usecase_from_list(adev, out->usecase); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, out->usecase); + return -EINVAL; + } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD && + adev->visualizer_stop_output != NULL) + adev->visualizer_stop_output(out->handle); + + /* 1. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 2. Disable the rx device */ + disable_snd_device(adev, uc_info->out_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + + /* Must be called after removing the usecase from list */ + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int start_output_stream(struct stream_out *out) +{ + int ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = out->dev; + + ALOGV("%s: enter: usecase(%d: %s) devices(%#x)", + __func__, out->usecase, use_case_table[out->usecase], out->devices); + out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); + if (out->pcm_device_id < 0) { + ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", + __func__, out->pcm_device_id, out->usecase); + ret = -EINVAL; + goto error_config; + } + + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = out->usecase; + uc_info->type = PCM_PLAYBACK; + uc_info->stream.out = out; + uc_info->devices = out->devices; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + /* This must be called before adding this usecase to the list */ + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + check_and_set_hdmi_channels(adev, out->config.channels); + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, out->usecase); + + ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", + __func__, 0, out->pcm_device_id); + if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { + out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, + PCM_OUT | PCM_MONOTONIC, &out->config); + if (out->pcm && !pcm_is_ready(out->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); + pcm_close(out->pcm); + out->pcm = NULL; + ret = -EIO; + goto error_open; + } + } else { + out->pcm = NULL; + out->compr = compress_open(SOUND_CARD, out->pcm_device_id, + COMPRESS_IN, &out->compr_config); + if (out->compr && !is_compress_ready(out->compr)) { + ALOGE("%s: %s", __func__, compress_get_error(out->compr)); + compress_close(out->compr); + out->compr = NULL; + ret = -EIO; + goto error_open; + } + if (out->offload_callback) + compress_nonblock(out->compr, out->non_blocking); + + if (adev->visualizer_start_output != NULL) + adev->visualizer_start_output(out->handle); + } + ALOGV("%s: exit", __func__); + return 0; +error_open: + stop_output_stream(out); +error_config: + return ret; +} + +static int check_input_parameters(uint32_t sample_rate, + audio_format_t format, + int channel_count) +{ + int ret = 0; + + if ((format != AUDIO_FORMAT_PCM_16_BIT)) ret = -EINVAL; + + switch (channel_count) { + case 1: + case 2: + case 6: + break; + default: + ret = -EINVAL; + } + + switch (sample_rate) { + case 8000: + case 11025: + case 12000: + case 16000: + case 22050: + case 24000: + case 32000: + case 44100: + case 48000: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static size_t get_input_buffer_size(uint32_t sample_rate, + audio_format_t format, + int channel_count) +{ + size_t size = 0; + + if (check_input_parameters(sample_rate, format, channel_count) != 0) + return 0; + + size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000; + /* ToDo: should use frame_size computed based on the format and + channel_count here. */ + size *= sizeof(short) * channel_count; + + /* make sure the size is multiple of 64 */ + size += 0x3f; + size &= ~0x3f; + + return size; +} + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->sample_rate; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return -ENOSYS; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + return out->compr_config.fragment_size; + + return out->config.period_size * audio_stream_frame_size(stream); +} + +static uint32_t out_get_channels(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->channel_mask; +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->format; +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + return -ENOSYS; +} + +static int out_standby(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + + ALOGV("%s: enter: usecase(%d: %s)", __func__, + out->usecase, use_case_table[out->usecase]); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + /* Ignore standby in case of voip call because the voip output + * stream is closed in adev_close_output_stream() + */ + ALOGV("%s: Ignore Standby in VOIP call", __func__); + return 0; + } + + pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->lock); + if (!out->standby) { + out->standby = true; + if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->pcm) { + pcm_close(out->pcm); + out->pcm = NULL; + } + } else { + stop_compressed_output_l(out); + out->gapless_mdata.encoder_delay = 0; + out->gapless_mdata.encoder_padding = 0; + if (out->compr != NULL) { + compress_close(out->compr); + out->compr = NULL; + } + } + stop_output_stream(out); + } + pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&out->lock); + ALOGV("%s: exit", __func__); + return 0; +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms) +{ + int ret = 0; + char value[32]; + struct compr_gapless_mdata tmp_mdata; + + if (!out || !parms) { + return -EINVAL; + } + + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value)); + if (ret >= 0) { + tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? + } else { + return -EINVAL; + } + + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); + if (ret >= 0) { + tmp_mdata.encoder_padding = atoi(value); + } else { + return -EINVAL; + } + + out->gapless_mdata = tmp_mdata; + out->send_new_metadata = 1; + ALOGV("%s new encoder delay %u and padding %u", __func__, + out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); + + return 0; +} + + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + struct audio_usecase *usecase; + struct listnode *node; + struct str_parms *parms; + char value[32]; + int ret, val = 0; + bool select_new_device = false; + + ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", + __func__, out->usecase, use_case_table[out->usecase], kvpairs); + parms = str_parms_create_str(kvpairs); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->lock); + + /* + * When HDMI cable is unplugged the music playback is paused and + * the policy manager sends routing=0. But the audioflinger + * continues to write data until standby time (3sec). + * As the HDMI core is turned off, the write gets blocked. + * Avoid this by routing audio to speaker until standby. + */ + if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL && + val == AUDIO_DEVICE_NONE) { + val = AUDIO_DEVICE_OUT_SPEAKER; + } + + /* + * select_devices() call below switches all the usecases on the same + * backend to the new device. Refer to check_usecases_codec_backend() in + * the select_devices(). But how do we undo this? + * + * For example, music playback is active on headset (deep-buffer usecase) + * and if we go to ringtones and select a ringtone, low-latency usecase + * will be started on headset+speaker. As we can't enable headset+speaker + * and headset devices at the same time, select_devices() switches the music + * playback to headset+speaker while starting low-lateny usecase for ringtone. + * So when the ringtone playback is completed, how do we undo the same? + * + * We are relying on the out_set_parameters() call on deep-buffer output, + * once the ringtone playback is ended. + * NOTE: We should not check if the current devices are same as new devices. + * Because select_devices() must be called to switch back the music + * playback to headset. + */ + if (val != 0) { + out->devices = val; + + if (!out->standby) + select_devices(adev, out->usecase); + } + + pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&out->lock); + } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + parse_compress_metadata(out, parms); + } + + str_parms_destroy(parms); + ALOGV("%s: exit: code(%d)", __func__, ret); + return ret; +} + +static char* out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + struct stream_out *out = (struct stream_out *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + size_t i, j; + int ret; + bool first = true; + ALOGV("%s: enter: keys - %s", __func__, keys); + ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value)); + if (ret >= 0) { + value[0] = '\0'; + i = 0; + while (out->supported_channel_masks[i] != 0) { + for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) { + if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) { + if (!first) { + strlcat(value, "|", sizeof(value)); + } + strlcat(value, out_channels_name_to_enum_table[j].name, sizeof(value)); + first = false; + break; + } + } + i++; + } + str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); + str = str_parms_to_str(reply); + } + str_parms_destroy(query); + str_parms_destroy(reply); + ALOGV("%s: exit: returns - %s", __func__, str); + return str; +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; + + return (out->config.period_count * out->config.period_size * 1000) / + (out->config.rate); +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + struct stream_out *out = (struct stream_out *)stream; + int volume[2]; + + if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) { + /* only take left channel into account: the API is for stereo anyway */ + out->muted = (left == 0.0f); + return 0; + } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + const char *mixer_ctl_name = "Compress Playback Volume"; + struct audio_device *adev = out->dev; + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX); + volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX); + mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0])); + return 0; + } + + return -ENOSYS; +} + +static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, + size_t bytes) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + ssize_t ret = 0; + + pthread_mutex_lock(&out->lock); + if (out->standby) { + out->standby = false; + pthread_mutex_lock(&adev->lock); + ret = start_output_stream(out); + pthread_mutex_unlock(&adev->lock); + /* ToDo: If use case is compress offload should return 0 */ + if (ret != 0) { + out->standby = true; + goto exit; + } + } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); + if (out->send_new_metadata) { + ALOGVV("send new gapless metadata"); + compress_set_gapless_metadata(out->compr, &out->gapless_mdata); + out->send_new_metadata = 0; + } + + ret = compress_write(out->compr, buffer, bytes); + ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); + if (ret >= 0 && ret < (ssize_t)bytes) { + send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); + } + if (!out->playback_started) { + compress_start(out->compr); + out->playback_started = 1; + out->offload_state = OFFLOAD_STATE_PLAYING; + } + pthread_mutex_unlock(&out->lock); + return ret; + } else { + if (out->pcm) { + if (out->muted) + memset((void *)buffer, 0, bytes); + ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); + ret = pcm_write(out->pcm, (void *)buffer, bytes); + if (ret == 0) + out->written += bytes / (out->config.channels * sizeof(short)); + } + } + +exit: + pthread_mutex_unlock(&out->lock); + + if (ret != 0) { + if (out->pcm) + ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); + out_standby(&out->stream.common); + usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / + out_get_sample_rate(&out->stream.common)); + } + return bytes; +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + struct stream_out *out = (struct stream_out *)stream; + *dsp_frames = 0; + if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { + pthread_mutex_lock(&out->lock); + if (out->compr != NULL) { + compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %d sample_rate %d", + __func__, *dsp_frames, out->sample_rate); + } + pthread_mutex_unlock(&out->lock); + return 0; + } else + return -EINVAL; +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + return -EINVAL; +} + +static int out_get_presentation_position(const struct audio_stream_out *stream, + uint64_t *frames, struct timespec *timestamp) +{ + struct stream_out *out = (struct stream_out *)stream; + int ret = -1; + unsigned long dsp_frames; + + pthread_mutex_lock(&out->lock); + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->compr != NULL) { + compress_get_tstamp(out->compr, &dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %ld sample_rate %d", + __func__, dsp_frames, out->sample_rate); + *frames = dsp_frames; + ret = 0; + /* this is the best we can do */ + clock_gettime(CLOCK_MONOTONIC, timestamp); + } + } else { + if (out->pcm) { + size_t avail; + if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { + size_t kernel_buffer_size = out->config.period_size * out->config.period_count; + int64_t signed_frames = out->written - kernel_buffer_size + avail; + // This adjustment accounts for buffering after app processor. + // It is based on estimated DSP latency per use case, rather than exact. + signed_frames -= + (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL); + + // It would be unusual for this value to be negative, but check just in case ... + if (signed_frames >= 0) { + *frames = signed_frames; + ret = 0; + } + } + } + } + + pthread_mutex_unlock(&out->lock); + + return ret; +} + +static int out_set_callback(struct audio_stream_out *stream, + stream_callback_t callback, void *cookie) +{ + struct stream_out *out = (struct stream_out *)stream; + + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + out->offload_callback = callback; + out->offload_cookie = cookie; + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int out_pause(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) { + status = compress_pause(out->compr); + out->offload_state = OFFLOAD_STATE_PAUSED; + } + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_resume(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + status = 0; + pthread_mutex_lock(&out->lock); + if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) { + status = compress_resume(out->compr); + out->offload_state = OFFLOAD_STATE_PLAYING; + } + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type ) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + if (type == AUDIO_DRAIN_EARLY_NOTIFY) + status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN); + else + status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN); + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_flush(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + stop_compressed_output_l(out); + pthread_mutex_unlock(&out->lock); + return 0; + } + return -ENOSYS; +} + +/** audio_stream_in implementation **/ +static uint32_t in_get_sample_rate(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + return in->config.rate; +} + +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return -ENOSYS; +} + +static size_t in_get_buffer_size(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + return in->config.period_size * audio_stream_frame_size(stream); +} + +static uint32_t in_get_channels(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + return in->channel_mask; +} + +static audio_format_t in_get_format(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + return in->format; +} + +static int in_set_format(struct audio_stream *stream, audio_format_t format) +{ + return -ENOSYS; +} + +static int in_standby(struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + int status = 0; + ALOGV("%s: enter", __func__); + + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + /* Ignore standby in case of voip call because the voip input + * stream is closed in adev_close_input_stream() + */ + ALOGV("%s: Ignore Standby in VOIP call", __func__); + return status; + } + + pthread_mutex_lock(&in->lock); + if (!in->standby) { + in->standby = true; + if (in->pcm) { + pcm_close(in->pcm); + in->pcm = NULL; + } + pthread_mutex_lock(&adev->lock); + status = stop_input_stream(in); + pthread_mutex_unlock(&adev->lock); + } + pthread_mutex_unlock(&in->lock); + ALOGV("%s: exit: status(%d)", __func__, status); + return status; +} + +static int in_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + struct str_parms *parms; + char *str; + char value[32]; + int ret, val = 0; + + ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs); + parms = str_parms_create_str(kvpairs); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); + + pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&adev->lock); + if (ret >= 0) { + val = atoi(value); + /* no audio source uses val == 0 */ + if ((in->source != val) && (val != 0)) { + in->source = val; + } + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + if ((in->device != val) && (val != 0)) { + in->device = val; + /* If recording is in progress, change the tx device to new device */ + if (!in->standby) + ret = select_devices(adev, in->usecase); + } + } + + pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&in->lock); + + str_parms_destroy(parms); + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +static char* in_get_parameters(const struct audio_stream *stream, + const char *keys) +{ + struct stream_in *in = (struct stream_in *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + ALOGV("%s: enter: keys - %s", __func__, keys); + + str = str_parms_to_str(reply); + str_parms_destroy(query); + str_parms_destroy(reply); + + ALOGV("%s: exit: returns - %s", __func__, str); + return str; +} + +static int in_set_gain(struct audio_stream_in *stream, float gain) +{ + return 0; +} + +static ssize_t in_read(struct audio_stream_in *stream, void *buffer, + size_t bytes) +{ + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + int i, ret = -1; + + pthread_mutex_lock(&in->lock); + if (in->standby) { + pthread_mutex_lock(&adev->lock); + ret = start_input_stream(in); + pthread_mutex_unlock(&adev->lock); + if (ret != 0) { + goto exit; + } + in->standby = 0; + } + + if (in->pcm) { + ret = pcm_read(in->pcm, buffer, bytes); + } + +exit: + pthread_mutex_unlock(&in->lock); + + if (ret != 0) { + in_standby(&in->stream.common); + ALOGV("%s: read failed - sleeping for buffer duration", __func__); + usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) / + in_get_sample_rate(&in->stream.common)); + } + return bytes; +} + +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) +{ + return 0; +} + +static int add_remove_audio_effect(const struct audio_stream *stream, + effect_handle_t effect, + bool enable) +{ + struct stream_in *in = (struct stream_in *)stream; + int status = 0; + effect_descriptor_t desc; + + status = (*effect)->get_descriptor(effect, &desc); + if (status != 0) + return status; + + pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&in->dev->lock); + if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) && + in->enable_aec != enable && + (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) { + in->enable_aec = enable; + if (!in->standby) + select_devices(in->dev, in->usecase); + } + if (in->enable_ns != enable && + (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) { + in->enable_ns = enable; + if (!in->standby) + select_devices(in->dev, in->usecase); + } + pthread_mutex_unlock(&in->dev->lock); + pthread_mutex_unlock(&in->lock); + + return 0; +} + +static int in_add_audio_effect(const struct audio_stream *stream, + effect_handle_t effect) +{ + ALOGV("%s: effect %p", __func__, effect); + return add_remove_audio_effect(stream, effect, true); +} + +static int in_remove_audio_effect(const struct audio_stream *stream, + effect_handle_t effect) +{ + ALOGV("%s: effect %p", __func__, effect); + return add_remove_audio_effect(stream, effect, false); +} + +static int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_out *out; + int i, ret; + + ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", + __func__, config->sample_rate, config->channel_mask, devices, flags); + *stream_out = NULL; + out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + + if (devices == AUDIO_DEVICE_NONE) + devices = AUDIO_DEVICE_OUT_SPEAKER; + + out->flags = flags; + out->devices = devices; + out->dev = adev; + out->format = config->format; + out->sample_rate = config->sample_rate; + out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; + out->handle = handle; + + /* Init use case and pcm_config */ + if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT && + out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + pthread_mutex_lock(&adev->lock); + ret = read_hdmi_channel_masks(out); + pthread_mutex_unlock(&adev->lock); + if (ret != 0) + goto error_open; + + if (config->sample_rate == 0) + config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; + if (config->channel_mask == 0) + config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1; + + out->channel_mask = config->channel_mask; + out->sample_rate = config->sample_rate; + out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH; + out->config = pcm_config_hdmi_multi; + out->config.rate = config->sample_rate; + out->config.channels = popcount(out->channel_mask); + out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); + } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || + config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { + ALOGE("%s: Unsupported Offload information", __func__); + ret = -EINVAL; + goto error_open; + } + if (!is_supported_format(config->offload_info.format)) { + ALOGE("%s: Unsupported audio format", __func__); + ret = -EINVAL; + goto error_open; + } + + out->compr_config.codec = (struct snd_codec *) + calloc(1, sizeof(struct snd_codec)); + + out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; + if (config->offload_info.channel_mask) + out->channel_mask = config->offload_info.channel_mask; + else if (config->channel_mask) + out->channel_mask = config->channel_mask; + out->format = config->offload_info.format; + out->sample_rate = config->offload_info.sample_rate; + + out->stream.set_callback = out_set_callback; + out->stream.pause = out_pause; + out->stream.resume = out_resume; + out->stream.drain = out_drain; + out->stream.flush = out_flush; + + out->compr_config.codec->id = + get_snd_codec_id(config->offload_info.format); + out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; + out->compr_config.codec->sample_rate = + compress_get_alsa_rate(config->offload_info.sample_rate); + out->compr_config.codec->bit_rate = + config->offload_info.bit_rate; + out->compr_config.codec->ch_in = + popcount(config->channel_mask); + out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + + if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) + out->non_blocking = 1; + + out->send_new_metadata = 1; + create_offload_callback_thread(out); + ALOGV("%s: offloaded output offload_info version %04x bit rate %d", + __func__, config->offload_info.version, + config->offload_info.bit_rate); + } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { + out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; + out->config = pcm_config_low_latency; + out->sample_rate = out->config.rate; + } else { + out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; + out->config = pcm_config_deep_buffer; + out->sample_rate = out->config.rate; + } + + if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { + if(adev->primary_output == NULL) + adev->primary_output = out; + else { + ALOGE("%s: Primary output is already opened", __func__); + ret = -EEXIST; + goto error_open; + } + } + + /* Check if this usecase is already existing */ + pthread_mutex_lock(&adev->lock); + if (get_usecase_from_list(adev, out->usecase) != NULL) { + ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase); + pthread_mutex_unlock(&adev->lock); + ret = -EEXIST; + goto error_open; + } + pthread_mutex_unlock(&adev->lock); + + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + out->stream.get_presentation_position = out_get_presentation_position; + + out->standby = 1; + /* out->muted = false; by calloc() */ + /* out->written = 0; by calloc() */ + + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + + config->format = out->stream.common.get_format(&out->stream.common); + config->channel_mask = out->stream.common.get_channels(&out->stream.common); + config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); + + *stream_out = &out->stream; + ALOGV("%s: exit", __func__); + return 0; + +error_open: + free(out); + *stream_out = NULL; + ALOGD("%s: exit: ret %d", __func__, ret); + return ret; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + int ret = 0; + + ALOGV("%s: enter", __func__); + out_standby(&stream->common); + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + destroy_offload_callback_thread(out); + + if (out->compr_config.codec != NULL) + free(out->compr_config.codec); + } + pthread_cond_destroy(&out->cond); + pthread_mutex_destroy(&out->lock); + free(stream); + ALOGV("%s: exit", __func__); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct str_parms *parms; + char *str; + char value[32]; + int val; + int ret; + + ALOGD("%s: enter: %s", __func__, kvpairs); + + pthread_mutex_lock(&adev->lock); + parms = str_parms_create_str(kvpairs); + + platform_set_parameters(adev->platform, parms); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); + if (ret >= 0) { + /* When set to false, HAL should disable EC and NS + * But it is currently not supported. + */ + if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) + adev->bluetooth_nrec = true; + else + adev->bluetooth_nrec = false; + } + + ret = str_parms_get_str(parms, "screen_state", value, sizeof(value)); + if (ret >= 0) { + if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) + adev->screen_off = false; + else + adev->screen_off = true; + } + + ret = str_parms_get_int(parms, "rotation", &val); + if (ret >= 0) { + bool reverse_speakers = false; + switch(val) { + // FIXME: note that the code below assumes that the speakers are in the correct placement + // relative to the user when the device is rotated 90deg from its default rotation. This + // assumption is device-specific, not platform-specific like this code. + case 270: + reverse_speakers = true; + break; + case 0: + case 90: + case 180: + break; + default: + ALOGE("%s: unexpected rotation of %d", __func__, val); + } + if (adev->speaker_lr_swap != reverse_speakers) { + adev->speaker_lr_swap = reverse_speakers; + // only update the selected device if there is active pcm playback + struct audio_usecase *usecase; + struct listnode *node; + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK) { + select_devices(adev, usecase->id); + break; + } + } + } + } + + str_parms_destroy(parms); + + pthread_mutex_unlock(&adev->lock); + ALOGV("%s: exit with code(%d)", __func__, ret); + return ret; +} + +static char* adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct str_parms *reply = str_parms_create(); + struct str_parms *query = str_parms_create_str(keys); + char *str; + + pthread_mutex_lock(&adev->lock); + + platform_get_parameters(adev->platform, query, reply); + str = str_parms_to_str(reply); + str_parms_destroy(query); + str_parms_destroy(reply); + + pthread_mutex_unlock(&adev->lock); + ALOGV("%s: exit: returns - %s", __func__, str); + return str; +} + +static int adev_init_check(const struct audio_hw_device *dev) +{ + return 0; +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + int ret = 0; + return ret; +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_get_master_volume(struct audio_hw_device *dev, + float *volume) +{ + return -ENOSYS; +} + +static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) +{ + return -ENOSYS; +} + +static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) +{ + return -ENOSYS; +} + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) +{ + struct audio_device *adev = (struct audio_device *)dev; + pthread_mutex_lock(&adev->lock); + if (adev->mode != mode) { + ALOGD("%s mode %d\n", __func__, mode); + adev->mode = mode; + } + pthread_mutex_unlock(&adev->lock); + return 0; +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + int ret = 0; + + return ret; +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + return 0; +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) +{ + int channel_count = popcount(config->channel_mask); + + return get_input_buffer_size(config->sample_rate, config->format, channel_count); +} + +static int adev_open_input_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + struct audio_stream_in **stream_in) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_in *in; + int ret = 0, buffer_size, frame_size; + int channel_count = popcount(config->channel_mask); + + ALOGV("%s: enter", __func__); + *stream_in = NULL; + if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) + return -EINVAL; + + in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); + + in->stream.common.get_sample_rate = in_get_sample_rate; + in->stream.common.set_sample_rate = in_set_sample_rate; + in->stream.common.get_buffer_size = in_get_buffer_size; + in->stream.common.get_channels = in_get_channels; + in->stream.common.get_format = in_get_format; + in->stream.common.set_format = in_set_format; + in->stream.common.standby = in_standby; + in->stream.common.dump = in_dump; + in->stream.common.set_parameters = in_set_parameters; + in->stream.common.get_parameters = in_get_parameters; + in->stream.common.add_audio_effect = in_add_audio_effect; + in->stream.common.remove_audio_effect = in_remove_audio_effect; + in->stream.set_gain = in_set_gain; + in->stream.read = in_read; + in->stream.get_input_frames_lost = in_get_input_frames_lost; + + in->device = devices; + in->source = AUDIO_SOURCE_DEFAULT; + in->dev = adev; + in->standby = 1; + in->channel_mask = config->channel_mask; + + /* Update config params with the requested sample rate and channels */ + in->usecase = USECASE_AUDIO_RECORD; + in->config = pcm_config_audio_capture; + in->config.rate = config->sample_rate; + in->format = config->format; + + { + in->config.channels = channel_count; + frame_size = audio_stream_frame_size((struct audio_stream *)in); + buffer_size = get_input_buffer_size(config->sample_rate, + config->format, + channel_count); + in->config.period_size = buffer_size / frame_size; + } + + *stream_in = &in->stream; + ALOGV("%s: exit", __func__); + return ret; + +err_open: + free(in); + *stream_in = NULL; + return ret; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ + int ret; + struct stream_in *in = (struct stream_in *)stream; + ALOGV("%s", __func__); + + in_standby(&stream->common); + + free(stream); + + return; +} + +static int adev_dump(const audio_hw_device_t *device, int fd) +{ + return 0; +} + +static int adev_close(hw_device_t *device) +{ + struct audio_device *adev = (struct audio_device *)device; + + if (!adev) + return 0; + + pthread_mutex_lock(&adev_init_lock); + + if ((--audio_device_ref_count) == 0) { + audio_route_free(adev->audio_route); + free(adev->snd_dev_ref_cnt); + platform_deinit(adev->platform); + free(device); + adev = NULL; + } + pthread_mutex_unlock(&adev_init_lock); + return 0; +} + +static int adev_open(const hw_module_t *module, const char *name, + hw_device_t **device) +{ + int i, ret; + + ALOGD("%s: enter", __func__); + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL; + + pthread_mutex_lock(&adev_init_lock); + if (audio_device_ref_count != 0){ + *device = &adev->device.common; + audio_device_ref_count++; + ALOGD("%s: returning existing instance of adev", __func__); + ALOGD("%s: exit", __func__); + pthread_mutex_unlock(&adev_init_lock); + return 0; + } + + adev = calloc(1, sizeof(struct audio_device)); + + adev->device.common.tag = HARDWARE_DEVICE_TAG; + adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; + adev->device.common.module = (struct hw_module_t *)module; + adev->device.common.close = adev_close; + + adev->device.init_check = adev_init_check; + adev->device.set_voice_volume = adev_set_voice_volume; + adev->device.set_master_volume = adev_set_master_volume; + adev->device.get_master_volume = adev_get_master_volume; + adev->device.set_master_mute = adev_set_master_mute; + adev->device.get_master_mute = adev_get_master_mute; + adev->device.set_mode = adev_set_mode; + adev->device.set_mic_mute = adev_set_mic_mute; + adev->device.get_mic_mute = adev_get_mic_mute; + adev->device.set_parameters = adev_set_parameters; + adev->device.get_parameters = adev_get_parameters; + adev->device.get_input_buffer_size = adev_get_input_buffer_size; + adev->device.open_output_stream = adev_open_output_stream; + adev->device.close_output_stream = adev_close_output_stream; + adev->device.open_input_stream = adev_open_input_stream; + adev->device.close_input_stream = adev_close_input_stream; + adev->device.dump = adev_dump; + + /* Set the default route before the PCM stream is opened */ + adev->mode = AUDIO_MODE_NORMAL; + adev->active_input = NULL; + adev->primary_output = NULL; + adev->out_device = AUDIO_DEVICE_NONE; + adev->bluetooth_nrec = true; + adev->acdb_settings = TTY_MODE_OFF; + /* adev->cur_hdmi_channels = 0; by calloc() */ + adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); + list_init(&adev->usecase_list); + + /* Loads platform specific libraries dynamically */ + adev->platform = platform_init(adev); + if (!adev->platform) { + free(adev->snd_dev_ref_cnt); + free(adev); + ALOGE("%s: Failed to init platform data, aborting.", __func__); + *device = NULL; + return -EINVAL; + } + + if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) { + adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW); + if (adev->visualizer_lib == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH); + adev->visualizer_start_output = + (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib, + "visualizer_hal_start_output"); + adev->visualizer_stop_output = + (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib, + "visualizer_hal_stop_output"); + } + } + *device = &adev->device.common; + + audio_device_ref_count++; + pthread_mutex_unlock(&adev_init_lock); + + ALOGV("%s: exit", __func__); + return 0; +} + +static struct hw_module_methods_t hal_module_methods = { + .open = adev_open, +}; + +struct audio_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = AUDIO_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = AUDIO_HARDWARE_MODULE_ID, + .name = "MPQ Audio HAL", + .author = "The Linux Foundation", + .methods = &hal_module_methods, + }, +}; diff --git a/hal_mpq/audio_hw.h b/hal_mpq/audio_hw.h new file mode 100644 index 000000000..262fda84e --- /dev/null +++ b/hal_mpq/audio_hw.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef QCOM_AUDIO_HW_H +#define QCOM_AUDIO_HW_H + +#include +#include +#include +#include + +#include + +#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so" + +/* Flags used to initialize acdb_settings variable that goes to ACDB library */ +#define DMIC_FLAG 0x00000002 +#define QMIC_FLAG 0x00000004 +#define TTY_MODE_OFF 0x00000010 +#define TTY_MODE_FULL 0x00000020 +#define TTY_MODE_VCO 0x00000040 +#define TTY_MODE_HCO 0x00000080 +#define TTY_MODE_CLEAR 0xFFFFFF0F + +#define ACDB_DEV_TYPE_OUT 1 +#define ACDB_DEV_TYPE_IN 2 + +#define MAX_SUPPORTED_CHANNEL_MASKS 2 +#define DEFAULT_HDMI_OUT_CHANNELS 2 + +typedef int snd_device_t; + +/* These are the supported use cases by the hardware. + * Each usecase is mapped to a specific PCM device. + * Refer to pcm_device_table[]. + */ +typedef enum { + USECASE_INVALID = -1, + /* Playback usecases */ + USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0, + USECASE_AUDIO_PLAYBACK_LOW_LATENCY, + USECASE_AUDIO_PLAYBACK_MULTI_CH, + USECASE_AUDIO_PLAYBACK_OFFLOAD, + + /* FM usecase */ + USECASE_AUDIO_PLAYBACK_FM, + + /* Capture usecases */ + USECASE_AUDIO_RECORD, + USECASE_AUDIO_RECORD_COMPRESS, + USECASE_AUDIO_RECORD_LOW_LATENCY, + USECASE_AUDIO_RECORD_FM_VIRTUAL, + + /* Voice usecase */ + USECASE_VOICE_CALL, + + /* Voice extension usecases */ + USECASE_VOICE2_CALL, + USECASE_VOLTE_CALL, + USECASE_QCHAT_CALL, + USECASE_COMPRESS_VOIP_CALL, + + USECASE_INCALL_REC_UPLINK, + USECASE_INCALL_REC_DOWNLINK, + USECASE_INCALL_REC_UPLINK_AND_DOWNLINK, + + USECASE_INCALL_MUSIC_UPLINK, + USECASE_INCALL_MUSIC_UPLINK2, + + USECASE_AUDIO_SPKR_CALIB_RX, + USECASE_AUDIO_SPKR_CALIB_TX, + AUDIO_USECASE_MAX +} audio_usecase_t; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +/* + * tinyAlsa library interprets period size as number of frames + * one frame = channel_count * sizeof (pcm sample) + * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes + * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes + * We should take care of returning proper size when AudioFlinger queries for + * the buffer size of an input/output stream + */ + +enum { + OFFLOAD_CMD_EXIT, /* exit compress offload thread loop*/ + OFFLOAD_CMD_DRAIN, /* send a full drain request to DSP */ + OFFLOAD_CMD_PARTIAL_DRAIN, /* send a partial drain request to DSP */ + OFFLOAD_CMD_WAIT_FOR_BUFFER, /* wait for buffer released by DSP */ +}; + +enum { + OFFLOAD_STATE_IDLE, + OFFLOAD_STATE_PLAYING, + OFFLOAD_STATE_PAUSED, +}; + +struct offload_cmd { + struct listnode node; + int cmd; + int data[]; +}; + +struct stream_out { + struct audio_stream_out stream; + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + pthread_cond_t cond; + struct pcm_config config; + struct compr_config compr_config; + struct pcm *pcm; + struct compress *compr; + int standby; + int pcm_device_id; + unsigned int sample_rate; + audio_channel_mask_t channel_mask; + audio_format_t format; + audio_devices_t devices; + audio_output_flags_t flags; + audio_usecase_t usecase; + /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */ + audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1]; + bool muted; + uint64_t written; /* total frames written, not cleared when entering standby */ + audio_io_handle_t handle; + + int non_blocking; + int playback_started; + int offload_state; + pthread_cond_t offload_cond; + pthread_t offload_thread; + struct listnode offload_cmd_list; + bool offload_thread_blocked; + + stream_callback_t offload_callback; + void *offload_cookie; + struct compr_gapless_mdata gapless_mdata; + int send_new_metadata; + + struct audio_device *dev; +}; + +struct stream_in { + struct audio_stream_in stream; + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + struct pcm_config config; + struct pcm *pcm; + int standby; + int source; + int pcm_device_id; + int device; + audio_channel_mask_t channel_mask; + audio_usecase_t usecase; + bool enable_aec; + bool enable_ns; + audio_format_t format; + + struct audio_device *dev; +}; + +typedef enum { + PCM_PLAYBACK, + PCM_CAPTURE, + VOICE_CALL, + VOIP_CALL +} usecase_type_t; + +union stream_ptr { + struct stream_in *in; + struct stream_out *out; +}; + +struct audio_usecase { + struct listnode list; + audio_usecase_t id; + usecase_type_t type; + audio_devices_t devices; + snd_device_t out_snd_device; + snd_device_t in_snd_device; + union stream_ptr stream; +}; + +struct audio_device { + struct audio_hw_device device; + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + struct mixer *mixer; + audio_mode_t mode; + audio_devices_t out_device; + struct stream_in *active_input; + struct stream_out *primary_output; + bool bluetooth_nrec; + bool screen_off; + int *snd_dev_ref_cnt; + struct listnode usecase_list; + struct audio_route *audio_route; + int acdb_settings; + bool speaker_lr_swap; + unsigned int cur_hdmi_channels; + + void *platform; + + void *visualizer_lib; + int (*visualizer_start_output)(audio_io_handle_t); + int (*visualizer_stop_output)(audio_io_handle_t); +}; + +int select_devices(struct audio_device *adev, + audio_usecase_t uc_id); +int disable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer); +int disable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer); +int enable_snd_device(struct audio_device *adev, + snd_device_t snd_device, + bool update_mixer); +int enable_audio_route(struct audio_device *adev, + struct audio_usecase *usecase, + bool update_mixer); +struct audio_usecase *get_usecase_from_list(struct audio_device *adev, + audio_usecase_t uc_id); +/* + * NOTE: when multiple mutexes have to be acquired, always take the + * stream_in or stream_out mutex first, followed by the audio_device mutex. + */ + +#endif // QCOM_AUDIO_HW_H diff --git a/hal_mpq/mpq8092/hw_info.c b/hal_mpq/mpq8092/hw_info.c new file mode 100644 index 000000000..97b78045d --- /dev/null +++ b/hal_mpq/mpq8092/hw_info.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "hardware_info" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" + + +struct hardware_info { + char name[HW_INFO_ARRAY_MAX_SIZE]; + char type[HW_INFO_ARRAY_MAX_SIZE]; + /* variables for handling target variants */ + uint32_t num_snd_devices; + char dev_extn[HW_INFO_ARRAY_MAX_SIZE]; + snd_device_t *snd_devices; +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define LITERAL_TO_STRING(x) #x +#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\ + __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ + " ASSERT_FATAL(" #condition ") failed.") + +static const snd_device_t tabla_cdp_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, +}; + +static const snd_device_t taiko_fluid_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static const snd_device_t taiko_CDP_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_QUAD_MIC, +}; + +static const snd_device_t taiko_liquid_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_VOICE_DMIC, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC, + SND_DEVICE_IN_VOICE_REC_DMIC_STEREO, + SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_QUAD_MIC, + SND_DEVICE_IN_HANDSET_STEREO_DMIC, + SND_DEVICE_IN_SPEAKER_STEREO_DMIC, +}; + +static const snd_device_t taiko_DB_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_QUAD_MIC, +}; + +static const snd_device_t tapan_lite_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, +}; + +static const snd_device_t tapan_skuf_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + /*SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,*/ +}; + +static const snd_device_t tapan_lite_skuf_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, +}; + +static const snd_device_t helicon_skuab_variant_devices[] = { + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, +}; + +static void update_hardware_info_8092(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "mpq8092-tabla-cdp-snd-card")) { + strlcpy(hw_info->type, "cdp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "mpq8092", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8084 device", __func__); + } +} + +static void update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card")) { + strlcpy(hw_info->type, "mtp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "apq8084-taiko-cdp-snd-card")) { + strlcpy(hw_info->type, " cdp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices); + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) { + strlcpy(hw_info->type , " liquid", sizeof(hw_info->type)); + strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type)); + hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices); + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8084 device", __func__); + } +} + +static void update_hardware_info_8974(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "msm8974-taiko-mtp-snd-card")) { + strlcpy(hw_info->type, " mtp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8974-taiko-cdp-snd-card")) { + strlcpy(hw_info->type, " cdp", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices); + strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8974-taiko-fluid-snd-card")) { + strlcpy(hw_info->type, " fluid", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *) taiko_fluid_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_fluid_variant_devices); + strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8974-taiko-liquid-snd-card")) { + strlcpy(hw_info->type, " liquid", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices); + strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "apq8074-taiko-db-snd-card")) { + strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)taiko_DB_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(taiko_DB_variant_devices); + strlcpy(hw_info->dev_extn, "-DB", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8974 device", __func__); + } +} + +static void update_hardware_info_8610(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "msm8x10-snd-card")) { + strlcpy(hw_info->type, "", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8x10-skuab-snd-card")) { + strlcpy(hw_info->type, "skuab", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)helicon_skuab_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(helicon_skuab_variant_devices); + strlcpy(hw_info->dev_extn, "-skuab", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8x10-skuaa-snd-card")) { + strlcpy(hw_info->type, " skuaa", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8x10 device", __func__); + } +} + +static void update_hardware_info_8226(struct hardware_info *hw_info, const char *snd_card_name) +{ + if (!strcmp(snd_card_name, "msm8226-tapan-snd-card")) { + strlcpy(hw_info->type, "", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = NULL; + hw_info->num_snd_devices = 0; + strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8226-tapan9302-snd-card")) { + strlcpy(hw_info->type, "tapan_lite", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)tapan_lite_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_variant_devices); + strlcpy(hw_info->dev_extn, "-lite", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8226-tapan-skuf-snd-card")) { + strlcpy(hw_info->type, " skuf", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *) tapan_skuf_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(tapan_skuf_variant_devices); + strlcpy(hw_info->dev_extn, "-skuf", sizeof(hw_info->dev_extn)); + } else if (!strcmp(snd_card_name, "msm8226-tapan9302-skuf-snd-card")) { + strlcpy(hw_info->type, " tapan9302-skuf", sizeof(hw_info->type)); + strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); + hw_info->snd_devices = (snd_device_t *)tapan_lite_skuf_variant_devices; + hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_skuf_variant_devices); + strlcpy(hw_info->dev_extn, "-skuf-lite", sizeof(hw_info->dev_extn)); + } else { + ALOGW("%s: Not an 8x26 device", __func__); + } +} + +void *hw_info_init(const char *snd_card_name) +{ + struct hardware_info *hw_info; + + hw_info = malloc(sizeof(struct hardware_info)); + + if(strstr(snd_card_name, "mpq8092") || + strstr(snd_card_name, "mpq8092")) { + ALOGV("8092 - variant soundcard"); + update_hardware_info_8092(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "msm8974") || + strstr(snd_card_name, "apq8074")) { + ALOGV("8974 - variant soundcard"); + update_hardware_info_8974(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "msm8226")) { + ALOGV("8x26 - variant soundcard"); + update_hardware_info_8226(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "msm8x10")) { + ALOGV("8x10 - variant soundcard"); + update_hardware_info_8610(hw_info, snd_card_name); + } else if(strstr(snd_card_name, "apq8084")) { + ALOGV("8084 - variant soundcard"); + update_hardware_info_8084(hw_info, snd_card_name); + } else { + ALOGE("%s: Unupported target %s:",__func__, snd_card_name); + CHECK(0); + free(hw_info); + hw_info = NULL; + } + + return hw_info; +} + +void hw_info_deinit(void *hw_info) +{ + struct hardware_info *my_data = (struct hardware_info*) hw_info; + + if(!my_data) + free(my_data); +} + +void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, + char *device_name) +{ + struct hardware_info *my_data = (struct hardware_info*) hw_info; + uint32_t i = 0; + + snd_device_t *snd_devices = + (snd_device_t *) my_data->snd_devices; + + if(snd_devices != NULL) { + for (i = 0; i < my_data->num_snd_devices; i++) { + if (snd_device == (snd_device_t)snd_devices[i]) { + ALOGV("extract dev_extn device %d, extn = %s", + (snd_device_t)snd_devices[i], my_data->dev_extn); + CHECK(strlcat(device_name, my_data->dev_extn, + DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE); + break; + } + } + } + ALOGD("%s : device_name = %s", __func__,device_name); +} diff --git a/hal_mpq/mpq8092/platform.c b/hal_mpq/mpq8092/platform.c new file mode 100644 index 000000000..d7d67d593 --- /dev/null +++ b/hal_mpq/mpq8092/platform.c @@ -0,0 +1,1272 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "msm8974_platform" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include "platform.h" + +#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" +#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" +#define LIB_ACDB_LOADER "libacdbloader.so" +#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" + +/* + * This file will have a maximum of 38 bytes: + * + * 4 bytes: number of audio blocks + * 4 bytes: total length of Short Audio Descriptor (SAD) blocks + * Maximum 10 * 3 bytes: SAD blocks + */ +#define MAX_SAD_BLOCKS 10 +#define SAD_BLOCK_SIZE 3 + +/* EDID format ID for LPCM audio */ +#define EDID_FORMAT_LPCM 1 + +/* Retry for delay in FW loading*/ +#define RETRY_NUMBER 10 +#define RETRY_US 500000 + +#define SAMPLE_RATE_8KHZ 8000 +#define SAMPLE_RATE_16KHZ 16000 + +#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence" +#define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate" +#define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable" + +struct audio_block_header +{ + int reserved; + int length; +}; + +/* Audio calibration related functions */ +typedef void (*acdb_deallocate_t)(); +typedef int (*acdb_init_t)(); +typedef void (*acdb_send_audio_cal_t)(int, int); +typedef void (*acdb_send_voice_cal_t)(int, int); + +struct platform_data { + struct audio_device *adev; + bool fluence_in_spkr_mode; + bool fluence_in_voice_call; + bool fluence_in_voice_rec; + bool fluence_in_audio_rec; + int fluence_type; + int btsco_sample_rate; + bool slowtalk; + /* Audio calibration related functions */ + void *acdb_handle; + acdb_init_t acdb_init; + acdb_deallocate_t acdb_deallocate; + acdb_send_audio_cal_t acdb_send_audio_cal; + acdb_send_voice_cal_t acdb_send_voice_cal; + + void *hw_info; + struct csd_data *csd; +}; + +static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE, + DEEP_BUFFER_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, + LOWLATENCY_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE, + MULTIMEDIA2_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_OFFLOAD] = + {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE}, + [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, + [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE}, + [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, + LOWLATENCY_PCM_DEVICE}, + [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE, + MULTIMEDIA2_PCM_DEVICE}, + [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, + [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, + [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, + [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, + [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE}, + [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE}, + [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE, + INCALL_MUSIC_UPLINK_PCM_DEVICE}, + [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE, + INCALL_MUSIC_UPLINK2_PCM_DEVICE}, + [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1}, + [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE}, +}; + +/* Array to store sound devices */ +static const char * const device_table[SND_DEVICE_MAX] = { + [SND_DEVICE_NONE] = "none", + /* Playback sound devices */ + [SND_DEVICE_OUT_HANDSET] = "handset", + [SND_DEVICE_OUT_SPEAKER] = "speaker", + [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse", + [SND_DEVICE_OUT_HEADPHONES] = "headphones", + [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones", + [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset", + [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker", + [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones", + [SND_DEVICE_OUT_HDMI] = "hdmi", + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi", + [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset", + [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb", + [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", + [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", + [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy", + [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones", + [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones", + [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm", + [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones", + [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones", + [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones", + [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones", + [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones", + [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset", + [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected", + + /* Capture sound devices */ + [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", + [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic", + [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic", + [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic", + [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire", + [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire", + [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire", + [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire", + [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic", + [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire", + [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire", + [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire", + [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire", + [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic", + [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = "headset-mic", + [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", + [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", + [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic", + [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic", + [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb", + [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", + [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", + [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", + [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", + [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", + [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", + [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic", + [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef", + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence", + [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic", + [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm", + [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic", + [SND_DEVICE_IN_QUAD_MIC] = "quad-mic", + [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef", + [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef", + [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback", +}; + +/* ACDB IDs (audio DSP path configuration IDs) for each sound device */ +static const int acdb_device_table[SND_DEVICE_MAX] = { + [SND_DEVICE_NONE] = -1, + [SND_DEVICE_OUT_HANDSET] = 7, + [SND_DEVICE_OUT_SPEAKER] = 14, + [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14, + [SND_DEVICE_OUT_HEADPHONES] = 10, + [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10, + [SND_DEVICE_OUT_VOICE_HANDSET] = 7, + [SND_DEVICE_OUT_VOICE_SPEAKER] = 14, + [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10, + [SND_DEVICE_OUT_HDMI] = 18, + [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14, + [SND_DEVICE_OUT_BT_SCO] = 22, + [SND_DEVICE_OUT_BT_SCO_WB] = 39, + [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, + [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, + [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + [SND_DEVICE_OUT_AFE_PROXY] = 0, + [SND_DEVICE_OUT_USB_HEADSET] = 0, + [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14, + [SND_DEVICE_OUT_TRANSMISSION_FM] = 0, + [SND_DEVICE_OUT_ANC_HEADSET] = 26, + [SND_DEVICE_OUT_ANC_FB_HEADSET] = 27, + [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26, + [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27, + [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26, + [SND_DEVICE_OUT_ANC_HANDSET] = 103, + [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101, + + [SND_DEVICE_IN_HANDSET_MIC] = 4, + [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106, + [SND_DEVICE_IN_HANDSET_MIC_NS] = 107, + [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108, + [SND_DEVICE_IN_HANDSET_DMIC] = 41, + [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109, + [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110, + [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111, + [SND_DEVICE_IN_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112, + [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113, + [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114, + [SND_DEVICE_IN_SPEAKER_DMIC] = 43, + [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115, + [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116, + [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117, + [SND_DEVICE_IN_HEADSET_MIC] = 8, + [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = 47, + [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, + [SND_DEVICE_IN_HDMI_MIC] = 4, + [SND_DEVICE_IN_BT_SCO_MIC] = 21, + [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38, + [SND_DEVICE_IN_CAMCORDER_MIC] = 4, + [SND_DEVICE_IN_VOICE_DMIC] = 41, + [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43, + [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, + [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_REC_MIC] = 4, + [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107, + [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34, + [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41, + [SND_DEVICE_IN_USB_HEADSET_MIC] = 44, + [SND_DEVICE_IN_CAPTURE_FM] = 0, + [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104, + [SND_DEVICE_IN_QUAD_MIC] = 46, + [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34, + [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35, + [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102, +}; + +#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) +#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) + +static int set_echo_reference(struct mixer *mixer, const char* ec_ref) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "EC_REF_RX"; + + ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting EC Reference: %s", ec_ref); + mixer_ctl_set_enum_by_string(ctl, ec_ref); + return 0; +} + +static struct csd_data *open_csd_client() +{ + struct csd_data *csd = calloc(1, sizeof(struct csd_data)); + + csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW); + if (csd->csd_client == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT); + goto error; + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT); + + csd->deinit = (deinit_t)dlsym(csd->csd_client, + "csd_client_deinit"); + if (csd->deinit == NULL) { + ALOGE("%s: dlsym error %s for csd_client_deinit", __func__, + dlerror()); + goto error; + } + csd->disable_device = (disable_device_t)dlsym(csd->csd_client, + "csd_client_disable_device"); + if (csd->disable_device == NULL) { + ALOGE("%s: dlsym error %s for csd_client_disable_device", + __func__, dlerror()); + goto error; + } + csd->enable_device = (enable_device_t)dlsym(csd->csd_client, + "csd_client_enable_device"); + if (csd->enable_device == NULL) { + ALOGE("%s: dlsym error %s for csd_client_enable_device", + __func__, dlerror()); + goto error; + } + csd->start_voice = (start_voice_t)dlsym(csd->csd_client, + "csd_client_start_voice"); + if (csd->start_voice == NULL) { + ALOGE("%s: dlsym error %s for csd_client_start_voice", + __func__, dlerror()); + goto error; + } + csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client, + "csd_client_stop_voice"); + if (csd->stop_voice == NULL) { + ALOGE("%s: dlsym error %s for csd_client_stop_voice", + __func__, dlerror()); + goto error; + } + csd->volume = (volume_t)dlsym(csd->csd_client, + "csd_client_volume"); + if (csd->volume == NULL) { + ALOGE("%s: dlsym error %s for csd_client_volume", + __func__, dlerror()); + goto error; + } + csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client, + "csd_client_mic_mute"); + if (csd->mic_mute == NULL) { + ALOGE("%s: dlsym error %s for csd_client_mic_mute", + __func__, dlerror()); + goto error; + } + csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client, + "csd_client_slow_talk"); + if (csd->slow_talk == NULL) { + ALOGE("%s: dlsym error %s for csd_client_slow_talk", + __func__, dlerror()); + goto error; + } + csd->start_playback = (start_playback_t)dlsym(csd->csd_client, + "csd_client_start_playback"); + if (csd->start_playback == NULL) { + ALOGE("%s: dlsym error %s for csd_client_start_playback", + __func__, dlerror()); + goto error; + } + csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client, + "csd_client_stop_playback"); + if (csd->stop_playback == NULL) { + ALOGE("%s: dlsym error %s for csd_client_stop_playback", + __func__, dlerror()); + goto error; + } + csd->start_record = (start_record_t)dlsym(csd->csd_client, + "csd_client_start_record"); + if (csd->start_record == NULL) { + ALOGE("%s: dlsym error %s for csd_client_start_record", + __func__, dlerror()); + goto error; + } + csd->stop_record = (stop_record_t)dlsym(csd->csd_client, + "csd_client_stop_record"); + if (csd->stop_record == NULL) { + ALOGE("%s: dlsym error %s for csd_client_stop_record", + __func__, dlerror()); + goto error; + } + csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init"); + + if (csd->init == NULL) { + ALOGE("%s: dlsym error %s for csd_client_init", + __func__, dlerror()); + goto error; + } else { + csd->init(); + } + } + return csd; + +error: + free(csd); + csd = NULL; + return csd; +} + +void close_csd_client(struct csd_data *csd) +{ + if (csd != NULL) { + csd->deinit(); + dlclose(csd->csd_client); + free(csd); + csd = NULL; + } +} + +void *platform_init(struct audio_device *adev) +{ + char platform[PROPERTY_VALUE_MAX]; + char baseband[PROPERTY_VALUE_MAX]; + char value[PROPERTY_VALUE_MAX]; + struct platform_data *my_data; + int retry_num = 0; + const char *snd_card_name; + + adev->mixer = mixer_open(MIXER_CARD); + + while (!adev->mixer && retry_num < RETRY_NUMBER) { + usleep(RETRY_US); + adev->mixer = mixer_open(MIXER_CARD); + retry_num++; + } + + if (!adev->mixer) { + ALOGE("Unable to open the mixer, aborting."); + return NULL; + } + + adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); + + if (!adev->audio_route) { + ALOGE("%s: Failed to init audio route controls, aborting.", __func__); + return NULL; + } + + my_data = calloc(1, sizeof(struct platform_data)); + + snd_card_name = mixer_get_name(adev->mixer); + my_data->hw_info = hw_info_init(snd_card_name); + if (!my_data->hw_info) { + ALOGE("%s: Failed to init hardware info", __func__); + } + + my_data->adev = adev; + my_data->btsco_sample_rate = SAMPLE_RATE_8KHZ; + my_data->fluence_in_spkr_mode = false; + my_data->fluence_in_voice_call = false; + my_data->fluence_in_voice_rec = false; + my_data->fluence_in_audio_rec = false; + my_data->fluence_type = FLUENCE_NONE; + + property_get("ro.qc.sdk.audio.fluencetype", value, ""); + if (!strncmp("fluencepro", value, sizeof("fluencepro"))) { + my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC; + } else if (!strncmp("fluence", value, sizeof("fluence"))) { + my_data->fluence_type = FLUENCE_DUAL_MIC; + } else { + my_data->fluence_type = FLUENCE_NONE; + } + + if (my_data->fluence_type != FLUENCE_NONE) { + property_get("persist.audio.fluence.voicecall",value,""); + if (!strncmp("true", value, sizeof("true"))) { + my_data->fluence_in_voice_call = true; + } + + property_get("persist.audio.fluence.voicerec",value,""); + if (!strncmp("true", value, sizeof("true"))) { + my_data->fluence_in_voice_rec = true; + } + + property_get("persist.audio.fluence.audiorec",value,""); + if (!strncmp("true", value, sizeof("true"))) { + my_data->fluence_in_audio_rec = true; + } + + property_get("persist.audio.fluence.speaker",value,""); + if (!strncmp("true", value, sizeof("true"))) { + my_data->fluence_in_spkr_mode = true; + } + } + + my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW); + if (my_data->acdb_handle == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER); + my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle, + "acdb_loader_deallocate_ACDB"); + my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle, + "acdb_loader_send_audio_cal"); + if (!my_data->acdb_send_audio_cal) + ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s", + __func__, LIB_ACDB_LOADER); + my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle, + "acdb_loader_send_voice_cal"); + my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle, + "acdb_loader_init_ACDB"); + if (my_data->acdb_init == NULL) + ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror()); + else + my_data->acdb_init(); + } + + /* If platform is apq8084 and baseband is MDM, load CSD Client specific + * symbols. Voice call is handled by MDM and apps processor talks to + * MDM through CSD Client + */ + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strncmp("apq8084", platform, sizeof("apq8084")) && + !strncmp("mdm", baseband, sizeof("mdm"))) { + my_data->csd = open_csd_client(); + } + + return my_data; +} + +void platform_deinit(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + + hw_info_deinit(my_data->hw_info); + close_csd_client(my_data->csd); + + free(platform); +} + +const char *platform_get_snd_device_name(snd_device_t snd_device) +{ + if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) + return device_table[snd_device]; + else + return ""; +} + +int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device, + char *device_name) +{ + struct platform_data *my_data = (struct platform_data *)platform; + + if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) { + strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE); + hw_info_append_hw_type(my_data->hw_info, snd_device, device_name); + } else { + strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE); + return -EINVAL; + } + + return 0; +} + +void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) +{ + if (snd_device == SND_DEVICE_IN_BT_SCO_MIC) + strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB) + strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH); + else if(snd_device == SND_DEVICE_OUT_BT_SCO) + strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH); + else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB) + strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_HDMI) + strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) + strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_AFE_PROXY) + strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_USB_HEADSET) + strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET) + strlcat(mixer_path, " speaker-and-usb-headphones", + MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC) + strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_CAPTURE_FM) + strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM) + strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH); +} + +int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) +{ + int device_id; + if (device_type == PCM_PLAYBACK) + device_id = pcm_device_table[usecase][0]; + else + device_id = pcm_device_table[usecase][1]; + return device_id; +} + +int platform_send_audio_calibration(void *platform, snd_device_t snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_dev_id, acdb_dev_type; + + acdb_dev_id = acdb_device_table[snd_device]; + if (acdb_dev_id < 0) { + ALOGE("%s: Could not find acdb id for device(%d)", + __func__, snd_device); + return -EINVAL; + } + if (my_data->acdb_send_audio_cal) { + ("%s: sending audio calibration for snd_device(%d) acdb_id(%d)", + __func__, snd_device, acdb_dev_id); + if (snd_device >= SND_DEVICE_OUT_BEGIN && + snd_device < SND_DEVICE_OUT_END) + acdb_dev_type = ACDB_DEV_TYPE_OUT; + else + acdb_dev_type = ACDB_DEV_TYPE_IN; + my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type); + } + return 0; +} + +int platform_switch_voice_call_device_pre(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd != NULL && + my_data->adev->mode == AUDIO_MODE_IN_CALL) { + /* This must be called before disabling mixer controls on APQ side */ + ret = my_data->csd->disable_device(); + if (ret < 0) { + ALOGE("%s: csd_client_disable_device, failed, error %d", + __func__, ret); + } + } + return ret; +} + +int platform_switch_voice_call_device_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_rx_id, acdb_tx_id; + + if (my_data->acdb_send_voice_cal == NULL) { + ALOGE("%s: dlsym error for acdb_send_voice_call", __func__); + } else { + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; + + if (acdb_rx_id > 0 && acdb_tx_id > 0) + my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id); + else + ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, + acdb_rx_id, acdb_tx_id); + } + + return 0; +} + +int platform_switch_voice_call_usecase_route_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int acdb_rx_id, acdb_tx_id; + int ret = 0; + + acdb_rx_id = acdb_device_table[out_snd_device]; + acdb_tx_id = acdb_device_table[in_snd_device]; + + if (my_data->csd != NULL) { + if (acdb_rx_id > 0 && acdb_tx_id > 0) { + ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id, + my_data->adev->acdb_settings); + if (ret < 0) { + ALOGE("%s: csd_enable_device, failed, error %d", + __func__, ret); + } + } else { + ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__, + acdb_rx_id, acdb_tx_id); + } + } + return ret; +} + +int platform_start_voice_call(void *platform, uint32_t vsid) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd != NULL) { + ret = my_data->csd->start_voice(vsid); + if (ret < 0) { + ALOGE("%s: csd_start_voice error %d\n", __func__, ret); + } + } + return ret; +} + +int platform_stop_voice_call(void *platform, uint32_t vsid) +{ + struct platform_data *my_data = (struct platform_data *)platform; + int ret = 0; + + if (my_data->csd != NULL) { + ret = my_data->csd->stop_voice(vsid); + if (ret < 0) { + ALOGE("%s: csd_stop_voice error %d\n", __func__, ret); + } + } + return ret; +} + +int platform_set_voice_volume(void *platform, int volume) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voice Rx Gain"; + int vol_index = 0, ret = 0; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID, + DEFAULT_VOLUME_RAMP_DURATION_MS}; + + // Voice volume levels are mapped to adsp volume levels as follows. + // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0 + // But this values don't changed in kernel. So, below change is need. + vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX); + set_values[0] = vol_index; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting voice volume index: %d", set_values[0]); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + if (my_data->csd != NULL) { + ret = my_data->csd->volume(ALL_SESSION_VSID, volume); + if (ret < 0) { + ALOGE("%s: csd_volume error %d", __func__, ret); + } + } + return ret; +} + +int platform_set_mic_mute(void *platform, bool state) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voice Tx Mute"; + int ret = 0; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID, + DEFAULT_VOLUME_RAMP_DURATION_MS}; + + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("Setting voice mute state: %d", state); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + if (my_data->csd != NULL) { + ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state); + if (ret < 0) { + ALOGE("%s: csd_mic_mute error %d", __func__, ret); + } + } + return ret; +} + +snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + audio_mode_t mode = adev->mode; + snd_device_t snd_device = SND_DEVICE_NONE; + + audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? + AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; + int channel_count = popcount(channel_mask); + + ALOGV("%s: enter: output devices(%#x)", __func__, devices); + if (devices == AUDIO_DEVICE_NONE || + devices & AUDIO_DEVICE_BIT_IN) { + ALOGV("%s: Invalid output devices (%#x)", __func__, devices); + goto exit; + } + + if (popcount(devices) == 2) { + if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; + } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET; + } else { + ALOGE("%s: Invalid combo device(%#x)", __func__, devices); + goto exit; + } + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + } + + if (popcount(devices) != 1) { + ALOGE("%s: Invalid output devices(%#x)", __func__, devices); + goto exit; + } + + if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_OUT_HEADPHONES; + } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) { + if (adev->speaker_lr_swap) + snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE; + else + snd_device = SND_DEVICE_OUT_SPEAKER; + } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) { + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_OUT_BT_SCO_WB; + else + snd_device = SND_DEVICE_OUT_BT_SCO; + } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + snd_device = SND_DEVICE_OUT_HDMI ; + } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || + devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_OUT_USB_HEADSET; + } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { + snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; + } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { + snd_device = SND_DEVICE_OUT_HANDSET; + } else { + ALOGE("%s: Unknown device(s) %#x", __func__, devices); + } +exit: + ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]); + return snd_device; +} + +snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + audio_source_t source = (adev->active_input == NULL) ? + AUDIO_SOURCE_DEFAULT : adev->active_input->source; + + audio_mode_t mode = adev->mode; + audio_devices_t in_device = ((adev->active_input == NULL) ? + AUDIO_DEVICE_NONE : adev->active_input->device) + & ~AUDIO_DEVICE_BIT_IN; + audio_channel_mask_t channel_mask = (adev->active_input == NULL) ? + AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask; + snd_device_t snd_device = SND_DEVICE_NONE; + int channel_count = popcount(channel_mask); + + ALOGV("%s: enter: out_device(%#x) in_device(%#x)", + __func__, out_device, in_device); + if (source == AUDIO_SOURCE_CAMCORDER) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC || + in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_CAMCORDER_MIC; + } + } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (channel_count == 2) { + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO; + adev->acdb_settings |= DMIC_FLAG; + } else if (adev->active_input->enable_ns) + snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS; + else if (my_data->fluence_type != FLUENCE_NONE && + my_data->fluence_in_voice_rec) { + snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE; + adev->acdb_settings |= DMIC_FLAG; + } else { + snd_device = SND_DEVICE_IN_VOICE_REC_MIC; + } + } + } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { + if (out_device & AUDIO_DEVICE_OUT_SPEAKER) + in_device = AUDIO_DEVICE_IN_BACK_MIC; + if (adev->active_input) { + if (adev->active_input->enable_aec && + adev->active_input->enable_ns) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC && + my_data->fluence_in_spkr_mode) { + snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; + } + set_echo_reference(adev->mixer, "SLIM_RX"); + } else if (adev->active_input->enable_aec) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; + } + set_echo_reference(adev->mixer, "SLIM_RX"); + } else if (adev->active_input->enable_ns) { + if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS; + } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS; + adev->acdb_settings |= DMIC_FLAG; + } else + snd_device = SND_DEVICE_IN_HANDSET_MIC_NS; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; + } + set_echo_reference(adev->mixer, "NONE"); + } else + set_echo_reference(adev->mixer, "NONE"); + } + } else if (source == AUDIO_SOURCE_MIC) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC && + channel_count == 1 ) { + if(my_data->fluence_type & FLUENCE_DUAL_MIC && + my_data->fluence_in_audio_rec) + snd_device = SND_DEVICE_IN_HANDSET_DMIC; + } + } else if (source == AUDIO_SOURCE_FM_RX || + source == AUDIO_SOURCE_FM_RX_A2DP) { + snd_device = SND_DEVICE_IN_CAPTURE_FM; + } else if (source == AUDIO_SOURCE_DEFAULT) { + goto exit; + } + + + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + + if (in_device != AUDIO_DEVICE_NONE && + !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) && + !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) { + if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { + if (channel_count == 2) + snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC; + else + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; + else + snd_device = SND_DEVICE_IN_BT_SCO_MIC; + } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) { + snd_device = SND_DEVICE_IN_HDMI_MIC; + } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET || + in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_IN_USB_HEADSET_MIC; + } else if (in_device & AUDIO_DEVICE_IN_FM_RX) { + snd_device = SND_DEVICE_IN_CAPTURE_FM; + } else { + ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); + ALOGW("%s: Using default handset-mic", __func__); + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } else { + if (out_device & AUDIO_DEVICE_OUT_EARPIECE) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + snd_device = SND_DEVICE_IN_HEADSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) { + if (channel_count > 1) + snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC; + else + snd_device = SND_DEVICE_IN_SPEAKER_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { + if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) + snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; + else + snd_device = SND_DEVICE_IN_BT_SCO_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + snd_device = SND_DEVICE_IN_HDMI_MIC; + } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || + out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { + snd_device = SND_DEVICE_IN_USB_HEADSET_MIC; + } else { + ALOGE("%s: Unknown output device(s) %#x", __func__, out_device); + ALOGW("%s: Using default handset-mic", __func__); + snd_device = SND_DEVICE_IN_HANDSET_MIC; + } + } +exit: + ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]); + return snd_device; +} + +int platform_set_hdmi_channels(void *platform, int channel_count) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *channel_cnt_str = NULL; + const char *mixer_ctl_name = "HDMI_RX Channels"; + switch (channel_count) { + case 8: + channel_cnt_str = "Eight"; break; + case 7: + channel_cnt_str = "Seven"; break; + case 6: + channel_cnt_str = "Six"; break; + case 5: + channel_cnt_str = "Five"; break; + case 4: + channel_cnt_str = "Four"; break; + case 3: + channel_cnt_str = "Three"; break; + default: + channel_cnt_str = "Two"; break; + } + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("HDMI channel count: %s", channel_cnt_str); + mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); + return 0; +} + +int platform_edid_get_max_channels(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE]; + char *sad = block; + int num_audio_blocks; + int channel_count; + int max_channels = 0; + int i, ret, count; + + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, AUDIO_DATA_BLOCK_MIXER_CTL); + return 0; + } + + mixer_ctl_update(ctl); + + count = mixer_ctl_get_num_values(ctl); + + /* Read SAD blocks, clamping the maximum size for safety */ + if (count > (int)sizeof(block)) + count = (int)sizeof(block); + + ret = mixer_ctl_get_array(ctl, block, count); + if (ret != 0) { + ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__); + return 0; + } + + /* Calculate the number of SAD blocks */ + num_audio_blocks = count / SAD_BLOCK_SIZE; + + for (i = 0; i < num_audio_blocks; i++) { + /* Only consider LPCM blocks */ + if ((sad[0] >> 3) != EDID_FORMAT_LPCM) { + sad += 3; + continue; + } + + channel_count = (sad[0] & 0x7) + 1; + if (channel_count > max_channels) + max_channels = channel_count; + + /* Advance to next block */ + sad += 3; + } + + return max_channels; +} + +static int platform_set_slowtalk(struct platform_data *my_data, bool state) +{ + int ret = 0; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Slowtalk Enable"; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID}; + + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + ret = -EINVAL; + } else { + ALOGV("Setting slowtalk state: %d", state); + ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + my_data->slowtalk = state; + } + + if (my_data->csd != NULL) { + ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state); + if (ret < 0) { + ALOGE("%s: csd_client_disable_device, failed, error %d", + __func__, ret); + } + } + return ret; +} + +int platform_set_parameters(void *platform, struct str_parms *parms) +{ + struct platform_data *my_data = (struct platform_data *)platform; + char *str; + char value[32]; + int val; + int ret = 0; + + ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + + ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO); + my_data->btsco_sample_rate = val; + } + + ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK); + ret = platform_set_slowtalk(my_data, val); + if (ret) + ALOGE("%s: Failed to set slow talk err: %d", __func__, ret); + } + + ALOGV("%s: exit with code(%d)", __func__, ret); + return ret; +} + +int platform_set_incall_recoding_session_id(void *platform, + uint32_t session_id) +{ + int ret = 0; + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Voc VSID"; + int num_ctl_values; + int i; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + ret = -EINVAL; + } else { + num_ctl_values = mixer_ctl_get_num_values(ctl); + for (i = 0; i < num_ctl_values; i++) { + if (mixer_ctl_set_value(ctl, i, session_id)) { + ALOGV("Error: invalid session_id: %x", session_id); + ret = -EINVAL; + break; + } + } + } + + return ret; +} + +void platform_get_parameters(void *platform, + struct str_parms *query, + struct str_parms *reply) +{ + struct platform_data *my_data = (struct platform_data *)platform; + char *str = NULL; + char value[256] = {0}; + int ret; + int fluence_type; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, + value, sizeof(value)); + if (ret >= 0) { + if (my_data->fluence_type & FLUENCE_QUAD_MIC) { + strlcpy(value, "fluencepro", sizeof(value)); + } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) { + strlcpy(value, "fluence", sizeof(value)); + } else { + strlcpy(value, "none", sizeof(value)); + } + + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value); + } + + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK, + value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SLOWTALK, + my_data->slowtalk); + } + + ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply)); +} + +/* Delay in Us */ +int64_t platform_render_latency(audio_usecase_t usecase) +{ + switch (usecase) { + case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: + return DEEP_BUFFER_PLATFORM_DELAY; + case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: + return LOW_LATENCY_PLATFORM_DELAY; + default: + return 0; + } +} + +int platform_update_usecase_from_source(int source, int usecase) +{ + ALOGV("%s: input source :%d", __func__, source); + if(source == AUDIO_SOURCE_FM_RX_A2DP) + usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL; + return usecase; +} diff --git a/hal_mpq/mpq8092/platform.h b/hal_mpq/mpq8092/platform.h new file mode 100644 index 000000000..3cd56cf4f --- /dev/null +++ b/hal_mpq/mpq8092/platform.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef QCOM_AUDIO_PLATFORM_H +#define QCOM_AUDIO_PLATFORM_H + +enum { + FLUENCE_NONE, + FLUENCE_DUAL_MIC = 0x1, + FLUENCE_QUAD_MIC = 0x2, +}; + +/* + * Below are the devices for which is back end is same, SLIMBUS_0_RX. + * All these devices are handled by the internal HW codec. We can + * enable any one of these devices at any time + */ +#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \ + (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \ + AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE) + +/* Sound devices specific to the platform + * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound + * devices to enable corresponding mixer paths + */ +enum { + SND_DEVICE_NONE = 0, + + /* Playback devices */ + SND_DEVICE_MIN, + SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN, + SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN, + SND_DEVICE_OUT_SPEAKER, + SND_DEVICE_OUT_SPEAKER_REVERSE, + SND_DEVICE_OUT_HEADPHONES, + SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, + SND_DEVICE_OUT_VOICE_HANDSET, + SND_DEVICE_OUT_VOICE_SPEAKER, + SND_DEVICE_OUT_VOICE_HEADPHONES, + SND_DEVICE_OUT_HDMI, + SND_DEVICE_OUT_SPEAKER_AND_HDMI, + SND_DEVICE_OUT_BT_SCO, + SND_DEVICE_OUT_BT_SCO_WB, + SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, + SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_AFE_PROXY, + SND_DEVICE_OUT_USB_HEADSET, + SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET, + SND_DEVICE_OUT_TRANSMISSION_FM, + SND_DEVICE_OUT_ANC_HEADSET, + SND_DEVICE_OUT_ANC_FB_HEADSET, + SND_DEVICE_OUT_VOICE_ANC_HEADSET, + SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET, + SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_OUT_ANC_HANDSET, + SND_DEVICE_OUT_SPEAKER_PROTECTED, + SND_DEVICE_OUT_END, + + /* + * Note: IN_BEGIN should be same as OUT_END because total number of devices + * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices. + */ + /* Capture devices */ + SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END, + SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN, + SND_DEVICE_IN_HANDSET_MIC_AEC, + SND_DEVICE_IN_HANDSET_MIC_NS, + SND_DEVICE_IN_HANDSET_MIC_AEC_NS, + SND_DEVICE_IN_HANDSET_DMIC, + SND_DEVICE_IN_HANDSET_DMIC_AEC, + SND_DEVICE_IN_HANDSET_DMIC_NS, + SND_DEVICE_IN_HANDSET_DMIC_AEC_NS, + SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_IN_SPEAKER_MIC_AEC, + SND_DEVICE_IN_SPEAKER_MIC_NS, + SND_DEVICE_IN_SPEAKER_MIC_AEC_NS, + SND_DEVICE_IN_SPEAKER_DMIC, + SND_DEVICE_IN_SPEAKER_DMIC_AEC, + SND_DEVICE_IN_SPEAKER_DMIC_NS, + SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS, + SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_HEADSET_MIC_FLUENCE, + SND_DEVICE_IN_VOICE_SPEAKER_MIC, + SND_DEVICE_IN_VOICE_HEADSET_MIC, + SND_DEVICE_IN_HDMI_MIC, + SND_DEVICE_IN_BT_SCO_MIC, + SND_DEVICE_IN_BT_SCO_MIC_WB, + SND_DEVICE_IN_CAMCORDER_MIC, + SND_DEVICE_IN_VOICE_DMIC, + SND_DEVICE_IN_VOICE_SPEAKER_DMIC, + SND_DEVICE_IN_VOICE_SPEAKER_QMIC, + SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, + SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC, + SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC, + SND_DEVICE_IN_VOICE_REC_MIC, + SND_DEVICE_IN_VOICE_REC_MIC_NS, + SND_DEVICE_IN_VOICE_REC_DMIC_STEREO, + SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_USB_HEADSET_MIC, + SND_DEVICE_IN_CAPTURE_FM, + SND_DEVICE_IN_AANC_HANDSET_MIC, + SND_DEVICE_IN_QUAD_MIC, + SND_DEVICE_IN_HANDSET_STEREO_DMIC, + SND_DEVICE_IN_SPEAKER_STEREO_DMIC, + SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, + SND_DEVICE_IN_END, + + SND_DEVICE_MAX = SND_DEVICE_IN_END, + +}; + +#define MIXER_CARD 0 +#define SOUND_CARD 0 + +#define DEFAULT_OUTPUT_SAMPLING_RATE 48000 + +#define ALL_SESSION_VSID 0xFFFFFFFF +#define DEFAULT_MUTE_RAMP_DURATION 500 +#define DEFAULT_VOLUME_RAMP_DURATION_MS 20 +#define MIXER_PATH_MAX_LENGTH 100 + +#define MAX_VOL_INDEX 5 +#define MIN_VOL_INDEX 0 +#define percent_to_index(val, min, max) \ + ((val) * ((max) - (min)) * 0.01 + (min) + .5) + +/* + * tinyAlsa library interprets period size as number of frames + * one frame = channel_count * sizeof (pcm sample) + * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes + * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes + * We should take care of returning proper size when AudioFlinger queries for + * the buffer size of an input/output stream + */ +#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 +#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8 +#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240 +#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 + +#define HDMI_MULTI_PERIOD_SIZE 336 +#define HDMI_MULTI_PERIOD_COUNT 8 +#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 +#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2) + +#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20 +#define AUDIO_CAPTURE_PERIOD_COUNT 2 + +#define DEVICE_NAME_MAX_SIZE 128 +#define HW_INFO_ARRAY_MAX_SIZE 32 + +#define DEEP_BUFFER_PCM_DEVICE 0 +#define AUDIO_RECORD_PCM_DEVICE 0 +#define MULTIMEDIA2_PCM_DEVICE 1 +#define FM_PLAYBACK_PCM_DEVICE 5 +#define FM_CAPTURE_PCM_DEVICE 6 +#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 +#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 +#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22 +#define PLAYBACK_OFFLOAD_DEVICE 9 +#define COMPRESS_VOIP_CALL_PCM_DEVICE 3 + +#ifdef PLATFORM_MSM8610 +#define LOWLATENCY_PCM_DEVICE 12 +#else +#define LOWLATENCY_PCM_DEVICE 15 +#endif +#define COMPRESS_CAPTURE_DEVICE 19 + +#ifdef PLATFORM_MSM8x26 +#define VOICE_CALL_PCM_DEVICE 2 +#define VOICE2_CALL_PCM_DEVICE 14 +#define VOLTE_CALL_PCM_DEVICE 17 +#define QCHAT_CALL_PCM_DEVICE 18 +#elif PLATFORM_APQ8084 +#define VOICE_CALL_PCM_DEVICE 20 +#define VOICE2_CALL_PCM_DEVICE 13 +#define VOLTE_CALL_PCM_DEVICE 21 +#define QCHAT_CALL_PCM_DEVICE 06 +#else +#define VOICE_CALL_PCM_DEVICE 2 +#define VOICE2_CALL_PCM_DEVICE 13 +#define VOLTE_CALL_PCM_DEVICE 14 +#define QCHAT_CALL_PCM_DEVICE 20 +#endif + +#define LIB_CSD_CLIENT "libcsd-client.so" +/* CSD-CLIENT related functions */ +typedef int (*init_t)(); +typedef int (*deinit_t)(); +typedef int (*disable_device_t)(); +typedef int (*enable_device_t)(int, int, uint32_t); +typedef int (*volume_t)(uint32_t, int); +typedef int (*mic_mute_t)(uint32_t, int); +typedef int (*slow_talk_t)(uint32_t, uint8_t); +typedef int (*start_voice_t)(uint32_t); +typedef int (*stop_voice_t)(uint32_t); +typedef int (*start_playback_t)(uint32_t); +typedef int (*stop_playback_t)(uint32_t); +typedef int (*start_record_t)(uint32_t, int); +typedef int (*stop_record_t)(uint32_t, int); +/* CSD Client structure */ +struct csd_data { + void *csd_client; + init_t init; + deinit_t deinit; + disable_device_t disable_device; + enable_device_t enable_device; + volume_t volume; + mic_mute_t mic_mute; + slow_talk_t slow_talk; + start_voice_t start_voice; + stop_voice_t stop_voice; + start_playback_t start_playback; + stop_playback_t stop_playback; + start_record_t start_record; + stop_record_t stop_record; +}; + +void *hw_info_init(const char *snd_card_name); +void hw_info_deinit(void *hw_info); +void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, + char *device_name); + +#endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal_mpq/platform_api.h b/hal_mpq/platform_api.h new file mode 100644 index 000000000..44ad7905d --- /dev/null +++ b/hal_mpq/platform_api.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef QCOM_AUDIO_PLATFORM_API_H +#define QCOM_AUDIO_PLATFORM_API_H + +void *platform_init(struct audio_device *adev); +void platform_deinit(void *platform); +const char *platform_get_snd_device_name(snd_device_t snd_device); +int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device, + char *device_name); +void platform_add_backend_name(char *mixer_path, snd_device_t snd_device); +int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type); +int platform_send_audio_calibration(void *platform, snd_device_t snd_device); +int platform_switch_voice_call_device_pre(void *platform); +int platform_switch_voice_call_device_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device); +int platform_switch_voice_call_usecase_route_post(void *platform, + snd_device_t out_snd_device, + snd_device_t in_snd_device); +int platform_start_voice_call(void *platform, uint32_t vsid); +int platform_stop_voice_call(void *platform, uint32_t vsid); +int platform_set_voice_volume(void *platform, int volume); +int platform_set_mic_mute(void *platform, bool state); +snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices); +snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device); +int platform_set_hdmi_channels(void *platform, int channel_count); +int platform_edid_get_max_channels(void *platform); +void platform_get_parameters(void *platform, struct str_parms *query, + struct str_parms *reply); +int platform_set_parameters(void *platform, struct str_parms *parms); +int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id); + +/* returns the latency for a usecase in Us */ +int64_t platform_render_latency(audio_usecase_t usecase); +int platform_update_usecase_from_source(int source, audio_usecase_t usecase); + +#endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From 01e921adf70d527e77b8536a457b5ea659e72530 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 26 Nov 2013 23:33:22 +0530 Subject: [PATCH 097/298] audio: mpq: Move audio output activities to audio_stream_out Move output activities to audio_stream_out, output activites on mpq may involve multiple handles for a single hal session, and needs elaborate handling. Change-Id: I42b7e16cf316be89cbe22bd70b6c685d89f15f27 --- hal_mpq/Android.mk | 1 + hal_mpq/audio_hw.c | 1160 ------------------------------------ hal_mpq/audio_hw.h | 35 ++ hal_mpq/audio_stream_out.c | 1157 +++++++++++++++++++++++++++++++++++ 4 files changed, 1193 insertions(+), 1160 deletions(-) create mode 100644 hal_mpq/audio_stream_out.c diff --git a/hal_mpq/Android.mk b/hal_mpq/Android.mk index 338ee401b..24fca4ea5 100644 --- a/hal_mpq/Android.mk +++ b/hal_mpq/Android.mk @@ -10,6 +10,7 @@ AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) LOCAL_SRC_FILES := \ audio_hw.c \ + audio_stream_out.c \ $(AUDIO_PLATFORM)/hw_info.c \ $(AUDIO_PLATFORM)/platform.c diff --git a/hal_mpq/audio_hw.c b/hal_mpq/audio_hw.c index 8df46be83..fb83245ef 100644 --- a/hal_mpq/audio_hw.c +++ b/hal_mpq/audio_hw.c @@ -40,135 +40,26 @@ #include #include #include -#include #include -#include #include #include #include "audio_hw.h" #include "platform_api.h" #include -#include "sound/compress_params.h" - -#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) -#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 -/* ToDo: Check and update a proper value in msec */ -#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 -#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 - -struct pcm_config pcm_config_deep_buffer = { - .channels = 2, - .rate = DEFAULT_OUTPUT_SAMPLING_RATE, - .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, - .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, - .stop_threshold = INT_MAX, - .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, -}; - -struct pcm_config pcm_config_low_latency = { - .channels = 2, - .rate = DEFAULT_OUTPUT_SAMPLING_RATE, - .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, - .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, - .stop_threshold = INT_MAX, - .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, -}; - -struct pcm_config pcm_config_hdmi_multi = { - .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */ - .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */ - .period_size = HDMI_MULTI_PERIOD_SIZE, - .period_count = HDMI_MULTI_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = 0, - .stop_threshold = INT_MAX, - .avail_min = 0, -}; - struct pcm_config pcm_config_audio_capture = { .channels = 2, .period_count = AUDIO_CAPTURE_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, }; -const char * const use_case_table[AUDIO_USECASE_MAX] = { - [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback", - [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", - [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", - [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", - [USECASE_AUDIO_RECORD] = "audio-record", - [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", - [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", - [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", - [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", - [USECASE_VOICE_CALL] = "voice-call", - - [USECASE_VOICE2_CALL] = "voice2-call", - [USECASE_VOLTE_CALL] = "volte-call", - [USECASE_QCHAT_CALL] = "qchat-call", - [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call", - [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", - [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", - [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", - [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink", - [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", - [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib", - [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record", -}; - - -#define STRING_TO_ENUM(string) { #string, string } - -struct string_to_enum { - const char *name; - uint32_t value; -}; - -static const struct string_to_enum out_channels_name_to_enum_table[] = { - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), -}; - static struct audio_device *adev = NULL; static pthread_mutex_t adev_init_lock; static unsigned int audio_device_ref_count; static int set_voice_volume_l(struct audio_device *adev, float volume); -static bool is_supported_format(audio_format_t format) -{ - if (format == AUDIO_FORMAT_MP3 || - format == AUDIO_FORMAT_AAC) - return true; - - return false; -} - -static int get_snd_codec_id(audio_format_t format) -{ - int id = 0; - - switch (format) { - case AUDIO_FORMAT_MP3: - id = SND_AUDIOCODEC_MP3; - break; - case AUDIO_FORMAT_AAC: - id = SND_AUDIOCODEC_AAC; - break; - default: - ALOGE("%s: Unsupported audio format", __func__); - } - - return id; -} - int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, bool update_mixer) @@ -483,34 +374,6 @@ static int enable_all_usecases_of_type(struct audio_device *adev, return ret; } -/* must be called with hw device mutex locked */ -static int read_hdmi_channel_masks(struct stream_out *out) -{ - int ret = 0; - int channels = platform_edid_get_max_channels(out->dev->platform); - - switch (channels) { - /* - * Do not handle stereo output in Multi-channel cases - * Stereo case is handled in normal playback path - */ - case 6: - ALOGV("%s: HDMI supports 5.1", __func__); - out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; - break; - case 8: - ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__); - out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; - out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1; - break; - default: - ALOGE("HDMI does not support multi channel playback"); - ret = -ENOSYS; - break; - } - return ret; -} - static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev) { struct audio_usecase *usecase; @@ -751,327 +614,6 @@ error_config: return ret; } -/* must be called with out->lock locked */ -static int send_offload_cmd_l(struct stream_out* out, int command) -{ - struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd)); - - ALOGVV("%s %d", __func__, command); - - cmd->cmd = command; - list_add_tail(&out->offload_cmd_list, &cmd->node); - pthread_cond_signal(&out->offload_cond); - return 0; -} - -/* must be called iwth out->lock locked */ -static void stop_compressed_output_l(struct stream_out *out) -{ - out->offload_state = OFFLOAD_STATE_IDLE; - out->playback_started = 0; - out->send_new_metadata = 1; - if (out->compr != NULL) { - compress_stop(out->compr); - while (out->offload_thread_blocked) { - pthread_cond_wait(&out->cond, &out->lock); - } - } -} - -static void *offload_thread_loop(void *context) -{ - struct stream_out *out = (struct stream_out *) context; - struct listnode *item; - - out->offload_state = OFFLOAD_STATE_IDLE; - out->playback_started = 0; - - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); - set_sched_policy(0, SP_FOREGROUND); - prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0); - - ALOGV("%s", __func__); - pthread_mutex_lock(&out->lock); - for (;;) { - struct offload_cmd *cmd = NULL; - stream_callback_event_t event; - bool send_callback = false; - - ALOGVV("%s offload_cmd_list %d out->offload_state %d", - __func__, list_empty(&out->offload_cmd_list), - out->offload_state); - if (list_empty(&out->offload_cmd_list)) { - ALOGV("%s SLEEPING", __func__); - pthread_cond_wait(&out->offload_cond, &out->lock); - ALOGV("%s RUNNING", __func__); - continue; - } - - item = list_head(&out->offload_cmd_list); - cmd = node_to_item(item, struct offload_cmd, node); - list_remove(item); - - ALOGVV("%s STATE %d CMD %d out->compr %p", - __func__, out->offload_state, cmd->cmd, out->compr); - - if (cmd->cmd == OFFLOAD_CMD_EXIT) { - free(cmd); - break; - } - - if (out->compr == NULL) { - ALOGE("%s: Compress handle is NULL", __func__); - pthread_cond_signal(&out->cond); - continue; - } - out->offload_thread_blocked = true; - pthread_mutex_unlock(&out->lock); - send_callback = false; - switch(cmd->cmd) { - case OFFLOAD_CMD_WAIT_FOR_BUFFER: - compress_wait(out->compr, -1); - send_callback = true; - event = STREAM_CBK_EVENT_WRITE_READY; - break; - case OFFLOAD_CMD_PARTIAL_DRAIN: - compress_next_track(out->compr); - compress_partial_drain(out->compr); - send_callback = true; - event = STREAM_CBK_EVENT_DRAIN_READY; - break; - case OFFLOAD_CMD_DRAIN: - compress_drain(out->compr); - send_callback = true; - event = STREAM_CBK_EVENT_DRAIN_READY; - break; - default: - ALOGE("%s unknown command received: %d", __func__, cmd->cmd); - break; - } - pthread_mutex_lock(&out->lock); - out->offload_thread_blocked = false; - pthread_cond_signal(&out->cond); - if (send_callback) { - out->offload_callback(event, NULL, out->offload_cookie); - } - free(cmd); - } - - pthread_cond_signal(&out->cond); - while (!list_empty(&out->offload_cmd_list)) { - item = list_head(&out->offload_cmd_list); - list_remove(item); - free(node_to_item(item, struct offload_cmd, node)); - } - pthread_mutex_unlock(&out->lock); - - return NULL; -} - -static int create_offload_callback_thread(struct stream_out *out) -{ - pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL); - list_init(&out->offload_cmd_list); - pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL, - offload_thread_loop, out); - return 0; -} - -static int destroy_offload_callback_thread(struct stream_out *out) -{ - pthread_mutex_lock(&out->lock); - stop_compressed_output_l(out); - send_offload_cmd_l(out, OFFLOAD_CMD_EXIT); - - pthread_mutex_unlock(&out->lock); - pthread_join(out->offload_thread, (void **) NULL); - pthread_cond_destroy(&out->offload_cond); - - return 0; -} - -static bool allow_hdmi_channel_config(struct audio_device *adev) -{ - struct listnode *node; - struct audio_usecase *usecase; - bool ret = true; - - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - /* - * If voice call is already existing, do not proceed further to avoid - * disabling/enabling both RX and TX devices, CSD calls, etc. - * Once the voice call done, the HDMI channels can be configured to - * max channels of remaining use cases. - */ - if (usecase->id == USECASE_VOICE_CALL) { - ALOGD("%s: voice call is active, no change in HDMI channels", - __func__); - ret = false; - break; - } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) { - ALOGD("%s: multi channel playback is active, " - "no change in HDMI channels", __func__); - ret = false; - break; - } - } - } - return ret; -} - -static int check_and_set_hdmi_channels(struct audio_device *adev, - unsigned int channels) -{ - struct listnode *node; - struct audio_usecase *usecase; - - /* Check if change in HDMI channel config is allowed */ - if (!allow_hdmi_channel_config(adev)) - return 0; - - if (channels == adev->cur_hdmi_channels) { - ALOGD("%s: Requested channels are same as current", __func__); - return 0; - } - - platform_set_hdmi_channels(adev->platform, channels); - adev->cur_hdmi_channels = channels; - - /* - * Deroute all the playback streams routed to HDMI so that - * the back end is deactivated. Note that backend will not - * be deactivated if any one stream is connected to it. - */ - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == PCM_PLAYBACK && - usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - disable_audio_route(adev, usecase, true); - } - } - - /* - * Enable all the streams disabled above. Now the HDMI backend - * will be activated with new channel configuration - */ - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == PCM_PLAYBACK && - usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - enable_audio_route(adev, usecase, true); - } - } - - return 0; -} - -static int stop_output_stream(struct stream_out *out) -{ - int i, ret = 0; - struct audio_usecase *uc_info; - struct audio_device *adev = out->dev; - - ALOGV("%s: enter: usecase(%d: %s)", __func__, - out->usecase, use_case_table[out->usecase]); - uc_info = get_usecase_from_list(adev, out->usecase); - if (uc_info == NULL) { - ALOGE("%s: Could not find the usecase (%d) in the list", - __func__, out->usecase); - return -EINVAL; - } - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD && - adev->visualizer_stop_output != NULL) - adev->visualizer_stop_output(out->handle); - - /* 1. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); - - /* 2. Disable the rx device */ - disable_snd_device(adev, uc_info->out_snd_device, true); - - list_remove(&uc_info->list); - free(uc_info); - - /* Must be called after removing the usecase from list */ - if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) - check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS); - - ALOGV("%s: exit: status(%d)", __func__, ret); - return ret; -} - -int start_output_stream(struct stream_out *out) -{ - int ret = 0; - struct audio_usecase *uc_info; - struct audio_device *adev = out->dev; - - ALOGV("%s: enter: usecase(%d: %s) devices(%#x)", - __func__, out->usecase, use_case_table[out->usecase], out->devices); - out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); - if (out->pcm_device_id < 0) { - ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", - __func__, out->pcm_device_id, out->usecase); - ret = -EINVAL; - goto error_config; - } - - uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); - uc_info->id = out->usecase; - uc_info->type = PCM_PLAYBACK; - uc_info->stream.out = out; - uc_info->devices = out->devices; - uc_info->in_snd_device = SND_DEVICE_NONE; - uc_info->out_snd_device = SND_DEVICE_NONE; - - /* This must be called before adding this usecase to the list */ - if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) - check_and_set_hdmi_channels(adev, out->config.channels); - - list_add_tail(&adev->usecase_list, &uc_info->list); - - select_devices(adev, out->usecase); - - ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", - __func__, 0, out->pcm_device_id); - if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { - out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, - PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm && !pcm_is_ready(out->pcm)) { - ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); - pcm_close(out->pcm); - out->pcm = NULL; - ret = -EIO; - goto error_open; - } - } else { - out->pcm = NULL; - out->compr = compress_open(SOUND_CARD, out->pcm_device_id, - COMPRESS_IN, &out->compr_config); - if (out->compr && !is_compress_ready(out->compr)) { - ALOGE("%s: %s", __func__, compress_get_error(out->compr)); - compress_close(out->compr); - out->compr = NULL; - ret = -EIO; - goto error_open; - } - if (out->offload_callback) - compress_nonblock(out->compr, out->non_blocking); - - if (adev->visualizer_start_output != NULL) - adev->visualizer_start_output(out->handle); - } - ALOGV("%s: exit", __func__); - return 0; -error_open: - stop_output_stream(out); -error_config: - return ret; -} - static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count) @@ -1128,493 +670,6 @@ static size_t get_input_buffer_size(uint32_t sample_rate, return size; } -static uint32_t out_get_sample_rate(const struct audio_stream *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - - return out->sample_rate; -} - -static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) -{ - return -ENOSYS; -} - -static size_t out_get_buffer_size(const struct audio_stream *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) - return out->compr_config.fragment_size; - - return out->config.period_size * audio_stream_frame_size(stream); -} - -static uint32_t out_get_channels(const struct audio_stream *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - - return out->channel_mask; -} - -static audio_format_t out_get_format(const struct audio_stream *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - - return out->format; -} - -static int out_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int out_standby(struct audio_stream *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - struct audio_device *adev = out->dev; - - ALOGV("%s: enter: usecase(%d: %s)", __func__, - out->usecase, use_case_table[out->usecase]); - if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { - /* Ignore standby in case of voip call because the voip output - * stream is closed in adev_close_output_stream() - */ - ALOGV("%s: Ignore Standby in VOIP call", __func__); - return 0; - } - - pthread_mutex_lock(&out->lock); - pthread_mutex_lock(&adev->lock); - if (!out->standby) { - out->standby = true; - if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { - if (out->pcm) { - pcm_close(out->pcm); - out->pcm = NULL; - } - } else { - stop_compressed_output_l(out); - out->gapless_mdata.encoder_delay = 0; - out->gapless_mdata.encoder_padding = 0; - if (out->compr != NULL) { - compress_close(out->compr); - out->compr = NULL; - } - } - stop_output_stream(out); - } - pthread_mutex_unlock(&adev->lock); - pthread_mutex_unlock(&out->lock); - ALOGV("%s: exit", __func__); - return 0; -} - -static int out_dump(const struct audio_stream *stream, int fd) -{ - return 0; -} - -static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms) -{ - int ret = 0; - char value[32]; - struct compr_gapless_mdata tmp_mdata; - - if (!out || !parms) { - return -EINVAL; - } - - ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value)); - if (ret >= 0) { - tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? - } else { - return -EINVAL; - } - - ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); - if (ret >= 0) { - tmp_mdata.encoder_padding = atoi(value); - } else { - return -EINVAL; - } - - out->gapless_mdata = tmp_mdata; - out->send_new_metadata = 1; - ALOGV("%s new encoder delay %u and padding %u", __func__, - out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); - - return 0; -} - - -static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) -{ - struct stream_out *out = (struct stream_out *)stream; - struct audio_device *adev = out->dev; - struct audio_usecase *usecase; - struct listnode *node; - struct str_parms *parms; - char value[32]; - int ret, val = 0; - bool select_new_device = false; - - ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", - __func__, out->usecase, use_case_table[out->usecase], kvpairs); - parms = str_parms_create_str(kvpairs); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { - val = atoi(value); - pthread_mutex_lock(&out->lock); - pthread_mutex_lock(&adev->lock); - - /* - * When HDMI cable is unplugged the music playback is paused and - * the policy manager sends routing=0. But the audioflinger - * continues to write data until standby time (3sec). - * As the HDMI core is turned off, the write gets blocked. - * Avoid this by routing audio to speaker until standby. - */ - if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL && - val == AUDIO_DEVICE_NONE) { - val = AUDIO_DEVICE_OUT_SPEAKER; - } - - /* - * select_devices() call below switches all the usecases on the same - * backend to the new device. Refer to check_usecases_codec_backend() in - * the select_devices(). But how do we undo this? - * - * For example, music playback is active on headset (deep-buffer usecase) - * and if we go to ringtones and select a ringtone, low-latency usecase - * will be started on headset+speaker. As we can't enable headset+speaker - * and headset devices at the same time, select_devices() switches the music - * playback to headset+speaker while starting low-lateny usecase for ringtone. - * So when the ringtone playback is completed, how do we undo the same? - * - * We are relying on the out_set_parameters() call on deep-buffer output, - * once the ringtone playback is ended. - * NOTE: We should not check if the current devices are same as new devices. - * Because select_devices() must be called to switch back the music - * playback to headset. - */ - if (val != 0) { - out->devices = val; - - if (!out->standby) - select_devices(adev, out->usecase); - } - - pthread_mutex_unlock(&adev->lock); - pthread_mutex_unlock(&out->lock); - } - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - parse_compress_metadata(out, parms); - } - - str_parms_destroy(parms); - ALOGV("%s: exit: code(%d)", __func__, ret); - return ret; -} - -static char* out_get_parameters(const struct audio_stream *stream, const char *keys) -{ - struct stream_out *out = (struct stream_out *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str; - char value[256]; - struct str_parms *reply = str_parms_create(); - size_t i, j; - int ret; - bool first = true; - ALOGV("%s: enter: keys - %s", __func__, keys); - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value)); - if (ret >= 0) { - value[0] = '\0'; - i = 0; - while (out->supported_channel_masks[i] != 0) { - for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) { - if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) { - if (!first) { - strlcat(value, "|", sizeof(value)); - } - strlcat(value, out_channels_name_to_enum_table[j].name, sizeof(value)); - first = false; - break; - } - } - i++; - } - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); - str = str_parms_to_str(reply); - } - str_parms_destroy(query); - str_parms_destroy(reply); - ALOGV("%s: exit: returns - %s", __func__, str); - return str; -} - -static uint32_t out_get_latency(const struct audio_stream_out *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) - return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; - - return (out->config.period_count * out->config.period_size * 1000) / - (out->config.rate); -} - -static int out_set_volume(struct audio_stream_out *stream, float left, - float right) -{ - struct stream_out *out = (struct stream_out *)stream; - int volume[2]; - - if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) { - /* only take left channel into account: the API is for stereo anyway */ - out->muted = (left == 0.0f); - return 0; - } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - const char *mixer_ctl_name = "Compress Playback Volume"; - struct audio_device *adev = out->dev; - struct mixer_ctl *ctl; - - ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX); - volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX); - mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0])); - return 0; - } - - return -ENOSYS; -} - -static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, - size_t bytes) -{ - struct stream_out *out = (struct stream_out *)stream; - struct audio_device *adev = out->dev; - ssize_t ret = 0; - - pthread_mutex_lock(&out->lock); - if (out->standby) { - out->standby = false; - pthread_mutex_lock(&adev->lock); - ret = start_output_stream(out); - pthread_mutex_unlock(&adev->lock); - /* ToDo: If use case is compress offload should return 0 */ - if (ret != 0) { - out->standby = true; - goto exit; - } - } - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); - if (out->send_new_metadata) { - ALOGVV("send new gapless metadata"); - compress_set_gapless_metadata(out->compr, &out->gapless_mdata); - out->send_new_metadata = 0; - } - - ret = compress_write(out->compr, buffer, bytes); - ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); - if (ret >= 0 && ret < (ssize_t)bytes) { - send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); - } - if (!out->playback_started) { - compress_start(out->compr); - out->playback_started = 1; - out->offload_state = OFFLOAD_STATE_PLAYING; - } - pthread_mutex_unlock(&out->lock); - return ret; - } else { - if (out->pcm) { - if (out->muted) - memset((void *)buffer, 0, bytes); - ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); - ret = pcm_write(out->pcm, (void *)buffer, bytes); - if (ret == 0) - out->written += bytes / (out->config.channels * sizeof(short)); - } - } - -exit: - pthread_mutex_unlock(&out->lock); - - if (ret != 0) { - if (out->pcm) - ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); - out_standby(&out->stream.common); - usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / - out_get_sample_rate(&out->stream.common)); - } - return bytes; -} - -static int out_get_render_position(const struct audio_stream_out *stream, - uint32_t *dsp_frames) -{ - struct stream_out *out = (struct stream_out *)stream; - *dsp_frames = 0; - if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { - pthread_mutex_lock(&out->lock); - if (out->compr != NULL) { - compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, - &out->sample_rate); - ALOGVV("%s rendered frames %d sample_rate %d", - __func__, *dsp_frames, out->sample_rate); - } - pthread_mutex_unlock(&out->lock); - return 0; - } else - return -EINVAL; -} - -static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - return 0; -} - -static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - return 0; -} - -static int out_get_next_write_timestamp(const struct audio_stream_out *stream, - int64_t *timestamp) -{ - return -EINVAL; -} - -static int out_get_presentation_position(const struct audio_stream_out *stream, - uint64_t *frames, struct timespec *timestamp) -{ - struct stream_out *out = (struct stream_out *)stream; - int ret = -1; - unsigned long dsp_frames; - - pthread_mutex_lock(&out->lock); - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - if (out->compr != NULL) { - compress_get_tstamp(out->compr, &dsp_frames, - &out->sample_rate); - ALOGVV("%s rendered frames %ld sample_rate %d", - __func__, dsp_frames, out->sample_rate); - *frames = dsp_frames; - ret = 0; - /* this is the best we can do */ - clock_gettime(CLOCK_MONOTONIC, timestamp); - } - } else { - if (out->pcm) { - size_t avail; - if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { - size_t kernel_buffer_size = out->config.period_size * out->config.period_count; - int64_t signed_frames = out->written - kernel_buffer_size + avail; - // This adjustment accounts for buffering after app processor. - // It is based on estimated DSP latency per use case, rather than exact. - signed_frames -= - (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL); - - // It would be unusual for this value to be negative, but check just in case ... - if (signed_frames >= 0) { - *frames = signed_frames; - ret = 0; - } - } - } - } - - pthread_mutex_unlock(&out->lock); - - return ret; -} - -static int out_set_callback(struct audio_stream_out *stream, - stream_callback_t callback, void *cookie) -{ - struct stream_out *out = (struct stream_out *)stream; - - ALOGV("%s", __func__); - pthread_mutex_lock(&out->lock); - out->offload_callback = callback; - out->offload_cookie = cookie; - pthread_mutex_unlock(&out->lock); - return 0; -} - -static int out_pause(struct audio_stream_out* stream) -{ - struct stream_out *out = (struct stream_out *)stream; - int status = -ENOSYS; - ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - pthread_mutex_lock(&out->lock); - if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) { - status = compress_pause(out->compr); - out->offload_state = OFFLOAD_STATE_PAUSED; - } - pthread_mutex_unlock(&out->lock); - } - return status; -} - -static int out_resume(struct audio_stream_out* stream) -{ - struct stream_out *out = (struct stream_out *)stream; - int status = -ENOSYS; - ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - status = 0; - pthread_mutex_lock(&out->lock); - if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) { - status = compress_resume(out->compr); - out->offload_state = OFFLOAD_STATE_PLAYING; - } - pthread_mutex_unlock(&out->lock); - } - return status; -} - -static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type ) -{ - struct stream_out *out = (struct stream_out *)stream; - int status = -ENOSYS; - ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - pthread_mutex_lock(&out->lock); - if (type == AUDIO_DRAIN_EARLY_NOTIFY) - status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN); - else - status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN); - pthread_mutex_unlock(&out->lock); - } - return status; -} - -static int out_flush(struct audio_stream_out* stream) -{ - struct stream_out *out = (struct stream_out *)stream; - ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - pthread_mutex_lock(&out->lock); - stop_compressed_output_l(out); - pthread_mutex_unlock(&out->lock); - return 0; - } - return -ENOSYS; -} - /** audio_stream_in implementation **/ static uint32_t in_get_sample_rate(const struct audio_stream *stream) { @@ -1801,29 +856,6 @@ static int add_remove_audio_effect(const struct audio_stream *stream, { struct stream_in *in = (struct stream_in *)stream; int status = 0; - effect_descriptor_t desc; - - status = (*effect)->get_descriptor(effect, &desc); - if (status != 0) - return status; - - pthread_mutex_lock(&in->lock); - pthread_mutex_lock(&in->dev->lock); - if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) && - in->enable_aec != enable && - (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) { - in->enable_aec = enable; - if (!in->standby) - select_devices(in->dev, in->usecase); - } - if (in->enable_ns != enable && - (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) { - in->enable_ns = enable; - if (!in->standby) - select_devices(in->dev, in->usecase); - } - pthread_mutex_unlock(&in->dev->lock); - pthread_mutex_unlock(&in->lock); return 0; } @@ -1842,198 +874,6 @@ static int in_remove_audio_effect(const struct audio_stream *stream, return add_remove_audio_effect(stream, effect, false); } -static int adev_open_output_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - audio_output_flags_t flags, - struct audio_config *config, - struct audio_stream_out **stream_out) -{ - struct audio_device *adev = (struct audio_device *)dev; - struct stream_out *out; - int i, ret; - - ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", - __func__, config->sample_rate, config->channel_mask, devices, flags); - *stream_out = NULL; - out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); - - if (devices == AUDIO_DEVICE_NONE) - devices = AUDIO_DEVICE_OUT_SPEAKER; - - out->flags = flags; - out->devices = devices; - out->dev = adev; - out->format = config->format; - out->sample_rate = config->sample_rate; - out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; - out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; - out->handle = handle; - - /* Init use case and pcm_config */ - if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT && - out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - pthread_mutex_lock(&adev->lock); - ret = read_hdmi_channel_masks(out); - pthread_mutex_unlock(&adev->lock); - if (ret != 0) - goto error_open; - - if (config->sample_rate == 0) - config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; - if (config->channel_mask == 0) - config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1; - - out->channel_mask = config->channel_mask; - out->sample_rate = config->sample_rate; - out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH; - out->config = pcm_config_hdmi_multi; - out->config.rate = config->sample_rate; - out->config.channels = popcount(out->channel_mask); - out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); - } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { - if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || - config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { - ALOGE("%s: Unsupported Offload information", __func__); - ret = -EINVAL; - goto error_open; - } - if (!is_supported_format(config->offload_info.format)) { - ALOGE("%s: Unsupported audio format", __func__); - ret = -EINVAL; - goto error_open; - } - - out->compr_config.codec = (struct snd_codec *) - calloc(1, sizeof(struct snd_codec)); - - out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; - if (config->offload_info.channel_mask) - out->channel_mask = config->offload_info.channel_mask; - else if (config->channel_mask) - out->channel_mask = config->channel_mask; - out->format = config->offload_info.format; - out->sample_rate = config->offload_info.sample_rate; - - out->stream.set_callback = out_set_callback; - out->stream.pause = out_pause; - out->stream.resume = out_resume; - out->stream.drain = out_drain; - out->stream.flush = out_flush; - - out->compr_config.codec->id = - get_snd_codec_id(config->offload_info.format); - out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; - out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; - out->compr_config.codec->sample_rate = - compress_get_alsa_rate(config->offload_info.sample_rate); - out->compr_config.codec->bit_rate = - config->offload_info.bit_rate; - out->compr_config.codec->ch_in = - popcount(config->channel_mask); - out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; - - if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) - out->non_blocking = 1; - - out->send_new_metadata = 1; - create_offload_callback_thread(out); - ALOGV("%s: offloaded output offload_info version %04x bit rate %d", - __func__, config->offload_info.version, - config->offload_info.bit_rate); - } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { - out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; - out->config = pcm_config_low_latency; - out->sample_rate = out->config.rate; - } else { - out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; - out->config = pcm_config_deep_buffer; - out->sample_rate = out->config.rate; - } - - if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { - if(adev->primary_output == NULL) - adev->primary_output = out; - else { - ALOGE("%s: Primary output is already opened", __func__); - ret = -EEXIST; - goto error_open; - } - } - - /* Check if this usecase is already existing */ - pthread_mutex_lock(&adev->lock); - if (get_usecase_from_list(adev, out->usecase) != NULL) { - ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase); - pthread_mutex_unlock(&adev->lock); - ret = -EEXIST; - goto error_open; - } - pthread_mutex_unlock(&adev->lock); - - out->stream.common.get_sample_rate = out_get_sample_rate; - out->stream.common.set_sample_rate = out_set_sample_rate; - out->stream.common.get_buffer_size = out_get_buffer_size; - out->stream.common.get_channels = out_get_channels; - out->stream.common.get_format = out_get_format; - out->stream.common.set_format = out_set_format; - out->stream.common.standby = out_standby; - out->stream.common.dump = out_dump; - out->stream.common.set_parameters = out_set_parameters; - out->stream.common.get_parameters = out_get_parameters; - out->stream.common.add_audio_effect = out_add_audio_effect; - out->stream.common.remove_audio_effect = out_remove_audio_effect; - out->stream.get_latency = out_get_latency; - out->stream.set_volume = out_set_volume; - out->stream.write = out_write; - out->stream.get_render_position = out_get_render_position; - out->stream.get_next_write_timestamp = out_get_next_write_timestamp; - out->stream.get_presentation_position = out_get_presentation_position; - - out->standby = 1; - /* out->muted = false; by calloc() */ - /* out->written = 0; by calloc() */ - - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); - - config->format = out->stream.common.get_format(&out->stream.common); - config->channel_mask = out->stream.common.get_channels(&out->stream.common); - config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); - - *stream_out = &out->stream; - ALOGV("%s: exit", __func__); - return 0; - -error_open: - free(out); - *stream_out = NULL; - ALOGD("%s: exit: ret %d", __func__, ret); - return ret; -} - -static void adev_close_output_stream(struct audio_hw_device *dev, - struct audio_stream_out *stream) -{ - struct stream_out *out = (struct stream_out *)stream; - struct audio_device *adev = out->dev; - int ret = 0; - - ALOGV("%s: enter", __func__); - out_standby(&stream->common); - - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - destroy_offload_callback_thread(out); - - if (out->compr_config.codec != NULL) - free(out->compr_config.codec); - } - pthread_cond_destroy(&out->cond); - pthread_mutex_destroy(&out->lock); - free(stream); - ALOGV("%s: exit", __func__); -} - static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) { struct audio_device *adev = (struct audio_device *)dev; diff --git a/hal_mpq/audio_hw.h b/hal_mpq/audio_hw.h index 262fda84e..e1319a5fb 100644 --- a/hal_mpq/audio_hw.h +++ b/hal_mpq/audio_hw.h @@ -220,6 +220,41 @@ struct audio_device { int (*visualizer_stop_output)(audio_io_handle_t); }; +static const char * const use_case_table[AUDIO_USECASE_MAX] = { + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback", + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", + [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", + [USECASE_AUDIO_RECORD] = "audio-record", + [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", + [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", + [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", + [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", + [USECASE_VOICE_CALL] = "voice-call", + + [USECASE_VOICE2_CALL] = "voice2-call", + [USECASE_VOLTE_CALL] = "volte-call", + [USECASE_QCHAT_CALL] = "qchat-call", + [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call", + [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", + [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", + [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink", + [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", + [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib", + [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record", +}; + +int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out); + +void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream); + int select_devices(struct audio_device *adev, audio_usecase_t uc_id); int disable_audio_route(struct audio_device *adev, diff --git a/hal_mpq/audio_stream_out.c b/hal_mpq/audio_stream_out.c new file mode 100644 index 000000000..71eb2f1dc --- /dev/null +++ b/hal_mpq/audio_stream_out.c @@ -0,0 +1,1157 @@ +/* audio_stream_out.c + ** + ** Copyright 2008-2009 Wind River Systems + ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved + ** Not a Contribution, Apache license notifications and license are retained + ** for attribution purposes only. + ** + ** 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. + */ + +#define LOG_TAG "audio_stream_out" +/*#define LOG_NDEBUG 0*/ +/*#define VERY_VERY_VERBOSE_LOGGING*/ +#ifdef VERY_VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "audio_hw.h" +#include "platform_api.h" +#include + +#include "sound/compress_params.h" + +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) +#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 +/* ToDo: Check and update a proper value in msec */ +#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 +#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 + +struct pcm_config pcm_config_deep_buffer = { + .channels = 2, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, + .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4, +}; + +struct pcm_config pcm_config_low_latency = { + .channels = 2, + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, + .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE, + .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, + .stop_threshold = INT_MAX, + .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4, +}; + +struct pcm_config pcm_config_hdmi_multi = { + .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */ + .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */ + .period_size = HDMI_MULTI_PERIOD_SIZE, + .period_count = HDMI_MULTI_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = 0, + .stop_threshold = INT_MAX, + .avail_min = 0, +}; + +#define STRING_TO_ENUM(string) { #string, string } + +struct string_to_enum { + const char *name; + uint32_t value; +}; + +static const struct string_to_enum out_channels_name_to_enum_table[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; + +static bool is_supported_format(audio_format_t format) +{ + if (format == AUDIO_FORMAT_MP3 || + format == AUDIO_FORMAT_AAC) + return true; + + return false; +} + +static int get_snd_codec_id(audio_format_t format) +{ + int id = 0; + + switch (format) { + case AUDIO_FORMAT_MP3: + id = SND_AUDIOCODEC_MP3; + break; + case AUDIO_FORMAT_AAC: + id = SND_AUDIOCODEC_AAC; + break; + default: + ALOGE("%s: Unsupported audio format", __func__); + } + + return id; +} + +/* must be called with hw device mutex locked */ +static int read_hdmi_channel_masks(struct stream_out *out) +{ + int ret = 0; + int channels = platform_edid_get_max_channels(out->dev->platform); + + switch (channels) { + /* + * Do not handle stereo output in Multi-channel cases + * Stereo case is handled in normal playback path + */ + case 6: + ALOGV("%s: HDMI supports 5.1", __func__); + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; + break; + case 8: + ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__); + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; + out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1; + break; + default: + ALOGE("HDMI does not support multi channel playback"); + ret = -ENOSYS; + break; + } + return ret; +} + +/* must be called with out->lock locked */ +static int send_offload_cmd_l(struct stream_out* out, int command) +{ + struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd)); + + ALOGVV("%s %d", __func__, command); + + cmd->cmd = command; + list_add_tail(&out->offload_cmd_list, &cmd->node); + pthread_cond_signal(&out->offload_cond); + return 0; +} + +/* must be called iwth out->lock locked */ +static void stop_compressed_output_l(struct stream_out *out) +{ + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + out->send_new_metadata = 1; + if (out->compr != NULL) { + compress_stop(out->compr); + while (out->offload_thread_blocked) { + pthread_cond_wait(&out->cond, &out->lock); + } + } +} + +static void *offload_thread_loop(void *context) +{ + struct stream_out *out = (struct stream_out *) context; + struct listnode *item; + + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); + set_sched_policy(0, SP_FOREGROUND); + prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0); + + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + for (;;) { + struct offload_cmd *cmd = NULL; + stream_callback_event_t event; + bool send_callback = false; + + ALOGVV("%s offload_cmd_list %d out->offload_state %d", + __func__, list_empty(&out->offload_cmd_list), + out->offload_state); + if (list_empty(&out->offload_cmd_list)) { + ALOGV("%s SLEEPING", __func__); + pthread_cond_wait(&out->offload_cond, &out->lock); + ALOGV("%s RUNNING", __func__); + continue; + } + + item = list_head(&out->offload_cmd_list); + cmd = node_to_item(item, struct offload_cmd, node); + list_remove(item); + + ALOGVV("%s STATE %d CMD %d out->compr %p", + __func__, out->offload_state, cmd->cmd, out->compr); + + if (cmd->cmd == OFFLOAD_CMD_EXIT) { + free(cmd); + break; + } + + if (out->compr == NULL) { + ALOGE("%s: Compress handle is NULL", __func__); + pthread_cond_signal(&out->cond); + continue; + } + out->offload_thread_blocked = true; + pthread_mutex_unlock(&out->lock); + send_callback = false; + switch(cmd->cmd) { + case OFFLOAD_CMD_WAIT_FOR_BUFFER: + compress_wait(out->compr, -1); + send_callback = true; + event = STREAM_CBK_EVENT_WRITE_READY; + break; + case OFFLOAD_CMD_PARTIAL_DRAIN: + compress_next_track(out->compr); + compress_partial_drain(out->compr); + send_callback = true; + event = STREAM_CBK_EVENT_DRAIN_READY; + break; + case OFFLOAD_CMD_DRAIN: + compress_drain(out->compr); + send_callback = true; + event = STREAM_CBK_EVENT_DRAIN_READY; + break; + default: + ALOGE("%s unknown command received: %d", __func__, cmd->cmd); + break; + } + pthread_mutex_lock(&out->lock); + out->offload_thread_blocked = false; + pthread_cond_signal(&out->cond); + if (send_callback) { + out->offload_callback(event, NULL, out->offload_cookie); + } + free(cmd); + } + + pthread_cond_signal(&out->cond); + while (!list_empty(&out->offload_cmd_list)) { + item = list_head(&out->offload_cmd_list); + list_remove(item); + free(node_to_item(item, struct offload_cmd, node)); + } + pthread_mutex_unlock(&out->lock); + + return NULL; +} + +static int create_offload_callback_thread(struct stream_out *out) +{ + pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL); + list_init(&out->offload_cmd_list); + pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL, + offload_thread_loop, out); + return 0; +} + +static int destroy_offload_callback_thread(struct stream_out *out) +{ + pthread_mutex_lock(&out->lock); + stop_compressed_output_l(out); + send_offload_cmd_l(out, OFFLOAD_CMD_EXIT); + + pthread_mutex_unlock(&out->lock); + pthread_join(out->offload_thread, (void **) NULL); + pthread_cond_destroy(&out->offload_cond); + + return 0; +} + +static bool allow_hdmi_channel_config(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + bool ret = true; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + /* + * If voice call is already existing, do not proceed further to avoid + * disabling/enabling both RX and TX devices, CSD calls, etc. + * Once the voice call done, the HDMI channels can be configured to + * max channels of remaining use cases. + */ + if (usecase->id == USECASE_VOICE_CALL) { + ALOGD("%s: voice call is active, no change in HDMI channels", + __func__); + ret = false; + break; + } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) { + ALOGD("%s: multi channel playback is active, " + "no change in HDMI channels", __func__); + ret = false; + break; + } + } + } + return ret; +} + +static int check_and_set_hdmi_channels(struct audio_device *adev, + unsigned int channels) +{ + struct listnode *node; + struct audio_usecase *usecase; + + /* Check if change in HDMI channel config is allowed */ + if (!allow_hdmi_channel_config(adev)) + return 0; + + if (channels == adev->cur_hdmi_channels) { + ALOGD("%s: Requested channels are same as current", __func__); + return 0; + } + + platform_set_hdmi_channels(adev->platform, channels); + adev->cur_hdmi_channels = channels; + + /* + * Deroute all the playback streams routed to HDMI so that + * the back end is deactivated. Note that backend will not + * be deactivated if any one stream is connected to it. + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + disable_audio_route(adev, usecase, true); + } + } + + /* + * Enable all the streams disabled above. Now the HDMI backend + * will be activated with new channel configuration + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK && + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + enable_audio_route(adev, usecase, true); + } + } + + return 0; +} + +static int stop_output_stream(struct stream_out *out) +{ + int i, ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = out->dev; + + ALOGV("%s: enter: usecase(%d: %s)", __func__, + out->usecase, use_case_table[out->usecase]); + uc_info = get_usecase_from_list(adev, out->usecase); + if (uc_info == NULL) { + ALOGE("%s: Could not find the usecase (%d) in the list", + __func__, out->usecase); + return -EINVAL; + } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD && + adev->visualizer_stop_output != NULL) + adev->visualizer_stop_output(out->handle); + + /* 1. Get and set stream specific mixer controls */ + disable_audio_route(adev, uc_info, true); + + /* 2. Disable the rx device */ + disable_snd_device(adev, uc_info->out_snd_device, true); + + list_remove(&uc_info->list); + free(uc_info); + + /* Must be called after removing the usecase from list */ + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS); + + ALOGV("%s: exit: status(%d)", __func__, ret); + return ret; +} + +int start_output_stream(struct stream_out *out) +{ + int ret = 0; + struct audio_usecase *uc_info; + struct audio_device *adev = out->dev; + + ALOGV("%s: enter: usecase(%d: %s) devices(%#x)", + __func__, out->usecase, use_case_table[out->usecase], out->devices); + out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); + if (out->pcm_device_id < 0) { + ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", + __func__, out->pcm_device_id, out->usecase); + ret = -EINVAL; + goto error_config; + } + + uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); + uc_info->id = out->usecase; + uc_info->type = PCM_PLAYBACK; + uc_info->stream.out = out; + uc_info->devices = out->devices; + uc_info->in_snd_device = SND_DEVICE_NONE; + uc_info->out_snd_device = SND_DEVICE_NONE; + + /* This must be called before adding this usecase to the list */ + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + check_and_set_hdmi_channels(adev, out->config.channels); + + list_add_tail(&adev->usecase_list, &uc_info->list); + + select_devices(adev, out->usecase); + + ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", + __func__, 0, out->pcm_device_id); + if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { + out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, + PCM_OUT | PCM_MONOTONIC, &out->config); + if (out->pcm && !pcm_is_ready(out->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); + pcm_close(out->pcm); + out->pcm = NULL; + ret = -EIO; + goto error_open; + } + } else { + out->pcm = NULL; + out->compr = compress_open(SOUND_CARD, out->pcm_device_id, + COMPRESS_IN, &out->compr_config); + if (out->compr && !is_compress_ready(out->compr)) { + ALOGE("%s: %s", __func__, compress_get_error(out->compr)); + compress_close(out->compr); + out->compr = NULL; + ret = -EIO; + goto error_open; + } + if (out->offload_callback) + compress_nonblock(out->compr, out->non_blocking); + + if (adev->visualizer_start_output != NULL) + adev->visualizer_start_output(out->handle); + } + ALOGV("%s: exit", __func__); + return 0; +error_open: + stop_output_stream(out); +error_config: + return ret; +} + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->sample_rate; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return -ENOSYS; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + return out->compr_config.fragment_size; + + return out->config.period_size * audio_stream_frame_size(stream); +} + +static uint32_t out_get_channels(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->channel_mask; +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->format; +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + return -ENOSYS; +} + +static int out_standby(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + + ALOGV("%s: enter: usecase(%d: %s)", __func__, + out->usecase, use_case_table[out->usecase]); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + /* Ignore standby in case of voip call because the voip output + * stream is closed in adev_close_output_stream() + */ + ALOGV("%s: Ignore Standby in VOIP call", __func__); + return 0; + } + + pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->lock); + if (!out->standby) { + out->standby = true; + if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->pcm) { + pcm_close(out->pcm); + out->pcm = NULL; + } + } else { + stop_compressed_output_l(out); + out->gapless_mdata.encoder_delay = 0; + out->gapless_mdata.encoder_padding = 0; + if (out->compr != NULL) { + compress_close(out->compr); + out->compr = NULL; + } + } + stop_output_stream(out); + } + pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&out->lock); + ALOGV("%s: exit", __func__); + return 0; +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms) +{ + int ret = 0; + char value[32]; + struct compr_gapless_mdata tmp_mdata; + + if (!out || !parms) { + return -EINVAL; + } + + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value)); + if (ret >= 0) { + tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? + } else { + return -EINVAL; + } + + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); + if (ret >= 0) { + tmp_mdata.encoder_padding = atoi(value); + } else { + return -EINVAL; + } + + out->gapless_mdata = tmp_mdata; + out->send_new_metadata = 1; + ALOGV("%s new encoder delay %u and padding %u", __func__, + out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); + + return 0; +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + struct audio_usecase *usecase; + struct listnode *node; + struct str_parms *parms; + char value[32]; + int ret, val = 0; + bool select_new_device = false; + + ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", + __func__, out->usecase, use_case_table[out->usecase], kvpairs); + parms = str_parms_create_str(kvpairs); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->lock); + + /* + * When HDMI cable is unplugged the music playback is paused and + * the policy manager sends routing=0. But the audioflinger + * continues to write data until standby time (3sec). + * As the HDMI core is turned off, the write gets blocked. + * Avoid this by routing audio to speaker until standby. + */ + if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL && + val == AUDIO_DEVICE_NONE) { + val = AUDIO_DEVICE_OUT_SPEAKER; + } + + /* + * select_devices() call below switches all the usecases on the same + * backend to the new device. Refer to check_usecases_codec_backend() in + * the select_devices(). But how do we undo this? + * + * For example, music playback is active on headset (deep-buffer usecase) + * and if we go to ringtones and select a ringtone, low-latency usecase + * will be started on headset+speaker. As we can't enable headset+speaker + * and headset devices at the same time, select_devices() switches the music + * playback to headset+speaker while starting low-lateny usecase for ringtone. + * So when the ringtone playback is completed, how do we undo the same? + * + * We are relying on the out_set_parameters() call on deep-buffer output, + * once the ringtone playback is ended. + * NOTE: We should not check if the current devices are same as new devices. + * Because select_devices() must be called to switch back the music + * playback to headset. + */ + if (val != 0) { + out->devices = val; + + if (!out->standby) + select_devices(adev, out->usecase); + } + + pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&out->lock); + } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + parse_compress_metadata(out, parms); + } + + str_parms_destroy(parms); + ALOGV("%s: exit: code(%d)", __func__, ret); + return ret; +} + +static char* out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + struct stream_out *out = (struct stream_out *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + size_t i, j; + int ret; + bool first = true; + ALOGV("%s: enter: keys - %s", __func__, keys); + ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value)); + if (ret >= 0) { + value[0] = '\0'; + i = 0; + while (out->supported_channel_masks[i] != 0) { + for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) { + if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) { + if (!first) { + strlcat(value, "|", sizeof(value)); + } + strlcat(value, out_channels_name_to_enum_table[j].name, sizeof(value)); + first = false; + break; + } + } + i++; + } + str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); + str = str_parms_to_str(reply); + } + str_parms_destroy(query); + str_parms_destroy(reply); + ALOGV("%s: exit: returns - %s", __func__, str); + return str; +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; + + return (out->config.period_count * out->config.period_size * 1000) / + (out->config.rate); +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + struct stream_out *out = (struct stream_out *)stream; + int volume[2]; + + if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) { + /* only take left channel into account: the API is for stereo anyway */ + out->muted = (left == 0.0f); + return 0; + } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + const char *mixer_ctl_name = "Compress Playback Volume"; + struct audio_device *adev = out->dev; + struct mixer_ctl *ctl; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX); + volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX); + mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0])); + return 0; + } + + return -ENOSYS; +} + +static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, + size_t bytes) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + ssize_t ret = 0; + + pthread_mutex_lock(&out->lock); + if (out->standby) { + out->standby = false; + pthread_mutex_lock(&adev->lock); + ret = start_output_stream(out); + pthread_mutex_unlock(&adev->lock); + /* ToDo: If use case is compress offload should return 0 */ + if (ret != 0) { + out->standby = true; + goto exit; + } + } + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); + if (out->send_new_metadata) { + ALOGVV("send new gapless metadata"); + compress_set_gapless_metadata(out->compr, &out->gapless_mdata); + out->send_new_metadata = 0; + } + + ret = compress_write(out->compr, buffer, bytes); + ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); + if (ret >= 0 && ret < (ssize_t)bytes) { + send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); + } + if (!out->playback_started) { + compress_start(out->compr); + out->playback_started = 1; + out->offload_state = OFFLOAD_STATE_PLAYING; + } + pthread_mutex_unlock(&out->lock); + return ret; + } else { + if (out->pcm) { + if (out->muted) + memset((void *)buffer, 0, bytes); + ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); + ret = pcm_write(out->pcm, (void *)buffer, bytes); + if (ret == 0) + out->written += bytes / (out->config.channels * sizeof(short)); + } + } + +exit: + pthread_mutex_unlock(&out->lock); + + if (ret != 0) { + if (out->pcm) + ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); + out_standby(&out->stream.common); + usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / + out_get_sample_rate(&out->stream.common)); + } + return bytes; +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + struct stream_out *out = (struct stream_out *)stream; + *dsp_frames = 0; + if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { + pthread_mutex_lock(&out->lock); + if (out->compr != NULL) { + compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %d sample_rate %d", + __func__, *dsp_frames, out->sample_rate); + } + pthread_mutex_unlock(&out->lock); + return 0; + } else + return -EINVAL; +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + return -EINVAL; +} + +static int out_get_presentation_position(const struct audio_stream_out *stream, + uint64_t *frames, struct timespec *timestamp) +{ + struct stream_out *out = (struct stream_out *)stream; + int ret = -1; + unsigned long dsp_frames; + + pthread_mutex_lock(&out->lock); + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->compr != NULL) { + compress_get_tstamp(out->compr, &dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %ld sample_rate %d", + __func__, dsp_frames, out->sample_rate); + *frames = dsp_frames; + ret = 0; + /* this is the best we can do */ + clock_gettime(CLOCK_MONOTONIC, timestamp); + } + } else { + if (out->pcm) { + size_t avail; + if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { + size_t kernel_buffer_size = out->config.period_size * out->config.period_count; + int64_t signed_frames = out->written - kernel_buffer_size + avail; + // This adjustment accounts for buffering after app processor. + // It is based on estimated DSP latency per use case, rather than exact. + signed_frames -= + (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL); + + // It would be unusual for this value to be negative, but check just in case ... + if (signed_frames >= 0) { + *frames = signed_frames; + ret = 0; + } + } + } + } + + pthread_mutex_unlock(&out->lock); + + return ret; +} + +static int out_set_callback(struct audio_stream_out *stream, + stream_callback_t callback, void *cookie) +{ + struct stream_out *out = (struct stream_out *)stream; + + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + out->offload_callback = callback; + out->offload_cookie = cookie; + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int out_pause(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) { + status = compress_pause(out->compr); + out->offload_state = OFFLOAD_STATE_PAUSED; + } + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_resume(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + status = 0; + pthread_mutex_lock(&out->lock); + if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) { + status = compress_resume(out->compr); + out->offload_state = OFFLOAD_STATE_PLAYING; + } + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type ) +{ + struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + if (type == AUDIO_DRAIN_EARLY_NOTIFY) + status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN); + else + status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN); + pthread_mutex_unlock(&out->lock); + } + return status; +} + +static int out_flush(struct audio_stream_out* stream) +{ + struct stream_out *out = (struct stream_out *)stream; + ALOGV("%s", __func__); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); + stop_compressed_output_l(out); + pthread_mutex_unlock(&out->lock); + return 0; + } + return -ENOSYS; +} + +int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_out *out; + int i, ret; + + ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", + __func__, config->sample_rate, config->channel_mask, devices, flags); + *stream_out = NULL; + out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + + if (devices == AUDIO_DEVICE_NONE) + devices = AUDIO_DEVICE_OUT_SPEAKER; + + out->flags = flags; + out->devices = devices; + out->dev = adev; + out->format = config->format; + out->sample_rate = config->sample_rate; + out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; + out->handle = handle; + + /* Init use case and pcm_config */ + if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT && + out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + pthread_mutex_lock(&adev->lock); + ret = read_hdmi_channel_masks(out); + pthread_mutex_unlock(&adev->lock); + if (ret != 0) + goto error_open; + + if (config->sample_rate == 0) + config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; + if (config->channel_mask == 0) + config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1; + + out->channel_mask = config->channel_mask; + out->sample_rate = config->sample_rate; + out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH; + out->config = pcm_config_hdmi_multi; + out->config.rate = config->sample_rate; + out->config.channels = popcount(out->channel_mask); + out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); + } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || + config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { + ALOGE("%s: Unsupported Offload information", __func__); + ret = -EINVAL; + goto error_open; + } + if (!is_supported_format(config->offload_info.format)) { + ALOGE("%s: Unsupported audio format", __func__); + ret = -EINVAL; + goto error_open; + } + + out->compr_config.codec = (struct snd_codec *) + calloc(1, sizeof(struct snd_codec)); + + out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; + if (config->offload_info.channel_mask) + out->channel_mask = config->offload_info.channel_mask; + else if (config->channel_mask) + out->channel_mask = config->channel_mask; + out->format = config->offload_info.format; + out->sample_rate = config->offload_info.sample_rate; + + out->stream.set_callback = out_set_callback; + out->stream.pause = out_pause; + out->stream.resume = out_resume; + out->stream.drain = out_drain; + out->stream.flush = out_flush; + + out->compr_config.codec->id = + get_snd_codec_id(config->offload_info.format); + out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; + out->compr_config.codec->sample_rate = + compress_get_alsa_rate(config->offload_info.sample_rate); + out->compr_config.codec->bit_rate = + config->offload_info.bit_rate; + out->compr_config.codec->ch_in = + popcount(config->channel_mask); + out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + + if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) + out->non_blocking = 1; + + out->send_new_metadata = 1; + create_offload_callback_thread(out); + ALOGV("%s: offloaded output offload_info version %04x bit rate %d", + __func__, config->offload_info.version, + config->offload_info.bit_rate); + } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { + out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; + out->config = pcm_config_low_latency; + out->sample_rate = out->config.rate; + } else { + out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; + out->config = pcm_config_deep_buffer; + out->sample_rate = out->config.rate; + } + + if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { + if(adev->primary_output == NULL) + adev->primary_output = out; + else { + ALOGE("%s: Primary output is already opened", __func__); + ret = -EEXIST; + goto error_open; + } + } + + /* Check if this usecase is already existing */ + pthread_mutex_lock(&adev->lock); + if (get_usecase_from_list(adev, out->usecase) != NULL) { + ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase); + pthread_mutex_unlock(&adev->lock); + ret = -EEXIST; + goto error_open; + } + pthread_mutex_unlock(&adev->lock); + + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + out->stream.get_presentation_position = out_get_presentation_position; + + out->standby = 1; + /* out->muted = false; by calloc() */ + /* out->written = 0; by calloc() */ + + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + + config->format = out->stream.common.get_format(&out->stream.common); + config->channel_mask = out->stream.common.get_channels(&out->stream.common); + config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); + + *stream_out = &out->stream; + ALOGV("%s: exit", __func__); + return 0; + +error_open: + free(out); + *stream_out = NULL; + ALOGD("%s: exit: ret %d", __func__, ret); + return ret; +} + +void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + int ret = 0; + + ALOGV("%s: enter", __func__); + out_standby(&stream->common); + + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + destroy_offload_callback_thread(out); + + if (out->compr_config.codec != NULL) + free(out->compr_config.codec); + } + pthread_cond_destroy(&out->cond); + pthread_mutex_destroy(&out->lock); + free(stream); + ALOGV("%s: exit", __func__); +} -- GitLab From 4e9a903e3f91dd088264bec557d6f61646232ede Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Mon, 18 Nov 2013 16:41:48 +0530 Subject: [PATCH 098/298] mpq8092: Add bitstream files Add bitstream files Change-Id: I002b2fe4249ffc28665b7efc80d9a5d7ad90ea74 --- hal_mpq/Android.mk | 1 + hal_mpq/audio_bitstream_sm.c | 445 +++++++++++++++++++++++++++++++++++ hal_mpq/audio_bitstream_sm.h | 65 +++++ hal_mpq/mpq8092/platform.h | 38 ++- 4 files changed, 545 insertions(+), 4 deletions(-) create mode 100644 hal_mpq/audio_bitstream_sm.c create mode 100644 hal_mpq/audio_bitstream_sm.h diff --git a/hal_mpq/Android.mk b/hal_mpq/Android.mk index 24fca4ea5..683de7a68 100644 --- a/hal_mpq/Android.mk +++ b/hal_mpq/Android.mk @@ -11,6 +11,7 @@ AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM) LOCAL_SRC_FILES := \ audio_hw.c \ audio_stream_out.c \ + audio_bitstream_sm.c \ $(AUDIO_PLATFORM)/hw_info.c \ $(AUDIO_PLATFORM)/platform.c diff --git a/hal_mpq/audio_bitstream_sm.c b/hal_mpq/audio_bitstream_sm.c new file mode 100644 index 000000000..9f2564d22 --- /dev/null +++ b/hal_mpq/audio_bitstream_sm.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "AudioBitstreamStateMachine" +//#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 +#include + +#include +#include "audio_hw.h" +#include "platform_api.h" +#include +// ---------------------------------------------------------------------------- + + +/* +Initialize all input and output pointers +Allocate twice the max buffer size of input and output for sufficient buffering +*/ +int audio_bitstream_init(struct audio_bitstream_sm *bstream, int buffering_factor) +{ + bstream->buffering_factor = buffering_factor; + bstream->buffering_factor_cnt = 0; + + bstream->inp_buf=(char *)malloc(SAMPLES_PER_CHANNEL* + MAX_INPUT_CHANNELS_SUPPORTED* + (bstream->buffering_factor+1)); + // multiplied by 2 to convert to bytes + if(bstream->inp_buf != NULL) { + bstream->inp_buf_curr_ptr = bstream->inp_buf; + bstream->inp_buf_write_ptr = bstream->inp_buf; + } else { + ALOGE("MS11 input buffer not allocated"); + return 0; + } + + bstream->enc_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL* + MAX_INPUT_CHANNELS_SUPPORTED* + FACTOR_FOR_BUFFERING); + if(bstream->enc_out_buf) { + bstream->enc_out_buf_write_ptr = bstream->enc_out_buf; + } else { + ALOGE("MS11 Enc output buffer not allocated"); + return 0; + } + bstream->pcm_2_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL*STEREO_CHANNELS * + FACTOR_FOR_BUFFERING); + if(bstream->pcm_2_out_buf) { + bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf; + } else { + ALOGE("MS11 PCM2Ch output buffer not allocated"); + return 0; + } + bstream->pcm_mch_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL * + MAX_OUTPUT_CHANNELS_SUPPORTED * + FACTOR_FOR_BUFFERING); + if(bstream->pcm_mch_out_buf) { + bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf; + } else { + ALOGE("MS11 PCMMCh output buffer not allocated"); + return 0; + } + bstream->passt_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL * + MAX_INPUT_CHANNELS_SUPPORTED * + FACTOR_FOR_BUFFERING); + if(bstream->passt_out_buf) { + bstream->passt_out_buf_write_ptr = bstream->passt_out_buf; + } else { + ALOGE("MS11 Enc output buffer not allocated"); + return 0; + } + return 1; +} + +/* +Free the allocated memory +*/ +int audio_bitstream_close(struct audio_bitstream_sm *bstream) +{ + if(bstream->inp_buf != NULL) { + free(bstream->inp_buf); + bstream->inp_buf = NULL; + } + if(bstream->enc_out_buf != NULL) { + free(bstream->enc_out_buf); + bstream->enc_out_buf = NULL; + } + if(bstream->pcm_2_out_buf != NULL) { + free(bstream->pcm_2_out_buf); + bstream->pcm_2_out_buf = NULL; + } + if(bstream->pcm_mch_out_buf != NULL) { + free(bstream->pcm_mch_out_buf); + bstream->pcm_mch_out_buf = NULL; + } + if(bstream->passt_out_buf != NULL) { + free(bstream->passt_out_buf); + bstream->passt_out_buf = NULL; + } + bstream->buffering_factor = 1; + bstream->buffering_factor_cnt = 0; + return 0; +} + +/* +Reset the buffer pointers to start for. This will be help in flush and close +*/ +void audio_bitstream_reset_ptr( struct audio_bitstream_sm *bstream) +{ + bstream->inp_buf_curr_ptr = bstream->inp_buf_write_ptr = bstream->inp_buf; + bstream->enc_out_buf_write_ptr = bstream->enc_out_buf; + bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf; + bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf; + bstream->passt_out_buf_write_ptr = bstream->passt_out_buf; + bstream->buffering_factor_cnt = 0; +} + +/* +Reset the output buffer pointers to start for port reconfiguration +*/ +void audio_bitstream_reset_output_bitstream_ptr( + struct audio_bitstream_sm *bstream) +{ + bstream->enc_out_buf_write_ptr = bstream->enc_out_buf; + bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf; + bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf; + bstream->passt_out_buf_write_ptr = bstream->passt_out_buf; +} + +/* +Copy the bitstream/pcm from Player to internal buffer. +The incoming bitstream is appended to existing bitstream +*/ +void audio_bitstream_copy_to_internal_buffer( + struct audio_bitstream_sm *bstream, + char *buf_ptr, size_t bytes) +{ + int32_t bufLen = SAMPLES_PER_CHANNEL*MAX_INPUT_CHANNELS_SUPPORTED*(bstream->buffering_factor+1); + // flush the input buffer if input is not consumed + if( (bstream->inp_buf_write_ptr+bytes) > (bstream->inp_buf+bufLen) ) { + ALOGE("Input bitstream is not consumed"); + return; + } + + memcpy(bstream->inp_buf_write_ptr, buf_ptr, bytes); + bstream->inp_buf_write_ptr += bytes; + if(bstream->buffering_factor_cnt < bstream->buffering_factor) + bstream->buffering_factor_cnt++; +} + +/* +Append zeros to the bitstream, so that the entire bitstream in ADIF is pushed +out for decoding +*/ +void audio_bitstream_append_silence_internal_buffer( + struct audio_bitstream_sm *bstream, + uint32_t bytes, unsigned char value) +{ + int32_t bufLen = SAMPLES_PER_CHANNEL*MAX_INPUT_CHANNELS_SUPPORTED* + (bstream->buffering_factor+1); + uint32_t i = 0; + if( (bstream->inp_buf_write_ptr+bytes) > (bstream->inp_buf+bufLen) ) { + bytes = bufLen + bstream->inp_buf - bstream->inp_buf_write_ptr; + } + for(i=0; i< bytes; i++) + *bstream->inp_buf_write_ptr++ = value; + if(bstream->buffering_factor_cnt < bstream->buffering_factor) + bstream->buffering_factor_cnt++; +} + +/* +Flags if sufficient bitstream is available to proceed to decode based on +the threshold +*/ +int audio_bitstream_sufficient_buffer_to_decode( + struct audio_bitstream_sm *bstream, + int min_bytes_to_decode) +{ + int proceed_decode = 0; + if( (bstream->inp_buf_write_ptr -\ + bstream->inp_buf_curr_ptr) > min_bytes_to_decode) + proceed_decode = 1; + return proceed_decode; +} + +/* +Gets the start address of the bitstream buffer. This is used for start of decode +*/ +char* audio_bitstream_get_input_buffer_ptr( + struct audio_bitstream_sm *bstream) +{ + return bstream->inp_buf_curr_ptr; +} + +/* +Gets the writePtr of the bitstream buffer. This is used for calculating length of +bitstream +*/ +char* audio_bitstream_get_input_buffer_write_ptr( + struct audio_bitstream_sm *bstream) +{ + return bstream->inp_buf_write_ptr; +} + +/* +Get the output buffer start pointer to start rendering the pcm sampled to driver +*/ +char* audio_bitstream_get_output_buffer_ptr( + struct audio_bitstream_sm *bstream, + int format) +{ + switch(format) { + case PCM_MCH_OUT: + return bstream->pcm_mch_out_buf; + case PCM_2CH_OUT: + return bstream->pcm_2_out_buf; + case COMPRESSED_OUT: + return bstream->enc_out_buf; + case TRANSCODE_OUT: + return bstream->passt_out_buf; + default: + return NULL; + } +} + +/* +Output the pointer from where the next PCM samples can be copied to buffer +*/ +char* audio_bitstream_get_output_buffer_write_ptr( + struct audio_bitstream_sm *bstream, + int format) +{ + switch(format) { + case PCM_MCH_OUT: + return bstream->pcm_mch_out_buf_write_ptr; + case PCM_2CH_OUT: + return bstream->pcm_2_out_buf_write_ptr; + case COMPRESSED_OUT: + return bstream->enc_out_buf_write_ptr; + case TRANSCODE_OUT: + return bstream->passt_out_buf_write_ptr; + default: + return NULL; + } +} + +/* +Provides the bitstream size available in the internal buffer +*/ +size_t audio_bitstream_get_size(struct audio_bitstream_sm *bstream) +{ + return (bstream->inp_buf_write_ptr-bstream->inp_buf_curr_ptr); +} + +/* +After decode, the residue bitstream in the buffer is moved to start, so as to +avoid circularity constraints +*/ +void audio_bitstream_copy_residue_to_start( + struct audio_bitstream_sm *bstream, + size_t bytes_consumed_in_decode) +{ + size_t remaining_curr_valid_bytes = bstream->inp_buf_write_ptr - + (bytes_consumed_in_decode+bstream->inp_buf_curr_ptr); + size_t remainingTotalBytes = bstream->inp_buf_write_ptr - + (bytes_consumed_in_decode+bstream->inp_buf); + if(bstream->buffering_factor_cnt == bstream->buffering_factor) { + memcpy(bstream->inp_buf, bstream->inp_buf+bytes_consumed_in_decode, remainingTotalBytes); + bstream->inp_buf_write_ptr = bstream->inp_buf+remainingTotalBytes; + bstream->inp_buf_curr_ptr = bstream->inp_buf_write_ptr-remaining_curr_valid_bytes; + } else { + bstream->inp_buf_curr_ptr += bytes_consumed_in_decode; + } +} + +/* +Remaing samples less than the one period size required for the pcm driver +is moved to start of the buffer +*/ +void audio_bitstream_copy_residue_output_start( + struct audio_bitstream_sm *bstream, + int format, + size_t samplesRendered) +{ + size_t remaining_bytes; + switch(format) { + case PCM_MCH_OUT: + remaining_bytes = bstream->pcm_mch_out_buf_write_ptr-\ + (bstream->pcm_mch_out_buf+samplesRendered); + memcpy(bstream->pcm_mch_out_buf, + bstream->pcm_mch_out_buf+samplesRendered, + remaining_bytes); + bstream->pcm_mch_out_buf_write_ptr = \ + bstream->pcm_mch_out_buf + remaining_bytes; + break; + case PCM_2CH_OUT: + remaining_bytes = bstream->pcm_2_out_buf_write_ptr-\ + (bstream->pcm_2_out_buf+samplesRendered); + memcpy(bstream->pcm_2_out_buf, + bstream->pcm_2_out_buf+samplesRendered, + remaining_bytes); + bstream->pcm_2_out_buf_write_ptr = \ + bstream->pcm_2_out_buf + remaining_bytes; + break; + case COMPRESSED_OUT: + remaining_bytes = bstream->enc_out_buf_write_ptr-\ + (bstream->enc_out_buf+samplesRendered); + memcpy(bstream->enc_out_buf, + bstream->enc_out_buf+samplesRendered, + remaining_bytes); + bstream->enc_out_buf_write_ptr = \ + bstream->enc_out_buf + remaining_bytes; + break; + case TRANSCODE_OUT: + remaining_bytes = bstream->passt_out_buf_write_ptr-\ + (bstream->passt_out_buf+samplesRendered); + memcpy(bstream->passt_out_buf, + bstream->passt_out_buf+samplesRendered, + remaining_bytes); + bstream->passt_out_buf_write_ptr = \ + bstream->passt_out_buf + remaining_bytes; + break; + default: + break; + } +} + +/* +The write pointer is updated after the incoming PCM samples are copied to the +output buffer +*/ +void audio_bitstream_set_output_buffer_write_ptr( + struct audio_bitstream_sm *bstream, + int format, size_t output_pcm_sample) +{ + int alloc_bytes; + switch(format) { + case PCM_MCH_OUT: + alloc_bytes = SAMPLES_PER_CHANNEL*\ + MAX_OUTPUT_CHANNELS_SUPPORTED*FACTOR_FOR_BUFFERING; + if (bstream->pcm_mch_out_buf + alloc_bytes >\ + bstream->pcm_mch_out_buf_write_ptr + output_pcm_sample) + bstream->pcm_mch_out_buf_write_ptr += output_pcm_sample; + break; + case PCM_2CH_OUT: + alloc_bytes = SAMPLES_PER_CHANNEL*STEREO_CHANNELS*FACTOR_FOR_BUFFERING; + if(bstream->pcm_2_out_buf + alloc_bytes > \ + bstream->pcm_2_out_buf_write_ptr + output_pcm_sample) + bstream->pcm_2_out_buf_write_ptr += output_pcm_sample; + break; + case COMPRESSED_OUT: + alloc_bytes = SAMPLES_PER_CHANNEL*\ + MAX_INPUT_CHANNELS_SUPPORTED*FACTOR_FOR_BUFFERING; + if (bstream->enc_out_buf + alloc_bytes > \ + bstream->enc_out_buf_write_ptr + output_pcm_sample) + bstream->enc_out_buf_write_ptr += output_pcm_sample; + break; + case TRANSCODE_OUT: + alloc_bytes = SAMPLES_PER_CHANNEL*\ + MAX_INPUT_CHANNELS_SUPPORTED*FACTOR_FOR_BUFFERING; + if (bstream->passt_out_buf + alloc_bytes > \ + bstream->passt_out_buf_write_ptr + output_pcm_sample) + bstream->passt_out_buf_write_ptr += output_pcm_sample; + break; + default: + break; + } +} + +/* +Flags if sufficient samples are available to render to PCM driver +*/ +int audio_bitstream_sufficient_sample_to_render( + struct audio_bitstream_sm *bstream, + int format, int mid_size_reqd) +{ + int status = 0; + char *buf_ptr = NULL, *buf_write_ptr = NULL; + switch(format) { + case PCM_MCH_OUT: + buf_ptr = bstream->pcm_mch_out_buf; + buf_write_ptr = bstream->pcm_mch_out_buf_write_ptr; + break; + case PCM_2CH_OUT: + buf_ptr = bstream->pcm_2_out_buf; + buf_write_ptr = bstream->pcm_2_out_buf_write_ptr; + break; + case COMPRESSED_OUT: + buf_ptr = bstream->enc_out_buf; + buf_write_ptr = bstream->enc_out_buf_write_ptr; + break; + case TRANSCODE_OUT: + buf_ptr = bstream->passt_out_buf; + buf_write_ptr = bstream->passt_out_buf_write_ptr; + break; + default: + break; + } + if( (buf_write_ptr-buf_ptr) >= mid_size_reqd ) + status = 1; + return status; +} + +void audio_bitstream_start_input_buffering_mode( + struct audio_bitstream_sm *bstream) +{ + bstream->buffering_factor_cnt = 0; +} + +void audio_bitstream_stop_input_buffering_mode( + struct audio_bitstream_sm *bstream) +{ + size_t remaining_curr_valid_bytes = \ + bstream->inp_buf_write_ptr - bstream->inp_buf_curr_ptr; + bstream->buffering_factor_cnt = bstream->buffering_factor; + memcpy(bstream->inp_buf, + bstream->inp_buf_curr_ptr, + remaining_curr_valid_bytes); + bstream->inp_buf_curr_ptr = bstream->inp_buf; + bstream->inp_buf_write_ptr = bstream->inp_buf + remaining_curr_valid_bytes; +} diff --git a/hal_mpq/audio_bitstream_sm.h b/hal_mpq/audio_bitstream_sm.h new file mode 100644 index 000000000..db03bf51d --- /dev/null +++ b/hal_mpq/audio_bitstream_sm.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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. + */ + +#ifndef QCOM_AUDIO_BITSTRM_SM_H +#define QCOM_AUDIO_BITSTRM_SM_H +int audio_bitstream_init(struct audio_bitstream_sm *bstream, int buffering_factor); +int audio_bitstream_close(struct audio_bitstream_sm *bstream); +int audio_bitstream_with_buffering_factor(struct audio_bitstream_sm *bstream, + int in_buffering_factor); +void audio_bitstream_reset_ptr( struct audio_bitstream_sm *bstream); +void audio_bitstream_reset_output_bitstream_ptr( + struct audio_bitstream_sm *bstream); +void audio_bitstream_copy_to_internal_buffer( + struct audio_bitstream_sm *bstream, + char *buf_ptr, size_t bytes); +void audio_bitstream_append_silence_internal_buffer( + struct audio_bitstream_sm *bstream, + uint32_t bytes, unsigned char value); +int audio_bitstream_sufficient_buffer_to_decode( + struct audio_bitstream_sm *bstream, + int min_bytes_to_decode); +char* audio_bitstream_get_input_buffer_ptr( + struct audio_bitstream_sm *bstream); +char* audio_bitstream_get_input_buffer_write_ptr( + struct audio_bitstream_sm *bstream); +char* audio_bitstream_get_output_buffer_ptr( + struct audio_bitstream_sm *bstream, + int format); +char* audio_bitstream_get_output_buffer_write_ptr( + struct audio_bitstream_sm *bstream, + int format); +size_t audio_bitstream_get_size(struct audio_bitstream_sm *bstream); +void audio_bitstream_copy_residue_to_start( + struct audio_bitstream_sm *bstream, + size_t bytes_consumed_in_decode); +void audio_bitstream_copy_residue_output_start( + struct audio_bitstream_sm *bstream, + int format, + size_t samplesRendered); +void audio_bitstream_set_output_buffer_write_ptr( + struct audio_bitstream_sm *bstream, + int format, size_t output_pcm_sample); +int audio_bitstream_sufficient_sample_to_render( + struct audio_bitstream_sm *bstream, + int format, int mid_size_reqd); +void audio_bitstream_start_input_buffering_mode( + struct audio_bitstream_sm *bstream); +void audio_bitstream_stop_input_buffering_mode( + struct audio_bitstream_sm *bstream); +#endif diff --git a/hal_mpq/mpq8092/platform.h b/hal_mpq/mpq8092/platform.h index 3cd56cf4f..7559258a7 100644 --- a/hal_mpq/mpq8092/platform.h +++ b/hal_mpq/mpq8092/platform.h @@ -177,11 +177,7 @@ enum { #define PLAYBACK_OFFLOAD_DEVICE 9 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3 -#ifdef PLATFORM_MSM8610 -#define LOWLATENCY_PCM_DEVICE 12 -#else #define LOWLATENCY_PCM_DEVICE 15 -#endif #define COMPRESS_CAPTURE_DEVICE 19 #ifdef PLATFORM_MSM8x26 @@ -239,4 +235,38 @@ void hw_info_deinit(void *hw_info); void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, char *device_name); +#define SAMPLES_PER_CHANNEL 1536*2 +#define MAX_INPUT_CHANNELS_SUPPORTED 8 +#define FACTOR_FOR_BUFFERING 2 +#define STEREO_CHANNELS 2 +#define MAX_OUTPUT_CHANNELS_SUPPORTED 8 + +#define PCM_2CH_OUT 0 +#define PCM_MCH_OUT 1 +#define SPDIF_OUT 2 +#define COMPRESSED_OUT 2 // should be same as SPDIF_OUT +#define TRANSCODE_OUT 3 +#define FACTOR_FOR_BUFFERING 2 + +struct audio_bitstream_sm { + int buffering_factor; + int buffering_factor_cnt; + // Buffer pointers for input and output + char *inp_buf; + char *inp_buf_curr_ptr; + char *inp_buf_write_ptr; + + char *enc_out_buf; + char *enc_out_buf_write_ptr; + + char *pcm_2_out_buf; + char *pcm_2_out_buf_write_ptr; + + char *pcm_mch_out_buf; + char *pcm_mch_out_buf_write_ptr; + + char *passt_out_buf; + char *passt_out_buf_write_ptr; +}; + #endif // QCOM_AUDIO_PLATFORM_H -- GitLab From 3eedc004e9adf5967f393d65c22b7806d0c63e6c Mon Sep 17 00:00:00 2001 From: Subhash Chandra Bose Naripeddy Date: Tue, 12 Nov 2013 20:45:15 -0800 Subject: [PATCH 099/298] post_proc: Support effects in DSP for tunnel mode playback Add interface to support configuring equlaizer, bass boost, virtualizer and reverb effects in DSP for tunnel mode of playback. Change-Id: I9a93ad6136c4de06df5136967908b4e888dae44f --- Android.mk | 1 + post_proc/Android.mk | 31 ++ post_proc/bass_boost.c | 252 ++++++++++++++ post_proc/bass_boost.h | 59 ++++ post_proc/bundle.c | 755 ++++++++++++++++++++++++++++++++++++++++ post_proc/bundle.h | 90 +++++ post_proc/effect_api.c | 612 ++++++++++++++++++++++++++++++++ post_proc/effect_api.h | 151 ++++++++ post_proc/equalizer.c | 504 +++++++++++++++++++++++++++ post_proc/equalizer.h | 63 ++++ post_proc/reverb.c | 612 ++++++++++++++++++++++++++++++++ post_proc/reverb.h | 84 +++++ post_proc/virtualizer.c | 250 +++++++++++++ post_proc/virtualizer.h | 59 ++++ 14 files changed, 3523 insertions(+) create mode 100644 post_proc/Android.mk create mode 100644 post_proc/bass_boost.c create mode 100644 post_proc/bass_boost.h create mode 100644 post_proc/bundle.c create mode 100644 post_proc/bundle.h create mode 100644 post_proc/effect_api.c create mode 100644 post_proc/effect_api.h create mode 100644 post_proc/equalizer.c create mode 100644 post_proc/equalizer.h create mode 100644 post_proc/reverb.c create mode 100644 post_proc/reverb.h create mode 100644 post_proc/virtualizer.c create mode 100644 post_proc/virtualizer.h diff --git a/Android.mk b/Android.mk index 0e94762bc..424bbe192 100644 --- a/Android.mk +++ b/Android.mk @@ -11,6 +11,7 @@ include $(MY_LOCAL_PATH)/mm-audio/Android.mk include $(MY_LOCAL_PATH)/policy_hal/Android.mk include $(MY_LOCAL_PATH)/visualizer/Android.mk include $(MY_LOCAL_PATH)/audiod/Android.mk +include $(MY_LOCAL_PATH)/post_proc/Android.mk endif endif diff --git a/post_proc/Android.mk b/post_proc/Android.mk new file mode 100644 index 000000000..b6966e669 --- /dev/null +++ b/post_proc/Android.mk @@ -0,0 +1,31 @@ + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + bundle.c \ + equalizer.c \ + bass_boost.c \ + virtualizer.c \ + reverb.c \ + effect_api.c + +LOCAL_CFLAGS+= -O2 -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libtinyalsa + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx +LOCAL_MODULE:= libqcompostprocbundle + +LOCAL_C_INCLUDES := \ + external/tinyalsa/include \ + kernel/include/sound \ + $(call include-path-for, audio-effects) + +include $(BUILD_SHARED_LIBRARY) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c new file mode 100644 index 000000000..c64ba6bc4 --- /dev/null +++ b/post_proc/bass_boost.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "offload_effect_bass_boost" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +#include "effect_api.h" +#include "bass_boost.h" + +/* Offload bassboost UUID: 2c4a8c24-1581-487f-94f6-0002a5d5c51b */ +const effect_descriptor_t bassboost_descriptor = { + {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, + {0x2c4a8c24, 0x1581, 0x487f, 0x94f6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload bassboost", + "The Android Open Source Project", +}; + +/* + * Bassboost operations + */ + +int bassboost_get_strength(bassboost_context_t *context) +{ + ALOGV("%s: strength: %d", __func__, context->strength); + return context->strength; +} + +int bassboost_set_strength(bassboost_context_t *context, uint32_t strength) +{ + ALOGV("%s: strength: %d", __func__, strength); + context->strength = strength; + + offload_bassboost_set_strength(&(context->offload_bass), strength); + if (context->ctl) + offload_bassboost_send_params(context->ctl, context->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + return 0; +} + +int bassboost_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + void *value = p->data + voffset; + int i; + + ALOGV("%s", __func__); + + p->status = 0; + + switch (param) { + case BASSBOOST_PARAM_STRENGTH_SUPPORTED: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case BASSBOOST_PARAM_STRENGTH: + if (p->vsize < sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = sizeof(int16_t); + break; + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case BASSBOOST_PARAM_STRENGTH_SUPPORTED: + ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__); + *(uint32_t *)value = 1; + break; + + case BASSBOOST_PARAM_STRENGTH: + ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__); + *(int16_t *)value = bassboost_get_strength(bass_ctxt); + break; + + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int bassboost_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + uint32_t strength; + + ALOGV("%s", __func__); + + p->status = 0; + + switch (param) { + case BASSBOOST_PARAM_STRENGTH: + ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__); + strength = (uint32_t)(*(int16_t *)value); + bassboost_set_strength(bass_ctxt, strength); + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int bassboost_set_device(effect_context_t *context, uint32_t device) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: device: %d", __func__, device); + bass_ctxt->device = device; + if((device == AUDIO_DEVICE_OUT_SPEAKER) || + (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || + (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) { + if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); + bass_ctxt->temp_disabled = true; + } + } else { + if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) && + bass_ctxt->temp_disabled) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); + bass_ctxt->temp_disabled = false; + } + } + offload_bassboost_set_device(&(bass_ctxt->offload_bass), device); + return 0; +} + +int bassboost_reset(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + return 0; +} + +int bassboost_init(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s", __func__); + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + bass_ctxt->temp_disabled = false; + memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params)); + + return 0; +} + +int bassboost_enable(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s", __func__); + + if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); + return 0; +} + +int bassboost_disable(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s", __func__); + if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); + } + return 0; +} + +int bassboost_start(effect_context_t *context, output_context_t *output) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s", __func__); + bass_ctxt->ctl = output->ctl; + ALOGV("output->ctl: %p", output->ctl); + return 0; +} + +int bassboost_stop(effect_context_t *context, output_context_t *output) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s", __func__); + bass_ctxt->ctl = NULL; + return 0; +} diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h new file mode 100644 index 000000000..430a07db9 --- /dev/null +++ b/post_proc/bass_boost.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef OFFLOAD_EFFECT_BASS_BOOST_H_ +#define OFFLOAD_EFFECT_BASS_BOOST_H_ + +#include "bundle.h" + +extern const effect_descriptor_t bassboost_descriptor; + +typedef struct bassboost_context_s { + effect_context_t common; + + int strength; + + // Offload vars + struct mixer_ctl *ctl; + bool temp_disabled; + uint32_t device; + struct bass_boost_params offload_bass; +} bassboost_context_t; + +int bassboost_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int bassboost_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int bassboost_set_device(effect_context_t *context, uint32_t device); + +int bassboost_reset(effect_context_t *context); + +int bassboost_init(effect_context_t *context); + +int bassboost_enable(effect_context_t *context); + +int bassboost_disable(effect_context_t *context); + +int bassboost_start(effect_context_t *context, output_context_t *output); + +int bassboost_stop(effect_context_t *context, output_context_t *output); + +#endif /* OFFLOAD_EFFECT_BASS_BOOST_H_ */ diff --git a/post_proc/bundle.c b/post_proc/bundle.c new file mode 100644 index 000000000..8e2bce8de --- /dev/null +++ b/post_proc/bundle.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "offload_effect_bundle" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +#include "bundle.h" +#include "equalizer.h" +#include "bass_boost.h" +#include "virtualizer.h" +#include "reverb.h" + +enum { + EFFECT_STATE_UNINITIALIZED, + EFFECT_STATE_INITIALIZED, + EFFECT_STATE_ACTIVE, +}; + +const effect_descriptor_t *descriptors[] = { + &equalizer_descriptor, + &bassboost_descriptor, + &virtualizer_descriptor, + &aux_env_reverb_descriptor, + &ins_env_reverb_descriptor, + &aux_preset_reverb_descriptor, + &ins_preset_reverb_descriptor, + NULL, +}; + +pthread_once_t once = PTHREAD_ONCE_INIT; +int init_status; +/* + * list of created effects. + * Updated by offload_effects_bundle_hal_start_output() + * and offload_effects_bundle_hal_stop_output() + */ +struct listnode created_effects_list; +/* + * list of active output streams. + * Updated by offload_effects_bundle_hal_start_output() + * and offload_effects_bundle_hal_stop_output() + */ +struct listnode active_outputs_list; +/* + * lock must be held when modifying or accessing + * created_effects_list or active_outputs_list + */ +pthread_mutex_t lock; + + +/* + * Local functions + */ +static void init_once() { + list_init(&created_effects_list); + list_init(&active_outputs_list); + + pthread_mutex_init(&lock, NULL); + + init_status = 0; +} + +int lib_init() +{ + pthread_once(&once, init_once); + return init_status; +} + +bool effect_exists(effect_context_t *context) +{ + struct listnode *node; + + list_for_each(node, &created_effects_list) { + effect_context_t *fx_ctxt = node_to_item(node, + effect_context_t, + effects_list_node); + if (fx_ctxt == context) { + return true; + } + } + return false; +} + +output_context_t *get_output(audio_io_handle_t output) +{ + struct listnode *node; + + list_for_each(node, &active_outputs_list) { + output_context_t *out_ctxt = node_to_item(node, + output_context_t, + outputs_list_node); + if (out_ctxt->handle == output) + return out_ctxt; + } + return NULL; +} + +void add_effect_to_output(output_context_t * output, effect_context_t *context) +{ + struct listnode *fx_node; + + list_for_each(fx_node, &output->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt == context) + return; + } + list_add_tail(&output->effects_list, &context->output_node); + if (context->ops.start) + context->ops.start(context, output); + +} + +void remove_effect_from_output(output_context_t * output, + effect_context_t *context) +{ + struct listnode *fx_node; + + list_for_each(fx_node, &output->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt == context) { + if (context->ops.stop) + context->ops.stop(context, output); + list_remove(&context->output_node); + return; + } + } +} + +bool effects_enabled() +{ + struct listnode *out_node; + + list_for_each(out_node, &active_outputs_list) { + struct listnode *fx_node; + output_context_t *out_ctxt = node_to_item(out_node, + output_context_t, + outputs_list_node); + + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) && + (fx_ctxt->ops.process != NULL)) + return true; + } + } + return false; +} + + +/* + * Interface from audio HAL + */ +__attribute__ ((visibility ("default"))) +int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id) +{ + int ret = 0; + struct listnode *node; + char mixer_string[128]; + + ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); + + if (lib_init() != 0) + return init_status; + + pthread_mutex_lock(&lock); + if (get_output(output) != NULL) { + ALOGW("%s output already started", __func__); + ret = -ENOSYS; + goto exit; + } + + output_context_t *out_ctxt = (output_context_t *) + malloc(sizeof(output_context_t)); + out_ctxt->handle = output; + out_ctxt->pcm_device_id = pcm_id; + + /* populate the mixer control to send offload parameters */ + snprintf(mixer_string, sizeof(mixer_string), + "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id); + out_ctxt->mixer = mixer_open(MIXER_CARD); + if (!out_ctxt->mixer) { + ALOGE("Failed to open mixer"); + out_ctxt->ctl = NULL; + ret = -EINVAL; + goto exit; + } else { + out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string); + if (!out_ctxt->ctl) { + ALOGE("mixer_get_ctl_by_name failed"); + mixer_close(out_ctxt->mixer); + out_ctxt->mixer = NULL; + ret = -EINVAL; + goto exit; + } + } + + list_init(&out_ctxt->effects_list); + + list_for_each(node, &created_effects_list) { + effect_context_t *fx_ctxt = node_to_item(node, + effect_context_t, + effects_list_node); + if (fx_ctxt->out_handle == output) { + if (fx_ctxt->ops.start) + fx_ctxt->ops.start(fx_ctxt, out_ctxt); + list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node); + } + } + list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node); +exit: + pthread_mutex_unlock(&lock); + return ret; +} + +__attribute__ ((visibility ("default"))) +int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id) +{ + int ret; + struct listnode *node; + struct listnode *fx_node; + output_context_t *out_ctxt; + + ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); + + if (lib_init() != 0) + return init_status; + + pthread_mutex_lock(&lock); + + out_ctxt = get_output(output); + if (out_ctxt == NULL) { + ALOGW("%s output not started", __func__); + ret = -ENOSYS; + goto exit; + } + + if (out_ctxt->mixer) + mixer_close(out_ctxt->mixer); + + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt->ops.stop) + fx_ctxt->ops.stop(fx_ctxt, out_ctxt); + } + + list_remove(&out_ctxt->outputs_list_node); + + free(out_ctxt); + +exit: + pthread_mutex_unlock(&lock); + return ret; +} + + +/* + * Effect operations + */ +int set_config(effect_context_t *context, effect_config_t *config) +{ + context->config = *config; + + if (context->ops.reset) + context->ops.reset(context); + + return 0; +} + +void get_config(effect_context_t *context, effect_config_t *config) +{ + *config = context->config; +} + + +/* + * Effect Library Interface Implementation + */ +int effect_lib_create(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle) { + int ret; + int i; + + ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId); + if (lib_init() != 0) + return init_status; + + if (pHandle == NULL || uuid == NULL) + return -EINVAL; + + for (i = 0; descriptors[i] != NULL; i++) { + if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) + break; + } + + if (descriptors[i] == NULL) + return -EINVAL; + + effect_context_t *context; + if (memcmp(uuid, &equalizer_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + equalizer_context_t *eq_ctxt = (equalizer_context_t *) + calloc(1, sizeof(equalizer_context_t)); + context = (effect_context_t *)eq_ctxt; + context->ops.init = equalizer_init; + context->ops.reset = equalizer_reset; + context->ops.set_parameter = equalizer_set_parameter; + context->ops.get_parameter = equalizer_get_parameter; + context->ops.set_device = equalizer_set_device; + context->ops.enable = equalizer_enable; + context->ops.disable = equalizer_disable; + context->ops.start = equalizer_start; + context->ops.stop = equalizer_stop; + + context->desc = &equalizer_descriptor; + eq_ctxt->ctl = NULL; + } else if (memcmp(uuid, &bassboost_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + bassboost_context_t *bass_ctxt = (bassboost_context_t *) + calloc(1, sizeof(bassboost_context_t)); + context = (effect_context_t *)bass_ctxt; + context->ops.init = bassboost_init; + context->ops.reset = bassboost_reset; + context->ops.set_parameter = bassboost_set_parameter; + context->ops.get_parameter = bassboost_get_parameter; + context->ops.set_device = bassboost_set_device; + context->ops.enable = bassboost_enable; + context->ops.disable = bassboost_disable; + context->ops.start = bassboost_start; + context->ops.stop = bassboost_stop; + + context->desc = &bassboost_descriptor; + bass_ctxt->ctl = NULL; + } else if (memcmp(uuid, &virtualizer_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *) + calloc(1, sizeof(virtualizer_context_t)); + context = (effect_context_t *)virt_ctxt; + context->ops.init = virtualizer_init; + context->ops.reset = virtualizer_reset; + context->ops.set_parameter = virtualizer_set_parameter; + context->ops.get_parameter = virtualizer_get_parameter; + context->ops.set_device = virtualizer_set_device; + context->ops.enable = virtualizer_enable; + context->ops.disable = virtualizer_disable; + context->ops.start = virtualizer_start; + context->ops.stop = virtualizer_stop; + + context->desc = &virtualizer_descriptor; + virt_ctxt->ctl = NULL; + } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) || + (memcmp(uuid, &ins_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) || + (memcmp(uuid, &aux_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) || + (memcmp(uuid, &ins_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0)) { + reverb_context_t *reverb_ctxt = (reverb_context_t *) + calloc(1, sizeof(reverb_context_t)); + context = (effect_context_t *)reverb_ctxt; + context->ops.init = reverb_init; + context->ops.reset = reverb_reset; + context->ops.set_parameter = reverb_set_parameter; + context->ops.get_parameter = reverb_get_parameter; + context->ops.set_device = reverb_set_device; + context->ops.enable = reverb_enable; + context->ops.disable = reverb_disable; + context->ops.start = reverb_start; + context->ops.stop = reverb_stop; + + if (memcmp(uuid, &aux_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &aux_env_reverb_descriptor; + reverb_auxiliary_init(reverb_ctxt); + } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &ins_env_reverb_descriptor; + reverb_preset_init(reverb_ctxt); + } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &aux_preset_reverb_descriptor; + reverb_auxiliary_init(reverb_ctxt); + } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &ins_preset_reverb_descriptor; + reverb_preset_init(reverb_ctxt); + } + reverb_ctxt->ctl = NULL; + } else { + return -EINVAL; + } + + context->itfe = &effect_interface; + context->state = EFFECT_STATE_UNINITIALIZED; + context->out_handle = (audio_io_handle_t)ioId; + + ret = context->ops.init(context); + if (ret < 0) { + ALOGW("%s init failed", __func__); + free(context); + return ret; + } + + context->state = EFFECT_STATE_INITIALIZED; + + pthread_mutex_lock(&lock); + list_add_tail(&created_effects_list, &context->effects_list_node); + output_context_t *out_ctxt = get_output(ioId); + if (out_ctxt != NULL) + add_effect_to_output(out_ctxt, context); + pthread_mutex_unlock(&lock); + + *pHandle = (effect_handle_t)context; + + ALOGV("%s created context %p", __func__, context); + + return 0; + +} + +int effect_lib_release(effect_handle_t handle) +{ + effect_context_t *context = (effect_context_t *)handle; + int status; + + if (lib_init() != 0) + return init_status; + + ALOGV("%s context %p", __func__, handle); + pthread_mutex_lock(&lock); + status = -EINVAL; + if (effect_exists(context)) { + output_context_t *out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + remove_effect_from_output(out_ctxt, context); + list_remove(&context->effects_list_node); + if (context->ops.release) + context->ops.release(context); + free(context); + status = 0; + } + pthread_mutex_unlock(&lock); + + return status; +} + +int effect_lib_get_descriptor(const effect_uuid_t *uuid, + effect_descriptor_t *descriptor) +{ + int i; + + if (lib_init() != 0) + return init_status; + + if (descriptor == NULL || uuid == NULL) { + ALOGV("%s called with NULL pointer", __func__); + return -EINVAL; + } + + for (i = 0; descriptors[i] != NULL; i++) { + if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) { + *descriptor = *descriptors[i]; + return 0; + } + } + + return -EINVAL; +} + + +/* + * Effect Control Interface Implementation + */ + +/* Stub function for effect interface: never called for offloaded effects */ +int effect_process(effect_handle_t self, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer) +{ + effect_context_t * context = (effect_context_t *)self; + int status = 0; + + ALOGW("%s Called ?????", __func__); + + pthread_mutex_lock(&lock); + if (!effect_exists(context)) { + status = -EINVAL; + goto exit; + } + + if (context->state != EFFECT_STATE_ACTIVE) { + status = -EINVAL; + goto exit; + } + +exit: + pthread_mutex_unlock(&lock); + return status; +} + +int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData) +{ + + effect_context_t * context = (effect_context_t *)self; + int retsize; + int status = 0; + + pthread_mutex_lock(&lock); + + if (!effect_exists(context)) { + status = -EINVAL; + goto exit; + } + + if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) { + status = -EINVAL; + goto exit; + } + + switch (cmdCode) { + case EFFECT_CMD_INIT: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->ops.init) + *(int *) pReplyData = context->ops.init(context); + else + *(int *) pReplyData = 0; + break; + case EFFECT_CMD_SET_CONFIG: + if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) + || pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData); + break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + status = -EINVAL; + goto exit; + } + if (!context->offload_enabled) { + status = -EINVAL; + goto exit; + } + + get_config(context, (effect_config_t *)pReplyData); + break; + case EFFECT_CMD_RESET: + if (context->ops.reset) + context->ops.reset(context); + break; + case EFFECT_CMD_ENABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->state != EFFECT_STATE_INITIALIZED) { + status = -ENOSYS; + goto exit; + } + context->state = EFFECT_STATE_ACTIVE; + if (context->ops.enable) + context->ops.enable(context); + ALOGV("%s EFFECT_CMD_ENABLE", __func__); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_DISABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->state != EFFECT_STATE_ACTIVE) { + status = -ENOSYS; + goto exit; + } + context->state = EFFECT_STATE_INITIALIZED; + if (context->ops.disable) + context->ops.disable(context); + ALOGV("%s EFFECT_CMD_DISABLE", __func__); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_GET_PARAM: { + if (pCmdData == NULL || + cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || + pReplyData == NULL || + *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + + sizeof(uint16_t))) { + status = -EINVAL; + ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d", + cmdSize, *replySize); + goto exit; + } + if (!context->offload_enabled) { + status = -EINVAL; + goto exit; + } + effect_param_t *q = (effect_param_t *)pCmdData; + memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize); + effect_param_t *p = (effect_param_t *)pReplyData; + if (context->ops.get_parameter) + context->ops.get_parameter(context, p, replySize); + } break; + case EFFECT_CMD_SET_PARAM: { + if (pCmdData == NULL || + cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + + sizeof(uint16_t)) || + pReplyData == NULL || *replySize != sizeof(int32_t)) { + status = -EINVAL; + ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d", + cmdSize, *replySize); + goto exit; + } + *(int32_t *)pReplyData = 0; + effect_param_t *p = (effect_param_t *)pCmdData; + if (context->ops.set_parameter) + *(int32_t *)pReplyData = context->ops.set_parameter(context, p, + *replySize); + + } break; + case EFFECT_CMD_SET_DEVICE: { + uint32_t device; + ALOGV("\t EFFECT_CMD_SET_DEVICE start"); + if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) { + status = -EINVAL; + ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize); + goto exit; + } + device = *(uint32_t *)pCmdData; + if (context->ops.set_device) + context->ops.set_device(context, device); + } break; + case EFFECT_CMD_SET_VOLUME: + case EFFECT_CMD_SET_AUDIO_MODE: + break; + + case EFFECT_CMD_OFFLOAD: { + output_context_t *out_ctxt; + + if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL + || pReplyData == NULL || *replySize != sizeof(int)) { + ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__); + status = -EINVAL; + break; + } + + effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData; + + ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__, + offload_param->isOffload, offload_param->ioHandle); + + *(int *)pReplyData = 0; + + context->offload_enabled = offload_param->isOffload; + if (context->out_handle == offload_param->ioHandle) + break; + + out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + remove_effect_from_output(out_ctxt, context); + + context->out_handle = offload_param->ioHandle; + out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + add_effect_to_output(out_ctxt, context); + + } break; + + + default: + if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command) + status = context->ops.command(context, cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + else { + ALOGW("%s invalid command %d", __func__, cmdCode); + status = -EINVAL; + } + break; + } + +exit: + pthread_mutex_unlock(&lock); + + return status; +} + +/* Effect Control Interface Implementation: get_descriptor */ +int effect_get_descriptor(effect_handle_t self, + effect_descriptor_t *descriptor) +{ + effect_context_t *context = (effect_context_t *)self; + + if (!effect_exists(context) || (descriptor == NULL)) + return -EINVAL; + + *descriptor = *context->desc; + + return 0; +} + + +/* effect_handle_t interface implementation for offload effects */ +const struct effect_interface_s effect_interface = { + effect_process, + effect_command, + effect_get_descriptor, + NULL, +}; + +__attribute__ ((visibility ("default"))) +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Offload Effects Bundle Library", + implementor : "The Linux Foundation", + create_effect : effect_lib_create, + release_effect : effect_lib_release, + get_descriptor : effect_lib_get_descriptor, +}; diff --git a/post_proc/bundle.h b/post_proc/bundle.h new file mode 100644 index 000000000..a8e0f932f --- /dev/null +++ b/post_proc/bundle.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef OFFLOAD_EFFECT_BUNDLE_H +#define OFFLOAD_EFFECT_BUNDLE_H + +#include +#include +#include "effect_api.h" + +/* Retry for delay for mixer open */ +#define RETRY_NUMBER 10 +#define RETRY_US 500000 + +#define MIXER_CARD 0 +#define SOUND_CARD 0 + +extern const struct effect_interface_s effect_interface; + +typedef struct output_context_s output_context_t; +typedef struct effect_ops_s effect_ops_t; +typedef struct effect_context_s effect_context_t; + +struct output_context_s { + /* node in active_outputs_list */ + struct listnode outputs_list_node; + /* io handle */ + audio_io_handle_t handle; + /* list of effects attached to this output */ + struct listnode effects_list; + /* pcm device id */ + int pcm_device_id; + struct mixer *mixer; + struct mixer_ctl *ctl; +}; + +/* effect specific operations. + * Only the init() and process() operations must be defined. + * Others are optional. + */ +struct effect_ops_s { + int (*init)(effect_context_t *context); + int (*release)(effect_context_t *context); + int (*reset)(effect_context_t *context); + int (*enable)(effect_context_t *context); + int (*start)(effect_context_t *context, output_context_t *output); + int (*stop)(effect_context_t *context, output_context_t *output); + int (*disable)(effect_context_t *context); + int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out); + int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size); + int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size); + int (*set_device)(effect_context_t *context, uint32_t device); + int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData); +}; + +struct effect_context_s { + const struct effect_interface_s *itfe; + /* node in created_effects_list */ + struct listnode effects_list_node; + /* node in output_context_t.effects_list */ + struct listnode output_node; + effect_config_t config; + const effect_descriptor_t *desc; + /* io handle of the output the effect is attached to */ + audio_io_handle_t out_handle; + uint32_t state; + bool offload_enabled; + effect_ops_t ops; +}; + +int set_config(effect_context_t *context, effect_config_t *config); + +#endif /* OFFLOAD_EFFECT_BUNDLE_H */ diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c new file mode 100644 index 000000000..a2e4f45fe --- /dev/null +++ b/post_proc/effect_api.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "offload_effect_api" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include + +#include "effect_api.h" + +#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +#define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19 +const int map_eq_opensl_preset_2_offload_preset[] = { + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL, /* Normal Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+1, /* Classical Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+2, /* Dance Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+3, /* Flat Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+4, /* Folk Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+5, /* Heavy Metal Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+6, /* Hip Hop Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+7, /* Jazz Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+8, /* Pop Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+9, /* Rock Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+10 /* FX Booster */ +}; + +const int map_reverb_opensl_preset_2_offload_preset + [NUM_OSL_REVERB_PRESETS_SUPPORTED][2] = { + {1, 15}, + {2, 16}, + {3, 17}, + {4, 18}, + {5, 3}, + {6, 20} +}; + +int offload_update_mixer_and_effects_ctl(int card, int device_id, + struct mixer *mixer, + struct mixer_ctl *ctl) +{ + char mixer_string[128]; + + snprintf(mixer_string, sizeof(mixer_string), + "%s %d", "Audio Effects Config", device_id); + ALOGV("%s: mixer_string: %s", __func__, mixer_string); + mixer = mixer_open(card); + if (!mixer) { + ALOGE("Failed to open mixer"); + ctl = NULL; + return -EINVAL; + } else { + ctl = mixer_get_ctl_by_name(mixer, mixer_string); + if (!ctl) { + ALOGE("mixer_get_ctl_by_name failed"); + mixer_close(mixer); + mixer = NULL; + return -EINVAL; + } + } + ALOGV("mixer: %p, ctl: %p", mixer, ctl); + return 0; +} + +void offload_close_mixer(struct mixer *mixer) +{ + mixer_close(mixer); +} + +void offload_bassboost_set_device(struct bass_boost_params *bassboost, + uint32_t device) +{ + ALOGV("%s", __func__); + bassboost->device = device; +} + +void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost, + bool enable) +{ + ALOGV("%s", __func__); + bassboost->enable_flag = enable; +} + +int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost) +{ + ALOGV("%s", __func__); + return bassboost->enable_flag; +} + +void offload_bassboost_set_strength(struct bass_boost_params *bassboost, + int strength) +{ + ALOGV("%s", __func__); + bassboost->strength = strength; +} + +void offload_bassboost_set_mode(struct bass_boost_params *bassboost, + int mode) +{ + ALOGV("%s", __func__); + bassboost->mode = mode; +} + +int offload_bassboost_send_params(struct mixer_ctl *ctl, + struct bass_boost_params bassboost, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + + ALOGV("%s", __func__); + *p_param_values++ = BASS_BOOST_MODULE; + *p_param_values++ = bassboost.device; + *p_param_values++ = 0; /* num of commands*/ + if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) { + *p_param_values++ = BASS_BOOST_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN; + *p_param_values++ = bassboost.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) { + *p_param_values++ = BASS_BOOST_STRENGTH; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN; + *p_param_values++ = bassboost.strength; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) { + *p_param_values++ = BASS_BOOST_MODE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN; + *p_param_values++ = bassboost.mode; + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} + +void offload_virtualizer_set_device(struct virtualizer_params *virtualizer, + uint32_t device) +{ + ALOGV("%s", __func__); + virtualizer->device = device; +} + +void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer, + bool enable) +{ + ALOGV("%s", __func__); + virtualizer->enable_flag = enable; +} + +int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer) +{ + ALOGV("%s", __func__); + return virtualizer->enable_flag; +} + +void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer, + int strength) +{ + ALOGV("%s", __func__); + virtualizer->strength = strength; +} + +void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer, + int out_type) +{ + ALOGV("%s", __func__); + virtualizer->out_type = out_type; +} + +void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer, + int gain_adjust) +{ + ALOGV("%s", __func__); + virtualizer->gain_adjust = gain_adjust; +} + +int offload_virtualizer_send_params(struct mixer_ctl *ctl, + struct virtualizer_params virtualizer, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + + ALOGV("%s", __func__); + *p_param_values++ = VIRTUALIZER_MODULE; + *p_param_values++ = virtualizer.device; + *p_param_values++ = 0; /* num of commands*/ + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) { + *p_param_values++ = VIRTUALIZER_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN; + *p_param_values++ = virtualizer.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) { + *p_param_values++ = VIRTUALIZER_STRENGTH; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN; + *p_param_values++ = virtualizer.strength; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) { + *p_param_values++ = VIRTUALIZER_OUT_TYPE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN; + *p_param_values++ = virtualizer.out_type; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) { + *p_param_values++ = VIRTUALIZER_GAIN_ADJUST; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN; + *p_param_values++ = virtualizer.gain_adjust; + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} + +void offload_eq_set_device(struct eq_params *eq, uint32_t device) +{ + ALOGV("%s", __func__); + eq->device = device; +} + +void offload_eq_set_enable_flag(struct eq_params *eq, bool enable) +{ + ALOGV("%s", __func__); + eq->enable_flag = enable; +} + +int offload_eq_get_enable_flag(struct eq_params *eq) +{ + ALOGV("%s", __func__); + return eq->enable_flag; +} + +void offload_eq_set_preset(struct eq_params *eq, int preset) +{ + ALOGV("%s", __func__); + eq->config.preset_id = preset; + eq->config.eq_pregain = Q27_UNITY; +} + +void offload_eq_set_bands_level(struct eq_params *eq, int num_bands, + const uint16_t *band_freq_list, + int *band_gain_list) +{ + int i; + ALOGV("%s", __func__); + eq->config.num_bands = num_bands; + for (i=0; iper_band_cfg[i].band_idx = i; + eq->per_band_cfg[i].filter_type = EQ_BAND_BOOST; + eq->per_band_cfg[i].freq_millihertz = band_freq_list[i] * 1000; + eq->per_band_cfg[i].gain_millibels = band_gain_list[i] * 100; + eq->per_band_cfg[i].quality_factor = Q8_UNITY; + } +} + +int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + uint32_t i; + + ALOGV("%s", __func__); + if (eq.config.preset_id < -1 ) { + ALOGV("No Valid preset to set"); + return 0; + } + *p_param_values++ = EQ_MODULE; + *p_param_values++ = eq.device; + *p_param_values++ = 0; /* num of commands*/ + if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) { + *p_param_values++ = EQ_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = EQ_ENABLE_PARAM_LEN; + *p_param_values++ = eq.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) { + *p_param_values++ = EQ_CONFIG; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = EQ_CONFIG_PARAM_LEN; + *p_param_values++ = eq.config.eq_pregain; + *p_param_values++ = + map_eq_opensl_preset_2_offload_preset[eq.config.preset_id]; + *p_param_values++ = 0; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_EQ_BANDS_LEVEL) { + *p_param_values++ = EQ_CONFIG; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = EQ_CONFIG_PARAM_LEN + + eq.config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN; + *p_param_values++ = eq.config.eq_pregain; + *p_param_values++ = CUSTOM_OPENSL_PRESET; + *p_param_values++ = eq.config.num_bands; + for (i=0; idevice = device; +} + +void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable) +{ + ALOGV("%s", __func__); + reverb->enable_flag = enable; +} + +int offload_reverb_get_enable_flag(struct reverb_params *reverb) +{ + ALOGV("%s", __func__); + return reverb->enable_flag; +} + +void offload_reverb_set_mode(struct reverb_params *reverb, int mode) +{ + ALOGV("%s", __func__); + reverb->mode = mode; +} + +void offload_reverb_set_preset(struct reverb_params *reverb, int preset) +{ + ALOGV("%s", __func__); + if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED)) + reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset][1]; +} + +void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix) +{ + ALOGV("%s", __func__); + reverb->wet_mix = wet_mix; +} + +void offload_reverb_set_gain_adjust(struct reverb_params *reverb, + int gain_adjust) +{ + ALOGV("%s", __func__); + reverb->gain_adjust = gain_adjust; +} + +void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level) +{ + ALOGV("%s", __func__); + reverb->room_level = room_level; +} + +void offload_reverb_set_room_hf_level(struct reverb_params *reverb, + int room_hf_level) +{ + ALOGV("%s", __func__); + reverb->room_hf_level = room_hf_level; +} + +void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time) +{ + ALOGV("%s", __func__); + reverb->decay_time = decay_time; +} + +void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb, + int decay_hf_ratio) +{ + ALOGV("%s", __func__); + reverb->decay_hf_ratio = decay_hf_ratio; +} + +void offload_reverb_set_reflections_level(struct reverb_params *reverb, + int reflections_level) +{ + ALOGV("%s", __func__); + reverb->reflections_level = reflections_level; +} + +void offload_reverb_set_reflections_delay(struct reverb_params *reverb, + int reflections_delay) +{ + ALOGV("%s", __func__); + reverb->reflections_delay = reflections_delay; +} + +void offload_reverb_set_reverb_level(struct reverb_params *reverb, + int reverb_level) +{ + ALOGV("%s", __func__); + reverb->level = reverb_level; +} + +void offload_reverb_set_delay(struct reverb_params *reverb, int delay) +{ + ALOGV("%s", __func__); + reverb->delay = delay; +} + +void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion) +{ + ALOGV("%s", __func__); + reverb->diffusion = diffusion; +} + +void offload_reverb_set_density(struct reverb_params *reverb, int density) +{ + ALOGV("%s", __func__); + reverb->density = density; +} + +int offload_reverb_send_params(struct mixer_ctl *ctl, + struct reverb_params reverb, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + + ALOGV("%s", __func__); + *p_param_values++ = REVERB_MODULE; + *p_param_values++ = reverb.device; + *p_param_values++ = 0; /* num of commands*/ + + if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) { + *p_param_values++ = REVERB_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_ENABLE_PARAM_LEN; + *p_param_values++ = reverb.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) { + *p_param_values++ = REVERB_MODE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_MODE_PARAM_LEN; + *p_param_values++ = reverb.mode; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) { + *p_param_values++ = REVERB_PRESET; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_PRESET_PARAM_LEN; + *p_param_values++ = reverb.preset; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) { + *p_param_values++ = REVERB_WET_MIX; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_WET_MIX_PARAM_LEN; + *p_param_values++ = reverb.wet_mix; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) { + *p_param_values++ = REVERB_GAIN_ADJUST; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN; + *p_param_values++ = reverb.gain_adjust; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) { + *p_param_values++ = REVERB_ROOM_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.room_level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) { + *p_param_values++ = REVERB_ROOM_HF_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.room_hf_level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) { + *p_param_values++ = REVERB_DECAY_TIME; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN; + *p_param_values++ = reverb.decay_time; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) { + *p_param_values++ = REVERB_DECAY_HF_RATIO; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN; + *p_param_values++ = reverb.decay_hf_ratio; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) { + *p_param_values++ = REVERB_REFLECTIONS_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.reflections_level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) { + *p_param_values++ = REVERB_REFLECTIONS_DELAY; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN; + *p_param_values++ = reverb.reflections_delay; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) { + *p_param_values++ = REVERB_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) { + *p_param_values++ = REVERB_DELAY; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DELAY_PARAM_LEN; + *p_param_values++ = reverb.delay; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) { + *p_param_values++ = REVERB_DIFFUSION; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN; + *p_param_values++ = reverb.diffusion; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) { + *p_param_values++ = REVERB_DENSITY; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DENSITY_PARAM_LEN; + *p_param_values++ = reverb.density; + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h new file mode 100644 index 000000000..342c60681 --- /dev/null +++ b/post_proc/effect_api.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OFFLOAD_EFFECT_API_H_ +#define OFFLOAD_EFFECT_API_H_ + +int offload_update_mixer_and_effects_ctl(int card, int device_id, + struct mixer *mixer, + struct mixer_ctl *ctl); +void offload_close_mixer(struct mixer *mixer); + +#define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_BASSBOOST_STRENGTH \ + (OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_BASSBOOST_MODE \ + (OFFLOAD_SEND_BASSBOOST_STRENGTH << 1) +void offload_bassboost_set_device(struct bass_boost_params *bassboost, + uint32_t device); +void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost, + bool enable); +int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost); +void offload_bassboost_set_strength(struct bass_boost_params *bassboost, + int strength); +void offload_bassboost_set_mode(struct bass_boost_params *bassboost, + int mode); +int offload_bassboost_send_params(struct mixer_ctl *ctl, + struct bass_boost_params bassboost, + unsigned param_send_flags); + +#define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_VIRTUALIZER_STRENGTH \ + (OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE \ + (OFFLOAD_SEND_VIRTUALIZER_STRENGTH << 1) +#define OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST \ + (OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE << 1) +void offload_virtualizer_set_device(struct virtualizer_params *virtualizer, + uint32_t device); +void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer, + bool enable); +int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer); +void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer, + int strength); +void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer, + int out_type); +void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer, + int gain_adjust); +int offload_virtualizer_send_params(struct mixer_ctl *ctl, + struct virtualizer_params virtualizer, + unsigned param_send_flags); + +#define OFFLOAD_SEND_EQ_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_EQ_PRESET \ + (OFFLOAD_SEND_EQ_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_EQ_BANDS_LEVEL \ + (OFFLOAD_SEND_EQ_PRESET << 1) +void offload_eq_set_device(struct eq_params *eq, uint32_t device); +void offload_eq_set_enable_flag(struct eq_params *eq, bool enable); +int offload_eq_get_enable_flag(struct eq_params *eq); +void offload_eq_set_preset(struct eq_params *eq, int preset); +void offload_eq_set_bands_level(struct eq_params *eq, int num_bands, + const uint16_t *band_freq_list, + int *band_gain_list); +int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, + unsigned param_send_flags); + +#define OFFLOAD_SEND_REVERB_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_REVERB_MODE \ + (OFFLOAD_SEND_REVERB_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_REVERB_PRESET \ + (OFFLOAD_SEND_REVERB_MODE << 1) +#define OFFLOAD_SEND_REVERB_WET_MIX \ + (OFFLOAD_SEND_REVERB_PRESET << 1) +#define OFFLOAD_SEND_REVERB_GAIN_ADJUST \ + (OFFLOAD_SEND_REVERB_WET_MIX << 1) +#define OFFLOAD_SEND_REVERB_ROOM_LEVEL \ + (OFFLOAD_SEND_REVERB_GAIN_ADJUST << 1) +#define OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL \ + (OFFLOAD_SEND_REVERB_ROOM_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_DECAY_TIME \ + (OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_DECAY_HF_RATIO \ + (OFFLOAD_SEND_REVERB_DECAY_TIME << 1) +#define OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL \ + (OFFLOAD_SEND_REVERB_DECAY_HF_RATIO << 1) +#define OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY \ + (OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_LEVEL \ + (OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY << 1) +#define OFFLOAD_SEND_REVERB_DELAY \ + (OFFLOAD_SEND_REVERB_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_DIFFUSION \ + (OFFLOAD_SEND_REVERB_DELAY << 1) +#define OFFLOAD_SEND_REVERB_DENSITY \ + (OFFLOAD_SEND_REVERB_DIFFUSION << 1) +void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device); +void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable); +int offload_reverb_get_enable_flag(struct reverb_params *reverb); +void offload_reverb_set_mode(struct reverb_params *reverb, int mode); +void offload_reverb_set_preset(struct reverb_params *reverb, int preset); +void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix); +void offload_reverb_set_gain_adjust(struct reverb_params *reverb, + int gain_adjust); +void offload_reverb_set_room_level(struct reverb_params *reverb, + int room_level); +void offload_reverb_set_room_hf_level(struct reverb_params *reverb, + int room_hf_level); +void offload_reverb_set_decay_time(struct reverb_params *reverb, + int decay_time); +void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb, + int decay_hf_ratio); +void offload_reverb_set_reflections_level(struct reverb_params *reverb, + int reflections_level); +void offload_reverb_set_reflections_delay(struct reverb_params *reverb, + int reflections_delay); +void offload_reverb_set_reverb_level(struct reverb_params *reverb, + int reverb_level); +void offload_reverb_set_delay(struct reverb_params *reverb, int delay); +void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion); +void offload_reverb_set_density(struct reverb_params *reverb, int density); +int offload_reverb_send_params(struct mixer_ctl *ctl, + struct reverb_params reverb, + unsigned param_send_flags); + +#endif /*OFFLOAD_EFFECT_API_H_*/ diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c new file mode 100644 index 000000000..e31d2b943 --- /dev/null +++ b/post_proc/equalizer.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "offload_effect_equalizer" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +#include "effect_api.h" +#include "equalizer.h" + +/* Offload equalizer UUID: a0dac280-401c-11e3-9379-0002a5d5c51b */ +const effect_descriptor_t equalizer_descriptor = { + {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type + {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload equalizer", + "The Android Open Source Project", +}; + +static const char *equalizer_preset_names[] = { + "Normal", + "Classical", + "Dance", + "Flat", + "Folk", + "Heavy Metal", + "Hip Hop", + "Jazz", + "Pop", + "Rock" + }; + +static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = { + {30000, 120000}, + {120001, 460000}, + {460001, 1800000}, + {1800001, 7000000}, + {7000001, 20000000}}; + +static const uint16_t equalizer_band_presets_level[] = { + 3, 0, 0, 0, 3, /* Normal Preset */ + 5, 3, -2, 4, 4, /* Classical Preset */ + 6, 0, 2, 4, 1, /* Dance Preset */ + 0, 0, 0, 0, 0, /* Flat Preset */ + 3, 0, 0, 2, -1, /* Folk Preset */ + 4, 1, 9, 3, 0, /* Heavy Metal Preset */ + 5, 3, 0, 1, 3, /* Hip Hop Preset */ + 4, 2, -2, 2, 5, /* Jazz Preset */ + -1, 2, 5, 1, -2, /* Pop Preset */ + 5, 3, -1, 3, 5}; /* Rock Preset */ + +const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = { + 60, /* Frequencies in Hz */ + 230, + 910, + 3600, + 14000 +}; + +/* + * Equalizer operations + */ + +int equalizer_get_band_level(equalizer_context_t *context, int32_t band) +{ + ALOGV("%s: band: %d level: %d", __func__, band, + context->band_levels[band] * 100); + return context->band_levels[band] * 100; +} + +int equalizer_set_band_level(equalizer_context_t *context, int32_t band, + int32_t level) +{ + ALOGV("%s: band: %d, level: %d", __func__, band, level); + if (level > 0) { + level = (int)((level+50)/100); + } else { + level = (int)((level-50)/100); + } + context->band_levels[band] = level; + context->preset = PRESET_CUSTOM; + + offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM); + offload_eq_set_bands_level(&(context->offload_eq), + NUM_EQ_BANDS, + equalizer_band_presets_freq, + context->band_levels); + if (context->ctl) + offload_eq_send_params(context->ctl, context->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_BANDS_LEVEL); + return 0; +} + +int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band) +{ + ALOGV("%s: band: %d", __func__, band); + return (equalizer_band_freq_range[band][0] + + equalizer_band_freq_range[band][1]) / 2; +} + +int equalizer_get_band_freq_range(equalizer_context_t *context, int32_t band, + uint32_t *low, uint32_t *high) +{ + ALOGV("%s: band: %d", __func__, band); + *low = equalizer_band_freq_range[band][0]; + *high = equalizer_band_freq_range[band][1]; + return 0; +} + +int equalizer_get_band(equalizer_context_t *context, uint32_t freq) +{ + int i; + + ALOGV("%s: freq: %d", __func__, freq); + for(i = 0; i < NUM_EQ_BANDS; i++) { + if (freq <= equalizer_band_freq_range[i][1]) { + return i; + } + } + return NUM_EQ_BANDS - 1; +} + +int equalizer_get_preset(equalizer_context_t *context) +{ + ALOGV("%s: preset: %d", __func__, context->preset); + return context->preset; +} + +int equalizer_set_preset(equalizer_context_t *context, int preset) +{ + int i; + + ALOGV("%s: preset: %d", __func__, preset); + context->preset = preset; + for (i=0; iband_levels[i] = + equalizer_band_presets_level[i + preset * NUM_EQ_BANDS]; + + offload_eq_set_preset(&(context->offload_eq), preset); + offload_eq_set_bands_level(&(context->offload_eq), + NUM_EQ_BANDS, + equalizer_band_presets_freq, + context->band_levels); + if(context->ctl) + offload_eq_send_params(context->ctl, context->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_PRESET); + return 0; +} + +const char * equalizer_get_preset_name(equalizer_context_t *context, + int32_t preset) +{ + ALOGV("%s: preset: %s", __func__, equalizer_preset_names[preset]); + if (preset == PRESET_CUSTOM) { + return "Custom"; + } else { + return equalizer_preset_names[preset]; + } +} + +int equalizer_get_num_presets(equalizer_context_t *context) +{ + ALOGV("%s: presets_num: %d", __func__, + sizeof(equalizer_preset_names)/sizeof(char *)); + return sizeof(equalizer_preset_names)/sizeof(char *); +} + +int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + int32_t param2; + char *name; + void *value = p->data + voffset; + int i; + + ALOGV("%s", __func__); + + p->status = 0; + + switch (param) { + case EQ_PARAM_NUM_BANDS: + case EQ_PARAM_CUR_PRESET: + case EQ_PARAM_GET_NUM_OF_PRESETS: + case EQ_PARAM_BAND_LEVEL: + case EQ_PARAM_GET_BAND: + if (p->vsize < sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = sizeof(int16_t); + break; + + case EQ_PARAM_LEVEL_RANGE: + if (p->vsize < 2 * sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = 2 * sizeof(int16_t); + break; + case EQ_PARAM_BAND_FREQ_RANGE: + if (p->vsize < 2 * sizeof(int32_t)) + p->status = -EINVAL; + p->vsize = 2 * sizeof(int32_t); + break; + + case EQ_PARAM_CENTER_FREQ: + if (p->vsize < sizeof(int32_t)) + p->status = -EINVAL; + p->vsize = sizeof(int32_t); + break; + + case EQ_PARAM_GET_PRESET_NAME: + break; + + case EQ_PARAM_PROPERTIES: + if (p->vsize < (2 + NUM_EQ_BANDS) * sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = (2 + NUM_EQ_BANDS) * sizeof(uint16_t); + break; + + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case EQ_PARAM_NUM_BANDS: + ALOGV("%s: EQ_PARAM_NUM_BANDS", __func__); + *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS; + break; + + case EQ_PARAM_LEVEL_RANGE: + ALOGV("%s: EQ_PARAM_LEVEL_RANGE", __func__); + *(int16_t *)value = -1500; + *((int16_t *)value + 1) = 1500; + break; + + case EQ_PARAM_BAND_LEVEL: + ALOGV("%s: EQ_PARAM_BAND_LEVEL", __func__); + param2 = *param_tmp; + if (param2 >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + *(int16_t *)value = (int16_t)equalizer_get_band_level(eq_ctxt, param2); + break; + + case EQ_PARAM_CENTER_FREQ: + ALOGV("%s: EQ_PARAM_CENTER_FREQ", __func__); + param2 = *param_tmp; + if (param2 >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + *(int32_t *)value = equalizer_get_center_frequency(eq_ctxt, param2); + break; + + case EQ_PARAM_BAND_FREQ_RANGE: + ALOGV("%s: EQ_PARAM_BAND_FREQ_RANGE", __func__); + param2 = *param_tmp; + if (param2 >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + equalizer_get_band_freq_range(eq_ctxt, param2, (uint32_t *)value, + ((uint32_t *)value + 1)); + break; + + case EQ_PARAM_GET_BAND: + ALOGV("%s: EQ_PARAM_GET_BAND", __func__); + param2 = *param_tmp; + *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2); + break; + + case EQ_PARAM_CUR_PRESET: + ALOGV("%s: EQ_PARAM_CUR_PRESET", __func__); + *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt); + break; + + case EQ_PARAM_GET_NUM_OF_PRESETS: + ALOGV("%s: EQ_PARAM_GET_NUM_OF_PRESETS", __func__); + *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt); + break; + + case EQ_PARAM_GET_PRESET_NAME: + ALOGV("%s: EQ_PARAM_GET_PRESET_NAME", __func__); + param2 = *param_tmp; + ALOGV("param2: %d", param2); + if (param2 >= equalizer_get_num_presets(eq_ctxt)) { + p->status = -EINVAL; + break; + } + name = (char *)value; + strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1); + name[p->vsize - 1] = 0; + p->vsize = strlen(name) + 1; + break; + + case EQ_PARAM_PROPERTIES: { + ALOGV("%s: EQ_PARAM_PROPERTIES", __func__); + int16_t *prop = (int16_t *)value; + prop[0] = (int16_t)equalizer_get_preset(eq_ctxt); + prop[1] = (int16_t)NUM_EQ_BANDS; + for (i = 0; i < NUM_EQ_BANDS; i++) { + prop[2 + i] = (int16_t)equalizer_get_band_level(eq_ctxt, i); + } + } break; + + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + int32_t preset; + int32_t band; + int32_t level; + int i; + + ALOGV("%s", __func__); + + p->status = 0; + + switch (param) { + case EQ_PARAM_CUR_PRESET: + ALOGV("EQ_PARAM_CUR_PRESET"); + preset = (int32_t)(*(uint16_t *)value); + + if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) { + p->status = -EINVAL; + break; + } + equalizer_set_preset(eq_ctxt, preset); + break; + case EQ_PARAM_BAND_LEVEL: + ALOGV("EQ_PARAM_BAND_LEVEL"); + band = *param_tmp; + level = (int32_t)(*(int16_t *)value); + if (band >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + equalizer_set_band_level(eq_ctxt, band, level); + break; + case EQ_PARAM_PROPERTIES: { + ALOGV("EQ_PARAM_PROPERTIES"); + int16_t *prop = (int16_t *)value; + if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) { + p->status = -EINVAL; + break; + } + if (prop[0] >= 0) { + equalizer_set_preset(eq_ctxt, (int)prop[0]); + } else { + if ((int)prop[1] != NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + for (i = 0; i < NUM_EQ_BANDS; i++) { + equalizer_set_band_level(eq_ctxt, i, (int)prop[2 + i]); + } + } + } break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int equalizer_set_device(effect_context_t *context, uint32_t device) +{ + ALOGV("%s: device: %d", __func__, device); + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + eq_ctxt->device = device; + offload_eq_set_device(&(eq_ctxt->offload_eq), device); + return 0; +} + +int equalizer_reset(effect_context_t *context) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + return 0; +} + +int equalizer_init(effect_context_t *context) +{ + ALOGV("%s", __func__); + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params)); + offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET); + + return 0; +} + +int equalizer_enable(effect_context_t *context) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s", __func__); + + if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { + offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true); + if (eq_ctxt->ctl) + offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_BANDS_LEVEL); + } + return 0; +} + +int equalizer_disable(effect_context_t *context) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s", __func__); + if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { + offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false); + if (eq_ctxt->ctl) + offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG); + } + return 0; +} + +int equalizer_start(effect_context_t *context, output_context_t *output) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s: %p", __func__, output->ctl); + eq_ctxt->ctl = output->ctl; + return 0; +} + +int equalizer_stop(effect_context_t *context, output_context_t *output) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s", __func__); + eq_ctxt->ctl = NULL; + return 0; +} diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h new file mode 100644 index 000000000..19af18670 --- /dev/null +++ b/post_proc/equalizer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef OFFLOAD_EQUALIZER_H_ +#define OFFLOAD_EQUALIZER_H_ + +#include "bundle.h" + +#define NUM_EQ_BANDS 5 +#define INVALID_PRESET -2 +#define PRESET_CUSTOM -1 + +extern const effect_descriptor_t equalizer_descriptor; + +typedef struct equalizer_context_s { + effect_context_t common; + + int preset; + int band_levels[NUM_EQ_BANDS]; + + // Offload vars + struct mixer_ctl *ctl; + uint32_t device; + struct eq_params offload_eq; +} equalizer_context_t; + +int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int equalizer_set_device(effect_context_t *context, uint32_t device); + +int equalizer_reset(effect_context_t *context); + +int equalizer_init(effect_context_t *context); + +int equalizer_enable(effect_context_t *context); + +int equalizer_disable(effect_context_t *context); + +int equalizer_start(effect_context_t *context, output_context_t *output); + +int equalizer_stop(effect_context_t *context, output_context_t *output); + +#endif /*OFFLOAD_EQUALIZER_H_*/ diff --git a/post_proc/reverb.c b/post_proc/reverb.c new file mode 100644 index 000000000..4fc8c8380 --- /dev/null +++ b/post_proc/reverb.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "offload_effect_reverb" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include + +#include "effect_api.h" +#include "reverb.h" + +/* Offload auxiliary environmental reverb UUID: 79a18026-18fd-4185-8233-0002a5d5c51b */ +const effect_descriptor_t aux_env_reverb_descriptor = { + { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } }, + { 0x79a18026, 0x18fd, 0x4185, 0x8233, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Auxiliary Environmental Reverb", + "The Android Open Source Project", +}; + +/* Offload insert environmental reverb UUID: eb64ea04-973b-43d2-8f5e-0002a5d5c51b */ +const effect_descriptor_t ins_env_reverb_descriptor = { + {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}}, + {0xeb64ea04, 0x973b, 0x43d2, 0x8f5e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Insert Environmental Reverb", + "The Android Open Source Project", +}; + +// Offload auxiliary preset reverb UUID: 6987be09-b142-4b41-9056-0002a5d5c51b */ +const effect_descriptor_t aux_preset_reverb_descriptor = { + {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0x6987be09, 0xb142, 0x4b41, 0x9056, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Auxiliary Preset Reverb", + "The Android Open Source Project", +}; + +// Offload insert preset reverb UUID: aa2bebf6-47cf-4613-9bca-0002a5d5c51b */ +const effect_descriptor_t ins_preset_reverb_descriptor = { + {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0xaa2bebf6, 0x47cf, 0x4613, 0x9bca, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Insert Preset Reverb", + "The Android Open Source Project", +}; + +static const reverb_settings_t reverb_presets[] = { + // REVERB_PRESET_NONE: values are unused + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // REVERB_PRESET_SMALLROOM + {-400, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000}, + // REVERB_PRESET_MEDIUMROOM + {-400, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000}, + // REVERB_PRESET_LARGEROOM + {-400, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000}, + // REVERB_PRESET_MEDIUMHALL + {-400, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000}, + // REVERB_PRESET_LARGEHALL + {-400, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000}, + // REVERB_PRESET_PLATE + {-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750}, +}; + + +void reverb_auxiliary_init(reverb_context_t *context) +{ + context->auxiliary = true; + context->preset = false; +} + +void reverb_preset_init(reverb_context_t *context) +{ + context->auxiliary = false; + context->preset = true; + context->cur_preset = REVERB_PRESET_LAST + 1; + context->next_preset = REVERB_DEFAULT_PRESET; +} + +/* + * Reverb operations + */ +int16_t reverb_get_room_level(reverb_context_t *context) +{ + ALOGV("%s: room level: %d", __func__, context->reverb_settings.roomLevel); + return context->reverb_settings.roomLevel; +} + +void reverb_set_room_level(reverb_context_t *context, int16_t room_level) +{ + ALOGV("%s: room level: %d", __func__, room_level); + context->reverb_settings.roomLevel = room_level; + offload_reverb_set_room_level(&(context->offload_reverb), room_level); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_ROOM_LEVEL); +} + +int16_t reverb_get_room_hf_level(reverb_context_t *context) +{ + ALOGV("%s: room hf level: %d", __func__, + context->reverb_settings.roomHFLevel); + return context->reverb_settings.roomHFLevel; +} + +void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level) +{ + ALOGV("%s: room hf level: %d", __func__, room_hf_level); + context->reverb_settings.roomHFLevel = room_hf_level; + offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL); +} + +uint32_t reverb_get_decay_time(reverb_context_t *context) +{ + ALOGV("%s: decay time: %d", __func__, context->reverb_settings.decayTime); + return context->reverb_settings.decayTime; +} + +void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time) +{ + ALOGV("%s: decay_time: %d", __func__, decay_time); + context->reverb_settings.decayTime = decay_time; + offload_reverb_set_decay_time(&(context->offload_reverb), decay_time); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DECAY_TIME); +} + +int16_t reverb_get_decay_hf_ratio(reverb_context_t *context) +{ + ALOGV("%s: decay hf ratio: %d", __func__, + context->reverb_settings.decayHFRatio); + return context->reverb_settings.decayHFRatio; +} + +void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio) +{ + ALOGV("%s: decay_hf_ratio: %d", __func__, decay_hf_ratio); + context->reverb_settings.decayHFRatio = decay_hf_ratio; + offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DECAY_HF_RATIO); +} + +int16_t reverb_get_reverb_level(reverb_context_t *context) +{ + ALOGV("%s: reverb level: %d", __func__, context->reverb_settings.reverbLevel); + return context->reverb_settings.reverbLevel; +} + +void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level) +{ + ALOGV("%s: reverb level: %d", __func__, reverb_level); + context->reverb_settings.reverbLevel = reverb_level; + offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_LEVEL); +} + +int16_t reverb_get_diffusion(reverb_context_t *context) +{ + ALOGV("%s: diffusion: %d", __func__, context->reverb_settings.diffusion); + return context->reverb_settings.diffusion; +} + +void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion) +{ + ALOGV("%s: diffusion: %d", __func__, diffusion); + context->reverb_settings.diffusion = diffusion; + offload_reverb_set_diffusion(&(context->offload_reverb), diffusion); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DIFFUSION); +} + +int16_t reverb_get_density(reverb_context_t *context) +{ + ALOGV("%s: density: %d", __func__, context->reverb_settings.density); + return context->reverb_settings.density; +} + +void reverb_set_density(reverb_context_t *context, int16_t density) +{ + ALOGV("%s: density: %d", __func__, density); + context->reverb_settings.density = density; + offload_reverb_set_density(&(context->offload_reverb), density); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DENSITY); +} + +void reverb_set_preset(reverb_context_t *context, int16_t preset) +{ + ALOGV("%s: preset: %d", __func__, preset); + context->next_preset = preset; + offload_reverb_set_preset(&(context->offload_reverb), preset); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_PRESET); +} + +void reverb_set_all_properties(reverb_context_t *context, + reverb_settings_t *reverb_settings) +{ + ALOGV("%s", __func__); + context->reverb_settings.roomLevel = reverb_settings->roomLevel; + context->reverb_settings.roomHFLevel = reverb_settings->roomHFLevel; + context->reverb_settings.decayTime = reverb_settings->decayTime; + context->reverb_settings.decayHFRatio = reverb_settings->decayHFRatio; + context->reverb_settings.reverbLevel = reverb_settings->reverbLevel; + context->reverb_settings.diffusion = reverb_settings->diffusion; + context->reverb_settings.density = reverb_settings->density; + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_ROOM_LEVEL | + OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL | + OFFLOAD_SEND_REVERB_DECAY_TIME | + OFFLOAD_SEND_REVERB_DECAY_HF_RATIO | + OFFLOAD_SEND_REVERB_LEVEL | + OFFLOAD_SEND_REVERB_DIFFUSION | + OFFLOAD_SEND_REVERB_DENSITY); +} + +void reverb_load_preset(reverb_context_t *context) +{ + context->cur_preset = context->next_preset; + + if (context->cur_preset != REVERB_PRESET_NONE) { + const reverb_settings_t *preset = &reverb_presets[context->cur_preset]; + reverb_set_room_level(context, preset->roomLevel); + reverb_set_room_hf_level(context, preset->roomHFLevel); + reverb_set_decay_time(context, preset->decayTime); + reverb_set_decay_hf_ratio(context, preset->decayHFRatio); + reverb_set_reverb_level(context, preset->reverbLevel); + reverb_set_diffusion(context, preset->diffusion); + reverb_set_density(context, preset->density); + } +} + +int reverb_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + void *value = p->data + voffset; + reverb_settings_t *reverb_settings; + int i; + + ALOGV("%s", __func__); + + p->status = 0; + + if (reverb_ctxt->preset) { + if (param != REVERB_PARAM_PRESET || p->vsize < sizeof(uint16_t)) + return -EINVAL; + *(uint16_t *)value = reverb_ctxt->next_preset; + ALOGV("get REVERB_PARAM_PRESET, preset %d", reverb_ctxt->next_preset); + } + switch (param) { + case REVERB_PARAM_ROOM_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_ROOM_HF_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_DECAY_TIME: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case REVERB_PARAM_DECAY_HF_RATIO: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_REFLECTIONS_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_REFLECTIONS_DELAY: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case REVERB_PARAM_REVERB_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_REVERB_DELAY: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case REVERB_PARAM_DIFFUSION: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_DENSITY: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_PROPERTIES: + if (p->vsize < sizeof(reverb_settings_t)) + p->status = -EINVAL; + p->vsize = sizeof(reverb_settings_t); + break; + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case REVERB_PARAM_PROPERTIES: + ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__); + reverb_settings = (reverb_settings_t *)value; + reverb_settings->roomLevel = reverb_get_room_level(reverb_ctxt); + reverb_settings->roomHFLevel = reverb_get_room_hf_level(reverb_ctxt); + reverb_settings->decayTime = reverb_get_decay_time(reverb_ctxt); + reverb_settings->decayHFRatio = reverb_get_decay_hf_ratio(reverb_ctxt); + reverb_settings->reflectionsLevel = 0; + reverb_settings->reflectionsDelay = 0; + reverb_settings->reverbDelay = 0; + reverb_settings->reverbLevel = reverb_get_reverb_level(reverb_ctxt); + reverb_settings->diffusion = reverb_get_diffusion(reverb_ctxt); + reverb_settings->density = reverb_get_density(reverb_ctxt); + break; + case REVERB_PARAM_ROOM_LEVEL: + ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__); + *(int16_t *)value = reverb_get_room_level(reverb_ctxt); + break; + case REVERB_PARAM_ROOM_HF_LEVEL: + ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__); + *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt); + break; + case REVERB_PARAM_DECAY_TIME: + ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__); + *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt); + break; + case REVERB_PARAM_DECAY_HF_RATIO: + ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__); + *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt); + break; + case REVERB_PARAM_REVERB_LEVEL: + ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__); + *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt); + break; + case REVERB_PARAM_DIFFUSION: + ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__); + *(int16_t *)value = reverb_get_diffusion(reverb_ctxt); + break; + case REVERB_PARAM_DENSITY: + ALOGV("%s: REVERB_PARAM_DENSITY", __func__); + *(int16_t *)value = reverb_get_density(reverb_ctxt); + break; + case REVERB_PARAM_REFLECTIONS_LEVEL: + ALOGV("%s: REVERB_PARAM_REFLECTIONS_LEVEL", __func__); + *(uint16_t *)value = 0; + break; + case REVERB_PARAM_REFLECTIONS_DELAY: + ALOGV("%s: REVERB_PARAM_REFLECTIONS_DELAY", __func__); + *(uint32_t *)value = 0; + break; + case REVERB_PARAM_REVERB_DELAY: + ALOGV("%s: REVERB_PARAM_REVERB_DELAY", __func__); + *(uint32_t *)value = 0; + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int reverb_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + reverb_settings_t *reverb_settings; + int16_t level; + int16_t ratio; + uint32_t time; + + ALOGV("%s", __func__); + + p->status = 0; + + if (reverb_ctxt->preset) { + if (param != REVERB_PARAM_PRESET) + return -EINVAL; + uint16_t preset = *(uint16_t *)value; + ALOGV("set REVERB_PARAM_PRESET, preset %d", preset); + if (preset > REVERB_PRESET_LAST) { + return -EINVAL; + } + reverb_set_preset(reverb_ctxt, preset); + } + switch (param) { + case REVERB_PARAM_PROPERTIES: + ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__); + reverb_settings = (reverb_settings_t *)value; + break; + case REVERB_PARAM_ROOM_LEVEL: + ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__); + level = *(int16_t *)value; + reverb_set_room_level(reverb_ctxt, level); + break; + case REVERB_PARAM_ROOM_HF_LEVEL: + ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__); + level = *(int16_t *)value; + reverb_set_room_hf_level(reverb_ctxt, level); + break; + case REVERB_PARAM_DECAY_TIME: + ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__); + time = *(uint32_t *)value; + reverb_set_decay_time(reverb_ctxt, time); + break; + case REVERB_PARAM_DECAY_HF_RATIO: + ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__); + ratio = *(int16_t *)value; + reverb_set_decay_hf_ratio(reverb_ctxt, ratio); + break; + case REVERB_PARAM_REVERB_LEVEL: + ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__); + level = *(int16_t *)value; + reverb_set_reverb_level(reverb_ctxt, level); + break; + case REVERB_PARAM_DIFFUSION: + ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__); + ratio = *(int16_t *)value; + reverb_set_diffusion(reverb_ctxt, ratio); + break; + case REVERB_PARAM_DENSITY: + ALOGV("%s: REVERB_PARAM_DENSITY", __func__); + ratio = *(int16_t *)value; + reverb_set_density(reverb_ctxt, ratio); + break; + case REVERB_PARAM_REFLECTIONS_LEVEL: + case REVERB_PARAM_REFLECTIONS_DELAY: + case REVERB_PARAM_REVERB_DELAY: + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int reverb_set_device(effect_context_t *context, uint32_t device) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: device: %d", __func__, device); + reverb_ctxt->device = device; + offload_reverb_set_device(&(reverb_ctxt->offload_reverb), device); + return 0; +} + +int reverb_reset(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + return 0; +} + +int reverb_init(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + /* + FIXME: channel mode is mono for auxiliary. is it needed for offload ? + If so, this set config needs to be updated accordingly + */ + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t)); + memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params)); + + if (reverb_ctxt->preset && + reverb_ctxt->next_preset != reverb_ctxt->cur_preset) + reverb_load_preset(reverb_ctxt); + + return 0; +} + +int reverb_enable(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s", __func__); + + if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) + offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true); + return 0; +} + +int reverb_disable(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s", __func__); + if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) { + offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false); + if (reverb_ctxt->ctl) + offload_reverb_send_params(reverb_ctxt->ctl, + reverb_ctxt->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG); + } + return 0; +} + +int reverb_start(effect_context_t *context, output_context_t *output) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s", __func__); + reverb_ctxt->ctl = output->ctl; + return 0; +} + +int reverb_stop(effect_context_t *context, output_context_t *output) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s", __func__); + reverb_ctxt->ctl = NULL; + return 0; +} + diff --git a/post_proc/reverb.h b/post_proc/reverb.h new file mode 100644 index 000000000..63192eb09 --- /dev/null +++ b/post_proc/reverb.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef OFFLOAD_REVERB_H_ +#define OFFLOAD_REVERB_H_ + +#include "bundle.h" + +#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE + +extern const effect_descriptor_t aux_env_reverb_descriptor; +extern const effect_descriptor_t ins_env_reverb_descriptor; +extern const effect_descriptor_t aux_preset_reverb_descriptor; +extern const effect_descriptor_t ins_preset_reverb_descriptor; + +typedef struct reverb_settings_s { + int16_t roomLevel; + int16_t roomHFLevel; + uint32_t decayTime; + int16_t decayHFRatio; + int16_t reflectionsLevel; + uint32_t reflectionsDelay; + int16_t reverbLevel; + uint32_t reverbDelay; + int16_t diffusion; + int16_t density; +} reverb_settings_t; + +typedef struct reverb_context_s { + effect_context_t common; + + // Offload vars + struct mixer_ctl *ctl; + bool auxiliary; + bool preset; + uint16_t cur_preset; + uint16_t next_preset; + reverb_settings_t reverb_settings; + uint32_t device; + struct reverb_params offload_reverb; +} reverb_context_t; + + +void reverb_auxiliary_init(reverb_context_t *context); + +void reverb_preset_init(reverb_context_t *context); + +int reverb_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int reverb_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int reverb_set_device(effect_context_t *context, uint32_t device); + +int reverb_reset(effect_context_t *context); + +int reverb_init(effect_context_t *context); + +int reverb_enable(effect_context_t *context); + +int reverb_disable(effect_context_t *context); + +int reverb_start(effect_context_t *context, output_context_t *output); + +int reverb_stop(effect_context_t *context, output_context_t *output); + +#endif /* OFFLOAD_REVERB_H_ */ diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c new file mode 100644 index 000000000..2f0ca6b87 --- /dev/null +++ b/post_proc/virtualizer.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "offload_effect_virtualizer" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +#include "effect_api.h" +#include "virtualizer.h" + +/* Offload Virtualizer UUID: 509a4498-561a-4bea-b3b1-0002a5d5c51b */ +const effect_descriptor_t virtualizer_descriptor = { + {0x37cc2c00, 0xdddd, 0x11db, 0x8577, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0x509a4498, 0x561a, 0x4bea, 0xb3b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload virtualizer", + "The Android Open Source Project", +}; + +/* + * Virtualizer operations + */ + +int virtualizer_get_strength(virtualizer_context_t *context) +{ + ALOGV("%s: strength: %d", __func__, context->strength); + return context->strength; +} + +int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength) +{ + ALOGV("%s: strength: %d", __func__, strength); + context->strength = strength; + + offload_virtualizer_set_strength(&(context->offload_virt), strength); + if (context->ctl) + offload_virtualizer_send_params(context->ctl, context->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG | + OFFLOAD_SEND_VIRTUALIZER_STRENGTH); + return 0; +} + +int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + void *value = p->data + voffset; + int i; + + ALOGV("%s", __func__); + + p->status = 0; + + switch (param) { + case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case VIRTUALIZER_PARAM_STRENGTH: + if (p->vsize < sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = sizeof(int16_t); + break; + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED: + ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH_SUPPORTED", __func__); + *(uint32_t *)value = 1; + break; + + case VIRTUALIZER_PARAM_STRENGTH: + ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH", __func__); + *(int16_t *)value = virtualizer_get_strength(virt_ctxt); + break; + + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + uint32_t strength; + + ALOGV("%s", __func__); + + p->status = 0; + + switch (param) { + case VIRTUALIZER_PARAM_STRENGTH: + ALOGV("%s VIRTUALIZER_PARAM_STRENGTH", __func__); + strength = (uint32_t)(*(int16_t *)value); + virtualizer_set_strength(virt_ctxt, strength); + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int virtualizer_set_device(effect_context_t *context, uint32_t device) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s: device: %d", __func__, device); + virt_ctxt->device = device; + if((device == AUDIO_DEVICE_OUT_SPEAKER) || + (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || + (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) { + if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); + virt_ctxt->temp_disabled = true; + } + } else { + if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) && + virt_ctxt->temp_disabled) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); + virt_ctxt->temp_disabled = false; + } + } + offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device); + return 0; +} + +int virtualizer_reset(effect_context_t *context) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + return 0; +} + +int virtualizer_init(effect_context_t *context) +{ + ALOGV("%s", __func__); + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params)); + + return 0; +} + +int virtualizer_enable(effect_context_t *context) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s", __func__); + + if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); + return 0; +} + +int virtualizer_disable(effect_context_t *context) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s", __func__); + if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + } + return 0; +} + +int virtualizer_start(effect_context_t *context, output_context_t *output) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s", __func__); + virt_ctxt->ctl = output->ctl; + return 0; +} + +int virtualizer_stop(effect_context_t *context, output_context_t *output) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s", __func__); + virt_ctxt->ctl = NULL; + return 0; +} diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h new file mode 100644 index 000000000..4a5005f65 --- /dev/null +++ b/post_proc/virtualizer.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#ifndef OFFLOAD_VIRTUALIZER_H_ +#define OFFLOAD_VIRTUALIZER_H_ + +#include "bundle.h" + +extern const effect_descriptor_t virtualizer_descriptor; + +typedef struct virtualizer_context_s { + effect_context_t common; + + int strength; + + // Offload vars + struct mixer_ctl *ctl; + bool temp_disabled; + uint32_t device; + struct virtualizer_params offload_virt; +} virtualizer_context_t; + +int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int virtualizer_set_device(effect_context_t *context, uint32_t device); + +int virtualizer_reset(effect_context_t *context); + +int virtualizer_init(effect_context_t *context); + +int virtualizer_enable(effect_context_t *context); + +int virtualizer_disable(effect_context_t *context); + +int virtualizer_start(effect_context_t *context, output_context_t *output); + +int virtualizer_stop(effect_context_t *context, output_context_t *output); + +#endif /* OFFLOAD_VIRTUALIZER_H_ */ -- GitLab From 1d0891672175d431e8872dd7dff21e0ce507361a Mon Sep 17 00:00:00 2001 From: Subhash Chandra Bose Naripeddy Date: Wed, 13 Nov 2013 13:31:50 -0800 Subject: [PATCH 100/298] hal: Add support for audio effects in DSP for tunnel mode playback Add support to enable or disable audio post processing effects in DSP for tunnel mode playback. Change-Id: I4e0b01ab4ae29d4b1c7986f2a6146e18e8bce2c1 --- hal/audio_hw.c | 40 +++++++++++++++++++++++++++------ hal/audio_hw.h | 8 +++++-- visualizer/offload_visualizer.c | 37 +++++++++++++++++++++--------- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c1ba5d349..12faa8860 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1042,9 +1042,12 @@ static int stop_output_stream(struct stream_out *out) return -EINVAL; } - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD && - adev->visualizer_stop_output != NULL) - adev->visualizer_stop_output(out->handle); + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (adev->visualizer_stop_output != NULL) + adev->visualizer_stop_output(out->handle, out->pcm_device_id); + if (adev->offload_effects_stop_output != NULL) + adev->offload_effects_stop_output(out->handle, out->pcm_device_id); + } /* 1. Get and set stream specific mixer controls */ disable_audio_route(adev, uc_info, true); @@ -1122,7 +1125,9 @@ int start_output_stream(struct stream_out *out) compress_nonblock(out->compr, out->non_blocking); if (adev->visualizer_start_output != NULL) - adev->visualizer_start_output(out->handle); + adev->visualizer_start_output(out->handle, out->pcm_device_id); + if (adev->offload_effects_start_output != NULL) + adev->offload_effects_start_output(out->handle, out->pcm_device_id); } ALOGV("%s: exit", __func__); return 0; @@ -1468,10 +1473,14 @@ static int out_set_volume(struct audio_stream_out *stream, float left, out->muted = (left == 0.0f); return 0; } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - const char *mixer_ctl_name = "Compress Playback Volume"; + char mixer_ctl_name[128]; struct audio_device *adev = out->dev; struct mixer_ctl *ctl; + int pcm_device_id = platform_get_pcm_device_id(out->usecase, + PCM_PLAYBACK); + snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), + "Compress Playback %d Volume", pcm_device_id); ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { ALOGE("%s: Could not get ctl for mixer cmd - %s", @@ -2574,15 +2583,32 @@ static int adev_open(const hw_module_t *module, const char *name, } else { ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH); adev->visualizer_start_output = - (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib, + (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib, "visualizer_hal_start_output"); adev->visualizer_stop_output = - (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib, + (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib, "visualizer_hal_stop_output"); } } audio_extn_listen_init(adev, SOUND_CARD); + if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) { + adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW); + if (adev->offload_effects_lib == NULL) { + ALOGE("%s: DLOPEN failed for %s", __func__, + OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); + } else { + ALOGV("%s: DLOPEN successful for %s", __func__, + OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); + adev->offload_effects_start_output = + (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, + "offload_effects_bundle_hal_start_output"); + adev->offload_effects_stop_output = + (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, + "offload_effects_bundle_hal_stop_output"); + } + } + *device = &adev->device.common; audio_device_ref_count++; diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 6ff6f40be..2555e2678 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -29,6 +29,7 @@ #include "voice.h" #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so" +#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so" /* Flags used to initialize acdb_settings variable that goes to ACDB library */ #define DMIC_FLAG 0x00000002 @@ -218,8 +219,11 @@ struct audio_device { void *platform; void *visualizer_lib; - int (*visualizer_start_output)(audio_io_handle_t); - int (*visualizer_stop_output)(audio_io_handle_t); + int (*visualizer_start_output)(audio_io_handle_t, int); + int (*visualizer_stop_output)(audio_io_handle_t, int); + void *offload_effects_lib; + int (*offload_effects_start_output)(audio_io_handle_t, int); + int (*offload_effects_stop_output)(audio_io_handle_t, int); }; int select_devices(struct audio_device *adev, diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c index eb43558d9..95b468746 100644 --- a/visualizer/offload_visualizer.c +++ b/visualizer/offload_visualizer.c @@ -37,6 +37,7 @@ enum { }; typedef struct effect_context_s effect_context_t; +typedef struct output_context_s output_context_t; /* effect specific operations. Only the init() and process() operations must be defined. * Others are optional. @@ -47,6 +48,8 @@ typedef struct effect_ops_s { int (*reset)(effect_context_t *context); int (*enable)(effect_context_t *context); int (*disable)(effect_context_t *context); + int (*start)(effect_context_t *context, output_context_t *output); + int (*stop)(effect_context_t *context, output_context_t *output); int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out); int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size); int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size); @@ -247,6 +250,8 @@ void add_effect_to_output(output_context_t * output, effect_context_t *context) return; } list_add_tail(&output->effects_list, &context->output_node); + if (context->ops.start) + context->ops.start(context, output); } void remove_effect_from_output(output_context_t * output, effect_context_t *context) { @@ -257,6 +262,8 @@ void remove_effect_from_output(output_context_t * output, effect_context_t *cont effect_context_t, output_node); if (fx_ctxt == context) { + if (context->ops.stop) + context->ops.stop(context, output); list_remove(&context->output_node); return; } @@ -276,7 +283,7 @@ bool effects_enabled() { effect_context_t *fx_ctxt = node_to_item(fx_node, effect_context_t, output_node); - if (fx_ctxt->state == EFFECT_STATE_ACTIVE) + if (fx_ctxt->state == EFFECT_STATE_ACTIVE && fx_ctxt->ops.process != NULL) return true; } } @@ -379,7 +386,8 @@ void *capture_thread_loop(void *arg) effect_context_t *fx_ctxt = node_to_item(fx_node, effect_context_t, output_node); - fx_ctxt->ops.process(fx_ctxt, &buf, &buf); + if (fx_ctxt->ops.process != NULL) + fx_ctxt->ops.process(fx_ctxt, &buf, &buf); } } } else { @@ -405,11 +413,11 @@ void *capture_thread_loop(void *arg) */ __attribute__ ((visibility ("default"))) -int visualizer_hal_start_output(audio_io_handle_t output) { +int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) { int ret; struct listnode *node; - ALOGV("%s", __func__); + ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); if (lib_init() != 0) return init_status; @@ -431,6 +439,8 @@ int visualizer_hal_start_output(audio_io_handle_t output) { effect_context_t, effects_list_node); if (fx_ctxt->out_handle == output) { + if (fx_ctxt->ops.start) + fx_ctxt->ops.start(fx_ctxt, out_ctxt); list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node); } } @@ -449,12 +459,13 @@ exit: } __attribute__ ((visibility ("default"))) -int visualizer_hal_stop_output(audio_io_handle_t output) { +int visualizer_hal_stop_output(audio_io_handle_t output, int pcm_id) { int ret; struct listnode *node; + struct listnode *fx_node; output_context_t *out_ctxt; - ALOGV("%s", __func__); + ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); if (lib_init() != 0) return init_status; @@ -468,7 +479,13 @@ int visualizer_hal_stop_output(audio_io_handle_t output) { ret = -ENOSYS; goto exit; } - + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt->ops.stop) + fx_ctxt->ops.stop(fx_ctxt, out_ctxt); + } list_remove(&out_ctxt->outputs_list_node); pthread_cond_signal(&cond); @@ -917,6 +934,7 @@ int effect_lib_create(const effect_uuid_t *uuid, context->ops.set_parameter = visualizer_set_parameter; context->ops.get_parameter = visualizer_get_parameter; context->ops.command = visualizer_command; + context->desc = &visualizer_descriptor; } else { return -EINVAL; } @@ -924,7 +942,6 @@ int effect_lib_create(const effect_uuid_t *uuid, context->itfe = &effect_interface; context->state = EFFECT_STATE_UNINITIALIZED; context->out_handle = (audio_io_handle_t)ioId; - context->desc = &visualizer_descriptor; ret = context->ops.init(context); if (ret < 0) { @@ -1177,12 +1194,12 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, out_ctxt = get_output(context->out_handle); if (out_ctxt != NULL) remove_effect_from_output(out_ctxt, context); + + context->out_handle = offload_param->ioHandle; out_ctxt = get_output(offload_param->ioHandle); if (out_ctxt != NULL) add_effect_to_output(out_ctxt, context); - context->out_handle = offload_param->ioHandle; - } break; -- GitLab From 067b96b45c566412e02b58a3529c0166f5b09994 Mon Sep 17 00:00:00 2001 From: Helen Zeng Date: Tue, 26 Nov 2013 12:10:29 -0800 Subject: [PATCH 101/298] hal: Fix for recording during voice call over BT Incall recording or Camcord recording is failed during voice call over BT device. The reason is that SND_DEVICE_NONE is as input, which causes the failure of getting input snd device. To solve the issue, update the condition check to get input snd device and add the device is AUDIO_DEVICE_IN_VOICE_CALL check. Change-Id: I59eecfa5bdbe68d54ff458a444d8fe981d312e2e CRs-Fixed: 579927 --- hal/audio_hw.c | 3 ++- hal/msm8974/platform.c | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ee6770396..244b080c9 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -609,7 +609,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) if (voice_is_in_call(adev)) { vc_usecase = get_usecase_from_list(adev, get_voice_usecase_id_from_list(adev)); - if (vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + if ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) || + (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL)) { in_snd_device = vc_usecase->in_snd_device; out_snd_device = vc_usecase->out_snd_device; } diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index a207c2f8d..3ac253846 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -954,12 +954,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d ALOGV("%s: enter: out_device(%#x) in_device(%#x)", __func__, out_device, in_device); - if ((mode == AUDIO_MODE_IN_CALL) || - voice_extn_compress_voip_is_active(adev)) { - if (out_device == AUDIO_DEVICE_NONE) { - ALOGE("%s: No output device set for voice call", __func__); - goto exit; - } + if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) || + voice_extn_compress_voip_is_active(adev))) { if ((adev->voice.tty_mode != TTY_MODE_OFF) && !voice_extn_compress_voip_is_active(adev)) { if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || -- GitLab From 1eceff805cce1890f4f98893ce3721af37683514 Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Mon, 2 Dec 2013 19:25:28 -0800 Subject: [PATCH 102/298] hal: Fix framesize issue for compress VoIP - Correct the framesize for 16KHz VoIP use cases - Add proper checks to enable compress VoIP use case - Add get_parameters() support to query audio mode Change-Id: I470d538f1e136780264e81b509fb439baead603d --- hal/audio_hw.c | 7 ++-- hal/voice_extn/compress_voip.c | 68 ++++++++++++++++++++++++++-------- hal/voice_extn/voice_extn.c | 17 +++++++++ hal/voice_extn/voice_extn.h | 17 +++++++++ 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c1ba5d349..407abedb6 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2009,15 +2009,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) && - (voice_extn_compress_voip_is_format_supported(out->format))) { + (voice_extn_compress_voip_is_config_supported(config))) { ret = voice_extn_compress_voip_open_output_stream(out); if (ret != 0) { ALOGE("%s: Compress voip output cannot be opened, error:%d", __func__, ret); goto error_open; } - out->config.rate = config->sample_rate; - out->sample_rate = config->sample_rate; } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { @@ -2277,6 +2275,7 @@ static char* adev_get_parameters(const struct audio_hw_device *dev, pthread_mutex_lock(&adev->lock); audio_extn_get_parameters(adev, query, reply); + voice_extn_get_parameters(adev, query, reply); platform_get_parameters(adev->platform, query, reply); str = str_parms_to_str(reply); str_parms_destroy(query); @@ -2409,7 +2408,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->format = config->format; if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && - (voice_extn_compress_voip_is_format_supported(in->format))) { + (voice_extn_compress_voip_is_config_supported(config))) { ret = voice_extn_compress_voip_open_input_stream(in); if (ret != 0) { diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 25668cc4f..d5b0f0eae 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -36,12 +36,21 @@ #include "platform.h" #include "voice_extn.h" -#define COMPRESS_VOIP_IO_BUF_SIZE 320 +#define COMPRESS_VOIP_IO_BUF_SIZE_NB 320 +#define COMPRESS_VOIP_IO_BUF_SIZE_WB 640 -struct pcm_config pcm_config_voip = { +struct pcm_config pcm_config_voip_nb = { .channels = 1, .rate = 8000, /* changed when the stream is opened */ - .period_size = COMPRESS_VOIP_IO_BUF_SIZE/2, + .period_size = COMPRESS_VOIP_IO_BUF_SIZE_NB/2, + .period_count = 10, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_voip_wb = { + .channels = 1, + .rate = 16000, /* changed when the stream is opened */ + .period_size = COMPRESS_VOIP_IO_BUF_SIZE_WB/2, .period_count = 10, .format = PCM_FORMAT_S16_LE, }; @@ -83,7 +92,8 @@ static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate, int max_rate); static int voip_set_dtx(struct audio_device *adev, bool enable); static int voip_stop_call(struct audio_device *adev); -static int voip_start_call(struct audio_device *adev); +static int voip_start_call(struct audio_device *adev, + struct pcm_config *voip_config); static int audio_format_to_voip_mode(int format) { @@ -304,12 +314,12 @@ static int voip_stop_call(struct audio_device *adev) return ret; } -static int voip_start_call(struct audio_device *adev) +static int voip_start_call(struct audio_device *adev, + struct pcm_config *voip_config) { int i, ret = 0; struct audio_usecase *uc_info; int pcm_dev_rx_id, pcm_dev_tx_id; - struct pcm_config voip_config = pcm_config_voip; ALOGD("%s: enter", __func__); @@ -341,7 +351,7 @@ static int voip_start_call(struct audio_device *adev) __func__, SOUND_CARD, pcm_dev_rx_id); voip_data.pcm_rx = pcm_open(SOUND_CARD, pcm_dev_rx_id, - PCM_OUT, &voip_config); + PCM_OUT, voip_config); if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) { ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx)); pcm_close(voip_data.pcm_rx); @@ -354,7 +364,7 @@ static int voip_start_call(struct audio_device *adev) __func__, SOUND_CARD, pcm_dev_tx_id); voip_data.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id, - PCM_IN, &voip_config); + PCM_IN, voip_config); if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) { ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx)); pcm_close(voip_data.pcm_rx); @@ -483,12 +493,18 @@ void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out) { - return COMPRESS_VOIP_IO_BUF_SIZE; + if (out->config.rate == 16000) + return COMPRESS_VOIP_IO_BUF_SIZE_WB; + else + return COMPRESS_VOIP_IO_BUF_SIZE_NB; } int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in) { - return COMPRESS_VOIP_IO_BUF_SIZE; + if (in->config.rate == 16000) + return COMPRESS_VOIP_IO_BUF_SIZE_WB; + else + return COMPRESS_VOIP_IO_BUF_SIZE_NB; } int voice_extn_compress_voip_start_output_stream(struct stream_out *out) @@ -499,7 +515,7 @@ int voice_extn_compress_voip_start_output_stream(struct stream_out *out) ALOGD("%s: enter", __func__); - ret = voip_start_call(adev); + ret = voip_start_call(adev, &out->config); out->pcm = voip_data.pcm_rx; uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); uc_info->stream.out = out; @@ -517,7 +533,7 @@ int voice_extn_compress_voip_start_input_stream(struct stream_in *in) ALOGD("%s: enter", __func__); - ret = voip_start_call(adev); + ret = voip_start_call(adev, &in->config); in->pcm = voip_data.pcm_tx; ALOGV("%s: exit: status(%d)", __func__, ret); @@ -548,7 +564,11 @@ int voice_extn_compress_voip_open_output_stream(struct stream_out *out) out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO; out->channel_mask = AUDIO_CHANNEL_OUT_MONO; out->usecase = USECASE_COMPRESS_VOIP_CALL; - out->config = pcm_config_voip; + if (out->sample_rate == 16000) + out->config = pcm_config_voip_wb; + else + out->config = pcm_config_voip_nb; + voip_data.out_stream = out; ret = voip_set_mode(out->dev, out->format); @@ -581,9 +601,10 @@ int voice_extn_compress_voip_open_input_stream(struct stream_in *in) ALOGD("%s: enter", __func__); in->usecase = USECASE_COMPRESS_VOIP_CALL; - sample_rate = in->config.rate; - in->config = pcm_config_voip; - in->config.rate = sample_rate; + if (in->config.rate == 16000) + in->config = pcm_config_voip_wb; + else + in->config = pcm_config_voip_nb; ret = voip_set_mode(in->dev, in->format); @@ -674,3 +695,18 @@ bool voice_extn_compress_voip_is_format_supported(audio_format_t format) return false; } } + +bool voice_extn_compress_voip_is_config_supported(struct audio_config *config) +{ + bool ret = false; + + ret = voice_extn_compress_voip_is_format_supported(config->format); + if (ret) { + if ((popcount(config->channel_mask) == 1) && + (config->sample_rate == 8000 || config->sample_rate == 16000)) + ret = true; + else + ret = false; + } + return ret; +} diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index c12fcb3bf..8d3a7f1ce 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -434,6 +434,23 @@ done: return ret; } +void voice_extn_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply) +{ + int ret; + char value[32]={0}; + char *str = NULL; + + ret = str_parms_get_str(query, "audio_mode", value, + sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, "audio_mode", adev->mode); + } + + ALOGV("%s: returns %s", __func__, str_parms_to_str(reply)); +} + void voice_extn_out_get_parameters(struct stream_out *out, struct str_parms *query, struct str_parms *reply) diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index b3643f908..0ca23863c 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -29,6 +29,9 @@ int voice_extn_get_session_from_use_case(struct audio_device *adev, void voice_extn_init(struct audio_device *adev); int voice_extn_set_parameters(struct audio_device *adev, struct str_parms *parms); +void voice_extn_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply); int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id); @@ -66,6 +69,12 @@ static int voice_extn_set_parameters(struct audio_device *adev, return -ENOSYS; } +static void voice_extn_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply) +{ +} + static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) { return -ENOSYS; @@ -131,6 +140,7 @@ void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, bool voice_extn_compress_voip_pcm_prop_check(); bool voice_extn_compress_voip_is_active(struct audio_device *adev); bool voice_extn_compress_voip_is_format_supported(audio_format_t format); +bool voice_extn_compress_voip_is_config_supported(struct audio_config *config); #else static int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) { @@ -231,11 +241,18 @@ static bool voice_extn_compress_voip_is_active(struct audio_device *adev) ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return false; } + static bool voice_extn_compress_voip_is_format_supported(audio_format_t format) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return true; } + +static bool voice_extn_compress_voip_is_config_supported(struct audio_config *config) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return true; +} #endif #endif //VOICE_EXTN_H -- GitLab From 67c42711906825c3c4210177b76f13d565e08d05 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Wed, 4 Dec 2013 14:03:06 -0800 Subject: [PATCH 103/298] hal: apply bt-sco-wb samplerate mixer - BTSCO WB sample rate mixer control applied after AFE port opened. This results sample rate mismatch and voice call over BT SCO WB does not work - Fix by apply the mixer control before AFE port opened Change-Id: I7efa0db9a24d307780bde03032313ad1f454d6ac --- hal/msm8974/platform.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 3b736f0a5..fea43a34a 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1312,6 +1312,11 @@ int platform_set_parameters(void *platform, struct str_parms *parms) if (ret >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO); my_data->btsco_sample_rate = val; + if (val == SAMPLE_RATE_16KHZ) { + audio_route_apply_path(my_data->adev->audio_route, + "bt-sco-wb-samplerate"); + audio_route_update_mixer(my_data->adev->audio_route); + } } ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val); -- GitLab From e56b485b7a25e397812deb2ef11c3f9aa0e6362a Mon Sep 17 00:00:00 2001 From: Helen Zeng Date: Tue, 3 Dec 2013 16:54:40 -0800 Subject: [PATCH 104/298] hal: Use compress audio for incall recording with AMR WB Currently, AMR WB recording uses tunnel mode instead of software encoding. Update audio hal to use compress audio path to do incall recording with AMR WB format. Change-Id: I93deb3dbc7dcd6a8d2b178334f8b43117ee6841c CRs-Fixed: 581298 --- hal/audio_extn/compress_capture.c | 5 ++++- hal/audio_hw.c | 4 ++++ hal/audio_hw.h | 3 +++ hal/msm8974/platform.c | 6 ++++++ hal/voice.c | 18 +++++++++++++++--- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/hal/audio_extn/compress_capture.c b/hal/audio_extn/compress_capture.c index f3db41926..0a2de3601 100644 --- a/hal/audio_extn/compress_capture.c +++ b/hal/audio_extn/compress_capture.c @@ -93,7 +93,10 @@ bool audio_extn_compr_cap_format_supported(audio_format_t format) bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase) { - if (usecase == USECASE_AUDIO_RECORD_COMPRESS) + if ((usecase == USECASE_AUDIO_RECORD_COMPRESS) || + (usecase == USECASE_INCALL_REC_UPLINK_COMPRESS) || + (usecase == USECASE_INCALL_REC_DOWNLINK_COMPRESS) || + (usecase == USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS)) return true; else return false; diff --git a/hal/audio_hw.c b/hal/audio_hw.c index cd7309490..94b87345d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -119,6 +119,10 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink", + [USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress", + [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress", + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress", + [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink", [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib", diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 0904137d4..ccb02981e 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -84,6 +84,9 @@ typedef enum { USECASE_INCALL_REC_UPLINK, USECASE_INCALL_REC_DOWNLINK, USECASE_INCALL_REC_UPLINK_AND_DOWNLINK, + USECASE_INCALL_REC_UPLINK_COMPRESS, + USECASE_INCALL_REC_DOWNLINK_COMPRESS, + USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS, USECASE_INCALL_MUSIC_UPLINK, USECASE_INCALL_MUSIC_UPLINK2, diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 25f52d699..dfc8ff7b3 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -121,6 +121,12 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { AUDIO_RECORD_PCM_DEVICE}, [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, + [USECASE_INCALL_REC_UPLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, + COMPRESS_CAPTURE_DEVICE}, + [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, + COMPRESS_CAPTURE_DEVICE}, + [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, + COMPRESS_CAPTURE_DEVICE}, [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE, INCALL_MUSIC_UPLINK_PCM_DEVICE}, [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE, diff --git a/hal/voice.c b/hal/voice.c index 25b53d4cd..afbd0afda 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -212,15 +212,27 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, if (voice_is_in_call(adev)) { switch (in->source) { case AUDIO_SOURCE_VOICE_UPLINK: - in->usecase = USECASE_INCALL_REC_UPLINK; + if (audio_extn_compr_cap_enabled() && + audio_extn_compr_cap_format_supported(in->config.format)) { + in->usecase = USECASE_INCALL_REC_UPLINK_COMPRESS; + } else + in->usecase = USECASE_INCALL_REC_UPLINK; rec_mode = INCALL_REC_UPLINK; break; case AUDIO_SOURCE_VOICE_DOWNLINK: - in->usecase = USECASE_INCALL_REC_DOWNLINK; + if (audio_extn_compr_cap_enabled() && + audio_extn_compr_cap_format_supported(in->config.format)) { + in->usecase = USECASE_INCALL_REC_DOWNLINK_COMPRESS; + } else + in->usecase = USECASE_INCALL_REC_DOWNLINK; rec_mode = INCALL_REC_DOWNLINK; break; case AUDIO_SOURCE_VOICE_CALL: - in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK; + if (audio_extn_compr_cap_enabled() && + audio_extn_compr_cap_format_supported(in->config.format)) { + in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS; + } else + in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK; rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK; break; default: -- GitLab From 735390cff998b22b3abcb580d3c9b19787d15429 Mon Sep 17 00:00:00 2001 From: Kiran Kandi Date: Thu, 5 Dec 2013 15:50:01 -0800 Subject: [PATCH 105/298] hal: pass set parameters call to listen hal Pass set parameters call to listen hal. Currently it used to handle SSR in listen hal. Change-Id: Ia8df94ca87916afff45fe4e3fd569f6268bc3560 --- hal/audio_extn/listen.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c index 65c0ae68f..9166f8eb5 100644 --- a/hal/audio_extn/listen.c +++ b/hal/audio_extn/listen.c @@ -119,6 +119,12 @@ void audio_extn_listen_update_status(snd_device_t snd_device, void audio_extn_listen_set_parameters(struct audio_device *adev, struct str_parms *parms) { + ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + + if (listen_dev) { + listen_dev->listen_set_parameters(&adev->device, str_parms_to_str(parms)); + } + return; } -- GitLab From 44733a4b2f666d9e5f34c519666481f740bb6d5d Mon Sep 17 00:00:00 2001 From: Nagender Date: Sun, 8 Dec 2013 00:05:20 -0700 Subject: [PATCH 106/298] qcom/audio: add kenel headers as dependency Ensures that kernel headers are built before they are utilized. Change-Id: Ie270bcf9ca0bb48a1a08c469f11e562953dbd5de --- hal/Android.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hal/Android.mk b/hal/Android.mk index d8a4733f7..037be5681 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -62,6 +62,7 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS)),true) LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED LOCAL_SRC_FILES += voice_extn/voice_extn.c LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED @@ -78,6 +79,7 @@ ifneq ($(filter msm8974,$(TARGET_BOARD_PLATFORM)),) LOCAL_CFLAGS += -DSPKR_PROT_ENABLED LOCAL_SRC_FILES += audio_extn/spkr_protection.c LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr endif endif @@ -94,6 +96,7 @@ endif ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true) LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr endif LOCAL_SHARED_LIBRARIES := \ -- GitLab From b9012ab54a0dba807653701d124de16ac4e4580a Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Tue, 10 Dec 2013 13:44:56 -0800 Subject: [PATCH 107/298] audio: Re-arrange member var initializations Rearrange initializations of some stream_out member variables to prevent possible uninitialized use. CRs-Fixed: 587676 Change-Id: I7018f38f29a19b130185b285f4acf22219e4228c --- hal/audio_hw.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 04066275e..afcb2e52d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -857,9 +857,6 @@ static void *offload_thread_loop(void *context) struct stream_out *out = (struct stream_out *) context; struct listnode *item; - out->offload_state = OFFLOAD_STATE_IDLE; - out->playback_started = 0; - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); set_sched_policy(0, SP_FOREGROUND); prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0); @@ -2001,6 +1998,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev, *stream_out = NULL; out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + if (!out) { + return -ENOMEM; + } + + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + if (devices == AUDIO_DEVICE_NONE) devices = AUDIO_DEVICE_OUT_SPEAKER; @@ -2094,6 +2098,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->non_blocking = 1; out->send_new_metadata = 1; + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + create_offload_callback_thread(out); ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, @@ -2168,9 +2175,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, /* out->muted = false; by calloc() */ /* out->written = 0; by calloc() */ - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); - config->format = out->stream.common.get_format(&out->stream.common); config->channel_mask = out->stream.common.get_channels(&out->stream.common); config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); -- GitLab From 7294f5224b9ed1d9e631e718c7d08fc67544eb7d Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Wed, 11 Dec 2013 05:07:00 +0530 Subject: [PATCH 108/298] audio: hal: Fix to use correct EC_REF_RX In 8610, we need to use I2S_RX as ec_ref_rx parameter and for SLIM based targets use SLIM_RX. CRs-Fixed: 575647 Change-Id: Ia220498f302a58dc3dbd42b1874fa01f081ce3dd --- hal/msm8974/platform.c | 6 +++--- hal/msm8974/platform.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index dfc8ff7b3..d88fb1099 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -992,7 +992,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (my_data->fluence_type == FLUENCE_NONE || my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; - set_echo_reference(adev->mixer, "SLIM_RX"); + set_echo_reference(adev->mixer, EC_REF_RX); } else { snd_device = SND_DEVICE_IN_VOICE_DMIC; adev->acdb_settings |= DMIC_FLAG; @@ -1061,7 +1061,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; } - set_echo_reference(adev->mixer, "SLIM_RX"); + set_echo_reference(adev->mixer, EC_REF_RX); } else if (adev->active_input->enable_aec) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { if (my_data->fluence_type & FLUENCE_DUAL_MIC) { @@ -1078,7 +1078,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; } - set_echo_reference(adev->mixer, "SLIM_RX"); + set_echo_reference(adev->mixer, EC_REF_RX); } else if (adev->active_input->enable_ns) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { if (my_data->fluence_type & FLUENCE_DUAL_MIC) { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 8518c7d05..8356cab9d 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -183,8 +183,10 @@ enum { #ifdef PLATFORM_MSM8610 #define LOWLATENCY_PCM_DEVICE 12 +#define EC_REF_RX "I2S_RX" #else #define LOWLATENCY_PCM_DEVICE 15 +#define EC_REF_RX "SLIM_RX" #endif #ifdef PLATFORM_MSM8x26 #define COMPRESS_CAPTURE_DEVICE 20 -- GitLab From 5a27e817c66db5740995e43eefdac98f80224dac Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Tue, 10 Dec 2013 19:19:46 -0800 Subject: [PATCH 109/298] hal: Remove repeated unwanted code - Remove the unwanted repeated code which happen during merge CRs-Fixed: 587086 Change-Id: If6c298b2006a2d130b2c88e4ca268eddea3acbcc --- hal/audio_hw.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 96691e673..937c79ba2 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -395,12 +395,6 @@ static void check_usecases_codec_backend(struct audio_device *adev, } } - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (switch_device[usecase->id]) { - enable_snd_device(adev, snd_device, false); - } - } /* Make sure new snd device is enabled before re-routing the streams */ audio_route_update_mixer(adev->audio_route); -- GitLab From be677c346d1995b98c36bb41741541bf357207bb Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Wed, 11 Dec 2013 13:34:09 -0800 Subject: [PATCH 110/298] hal: Device switch should happen only during anc enable/disable -Device switch used to happend even if the setparameter was not for AUDIO_PARAMETER_KEY_ANC since it was outside the if condition. Hence move the switch device inside the condition. Change-Id: I0f51356900709401bf2f1ea3c98b80861128aef3 CRs-Fixed: 575732 --- hal/audio_extn/audio_extn.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 72e2f9c13..176df8ca7 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -119,18 +119,18 @@ void audio_extn_set_anc_parameters(struct audio_device *adev, aextnmod.anc_enabled = true; else aextnmod.anc_enabled = false; - } - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == PCM_PLAYBACK) { - if (usecase->stream.out->devices == \ - AUDIO_DEVICE_OUT_WIRED_HEADPHONE || - usecase->stream.out->devices == \ - AUDIO_DEVICE_OUT_WIRED_HEADSET) { - select_devices(adev, usecase->id); - ALOGV("%s: switching device", __func__); - break; + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK) { + if (usecase->stream.out->devices == \ + AUDIO_DEVICE_OUT_WIRED_HEADPHONE || + usecase->stream.out->devices == \ + AUDIO_DEVICE_OUT_WIRED_HEADSET) { + select_devices(adev, usecase->id); + ALOGV("%s: switching device", __func__); + break; + } } } } -- GitLab From 584048b714c6e6945c0d85fb30fdef31874cefc9 Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Wed, 11 Dec 2013 17:00:50 -0800 Subject: [PATCH 111/298] hal: HFP device id change due to reorder of dai link in kernel - Front end Dai link for HFP was moved to group with all the Front End Dai in kernel. Hence the device id would change. Also cleanup of the code to match up other implementations Change-Id: I0b5444190ddb8610c234a9608d53c3e845d86fd5 --- hal/audio_extn/hfp.c | 40 ++++++++++++++++++++-------------------- hal/msm8974/platform.h | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index 73824bdff..e0bdc52eb 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -43,10 +43,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ #ifdef HFP_ENABLED #define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable" -static int32_t audio_extn_start_hfp(struct audio_device *adev, +static int32_t start_hfp(struct audio_device *adev, struct str_parms *parms); -static int32_t audio_extn_stop_hfp(struct audio_device *adev); +static int32_t stop_hfp(struct audio_device *adev); struct hfp_module { struct pcm *hfp_sco_rx; @@ -76,22 +76,7 @@ static struct pcm_config pcm_config_hfp = { .avail_min = 0, }; -void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) -{ - int ret; - char value[32]={0}; - - ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, - sizeof(value)); - if (ret >= 0) { - if(!strncmp(value,"true",sizeof(value))) - ret = audio_extn_start_hfp(adev,parms); - else - audio_extn_stop_hfp(adev); - } -} - -static int32_t audio_extn_start_hfp(struct audio_device *adev, +static int32_t start_hfp(struct audio_device *adev, struct str_parms *parms) { int32_t i, ret = 0; @@ -177,12 +162,12 @@ static int32_t audio_extn_start_hfp(struct audio_device *adev, return 0; exit: - audio_extn_stop_hfp(adev); + stop_hfp(adev); ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret); return ret; } -static int32_t audio_extn_stop_hfp(struct audio_device *adev) +static int32_t stop_hfp(struct audio_device *adev) { int32_t i, ret = 0; struct audio_usecase *uc_info; @@ -228,4 +213,19 @@ static int32_t audio_extn_stop_hfp(struct audio_device *adev) ALOGD("%s: exit: status(%d)", __func__, ret); return ret; } + +void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) +{ + int ret; + char value[32]={0}; + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, + sizeof(value)); + if (ret >= 0) { + if(!strncmp(value,"true",sizeof(value))) + ret = start_hfp(adev,parms); + else + stop_hfp(adev); + } +} #endif /*HFP_ENABLED*/ diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 8518c7d05..bac7fc379 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -171,8 +171,8 @@ enum { #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 #define HFP_PCM_RX 5 -#define HFP_SCO_RX 35 -#define HFP_ASM_RX_TX 36 +#define HFP_SCO_RX 22 +#define HFP_ASM_RX_TX 23 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 -- GitLab From eff07efe6e05723173fd2edecab2ee7ee204946c Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Thu, 21 Nov 2013 20:39:59 -0800 Subject: [PATCH 112/298] hal: Add property to configure the compress offload fragment size. Add property - audio.offload.buffer.size.kbytes to configure offload fragment size. The maximum value for fragment size is 256k. Default value is 32k. The minimum value is 8k. Change-Id: I9b440a420270b27f5fdba9f82de6944da0afb9d2 --- hal/audio_hw.c | 28 ++++++++++++++++++++++++++-- hal/audio_hw.h | 6 ++++++ hal/msm8974/hw_info.c | 5 ----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index bca6a2674..bc3cd0d7c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -53,7 +53,8 @@ #include "voice_extn.h" #include "sound/compress_params.h" - +#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024) +#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (8 * 1024) #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 /* ToDo: Check and update a proper value in msec */ @@ -144,6 +145,7 @@ static pthread_mutex_t adev_init_lock; static unsigned int audio_device_ref_count; static int set_voice_volume_l(struct audio_device *adev, float volume); +static uint32_t get_offload_buffer_size(); static bool is_supported_format(audio_format_t format) { @@ -2076,7 +2078,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, else out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); - out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + out->compr_config.fragment_size = get_offload_buffer_size(); out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; out->compr_config.codec->sample_rate = compress_get_alsa_rate(config->offload_info.sample_rate); @@ -2631,6 +2633,28 @@ static int adev_open(const hw_module_t *module, const char *name, return 0; } +/* Read offload buffer size from a property. + * If value is not power of 2 round it to + * power of 2. + */ +static uint32_t get_offload_buffer_size() +{ + char value[PROPERTY_VALUE_MAX] = {0}; + uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + if((property_get("audio.offload.buffer.size.kb", value, "")) && + atoi(value)) { + fragment_size = atoi(value) * 1024; + //ring buffer size needs to be 4k aligned. + CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096)); + } + if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + ALOGVV("%s: fragment_size %d", __func__, fragment_size); + return fragment_size; +} + static struct hw_module_methods_t hal_module_methods = { .open = adev_open, }; diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 0904137d4..d23c184fc 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -246,6 +246,12 @@ int enable_audio_route(struct audio_device *adev, bool update_mixer); struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id); + +#define LITERAL_TO_STRING(x) #x +#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\ + __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ + " ASSERT_FATAL(" #condition ") failed.") + /* * NOTE: when multiple mutexes have to be acquired, always take the * stream_in or stream_out mutex first, followed by the audio_device mutex. diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index 58ca4dc54..fd943bac2 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -51,11 +51,6 @@ struct hardware_info { #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#define LITERAL_TO_STRING(x) #x -#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\ - __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ - " ASSERT_FATAL(" #condition ") failed.") - static const snd_device_t taiko_fluid_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, -- GitLab From 3ade279a804814f92b0c30bae089b61e509ad998 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Mon, 2 Dec 2013 11:02:20 -0800 Subject: [PATCH 113/298] hal: Fix slowtalk key value type Slowtalk key value is defined as string in upper layer but HAL expects key value as type 'int' which causes type mismatch. change slowtalk key value as string. Change-Id: I66499436d1d09528e4f4b3079c39c9c1a0777385 --- hal/msm8974/platform.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index dfc8ff7b3..0cb47cd06 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1306,7 +1306,7 @@ int platform_set_parameters(void *platform, struct str_parms *parms) { struct platform_data *my_data = (struct platform_data *)platform; char *str; - char value[32]; + char value[256] = {0}; int val; int ret = 0; @@ -1323,10 +1323,15 @@ int platform_set_parameters(void *platform, struct str_parms *parms) } } - ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value)); if (ret >= 0) { + bool state = false; + if (!strncmp("true", value, sizeof("true"))) { + state = true; + } + str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK); - ret = platform_set_slowtalk(my_data, val); + ret = platform_set_slowtalk(my_data, state); if (ret) ALOGE("%s: Failed to set slow talk err: %d", __func__, ret); } @@ -1449,8 +1454,8 @@ void platform_get_parameters(void *platform, ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value)); if (ret >= 0) { - str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SLOWTALK, - my_data->slowtalk); + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SLOWTALK, + my_data->slowtalk?"true":"false"); } ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply)); -- GitLab From 947cb9053a08291fd62d99e4049aecb41c9f599f Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Mon, 9 Dec 2013 13:45:39 -0800 Subject: [PATCH 114/298] hal: Support for multi-channel for AFE_PROXY - Add 5.1 and 7.1 channel support to AFE_PROXY device Change-Id: I124af373f8823ae670a392fdedbfe26141a137e5 CRs-fixed: 585698 --- hal/audio_extn/audio_extn.c | 105 +++++++++++++++++++++++++++++++++++- hal/audio_extn/audio_extn.h | 2 + hal/audio_hw.c | 12 +++-- 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 176df8ca7..3f457d20f 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -143,6 +143,77 @@ void audio_extn_set_anc_parameters(struct audio_device *adev, #define audio_extn_set_afe_proxy_parameters(parms) (0) #define audio_extn_get_afe_proxy_parameters(query, reply) (0) #else +/* Front left channel. */ +#define PCM_CHANNEL_FL 1 + +/* Front right channel. */ +#define PCM_CHANNEL_FR 2 + +/* Front center channel. */ +#define PCM_CHANNEL_FC 3 + +/* Left surround channel.*/ +#define PCM_CHANNEL_LS 4 + +/* Right surround channel.*/ +#define PCM_CHANNEL_RS 5 + +/* Low frequency effect channel. */ +#define PCM_CHANNEL_LFE 6 + +/* Left back channel; Rear left channel. */ +#define PCM_CHANNEL_LB 8 + +/* Right back channel; Rear right channel. */ +#define PCM_CHANNEL_RB 9 + +static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev, + int channel_count) +{ + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Playback Channel Map"; + int set_values[8] = {0}; + int ret; + ALOGV("%s channel_count:%d",__func__, channel_count); + + switch (channel_count) { + case 6: + set_values[0] = PCM_CHANNEL_FL; + set_values[1] = PCM_CHANNEL_FR; + set_values[2] = PCM_CHANNEL_FC; + set_values[3] = PCM_CHANNEL_LFE; + set_values[4] = PCM_CHANNEL_LS; + set_values[5] = PCM_CHANNEL_RS; + break; + case 8: + set_values[0] = PCM_CHANNEL_FL; + set_values[1] = PCM_CHANNEL_FR; + set_values[2] = PCM_CHANNEL_FC; + set_values[3] = PCM_CHANNEL_LFE; + set_values[4] = PCM_CHANNEL_LS; + set_values[5] = PCM_CHANNEL_RS; + set_values[6] = PCM_CHANNEL_LB; + set_values[7] = PCM_CHANNEL_RB; + break; + default: + ALOGE("unsupported channels(%d) for setting channel map", + channel_count); + return -EINVAL; + } + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + ALOGV("AFE: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", + set_values[0], set_values[1], set_values[2], set_values[3], set_values[4], + set_values[5], set_values[6], set_values[7], channel_count); + ret = mixer_ctl_set_array(ctl, set_values, channel_count); + return ret; +} + int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) { int32_t ret = 0; @@ -150,7 +221,6 @@ int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) struct mixer_ctl *ctl = NULL; const char *mixer_ctl_name = "PROXY_RX Channels"; - ALOGD("%s: entry", __func__); /* use the existing channel count set by hardware params to configure the back end for stereo as usb/a2dp would be @@ -177,6 +247,11 @@ int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) } mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); + if (aextnmod.proxy_channel_num == 6 || + aextnmod.proxy_channel_num == 8) + ret = afe_proxy_set_channel_mapping(adev, + aextnmod.proxy_channel_num); + ALOGD("%s: exit", __func__); return ret; } @@ -215,6 +290,34 @@ int audio_extn_get_afe_proxy_parameters(struct str_parms *query, return 0; } + +/* must be called with hw device mutex locked */ +int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out) +{ + int ret = 0; + int channels = aextnmod.proxy_channel_num; + + switch (channels) { + /* + * Do not handle stereo output in Multi-channel cases + * Stereo case is handled in normal playback path + */ + case 6: + ALOGV("%s: AFE PROXY supports 5.1", __func__); + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; + break; + case 8: + ALOGV("%s: AFE PROXY supports 5.1 and 7.1 channels", __func__); + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1; + out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1; + break; + default: + ALOGE("AFE PROXY does not support multi channel playback"); + ret = -ENOSYS; + break; + } + return ret; +} #endif /* AFE_PROXY_ENABLED */ void audio_extn_set_parameters(struct audio_device *adev, diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index e6db5c152..c6d06df3a 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -41,8 +41,10 @@ bool audio_extn_should_use_handset_anc(int in_channels); #ifndef AFE_PROXY_ENABLED #define audio_extn_set_afe_proxy_channel_mixer(adev) (0) +#define audio_extn_read_afe_proxy_channel_masks(out) (0) #else int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev); +int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out); #endif #ifndef USB_HEADSET_ENABLED diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 937c79ba2..b8195b40a 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2008,10 +2008,16 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->handle = handle; /* Init use case and pcm_config */ - if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT && - out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) && + (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL || + out->devices & AUDIO_DEVICE_OUT_PROXY)) { + pthread_mutex_lock(&adev->lock); - ret = read_hdmi_channel_masks(out); + if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + ret = read_hdmi_channel_masks(out); + + if (out->devices & AUDIO_DEVICE_OUT_PROXY) + ret = audio_extn_read_afe_proxy_channel_masks(out); pthread_mutex_unlock(&adev->lock); if (ret != 0) goto error_open; -- GitLab From adfe4e32250ff905d4e0af9037b607794e9d6b4e Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Fri, 13 Dec 2013 14:51:26 -0800 Subject: [PATCH 115/298] hal: Fix voice call with QUAD MIC voice call using quad mic doesn't work. Fix this by update quad mic acdb entry in the table. Change-Id: I744ac2fe26e39e24f0b0c8f0eed337c86cd7bd6c --- hal/msm8974/platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index dfc8ff7b3..4434ee79d 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -193,6 +193,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic", [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef", [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", + [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = "voice-speaker-qmic", [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", @@ -265,6 +266,7 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_CAMCORDER_MIC] = 4, [SND_DEVICE_IN_VOICE_DMIC] = 41, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43, + [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = 19, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, -- GitLab From 84fa2fe20e798e0a0a353ec2dddf0a070aacfe3e Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Wed, 4 Dec 2013 11:57:47 -0800 Subject: [PATCH 116/298] hal: Detect sound card dynamically - HAL always assumed SOUND_CARD/MIXER_CARD number to be zero. This could cause HAL not to load when some other card is detected earlier to HAL. - Fix by removing these Macro(s) and reading correct sound card number runtime while loading - Corrected its use cases across HAL replacing it with appropriate platform API CRs-fixed: 580226 Change-Id: I4512e4a2f7f81d8415c3ba8ec393c96867e6d69a --- hal/audio_extn/audio_extn.h | 6 +-- hal/audio_extn/fm.c | 16 +++---- hal/audio_extn/hfp.c | 14 +++---- hal/audio_extn/spkr_protection.c | 15 ++++--- hal/audio_extn/usb.c | 10 ++++- hal/audio_hw.c | 17 ++++---- hal/audio_hw.h | 1 + hal/msm8974/platform.c | 71 +++++++++++++++++++++----------- hal/msm8974/platform.h | 3 -- hal/voice.c | 8 ++-- hal/voice_extn/compress_voip.c | 8 ++-- 11 files changed, 99 insertions(+), 70 deletions(-) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index c6d06df3a..6bd03eeb8 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -96,14 +96,11 @@ void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, #endif #ifndef AUDIO_LISTEN_ENABLED - #define audio_extn_listen_init(adev, snd_card) (0) #define audio_extn_listen_deinit(adev) (0) #define audio_extn_listen_update_status(uc_info, event) (0) #define audio_extn_listen_set_parameters(adev, parms) (0) - #else - enum listen_event_type { LISTEN_EVENT_SND_DEVICE_FREE, LISTEN_EVENT_SND_DEVICE_BUSY @@ -116,11 +113,10 @@ void audio_extn_listen_update_status(snd_device_t snd_device, listen_event_type_t event); void audio_extn_listen_set_parameters(struct audio_device *adev, struct str_parms *parms); - #endif /* AUDIO_LISTEN_ENABLED */ #ifndef AUXPCM_BT_ENABLED -#define audio_extn_read_xml(adev, MIXER_CARD, MIXER_XML_PATH, \ +#define audio_extn_read_xml(adev, mixer_card, MIXER_XML_PATH, \ MIXER_XML_PATH_AUXPCM) (-ENOSYS) #else int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card, diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c index eeba404a7..a4157f8a5 100644 --- a/hal/audio_extn/fm.c +++ b/hal/audio_extn/fm.c @@ -170,10 +170,10 @@ static int32_t fm_start(struct audio_device *adev) __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_rx_id); - fmmod.fm_pcm_rx = pcm_open(SOUND_CARD, - pcm_dev_rx_id, - PCM_OUT, &pcm_config_fm); + __func__, adev->snd_card, pcm_dev_rx_id); + fmmod.fm_pcm_rx = pcm_open(adev->snd_card, + pcm_dev_rx_id, + PCM_OUT, &pcm_config_fm); if (fmmod.fm_pcm_rx && !pcm_is_ready(fmmod.fm_pcm_rx)) { ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_rx)); ret = -EIO; @@ -181,10 +181,10 @@ static int32_t fm_start(struct audio_device *adev) } ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_tx_id); - fmmod.fm_pcm_tx = pcm_open(SOUND_CARD, - pcm_dev_tx_id, - PCM_IN, &pcm_config_fm); + __func__, adev->snd_card, pcm_dev_tx_id); + fmmod.fm_pcm_tx = pcm_open(adev->snd_card, + pcm_dev_tx_id, + PCM_IN, &pcm_config_fm); if (fmmod.fm_pcm_tx && !pcm_is_ready(fmmod.fm_pcm_tx)) { ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_tx)); ret = -EIO; diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index e0bdc52eb..6b0546a3b 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -113,8 +113,8 @@ static int32_t start_hfp(struct audio_device *adev, __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id); ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_rx_id); - hfpmod.hfp_sco_rx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_rx_id); + hfpmod.hfp_sco_rx = pcm_open(adev->snd_card, pcm_dev_asm_rx_id, PCM_OUT, &pcm_config_hfp); if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) { @@ -123,8 +123,8 @@ static int32_t start_hfp(struct audio_device *adev, goto exit; } ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_tx_id); - hfpmod.hfp_pcm_rx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_tx_id); + hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card, pcm_dev_rx_id, PCM_OUT, &pcm_config_hfp); if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) { @@ -132,7 +132,7 @@ static int32_t start_hfp(struct audio_device *adev, ret = -EIO; goto exit; } - hfpmod.hfp_sco_tx = pcm_open(SOUND_CARD, + hfpmod.hfp_sco_tx = pcm_open(adev->snd_card, pcm_dev_asm_tx_id, PCM_IN, &pcm_config_hfp); if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) { @@ -141,8 +141,8 @@ static int32_t start_hfp(struct audio_device *adev, goto exit; } ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_tx_id); - hfpmod.hfp_pcm_tx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_tx_id); + hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card, pcm_dev_tx_id, PCM_IN, &pcm_config_hfp); if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) { diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c index 0fc790aa0..5ec7ebaf1 100644 --- a/hal/audio_extn/spkr_protection.c +++ b/hal/audio_extn/spkr_protection.c @@ -240,8 +240,9 @@ static int spkr_calibrate(int t0) goto exit; } handle.pcm_rx = handle.pcm_tx = NULL; - handle.pcm_rx = pcm_open(SOUND_CARD, pcm_dev_rx_id, - PCM_OUT, &pcm_config_skr_prot); + handle.pcm_rx = pcm_open(adev->snd_card, + pcm_dev_rx_id, + PCM_OUT, &pcm_config_skr_prot); if (handle.pcm_rx && !pcm_is_ready(handle.pcm_rx)) { ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_rx)); status.status = -EIO; @@ -267,8 +268,9 @@ static int spkr_calibrate(int t0) status.status = -ENODEV; goto exit; } - handle.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id, - PCM_IN, &pcm_config_skr_prot); + handle.pcm_tx = pcm_open(adev->snd_card, + pcm_dev_tx_id, + PCM_IN, &pcm_config_skr_prot); if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) { ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx)); status.status = -EIO; @@ -618,8 +620,9 @@ int audio_extn_spkr_prot_start_processing(snd_device_t snd_device) ret = -ENODEV; goto exit; } - handle.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id, - PCM_IN, &pcm_config_skr_prot); + handle.pcm_tx = pcm_open(adev->snd_card, + pcm_dev_tx_id, + PCM_IN, &pcm_config_skr_prot); if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) { ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx)); ret = -EIO; diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c index 88af9bef2..88e3cad00 100644 --- a/hal/audio_extn/usb.c +++ b/hal/audio_extn/usb.c @@ -348,7 +348,10 @@ static int32_t usb_playback_entry(void *adev) usbmod->proxy_pcm_playback_handle = pcm_open(usbmod->proxy_card, usbmod->proxy_device_id, PCM_IN | PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod); - if(!usbmod->proxy_pcm_playback_handle){ + if(usbmod->proxy_pcm_playback_handle + && !pcm_is_ready(usbmod->proxy_pcm_playback_handle)){ + pcm_close(usbmod->proxy_pcm_playback_handle); + usbmod->proxy_pcm_playback_handle = NULL; proxy_open_retry_count--; usleep(USB_PROXY_OPEN_WAIT_TIME * 1000); ALOGE("%s: pcm_open for proxy failed retrying = %d", @@ -463,7 +466,10 @@ static int32_t usb_record_entry(void *adev) usbmod->proxy_pcm_record_handle = pcm_open(usbmod->proxy_card, usbmod->proxy_device_id, PCM_OUT | PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod); - if(!usbmod->proxy_pcm_record_handle){ + if(usbmod->proxy_pcm_record_handle + && !pcm_is_ready(usbmod->proxy_pcm_record_handle)){ + pcm_close(usbmod->proxy_pcm_record_handle); + usbmod->proxy_pcm_record_handle = NULL; proxy_open_retry_count--; usleep(USB_PROXY_OPEN_WAIT_TIME * 1000); ALOGE("%s: pcm_open for proxy(recording) failed retrying = %d", diff --git a/hal/audio_hw.c b/hal/audio_hw.c index b8195b40a..fc786109b 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -796,9 +796,10 @@ int start_input_stream(struct stream_in *in) select_devices(adev, in->usecase); ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", - __func__, SOUND_CARD, in->pcm_device_id, in->config.channels); - in->pcm = pcm_open(SOUND_CARD, in->pcm_device_id, - PCM_IN, &in->config); + __func__, adev->snd_card, + in->pcm_device_id, in->config.channels); + in->pcm = pcm_open(adev->snd_card, + in->pcm_device_id, PCM_IN, &in->config); if (in->pcm && !pcm_is_ready(in->pcm)) { ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); pcm_close(in->pcm); @@ -1113,8 +1114,9 @@ int start_output_stream(struct stream_out *out) ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", __func__, 0, out->pcm_device_id); if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { - out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, - PCM_OUT | PCM_MONOTONIC, &out->config); + out->pcm = pcm_open(adev->snd_card, + out->pcm_device_id, + PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm && !pcm_is_ready(out->pcm)) { ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); pcm_close(out->pcm); @@ -1124,7 +1126,8 @@ int start_output_stream(struct stream_out *out) } } else { out->pcm = NULL; - out->compr = compress_open(SOUND_CARD, out->pcm_device_id, + out->compr = compress_open(adev->snd_card, + out->pcm_device_id, COMPRESS_IN, &out->compr_config); if (out->compr && !is_compress_ready(out->compr)) { ALOGE("%s: %s", __func__, compress_get_error(out->compr)); @@ -2607,7 +2610,7 @@ static int adev_open(const hw_module_t *module, const char *name, "visualizer_hal_stop_output"); } } - audio_extn_listen_init(adev, SOUND_CARD); + audio_extn_listen_init(adev, adev->snd_card); if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) { adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index ccb02981e..305547096 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -223,6 +223,7 @@ struct audio_device { struct voice voice; unsigned int cur_hdmi_channels; + int snd_card; void *platform; void *visualizer_lib; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index dfc8ff7b3..4c2183602 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -53,6 +53,7 @@ /* Retry for delay in FW loading*/ #define RETRY_NUMBER 10 #define RETRY_US 500000 +#define MAX_SND_CARD 8 #define SAMPLE_RATE_8KHZ 8000 #define SAMPLE_RATE_16KHZ 16000 @@ -428,38 +429,58 @@ void *platform_init(struct audio_device *adev) char platform[PROPERTY_VALUE_MAX]; char baseband[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX]; - struct platform_data *my_data; - int retry_num = 0; + struct platform_data *my_data = NULL; + int retry_num = 0, snd_card_num = 0; const char *snd_card_name; - adev->mixer = mixer_open(MIXER_CARD); + my_data = calloc(1, sizeof(struct platform_data)); - while (!adev->mixer && retry_num < RETRY_NUMBER) { - usleep(RETRY_US); - adev->mixer = mixer_open(MIXER_CARD); - retry_num++; - } + while (snd_card_num < MAX_SND_CARD) { + adev->mixer = mixer_open(snd_card_num); - if (!adev->mixer) { - ALOGE("Unable to open the mixer, aborting."); - return NULL; - } + while (!adev->mixer && retry_num < RETRY_NUMBER) { + usleep(RETRY_US); + adev->mixer = mixer_open(snd_card_num); + retry_num++; + } - if (audio_extn_read_xml(adev, MIXER_CARD, MIXER_XML_PATH, - MIXER_XML_PATH_AUXPCM) == -ENOSYS) - adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH); + if (!adev->mixer) { + ALOGE("%s: Unable to open the mixer card: %d", __func__, + snd_card_num); + retry_num = 0; + snd_card_num++; + continue; + } - if (!adev->audio_route) { - ALOGE("%s: Failed to init audio route controls, aborting.", __func__); - return NULL; - } + snd_card_name = mixer_get_name(adev->mixer); + ALOGV("%s: snd_card_name: %s", __func__, snd_card_name); - my_data = calloc(1, sizeof(struct platform_data)); + my_data->hw_info = hw_info_init(snd_card_name); + if (!my_data->hw_info) { + ALOGE("%s: Failed to init hardware info", __func__); + } else { + if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH, + MIXER_XML_PATH_AUXPCM) == -ENOSYS) + adev->audio_route = audio_route_init(snd_card_num, + MIXER_XML_PATH); + if (!adev->audio_route) { + ALOGE("%s: Failed to init audio route controls, aborting.", + __func__); + free(my_data); + return NULL; + } + adev->snd_card = snd_card_num; + ALOGD("%s: Opened sound card:%d", __func__, snd_card_num); + break; + } + retry_num = 0; + snd_card_num++; + } - snd_card_name = mixer_get_name(adev->mixer); - my_data->hw_info = hw_info_init(snd_card_name); - if (!my_data->hw_info) { - ALOGE("%s: Failed to init hardware info", __func__); + if (snd_card_num >= MAX_SND_CARD) { + ALOGE("%s: Unable to find correct sound card, aborting.", __func__); + free(my_data); + return NULL; } my_data->adev = adev; @@ -536,6 +557,8 @@ void *platform_init(struct audio_device *adev) /* init usb */ audio_extn_usb_init(adev); + /* update sound cards appropriately */ + audio_extn_usb_set_proxy_sound_card(adev->snd_card); /* Read one time ssr property */ audio_extn_ssr_update_enabled(adev); diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index bac7fc379..388c36ec9 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -126,9 +126,6 @@ enum { }; -#define MIXER_CARD 0 -#define SOUND_CARD 0 - #define DEFAULT_OUTPUT_SAMPLING_RATE 48000 #define ALL_SESSION_VSID 0xFFFFFFFF diff --git a/hal/voice.c b/hal/voice.c index afbd0afda..cbf895641 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -135,8 +135,8 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) } ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_rx_id); - session->pcm_rx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_rx_id); + session->pcm_rx = pcm_open(adev->snd_card, pcm_dev_rx_id, PCM_OUT, &voice_config); if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) { @@ -146,8 +146,8 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) } ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_tx_id); - session->pcm_tx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_tx_id); + session->pcm_tx = pcm_open(adev->snd_card, pcm_dev_tx_id, PCM_IN, &voice_config); if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) { diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index d5b0f0eae..ee9fd309f 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -348,8 +348,8 @@ static int voip_start_call(struct audio_device *adev, } ALOGD("%s: Opening PCM playback device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_rx_id); - voip_data.pcm_rx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_rx_id); + voip_data.pcm_rx = pcm_open(adev->snd_card, pcm_dev_rx_id, PCM_OUT, voip_config); if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) { @@ -361,8 +361,8 @@ static int voip_start_call(struct audio_device *adev, } ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)", - __func__, SOUND_CARD, pcm_dev_tx_id); - voip_data.pcm_tx = pcm_open(SOUND_CARD, + __func__, adev->snd_card, pcm_dev_tx_id); + voip_data.pcm_tx = pcm_open(adev->snd_card, pcm_dev_tx_id, PCM_IN, voip_config); if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) { -- GitLab From 6e57d7e4b8eb728ca480cc763ed57b1c1e0b6f5c Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Mon, 16 Dec 2013 16:02:45 -0800 Subject: [PATCH 117/298] hal: Fix for adev_open causing hang - Mutex acquired in the begining of the synchronised block but is not unlocked when platform_init fails. - Fix by adding the mutex unlock code. Change-Id: I02b7f7cac0185dd40ec9f03e443e4de98b18c105 CRs-fixed: 590216 --- hal/audio_hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fc786109b..bf08eb8a0 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2593,6 +2593,7 @@ static int adev_open(const hw_module_t *module, const char *name, free(adev); ALOGE("%s: Failed to init platform data, aborting.", __func__); *device = NULL; + pthread_mutex_unlock(&adev_init_lock); return -EINVAL; } -- GitLab From eeb9024bef43c03fddc8f3f01062983749310f08 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Tue, 17 Dec 2013 12:24:16 -0800 Subject: [PATCH 118/298] policy_hal: remove unused function isVirtualInputDevice - isVirtualInputDevice is a static member function and its implementation should be modified in base class only. - Remove isVirtualInputDevice in policy_hal and modify APM_AUDIO_IN_DEVICE_VIRTUAL_ALL in base class to support FM recording over A2DP headset. Change-Id: Ib0527cfdff170367491feb62b117815558e139e1 CRs-Fixed: 581377 --- policy_hal/AudioPolicyManager.cpp | 13 ------------- policy_hal/AudioPolicyManager.h | 2 -- 2 files changed, 15 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 07166569b..4fa23561a 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -27,9 +27,6 @@ #define ALOGVV(a...) do { } while(0) #endif -// A device mask for all audio input devices that are considered "virtual" when evaluating -// active inputs in getActiveInput() -#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX | AUDIO_DEVICE_IN_FM_RX_A2DP // A device mask for all audio output devices that are considered "remote" when evaluating // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX @@ -739,16 +736,6 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource) return device; } -bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device) -{ - if ((device & AUDIO_DEVICE_BIT_IN) != 0) { - device &= ~AUDIO_DEVICE_BIT_IN; - if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0)) - return true; - } - return false; -} - AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device) { switch(getDeviceForVolume(device)) { diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 2e0c6fb14..7a8cfa911 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -68,8 +68,6 @@ protected: // select input device corresponding to requested audio source virtual audio_devices_t getDeviceForInputSource(int inputSource); - static bool isVirtualInputDevice(audio_devices_t device); - // compute the actual volume for a given stream according to the requested index and a particular // device virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device); -- GitLab From bf14371af9ec25c0a5e47f6f68eb09535f72155f Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Tue, 3 Dec 2013 13:02:53 -0800 Subject: [PATCH 119/298] hal: Avoid duplicate primary outputs open_output_stream API expects the default usecase to be returned if other usecases are unavailable or unusable. However, the output returned in this default case must be the default primary if it exists. Change-Id: Ie5cc53f077358d7039d62b09b29edb58c213bc08 --- hal/audio_hw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fc786109b..aff0cf98b 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -60,6 +60,8 @@ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 +#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER + struct pcm_config pcm_config_deep_buffer = { .channels = 2, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, @@ -2123,12 +2125,15 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config = pcm_config_low_latency; out->sample_rate = out->config.rate; } else { - out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; + /* primary path is the default path selected if no other outputs are available/suitable */ + out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY; out->config = pcm_config_deep_buffer; out->sample_rate = out->config.rate; } - if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { + if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) || + (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) { + /* Ensure the default output is not selected twice */ if(adev->primary_output == NULL) adev->primary_output = out; else { -- GitLab From f55b03c5d4aad45ace2ed7a20a57ff43708f62bc Mon Sep 17 00:00:00 2001 From: Vicky Sehrawat Date: Mon, 9 Dec 2013 14:56:18 -0800 Subject: [PATCH 120/298] audio: Add support for 8974 Voice2 Add the Voice2 pcm ID to enable DSDS on 8974. CRs-fixed: 587066 Change-Id: Ifd134313a49af601f4e0f1d66ad0b4ff8596609d --- hal/msm8974/platform.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index a79144544..e7980d60f 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -168,8 +168,8 @@ enum { #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 #define HFP_PCM_RX 5 -#define HFP_SCO_RX 22 -#define HFP_ASM_RX_TX 23 +#define HFP_SCO_RX 23 +#define HFP_ASM_RX_TX 24 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 @@ -201,11 +201,16 @@ enum { #define VOICE2_CALL_PCM_DEVICE 13 #define VOLTE_CALL_PCM_DEVICE 21 #define QCHAT_CALL_PCM_DEVICE 06 -#else +#elif PLATFORM_MSM8610 #define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 13 #define VOLTE_CALL_PCM_DEVICE 14 #define QCHAT_CALL_PCM_DEVICE 20 +#else +#define VOICE_CALL_PCM_DEVICE 2 +#define VOICE2_CALL_PCM_DEVICE 22 +#define VOLTE_CALL_PCM_DEVICE 14 +#define QCHAT_CALL_PCM_DEVICE 20 #endif #define LIB_CSD_CLIENT "libcsd-client.so" -- GitLab From eb78be7e656d1048aab20e882dc7b6ceb29486af Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Sun, 15 Dec 2013 12:03:07 -0800 Subject: [PATCH 121/298] hal: set gapless metadata for compress offload playback -If any of the metadata parameters are set from the framework. set the gapless metadata to one. CRs-Fixed: 588353 Change-Id: I66a79d3f64515d108585527496a754c06a441560 --- hal/audio_hw.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fc786109b..7b3ce5371 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1303,26 +1303,39 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par { int ret = 0; char value[32]; + bool is_meta_data_params = false; struct compr_gapless_mdata tmp_mdata; - + tmp_mdata.encoder_delay = 0; + tmp_mdata.encoder_padding = 0; if (!out || !parms) { + ALOGE("%s: return invalid ",__func__); return -EINVAL; } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value)); + if(ret >= 0) + is_meta_data_params = true; + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_NUM_CHANNEL, value, sizeof(value)); + if(ret >= 0 ) + is_meta_data_params = true; + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value)); + if(ret >= 0 ) + is_meta_data_params = true; ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value)); if (ret >= 0) { + is_meta_data_params = true; tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? - } else { - return -EINVAL; } - ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); if (ret >= 0) { + is_meta_data_params = true; tmp_mdata.encoder_padding = atoi(value); - } else { - return -EINVAL; } + if(!is_meta_data_params) { + ALOGV("%s: Not gapless meta data params", __func__); + return 0; + } out->gapless_mdata = tmp_mdata; out->send_new_metadata = 1; ALOGV("%s new encoder delay %u and padding %u", __func__, @@ -1415,7 +1428,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&adev->lock); } if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); parse_compress_metadata(out, parms); + pthread_mutex_unlock(&out->lock); } str_parms_destroy(parms); -- GitLab From 4b7fdaaf6b7084032cf6f58bf23fc97027d9fdd7 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Mon, 16 Dec 2013 00:40:11 -0800 Subject: [PATCH 122/298] policy_hal: Do not allow sonification for USB headset. - Ringtone will be played on speaker when USB headset is connected. - Sonification is not allowed for USB headset. The behavior is similar to HDMI. CRs-Fixed: 588622 Change-Id: I5fba6ae0e42235f4144ccebac2a55fe1529b530a --- policy_hal/AudioPolicyManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 07166569b..c1efeb6e9 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -640,7 +640,8 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; } if ((device2 == AUDIO_DEVICE_NONE) && - (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) { + (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK) + && (strategy != STRATEGY_SONIFICATION)) { device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; } #ifdef AUDIO_EXTN_FM_ENABLED -- GitLab From bbce4957f6b7d5ef5b103e1c36753f0db02d8f63 Mon Sep 17 00:00:00 2001 From: Helen Zeng Date: Mon, 16 Dec 2013 20:26:46 -0800 Subject: [PATCH 123/298] policy_hal: Fix to route the call to proper device When voice/volte call is setup over USB headset, the call is still on USB headset even after turning on speaker. Don't set the device to USB headset when speaker is forced by Telephony during call. Change-Id: If6a95895a33423ff5150862a823fc669fd44e59a CRs-Fixed: 588884 --- policy_hal/AudioPolicyManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 07166569b..93bed2e2f 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -542,9 +542,9 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (device) break; device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; - if (device) break; device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; if (device) break; device = mDefaultOutputDevice; -- GitLab From 499f1b22e14b475076fe322db5f4d61e39622c85 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Mon, 16 Dec 2013 16:02:45 -0800 Subject: [PATCH 124/298] hal: Fix for adev_open causing hang - Mutex acquired in the begining of the synchronised block but is not unlocked when platform_init fails. - Fix by adding the mutex unlock code. Change-Id: I02b7f7cac0185dd40ec9f03e443e4de98b18c105 CRs-fixed: 590216 --- hal/audio_hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fc786109b..bf08eb8a0 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2593,6 +2593,7 @@ static int adev_open(const hw_module_t *module, const char *name, free(adev); ALOGE("%s: Failed to init platform data, aborting.", __func__); *device = NULL; + pthread_mutex_unlock(&adev_init_lock); return -EINVAL; } -- GitLab From c1dc70db704bbd3dde20b3774dfdd65b0be5b9f7 Mon Sep 17 00:00:00 2001 From: Ben Romberger Date: Thu, 19 Dec 2013 15:11:17 -0800 Subject: [PATCH 125/298] hal: Add support for Volume Boost Add support in AHAL for Volume Boost. A parameter is received from the UI and the volume boost feature set ID is sent to the calibration driver to send the volume boosted calibration. Change-Id: Iafb099b2750deaf58dc5f073f31a23abb9bfe950 --- hal/msm8974/platform.c | 67 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 272dea84b..d562a0c7e 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -61,6 +61,12 @@ #define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence" #define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate" #define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable" +#define AUDIO_PARAMETER_KEY_VOLUME_BOOST "volume_boost" + +enum { + VOICE_FEATURE_SET_DEFAULT, + VOICE_FEATURE_SET_VOLUME_BOOST +}; struct audio_block_header { @@ -73,6 +79,7 @@ typedef void (*acdb_deallocate_t)(); typedef int (*acdb_init_t)(); typedef void (*acdb_send_audio_cal_t)(int, int); typedef void (*acdb_send_voice_cal_t)(int, int); +typedef int (*acdb_reload_vocvoltable_t)(int); struct platform_data { struct audio_device *adev; @@ -84,11 +91,13 @@ struct platform_data { int btsco_sample_rate; bool slowtalk; /* Audio calibration related functions */ - void *acdb_handle; - acdb_init_t acdb_init; - acdb_deallocate_t acdb_deallocate; - acdb_send_audio_cal_t acdb_send_audio_cal; - acdb_send_voice_cal_t acdb_send_voice_cal; + void *acdb_handle; + int voice_feature_set; + acdb_init_t acdb_init; + acdb_deallocate_t acdb_deallocate; + acdb_send_audio_cal_t acdb_send_audio_cal; + acdb_send_voice_cal_t acdb_send_voice_cal; + acdb_reload_vocvoltable_t acdb_reload_vocvoltable; void *hw_info; struct csd_data *csd; @@ -522,6 +531,7 @@ void *platform_init(struct audio_device *adev) } } + my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT; my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW); if (my_data->acdb_handle == NULL) { ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER); @@ -529,13 +539,28 @@ void *platform_init(struct audio_device *adev) ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER); my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle, "acdb_loader_deallocate_ACDB"); + if (!my_data->acdb_deallocate) + ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s", + __func__, LIB_ACDB_LOADER); + my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle, "acdb_loader_send_audio_cal"); if (!my_data->acdb_send_audio_cal) - ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s", + ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s", __func__, LIB_ACDB_LOADER); + my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle, "acdb_loader_send_voice_cal"); + if (!my_data->acdb_send_voice_cal) + ALOGE("%s: Could not find the symbol acdb_loader_send_voice_cal from %s", + __func__, LIB_ACDB_LOADER); + + my_data->acdb_reload_vocvoltable = (acdb_reload_vocvoltable_t)dlsym(my_data->acdb_handle, + "acdb_loader_reload_vocvoltable"); + if (!my_data->acdb_reload_vocvoltable) + ALOGE("%s: Could not find the symbol acdb_loader_reload_vocvoltable from %s", + __func__, LIB_ACDB_LOADER); + my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle, "acdb_loader_init_ACDB"); if (my_data->acdb_init == NULL) @@ -1354,6 +1379,24 @@ int platform_set_parameters(void *platform, struct str_parms *parms) ALOGE("%s: Failed to set slow talk err: %d", __func__, ret); } + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST, + value, sizeof(value)); + if (ret >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST); + + if (my_data->acdb_reload_vocvoltable == NULL) { + ALOGE("%s: acdb_reload_vocvoltable is NULL", __func__); + } else if (!strcmp(value, "on")) { + if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_VOLUME_BOOST)) { + my_data->voice_feature_set = 1; + } + } else { + if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_DEFAULT)) { + my_data->voice_feature_set = 0; + } + } + } + ALOGV("%s: exit with code(%d)", __func__, ret); return ret; } @@ -1476,6 +1519,18 @@ void platform_get_parameters(void *platform, my_data->slowtalk); } + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOLUME_BOOST, + value, sizeof(value)); + if (ret >= 0) { + if (my_data->voice_feature_set == VOICE_FEATURE_SET_VOLUME_BOOST) { + strlcpy(value, "on", sizeof(value)); + } else { + strlcpy(value, "off", sizeof(value)); + } + + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value); + } + ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply)); } -- GitLab From 49be803409bcef7bc3ec6e054136d95497618a60 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Thu, 19 Dec 2013 12:51:25 -0800 Subject: [PATCH 126/298] hal: fix for surround sound recording - Use proper period_size(512) and period_count(8) for 4ch pcm recording. - Fix read logic in ssr_read to capture 4k data for each read - Miscellaneous code clean up for variables, APIS, and debug dumps. Change-Id: I01c0e99a717a3536bd7d19c2f46ed10be77661e4 Crs-Fixed: 589342 --- hal/audio_extn/audio_extn.c | 8 -- hal/audio_extn/audio_extn.h | 4 +- hal/audio_extn/ssr.c | 239 ++++++++++-------------------------- hal/msm8974/platform.c | 2 +- 4 files changed, 65 insertions(+), 188 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 3f457d20f..80ce0631b 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -61,13 +61,6 @@ void audio_extn_hfp_set_parameters(adev, parms) (0) void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms); #endif -#ifndef SSR_ENABLED -#define audio_extn_ssr_get_parameters(query, reply) (0) -#else -void audio_extn_ssr_get_parameters(struct str_parms *query, - - struct str_parms *reply); -#endif #ifndef ANC_HEADSET_ENABLED #define audio_extn_set_anc_parameters(adev, parms) (0) @@ -335,7 +328,6 @@ void audio_extn_get_parameters(const struct audio_device *adev, struct str_parms *reply) { audio_extn_get_afe_proxy_parameters(query, reply); - audio_extn_ssr_get_parameters(query, reply); ALOGD("%s: returns %s", __func__, str_parms_to_str(reply)); } diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 6bd03eeb8..e17aa6ba3 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -70,14 +70,14 @@ bool audio_extn_usb_is_proxy_inuse(); #ifndef SSR_ENABLED #define audio_extn_ssr_init(adev, in) (0) #define audio_extn_ssr_deinit() (0) -#define audio_extn_ssr_update_enabled(adev) (0) +#define audio_extn_ssr_update_enabled() (0) #define audio_extn_ssr_get_enabled() (0) #define audio_extn_ssr_read(stream, buffer, bytes) (0) #else int32_t audio_extn_ssr_init(struct audio_device *adev, struct stream_in *in); int32_t audio_extn_ssr_deinit(); -int32_t audio_extn_ssr_update_enabled(struct audio_device *adev); +void audio_extn_ssr_update_enabled(); bool audio_extn_ssr_get_enabled(); int32_t audio_extn_ssr_read(struct audio_stream_in *stream, void *buffer, size_t bytes); diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c index efd92ea38..ac6da8b7f 100644 --- a/hal/audio_extn/ssr.c +++ b/hal/audio_extn/ssr.c @@ -34,14 +34,13 @@ #include "surround_filters_interface.h" #ifdef SSR_ENABLED -#define COEFF_ARRAY_SIZE 4 -#define FILT_SIZE ((512+1)* 6) /* # ((FFT bins)/2+1)*numOutputs */ -#define SSR_FRAME_SIZE 512 -#define SSR_INPUT_FRAME_SIZE (SSR_FRAME_SIZE * 4) -#define SSR_OUTPUT_FRAME_SIZE (SSR_FRAME_SIZE * 6) -#define SSR_CHANNEL_COUNT 4 -#define SSR_PERIOD_SIZE 256 -#define SSR_PERIOD_COUNT 8 +#define COEFF_ARRAY_SIZE 4 +#define FILT_SIZE ((512+1)* 6) /* # ((FFT bins)/2+1)*numOutputs */ +#define SSR_CHANNEL_INPUT_NUM 4 +#define SSR_CHANNEL_OUTPUT_NUM 6 +#define SSR_PERIOD_COUNT 8 +#define SSR_PERIOD_SIZE 512 +#define SSR_INPUT_FRAME_SIZE (SSR_PERIOD_SIZE * SSR_PERIOD_COUNT) #define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm" #define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm" @@ -52,7 +51,7 @@ #define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm" #define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm" #define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm" -#define AUDIO_PARAMETER_KEY_SSR "ssr" + #define LIB_SURROUND_PROC "libsurround_proc.so" typedef int (*surround_filters_init_t)(void *, int, int, Word16 **, @@ -67,11 +66,7 @@ struct ssr_module { int16_t **real_coeffs; int16_t **imag_coeffs; void *surround_obj; - - int16_t *surround_input_buffer; - int16_t *surround_output_buffer; - int surround_input_bufferIdx; - int surround_output_bufferIdx; + int16_t *surround_raw_buffer; bool is_ssr_enabled; void *surround_filters_handle; @@ -81,19 +76,13 @@ struct ssr_module { surround_filters_intl_process_t surround_filters_intl_process; }; -static int32_t ssr_init_surround_sound_lib(unsigned long buffersize); -static int32_t ssr_read_coeffs_from_file(); - static struct ssr_module ssrmod = { .fp_4ch = NULL, - .fp_6ch= NULL, + .fp_6ch = NULL, .real_coeffs = NULL, .imag_coeffs = NULL, .surround_obj = NULL, - .surround_output_buffer = NULL, - .surround_input_buffer = NULL, - .surround_output_bufferIdx = 0, - .surround_input_bufferIdx= 0, + .surround_raw_buffer = NULL, .is_ssr_enabled = 0, .surround_filters_handle = NULL, @@ -230,32 +219,20 @@ static int32_t ssr_init_surround_sound_lib(unsigned long buffersize) int high_freq = 100; int i, ret = 0; - ssrmod.surround_input_bufferIdx = 0; - ssrmod.surround_output_bufferIdx = 0; - if ( ssrmod.surround_obj ) { ALOGE("%s: ola filter library is already initialized", __func__); return 0; } /* Allocate memory for input buffer */ - ssrmod.surround_input_buffer = (Word16 *) calloc(2 * SSR_INPUT_FRAME_SIZE, + ssrmod.surround_raw_buffer = (Word16 *) calloc(buffersize, sizeof(Word16)); - if ( !ssrmod.surround_input_buffer ) { + if ( !ssrmod.surround_raw_buffer ) { ALOGE("%s: Memory allocation failure. Not able to allocate " "memory for surroundInputBuffer", __func__); goto init_fail; } - /* Allocate memory for output buffer */ - ssrmod.surround_output_buffer = (Word16 *) calloc(2 * SSR_OUTPUT_FRAME_SIZE, - sizeof(Word16)); - if ( !ssrmod.surround_output_buffer ) { - ALOGE("%s: Memory allocation failure. Not able to " - "allocate memory for surroundOutputBuffer", __func__); - goto init_fail; - } - /* Allocate memory for real and imag coeffs array */ ssrmod.real_coeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *)); if ( !ssrmod.real_coeffs ) { @@ -353,13 +330,9 @@ init_fail: free(ssrmod.surround_obj); ssrmod.surround_obj = NULL; } - if (ssrmod.surround_output_buffer) { - free(ssrmod.surround_output_buffer); - ssrmod.surround_output_buffer = NULL; - } - if (ssrmod.surround_input_buffer) { - free(ssrmod.surround_input_buffer); - ssrmod.surround_input_buffer = NULL; + if (ssrmod.surround_raw_buffer) { + free(ssrmod.surround_raw_buffer); + ssrmod.surround_raw_buffer = NULL; } if (ssrmod.real_coeffs){ for (i =0; iconfig.channels = SSR_CHANNEL_COUNT; + in->config.channels = SSR_CHANNEL_INPUT_NUM; in->config.period_size = SSR_PERIOD_SIZE; in->config.period_count = SSR_PERIOD_COUNT; - buffer_size = (SSR_PERIOD_SIZE)*(SSR_PERIOD_COUNT); - ALOGD("%s: buffer_size: %d", __func__, buffer_size); + /* use 4k hardcoded buffer size for ssr*/ + buffer_size = SSR_INPUT_FRAME_SIZE; + ALOGV("%s: buffer_size: %d", __func__, buffer_size); ret = ssr_init_surround_sound_lib(buffer_size); if (0 != ret) { @@ -429,16 +402,16 @@ int32_t audio_extn_ssr_init(struct audio_device *adev, } property_get("ssr.pcmdump",c_multi_ch_dump,"0"); - if (0 == strncmp("true",c_multi_ch_dump, sizeof("ssr.dump-pcm"))) { - /* Remember to change file system permission of data(e.g. chmod 777 data/), - otherwise, fopen may fail */ - if ( !ssrmod.fp_4ch) - ssrmod.fp_4ch = fopen("/data/media/0/4ch_ssr.pcm", "wb"); - if ( !ssrmod.fp_6ch) - ssrmod.fp_6ch = fopen("/data/media/0/6ch_ssr.pcm", "wb"); - if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch)) - ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p", - __func__, ssrmod.fp_4ch, ssrmod.fp_6ch); + if (0 == strncmp("true", c_multi_ch_dump, sizeof("ssr.dump-pcm"))) { + /* Remember to change file system permission of data(e.g. chmod 777 data/), + otherwise, fopen may fail */ + if ( !ssrmod.fp_4ch) + ssrmod.fp_4ch = fopen("/data/4ch.pcm", "wb"); + if ( !ssrmod.fp_6ch) + ssrmod.fp_6ch = fopen("/data/6ch.pcm", "wb"); + if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch)) + ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p", + __func__, ssrmod.fp_4ch, ssrmod.fp_6ch); } return 0; @@ -449,7 +422,7 @@ int32_t audio_extn_ssr_deinit() int i; if (ssrmod.surround_obj) { - ALOGD("%s: entry", __func__); + ALOGV("%s: entry", __func__); ssrmod.surround_filters_release(ssrmod.surround_obj); if (ssrmod.surround_obj) free(ssrmod.surround_obj); @@ -474,25 +447,21 @@ int32_t audio_extn_ssr_deinit() free(ssrmod.imag_coeffs); ssrmod.imag_coeffs = NULL; } - if (ssrmod.surround_output_buffer){ - free(ssrmod.surround_output_buffer); - ssrmod.surround_output_buffer = NULL; - } - if (ssrmod.surround_input_buffer) { - free(ssrmod.surround_input_buffer); - ssrmod.surround_input_buffer = NULL; + if (ssrmod.surround_raw_buffer) { + free(ssrmod.surround_raw_buffer); + ssrmod.surround_raw_buffer = NULL; } - - if ( ssrmod.fp_4ch ) fclose(ssrmod.fp_4ch); - if ( ssrmod.fp_6ch ) fclose(ssrmod.fp_6ch); + if (ssrmod.fp_4ch) + fclose(ssrmod.fp_4ch); + if (ssrmod.fp_6ch) + fclose(ssrmod.fp_6ch); } - if(ssrmod.surround_filters_handle) - { + if(ssrmod.surround_filters_handle) { dlclose(ssrmod.surround_filters_handle); ssrmod.surround_filters_handle = NULL; } - ALOGD("%s: exit", __func__); + ALOGV("%s: exit", __func__); return 0; } @@ -500,120 +469,36 @@ int32_t audio_extn_ssr_deinit() int32_t audio_extn_ssr_read(struct audio_stream_in *stream, void *buffer, size_t bytes) { - int processed = 0; - int processed_pending; - void *buffer_start = buffer; - unsigned period_bytes; - unsigned period_samples; - int read_pending, n; - size_t read_bytes = 0; - int samples = bytes >> 1; - struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; + size_t peroid_bytes; + int32_t ret; - period_bytes = in->config.period_size; - ALOGD("%s: period_size: %d", __func__, in->config.period_size); - period_samples = period_bytes >> 1; + /* Convert bytes for 6ch to 4ch*/ + peroid_bytes = (bytes / SSR_CHANNEL_OUTPUT_NUM) * SSR_CHANNEL_INPUT_NUM; - if (!ssrmod.surround_obj) + if (!ssrmod.surround_obj) { + ALOGE("%s: surround_obj not initialized", __func__); return -ENOMEM; + } - do { - if (ssrmod.surround_output_bufferIdx > 0) { - ALOGV("%s: copy processed output " - "to buffer, surround_output_bufferIdx = %d", - __func__, ssrmod.surround_output_bufferIdx); - /* Copy processed output to buffer */ - processed_pending = ssrmod.surround_output_bufferIdx; - if (processed_pending > (samples - processed)) { - processed_pending = (samples - processed); - } - memcpy(buffer, ssrmod.surround_output_buffer, processed_pending * sizeof(Word16)); - buffer = (char*)buffer + processed_pending * sizeof(Word16); - processed += processed_pending; - if (ssrmod.surround_output_bufferIdx > processed_pending) { - /* Shift leftover samples to beginning of the buffer */ - memcpy(&ssrmod.surround_output_buffer[0], - &ssrmod.surround_output_buffer[processed_pending], - (ssrmod.surround_output_bufferIdx - processed_pending) * sizeof(Word16)); - } - ssrmod.surround_output_bufferIdx -= processed_pending; - } - - if (processed >= samples) { - ALOGV("%s: done processing buffer, " - "processed = %d", __func__, processed); - /* Done processing this buffer */ - break; - } - - /* Fill input buffer until there is enough to process */ - read_pending = SSR_INPUT_FRAME_SIZE - ssrmod.surround_input_bufferIdx; - read_bytes = ssrmod.surround_input_bufferIdx; - while (in->pcm && read_pending > 0) { - n = pcm_read(in->pcm, &ssrmod.surround_input_buffer[read_bytes], - period_bytes); - ALOGV("%s: pcm_read() returned n = %d buffer:%p size:%d", __func__, - n, &ssrmod.surround_input_buffer[read_bytes], period_bytes); - if (n && n != -EAGAIN) { - /* Recovery part of pcm_read. TODO:split recovery */ - return (ssize_t)n; - } - else if (n < 0) { - /* Recovery is part of pcm_write. TODO split is later */ - return (ssize_t)n; - } - else { - read_pending -= period_samples; - read_bytes += period_samples; - } - } - - - if (ssrmod.fp_4ch) { - fwrite( ssrmod.surround_input_buffer, 1, - SSR_INPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_4ch); - } - - /* apply ssr libs to conver 4ch to 6ch */ - ssrmod.surround_filters_intl_process(ssrmod.surround_obj, - &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx], - (Word16 *)ssrmod.surround_input_buffer); - - /* Shift leftover samples to beginning of input buffer */ - if (read_pending < 0) { - memcpy(&ssrmod.surround_input_buffer[0], - &ssrmod.surround_input_buffer[SSR_INPUT_FRAME_SIZE], - (-read_pending) * sizeof(Word16)); - } - ssrmod.surround_input_bufferIdx = -read_pending; + ret = pcm_read(in->pcm, ssrmod.surround_raw_buffer, peroid_bytes); + if (ret < 0) { + ALOGE("%s: %s ret:%d", __func__, pcm_get_error(in->pcm),ret); + return ret; + } - if (ssrmod.fp_6ch) { - fwrite( &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx], - 1, SSR_OUTPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_6ch); - } + /* apply ssr libs to conver 4ch to 6ch */ + ssrmod.surround_filters_intl_process(ssrmod.surround_obj, + buffer, ssrmod.surround_raw_buffer); - ssrmod.surround_output_bufferIdx += SSR_OUTPUT_FRAME_SIZE; - ALOGV("%s: do_while loop: processed=%d, samples=%d\n", __func__, processed, samples); - } while (in->pcm && processed < samples); - read_bytes = processed * sizeof(Word16); - buffer = buffer_start; + /*dump for raw pcm data*/ + if (ssrmod.fp_4ch) + fwrite(ssrmod.surround_raw_buffer, 1, peroid_bytes, ssrmod.fp_4ch); + if (ssrmod.fp_6ch) + fwrite(buffer, 1, bytes, ssrmod.fp_6ch); - return 0; + return ret; } -void audio_extn_ssr_get_parameters(struct str_parms *query, - struct str_parms *reply) -{ - int ret, val; - char value[32]={0}; - - ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SSR, value, sizeof(value)); - - if (ret >= 0) { - memcpy(value, "true", 4); - str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SSR, value); - } -} #endif /* SSR_ENABLED */ diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 272dea84b..69c88f439 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -561,7 +561,7 @@ void *platform_init(struct audio_device *adev) audio_extn_usb_set_proxy_sound_card(adev->snd_card); /* Read one time ssr property */ - audio_extn_ssr_update_enabled(adev); + audio_extn_ssr_update_enabled(); audio_extn_spkr_prot_init(adev); return my_data; } -- GitLab From 09cbbf0c1fdbd6479001f2370e503abb1317c667 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Mon, 25 Nov 2013 15:49:57 +0530 Subject: [PATCH 127/298] mpq8092: Porting audio HAL changes Porting audio HAL changes Change-Id: I85e739ed231ee09ebf150da2ea3fd4f5d4aa3a24 --- hal_mpq/audio_bitstream_sm.c | 74 +- hal_mpq/audio_hw.h | 115 +- hal_mpq/audio_stream_out.c | 2117 ++++++++++++++++++++++++++++++---- hal_mpq/mpq8092/platform.c | 77 +- hal_mpq/mpq8092/platform.h | 402 ++++++- hal_mpq/platform_api.h | 2 + 6 files changed, 2530 insertions(+), 257 deletions(-) diff --git a/hal_mpq/audio_bitstream_sm.c b/hal_mpq/audio_bitstream_sm.c index 9f2564d22..d2e4e6e77 100644 --- a/hal_mpq/audio_bitstream_sm.c +++ b/hal_mpq/audio_bitstream_sm.c @@ -26,7 +26,7 @@ #include #define LOG_TAG "AudioBitstreamStateMachine" -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #define LOG_NDDEBUG 0 #include @@ -36,7 +36,6 @@ #include // ---------------------------------------------------------------------------- - /* Initialize all input and output pointers Allocate twice the max buffer size of input and output for sufficient buffering @@ -45,52 +44,62 @@ int audio_bitstream_init(struct audio_bitstream_sm *bstream, int buffering_facto { bstream->buffering_factor = buffering_factor; bstream->buffering_factor_cnt = 0; + bstream->inp_buf_size = SAMPLES_PER_CHANNEL * + MAX_INPUT_CHANNELS_SUPPORTED* + (bstream->buffering_factor+1); + bstream->inp_buf = (char *)malloc( bstream->inp_buf_size); - bstream->inp_buf=(char *)malloc(SAMPLES_PER_CHANNEL* - MAX_INPUT_CHANNELS_SUPPORTED* - (bstream->buffering_factor+1)); // multiplied by 2 to convert to bytes if(bstream->inp_buf != NULL) { bstream->inp_buf_curr_ptr = bstream->inp_buf; bstream->inp_buf_write_ptr = bstream->inp_buf; } else { ALOGE("MS11 input buffer not allocated"); + bstream->inp_buf_size = 0; return 0; } - bstream->enc_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL* - MAX_INPUT_CHANNELS_SUPPORTED* - FACTOR_FOR_BUFFERING); + bstream->enc_out_buf_size = SAMPLES_PER_CHANNEL * MAX_INPUT_CHANNELS_SUPPORTED* + FACTOR_FOR_BUFFERING; + bstream->enc_out_buf =(char *)malloc(bstream->enc_out_buf_size); + if(bstream->enc_out_buf) { bstream->enc_out_buf_write_ptr = bstream->enc_out_buf; } else { ALOGE("MS11 Enc output buffer not allocated"); + bstream->enc_out_buf_size = 0; return 0; } - bstream->pcm_2_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL*STEREO_CHANNELS * - FACTOR_FOR_BUFFERING); + bstream->pcm_2_out_buf_size = SAMPLES_PER_CHANNEL*STEREO_CHANNELS * + FACTOR_FOR_BUFFERING; + bstream->pcm_2_out_buf =(char *)malloc(bstream->pcm_2_out_buf_size); if(bstream->pcm_2_out_buf) { bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf; } else { ALOGE("MS11 PCM2Ch output buffer not allocated"); + bstream->pcm_2_out_buf_size = 0; return 0; } - bstream->pcm_mch_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL * - MAX_OUTPUT_CHANNELS_SUPPORTED * - FACTOR_FOR_BUFFERING); + bstream->pcm_mch_out_buf_size = SAMPLES_PER_CHANNEL * MAX_OUTPUT_CHANNELS_SUPPORTED * + FACTOR_FOR_BUFFERING; + + bstream->pcm_mch_out_buf =(char *)malloc(bstream->pcm_mch_out_buf_size); if(bstream->pcm_mch_out_buf) { bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf; } else { ALOGE("MS11 PCMMCh output buffer not allocated"); + bstream->pcm_mch_out_buf_size = 0; return 0; } - bstream->passt_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL * + bstream->passt_out_buf_size =SAMPLES_PER_CHANNEL * MAX_INPUT_CHANNELS_SUPPORTED * - FACTOR_FOR_BUFFERING); + FACTOR_FOR_BUFFERING; + bstream->passt_out_buf =(char *)malloc(bstream->passt_out_buf_size); if(bstream->passt_out_buf) { bstream->passt_out_buf_write_ptr = bstream->passt_out_buf; } else { ALOGE("MS11 Enc output buffer not allocated"); + bstream->passt_out_buf_size = 0; return 0; } return 1; @@ -159,9 +168,8 @@ void audio_bitstream_copy_to_internal_buffer( struct audio_bitstream_sm *bstream, char *buf_ptr, size_t bytes) { - int32_t bufLen = SAMPLES_PER_CHANNEL*MAX_INPUT_CHANNELS_SUPPORTED*(bstream->buffering_factor+1); // flush the input buffer if input is not consumed - if( (bstream->inp_buf_write_ptr+bytes) > (bstream->inp_buf+bufLen) ) { + if( (bstream->inp_buf_write_ptr+bytes) > (bstream->inp_buf+bstream->inp_buf_size) ) { ALOGE("Input bitstream is not consumed"); return; } @@ -226,6 +234,38 @@ char* audio_bitstream_get_input_buffer_write_ptr( return bstream->inp_buf_write_ptr; } +int audio_bitstream_set_input_buffer_ptr( + struct audio_bitstream_sm *bstream, int bytes) +{ + if(((bstream->inp_buf_curr_ptr + bytes) <= + (bstream->inp_buf + bstream->inp_buf_size)) && + ((bstream->inp_buf_curr_ptr + bytes) >= bstream->inp_buf)) + + bstream->inp_buf_curr_ptr += bytes; + else { + ALOGE("Invalid input buffer size %d bytes", bytes); + return -EINVAL; + } + + return 0; +} + +int audio_bitstream_set_input_buffer_write_ptr( + struct audio_bitstream_sm *bstream, int bytes) +{ + if(((bstream->inp_buf_write_ptr + bytes) <= + (bstream->inp_buf + bstream->inp_buf_size)) && + ((bstream->inp_buf_write_ptr + bytes) >= bstream->inp_buf)) + + bstream->inp_buf_write_ptr += bytes; + else { + ALOGE("Invalid input buffer size %d bytes", bytes); + return -EINVAL; + } + + return 0; +} + /* Get the output buffer start pointer to start rendering the pcm sampled to driver */ diff --git a/hal_mpq/audio_hw.h b/hal_mpq/audio_hw.h index e1319a5fb..7814d9565 100644 --- a/hal_mpq/audio_hw.h +++ b/hal_mpq/audio_hw.h @@ -24,7 +24,7 @@ #include #include #include - +#include "sound/compress_params.h" #include #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so" @@ -45,6 +45,7 @@ #define DEFAULT_HDMI_OUT_CHANNELS 2 typedef int snd_device_t; +#include /* These are the supported use cases by the hardware. * Each usecase is mapped to a specific PCM device. @@ -56,11 +57,11 @@ typedef enum { USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0, USECASE_AUDIO_PLAYBACK_LOW_LATENCY, USECASE_AUDIO_PLAYBACK_MULTI_CH, - USECASE_AUDIO_PLAYBACK_OFFLOAD, - - /* FM usecase */ USECASE_AUDIO_PLAYBACK_FM, - + USECASE_AUDIO_PLAYBACK_OFFLOAD, + USECASE_AUDIO_PLAYBACK_OFFLOAD1, + USECASE_AUDIO_PLAYBACK_OFFLOAD2, + USECASE_AUDIO_PLAYBACK_OFFLOAD3, /* Capture usecases */ USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_COMPRESS, @@ -88,6 +89,28 @@ typedef enum { AUDIO_USECASE_MAX } audio_usecase_t; +typedef enum { + DEEP_BUFFER_PLAYBACK_STREAM = 0, + LOW_LATENCY_PLAYBACK_STREAM, + MCH_PCM_PLAYBACK_STREAM, + OFFLOAD_PLAYBACK_STREAM, + LOW_LATENCY_RECORD_STREAM, + RECORD_STREAM, + VOICE_CALL_STREAM +} audio_usecase_stream_type_t; + +#define STRING_TO_ENUM(string) { #string, string } +struct string_to_enum { + const char *name; + uint32_t value; +}; + +static const struct string_to_enum out_channels_name_to_enum_table[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /* @@ -118,14 +141,43 @@ struct offload_cmd { int data[]; }; +struct alsa_handle { + + struct listnode list; +//Parameters of the stream + struct pcm *pcm; + struct pcm_config config; + + struct compress *compr; + struct compr_config compr_config; + + struct stream_out *out; + + audio_usecase_t usecase; + int device_id; + unsigned int sample_rate; + audio_channel_mask_t channel_mask; + audio_format_t input_format; + audio_format_t output_format; + audio_devices_t devices; + + route_format_t route_format; + int decoder_type; + + bool cmd_pending ; +}; + struct stream_out { struct audio_stream_out stream; pthread_mutex_t lock; /* see note below on mutex acquisition order */ pthread_cond_t cond; + /* TODO remove this */ + /* struct pcm_config config; struct compr_config compr_config; struct pcm *pcm; struct compress *compr; + */ int standby; int pcm_device_id; unsigned int sample_rate; @@ -154,6 +206,54 @@ struct stream_out { int send_new_metadata; struct audio_device *dev; + + /*devices configuration */ + int left_volume; + int right_volume; + audio_usecase_stream_type_t uc_strm_type; + int hdmi_format; + int spdif_format; + int* device_formats; //TODO:Needs to come from AudioRutingManager + struct audio_config *config; + + /* list of the session handles */ + struct listnode session_list; + + /* /MS11 instance */ + int use_ms11_decoder; + void *ms11_decoder; + struct compr_config compr_config; + + int channels; + + /* Buffering utility */ + struct audio_bitstream_sm *bitstrm; + + int buffer_size; + int decoder_type; + bool dec_conf_set; + uint32_t min_bytes_req_to_dec; + bool is_m11_file_mode; + void *dec_conf_buf; + int32_t dec_conf_bufLength; + bool first_bitstrm_buf; + + bool open_dec_route; + int dec_format_devices; + bool open_dec_mch_route; + int dec_mch_format_devices; + bool open_passt_route; + int passt_format_devices; + bool sw_open_trans_route; + int sw_trans_format_devices; + bool hw_open_trans_route; + int hw_trans_format_devices; + bool channel_status_set; + unsigned char channel_status[24]; + int route_audio_to_a2dp; + int is_ms11_file_playback_mode; + char * write_temp_buf; + struct output_metadata output_meta_data; }; struct stream_in { @@ -194,6 +294,7 @@ struct audio_usecase { snd_device_t out_snd_device; snd_device_t in_snd_device; union stream_ptr stream; + struct alsa_handle *handle; }; struct audio_device { @@ -225,6 +326,9 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", + [USECASE_AUDIO_PLAYBACK_OFFLOAD1] = "compress-offload-playback1", + [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2", + [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", @@ -245,6 +349,7 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record", }; + int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, diff --git a/hal_mpq/audio_stream_out.c b/hal_mpq/audio_stream_out.c index 71eb2f1dc..5e9eb74f3 100644 --- a/hal_mpq/audio_stream_out.c +++ b/hal_mpq/audio_stream_out.c @@ -49,12 +49,24 @@ #include #include "sound/compress_params.h" +#include "audio_bitstream_sm.h" + +//TODO: enable sw_decode if required +#define USE_SWDECODE 0 + +#if USE_SWDECODE +#include "SoftMS11.h" +#endif #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 /* ToDo: Check and update a proper value in msec */ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 +#define STRING_LENGTH_OF_INTEGER 12 + +static int send_offload_cmd_l(struct stream_out* out, int command); +static int get_snd_codec_id(audio_format_t format); struct pcm_config pcm_config_deep_buffer = { .channels = 2, @@ -89,18 +101,1230 @@ struct pcm_config pcm_config_hdmi_multi = { .avail_min = 0, }; -#define STRING_TO_ENUM(string) { #string, string } +inline int nextMultiple(int n, int m) { + return ((n/m) + 1) * m; +} -struct string_to_enum { - const char *name; - uint32_t value; -}; +/******************************************************************************* +Description: check for MS11 supported formats +*******************************************************************************/ +//TODO: enable sw_decode if required +#if USE_SWDECODE +int is_ms11_supported_fromats(int format) +{ + ALOGVV("is_ms11_supported_fromats"); + int main_format = format & AUDIO_FORMAT_MAIN_MASK; + if(((main_format == AUDIO_FORMAT_AAC) || + (main_format == AUDIO_FORMAT_HE_AAC_V1) || + (main_format == AUDIO_FORMAT_HE_AAC_V2) || + (main_format == AUDIO_FORMAT_AC3) || + (main_format == AUDIO_FORMAT_AC3_PLUS) || + (main_format == AUDIO_FORMAT_EAC3))) { + return 1; + } else { + return 0; + } +} +#endif -static const struct string_to_enum out_channels_name_to_enum_table[] = { - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), - STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), -}; +/******************************************************************************* +Description: check if ac3 can played as pass through without MS11 decoder +*******************************************************************************/ +//TODO: enable sw_decode if required +#if USE_SWDECODE +int can_ac3_passthrough_without_ms11(struct stream_out *out, int format) +{ + ALOGVV("can_ac3_passthrough_without_ms11"); + int main_format = format & AUDIO_FORMAT_MAIN_MASK; + if(main_format == AUDIO_FORMAT_AC3) { + if(((out->hdmi_format == COMPRESSED) || + (out->hdmi_format == AUTO_DEVICE_FORMAT) || + (out->hdmi_format == COMPRESSED_CONVERT_EAC3_AC3) || + (out->hdmi_format == COMPRESSED_CONVERT_ANY_AC3)) && + ((out->spdif_format == COMPRESSED) || + (out->spdif_format == AUTO_DEVICE_FORMAT) || + (out->spdif_format == COMPRESSED_CONVERT_EAC3_AC3) || + (out->spdif_format == COMPRESSED_CONVERT_ANY_AC3))) { + return 1; + } + } + return 0; +} +#endif + +/******************************************************************************* +Description: get levels of buffering, interms of number of buffers +*******************************************************************************/ +int get_buffering_factor(struct stream_out *out) +{ + ALOGVV("get_buffering_factor"); + if((out->format == AUDIO_FORMAT_PCM_16_BIT) || + (out->format == AUDIO_FORMAT_PCM_24_BIT)) + return 1; + else + return NUM_OF_PERIODS; +} + +/******************************************************************************* +Description: get the buffer size based on format and device format type +*******************************************************************************/ +void get_fragment_size_and_format(struct stream_out *out, int routeFormat, int *fragment_size, + int *fragment_count, int *format) +{ + ALOGV("get_fragment_size_and_format"); + + int frame_size = 0; + *format = out->format; + *fragment_count = NUM_OF_PERIODS; + switch(out->format) { + case AUDIO_FORMAT_PCM_16_BIT: + frame_size = PCM_16_BITS_PER_SAMPLE * out->channels; + /*TODO: do we need below calculation */ + *fragment_size = nextMultiple(((frame_size * out->sample_rate * TIME_PER_BUFFER)/1000) + MIN_SIZE_FOR_METADATA , frame_size * 32); + break; + case AUDIO_FORMAT_PCM_24_BIT: + frame_size = PCM_24_BITS_PER_SAMPLE * out->channels; + *fragment_size = nextMultiple(((frame_size * out->sample_rate * TIME_PER_BUFFER)/1000) + MIN_SIZE_FOR_METADATA, frame_size * 32); + break; + case AUDIO_FORMAT_AAC: + case AUDIO_FORMAT_HE_AAC_V1: + case AUDIO_FORMAT_HE_AAC_V2: + case AUDIO_FORMAT_AAC_ADIF: + case AUDIO_FORMAT_AC3: + case AUDIO_FORMAT_AC3_DM: + case AUDIO_FORMAT_EAC3: + case AUDIO_FORMAT_EAC3_DM: + if(routeFormat == ROUTE_UNCOMPRESSED_MCH) { + frame_size = PCM_16_BITS_PER_SAMPLE * out->channels; + *fragment_size = nextMultiple(AC3_PERIOD_SIZE * out->channels + MIN_SIZE_FOR_METADATA, frame_size * 32); + *format = AUDIO_FORMAT_PCM_16_BIT; + } else if(routeFormat == ROUTE_UNCOMPRESSED) { + frame_size = PCM_16_BITS_PER_SAMPLE * 2; + *fragment_size = nextMultiple(AC3_PERIOD_SIZE * 2 + MIN_SIZE_FOR_METADATA, frame_size * 32); + *format = AUDIO_FORMAT_PCM_16_BIT; + } else { + *fragment_size = PERIOD_SIZE_COMPR; + } + break; + case AUDIO_FORMAT_DTS: + case AUDIO_FORMAT_DTS_LBR: + case AUDIO_FORMAT_MP3: + case AUDIO_FORMAT_WMA: + case AUDIO_FORMAT_WMA_PRO: + case AUDIO_FORMAT_MP2: + *fragment_size = PERIOD_SIZE_COMPR; + break; + default: + *fragment_size = PERIOD_SIZE_COMPR; + *format = out->format; + } + + /*TODO: remove this if fragement count needs to be decided based on the format*/ + *fragment_count = COMPRESS_OFFLOAD_NUM_FRAGMENTS; + fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + + ALOGV("fragment_size: %d, fragment_count: %d", *fragment_size, *fragment_count); + return; +} + +/******************************************************************************* +Description: buffer length updated to player +*******************************************************************************/ +int get_buffer_length(struct stream_out *out) +{ + /* TODO: Do we need below */ + ALOGV("get_buffer_length"); + int buffer_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + switch(out->format) { + case AUDIO_FORMAT_PCM_16_BIT: + buffer_size = ((PCM_16_BITS_PER_SAMPLE * out->channels * out->sample_rate * TIME_PER_BUFFER)/1000); + break; + case AUDIO_FORMAT_PCM_24_BIT: + buffer_size = ((PCM_24_BITS_PER_SAMPLE * out->channels * out->sample_rate * TIME_PER_BUFFER)/1000); + break; + case AUDIO_FORMAT_AAC: + case AUDIO_FORMAT_HE_AAC_V1: + case AUDIO_FORMAT_HE_AAC_V2: + case AUDIO_FORMAT_AAC_ADIF: + buffer_size = AAC_BLOCK_PER_CHANNEL_MS11 * out->channels; + break; + case AUDIO_FORMAT_AC3: + case AUDIO_FORMAT_AC3_DM: + case AUDIO_FORMAT_EAC3: + case AUDIO_FORMAT_EAC3_DM: + buffer_size = AC3_BUFFER_SIZE; + break; + case AUDIO_FORMAT_DTS: + case AUDIO_FORMAT_DTS_LBR: + case AUDIO_FORMAT_MP3: + case AUDIO_FORMAT_WMA: + case AUDIO_FORMAT_WMA_PRO: + case AUDIO_FORMAT_MP2: + buffer_size = COMPR_INPUT_BUFFER_SIZE; + break; + default: + buffer_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + } + + /*TODO: remove this if fragement count needs to be decided based on the format*/ + buffer_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + return buffer_size; +} + +/* TODO: Uncomment this when enabling A2DP + TODO: add support for the 24 bit playback*/ +#if 0 +/******************************************************************************* +Description: fix up devices for supporting A2DP playback +*******************************************************************************/ +void fixUpDevicesForA2DPPlayback(struct stream_out *out) +{ + ALOGVV("fixUpDevicesForA2DPPlayback"); + if(out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) { + out->route_audio_to_a2dp = 1; + out->devices &= ~AUDIO_DEVICE_OUT_ALL_A2DP; + //TODO: add spdif and proxy + //out->devices &= ~AUDIO_DEVICE_OUT_SPDIF; + //out->devices |= AudioSystem::DEVICE_OUT_PROXY; + } +} +#endif + +/******************************************************************************* +Description: open temp buffer so that meta data mode can be updated properly +*******************************************************************************/ +int open_temp_buf_for_metadata(struct stream_out *out) +{ + ALOGV("%s", __func__); + if (out->write_temp_buf == NULL) { + /*Max Period size which is exposed by the compr driver + The value needs to be modified when the period size is modified*/ + out->write_temp_buf = (char *) malloc(PLAYBACK_MAX_PERIOD_SIZE); + if (out->write_temp_buf == NULL) { + ALOGE("Memory allocation of temp buffer to write pcm to driver failed"); + return -EINVAL; + } + } + return 0; +} + +/******************************************************************************* +Description: get index of handle based on device handle device +*******************************************************************************/ +struct alsa_handle * get_handle_based_on_devices(struct stream_out *out, int handleDevices) +{ + ALOGVV("get_handle_based_on_devices"); + struct listnode *node; + struct alsa_handle *handle = NULL; + + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if(handle->devices & handleDevices) + break; + } + return handle; +} + +void reset_out_parameters(struct stream_out *out) { + + out->hdmi_format = UNCOMPRESSED; + out->spdif_format = UNCOMPRESSED; + out->decoder_type = UNCOMPRESSED ; + out->dec_conf_set = false; + out->min_bytes_req_to_dec = 0; + out->is_m11_file_mode = false; + out->dec_conf_bufLength = 0; + out->first_bitstrm_buf = false; + out->open_dec_route = false; + out->dec_format_devices = AUDIO_DEVICE_NONE; + out->open_dec_mch_route = false; + out->dec_mch_format_devices =AUDIO_DEVICE_NONE; + out->open_passt_route = false; + out->passt_format_devices = AUDIO_DEVICE_NONE; + out->sw_open_trans_route = false; + out->sw_trans_format_devices = AUDIO_DEVICE_NONE; + out->hw_open_trans_route =false ; + out->hw_trans_format_devices = AUDIO_DEVICE_NONE; + out->channel_status_set = false; + out->route_audio_to_a2dp = false; + out->is_ms11_file_playback_mode = false; + out->write_temp_buf = NULL; + return; +} + +struct alsa_handle *get_alsa_handle() { + + struct alsa_handle *handle; + handle = (struct alsa_handle *)calloc(1, sizeof(struct alsa_handle)); + if(handle == NULL) { + ALOGE("%s calloc failed for handle", __func__); + } else { + ALOGE("%s handle is 0x%x", __func__,(uint32_t)handle); + } + + return handle; +} + +void free_alsa_handle(struct alsa_handle *handle) { + + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + } + free(handle); + + return; +} + + +struct alsa_handle *get_handle_by_route_format(struct stream_out *out, + int route_format) +{ + struct listnode *node; + struct alsa_handle *handle = NULL; + ALOGV("%s",__func__); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if(handle->route_format & route_format) { + ALOGV("%s found handle %x",__func__,(uint32_t)handle); + break; + } + } + + return handle; +} + +/******************************************************************************* +Description: get the format index +*******************************************************************************/ +int get_format_index(int format) +{ + ALOGVV("get_format_index"); + int idx = 0,i; + for(i=0; icompr,&avail, &tstamp); + if(ret!=0) { + ALOGE("cannot get available space\n"); + } else + ret = (int)avail; + return ret; +} + + +/******************************************************************************* +Description: validate if the decoder requires configuration to be set as first + buffer +*******************************************************************************/ +int is_decoder_config_required(struct stream_out *out) +{ + ALOGVV("is_decoder_config_required"); + int main_format = out->format & AUDIO_FORMAT_MAIN_MASK; + uint32_t i; + if(!out->is_ms11_file_playback_mode) + return 0; + for(i=0; idecoder_type == SW_PASSTHROUGH) || + (out->decoder_type == DSP_PASSTHROUGH)) + return 1; + else + return 0; +} + + + +/******************************************************************************* +Description: update use case and routing flags +*******************************************************************************/ +void update_decode_type_and_routing_states(struct stream_out *out) +{ + ALOGV("%s", __func__); + + int format_index = get_format_index(out->format); + int decodeType, idx; + + out->open_dec_route = false; + out->open_dec_mch_route = false; + out->open_passt_route = false; + out->sw_open_trans_route = false; + out->hw_open_trans_route = false; + out->dec_format_devices = out->devices; + out->dec_mch_format_devices = AUDIO_DEVICE_NONE; + out->passt_format_devices = AUDIO_DEVICE_NONE; + out->sw_trans_format_devices = AUDIO_DEVICE_NONE; + out->hw_trans_format_devices = AUDIO_DEVICE_NONE; + out->decoder_type = 0; + +//TODO: enable sw_decode if required +#if USE_SWDECODE + if(is_ms11_supported_fromats(out->format)) + out->use_ms11_decoder = true; +#endif + + ALOGV("format_index: %d devices %x", format_index,out->devices); + if(out->devices & AUDIO_DEVICE_OUT_SPDIF) { + decodeType = usecase_docode_hdmi_spdif[NUM_STATES_FOR_EACH_DEVICE_FMT*format_index] + [out->spdif_format]; + ALOGV("SPDIF: decoderType: %d", decodeType); + out->decoder_type = decodeType; + for(idx=0; idxopen_dec_route = true; + break; + case ROUTE_UNCOMPRESSED_MCH: + ALOGVV("ROUTE_UNCOMPRESSED_MCH"); + ALOGVV("SPDIF opened with multichannel decode"); + out->open_dec_mch_route = true; + out->dec_format_devices &= ~AUDIO_DEVICE_OUT_SPDIF; + out->dec_mch_format_devices |= AUDIO_DEVICE_OUT_SPDIF; + break; + case ROUTE_COMPRESSED: + ALOGVV("ROUTE_COMPRESSED"); + out->open_passt_route = true; + out->dec_format_devices &= ~AUDIO_DEVICE_OUT_SPDIF; + out->passt_format_devices = AUDIO_DEVICE_OUT_SPDIF; + break; + case ROUTE_DSP_TRANSCODED_COMPRESSED: + ALOGVV("ROUTE_DSP_TRANSCODED_COMPRESSED"); + out->hw_open_trans_route = true; + out->hw_trans_format_devices = AUDIO_DEVICE_OUT_SPDIF; + break; + case ROUTE_SW_TRANSCODED_COMPRESSED: + ALOGVV("ROUTE_SW_TRANSCODED_COMPRESSED"); + out->sw_open_trans_route = true; + out->dec_format_devices &= ~AUDIO_DEVICE_OUT_SPDIF; + out->sw_trans_format_devices = AUDIO_DEVICE_OUT_SPDIF; + break; + default: + ALOGW("INVALID ROUTE for SPDIF, decoderType %d, routeFormat %d", + decodeType, route_to_driver[idx][ROUTE_FORMAT_IDX]); + break; + } + } + } + } + if(out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { + decodeType = usecase_docode_hdmi_spdif[NUM_STATES_FOR_EACH_DEVICE_FMT*format_index] + [out->hdmi_format]; + ALOGV("HDMI: decoderType: %d", decodeType); + out->decoder_type |= decodeType; + for(idx=0; idxopen_dec_route = true; + break; + case ROUTE_UNCOMPRESSED_MCH: + ALOGVV("ROUTE_UNCOMPRESSED_MCH"); + ALOGVV("HDMI opened with multichannel decode"); + out->open_dec_mch_route = true; + out->dec_format_devices &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL; + out->dec_mch_format_devices |= AUDIO_DEVICE_OUT_AUX_DIGITAL; + break; + case ROUTE_COMPRESSED: + ALOGVV("ROUTE_COMPRESSED"); + out->open_passt_route = true; + out->dec_format_devices &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL; + out->passt_format_devices |= AUDIO_DEVICE_OUT_AUX_DIGITAL; + break; + case ROUTE_DSP_TRANSCODED_COMPRESSED: + ALOGVV("ROUTE_DSP_TRANSCODED_COMPRESSED"); + out->hw_open_trans_route = true; + out->hw_trans_format_devices |= AUDIO_DEVICE_OUT_AUX_DIGITAL; + break; + case ROUTE_SW_TRANSCODED_COMPRESSED: + ALOGVV("ROUTE_SW_TRANSCODED_COMPRESSED"); + out->sw_open_trans_route = true; + out->dec_format_devices &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL; + out->sw_trans_format_devices |= AUDIO_DEVICE_OUT_AUX_DIGITAL; + break; + default: + ALOGW("INVALID ROUTE for HDMI, decoderType %d, routeFormat %d", + decodeType, route_to_driver[idx][ROUTE_FORMAT_IDX]); + break; + } + } + } + } + if(out->devices & ~(AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_SPDIF)) { + decodeType = usecase_decode_format[NUM_STATES_FOR_EACH_DEVICE_FMT*format_index]; + ALOGV("Other Devices: decoderType: %d", decodeType); + out->decoder_type |= decodeType; + for(idx=0; idxopen_dec_route = true; + break; + case ROUTE_UNCOMPRESSED_MCH: + ALOGVV("ROUTE_UNCOMPRESSED_MCH"); + ALOGVV("Other Devices opened with multichannel decode"); + out->open_dec_mch_route = true; + out->dec_format_devices &= ~(out->devices & + ~(AUDIO_DEVICE_OUT_SPDIF | + AUDIO_DEVICE_OUT_AUX_DIGITAL)); + out->dec_mch_format_devices |= (out->devices & + ~(AUDIO_DEVICE_OUT_SPDIF | + AUDIO_DEVICE_OUT_AUX_DIGITAL)); + break; + default: + ALOGW("INVALID ROUTE for Other Devices, decoderType %d, routeFormat %d", + decodeType, route_to_driver[idx][ROUTE_FORMAT_IDX]); + break; + } + } + } + } +} + +/******************************************************************************* +Description: update handle states +*******************************************************************************/ +int update_alsa_handle_state(struct stream_out *out) +{ + ALOGV("%s", __func__); + + struct alsa_handle *handle = NULL; + struct listnode *node; + + if(out->open_dec_route) { + if((handle = get_alsa_handle())== NULL) + goto error; + list_add_tail(&out->session_list, &handle->list); + handle->route_format = ROUTE_UNCOMPRESSED; + handle->devices = out->dec_format_devices; + handle->usecase = platform_get_usecase(USECASE_AUDIO_PLAYBACK_OFFLOAD); + handle->out = out; + handle->cmd_pending = false; + ALOGD("open_dec_route: routeformat: %d, devices: 0x%x: " + ,handle->route_format, handle->devices); + } + if(out->open_dec_mch_route) { + if((handle = get_alsa_handle())== NULL) + goto error; + list_add_tail(&out->session_list, &handle->list); + handle->route_format = ROUTE_UNCOMPRESSED_MCH; + handle->devices = out->dec_mch_format_devices; + handle->usecase = platform_get_usecase(USECASE_AUDIO_PLAYBACK_OFFLOAD); + handle->out = out; + handle->cmd_pending = false; + ALOGD("OpenMCHDecodeRoute: routeformat: %d, devices: 0x%x: " + ,handle->route_format, handle->devices); + } + if(out->open_passt_route) { + if((handle = get_alsa_handle())== NULL) + goto error; + list_add_tail(&out->session_list, &handle->list); + handle->route_format = ROUTE_COMPRESSED; + handle->devices = out->passt_format_devices; + handle->usecase = platform_get_usecase(USECASE_AUDIO_PLAYBACK_OFFLOAD); + handle->out = out; + handle->cmd_pending = false; + ALOGD("open_passt_route: routeformat: %d, devices: 0x%x: " + ,handle->route_format, handle->devices); + } + if(out->sw_open_trans_route) { + if((handle = get_alsa_handle())== NULL) + goto error; + handle->route_format = ROUTE_SW_TRANSCODED_COMPRESSED; + handle->devices = out->sw_trans_format_devices; + handle->usecase = platform_get_usecase(USECASE_AUDIO_PLAYBACK_OFFLOAD); + handle->out = out; + handle->cmd_pending = false; + ALOGD("OpenTranscodeRoute: routeformat: %d, devices: 0x%x: " + ,handle->route_format, handle->devices); + } + if(out->hw_open_trans_route) { + if((handle = get_alsa_handle())== NULL) + goto error; + handle->route_format = ROUTE_DSP_TRANSCODED_COMPRESSED; + handle->devices = out->hw_trans_format_devices; + handle->usecase = platform_get_usecase(USECASE_AUDIO_PLAYBACK_OFFLOAD); + handle->out = out; + handle->cmd_pending = false; + ALOGD("OpenTranscodeRoute: routeformat: %d, devices: 0x%x: " + ,handle->route_format, handle->devices); + } + +return 0; + +error: + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + free_alsa_handle(handle); + } + + return -ENOMEM; +} + +/******************************************************************************* +Description: setup input path +*******************************************************************************/ +int allocate_internal_buffers(struct stream_out *out) +{ + ALOGV("%s",__func__); + int ret = 0; + int main_format = out->format & AUDIO_FORMAT_MAIN_MASK; + + /* + setup the bitstream state machine + */ + out->bitstrm = ( struct audio_bitstream_sm *)calloc(1, + sizeof(struct audio_bitstream_sm)); + if(!audio_bitstream_init(out->bitstrm, get_buffering_factor(out))) { + ALOGE("%s Unable to allocate bitstream buffering for MS11",__func__); + free(out->bitstrm); + out->bitstrm = NULL; + return -EINVAL; + } + + if(is_input_buffering_mode_reqd(out)) + audio_bitstream_start_input_buffering_mode(out->bitstrm); + + /* + setup the buffering data required for decode to start + AAC_ADIF would require worst case frame size before decode starts + other decoder formats handles the partial data, hence threshold is zero. + */ + + if(main_format == AUDIO_FORMAT_AAC_ADIF) + out->min_bytes_req_to_dec = AAC_BLOCK_PER_CHANNEL_MS11*out->channels-1; + else + out->min_bytes_req_to_dec = 0; + + ret = open_temp_buf_for_metadata(out); + if(ret < 0) { + free(out->bitstrm); + out->bitstrm = NULL; + } + out->buffer_size = get_buffer_length(out); + + return ret; +} + +/******************************************************************************* +Description: setup input path +*******************************************************************************/ +int free_internal_buffers(struct stream_out *out) +{ + if(out->bitstrm) { + free(out->bitstrm); + out->bitstrm = NULL; + } + + if(out->write_temp_buf) { + free(out->write_temp_buf); + out->write_temp_buf = NULL; + } + + if(out->dec_conf_buf) { + free(out->dec_conf_buf); + out->dec_conf_buf = NULL; + } + return 0; +} + +/******************************************************************************* +Description: open MS11 instance +*******************************************************************************/ +//TODO: enable sw_decode if required +#if USE_SWDECODE +static int open_ms11_instance(struct stream_out *out) +{ + ALOGV("openMS11Instance"); + int32_t formatMS11; + int main_format = out->format & AUDIO_FORMAT_MAIN_MASK; + out->ms11_decoder = get_soft_ms11(); + if(!out->ms11_decoder) { + ALOGE("Could not resolve all symbols Required for MS11"); + return -EINVAL; + } + /* + MS11 created + */ + if(initialize_ms11_function_pointers(out->ms11_decoder) == false) { + ALOGE("Could not resolve all symbols Required for MS11"); + free_soft_ms11(out->ms11_decoder); + return -EINVAL; + } + /* + update format + */ + if((main_format == AUDIO_FORMAT_AC3) || + (main_format == AUDIO_FORMAT_EAC3)) { + /*TODO: who wil setCOMPRESSED_CONVERT_AC3_ASSOC */ + if (out->spdif_format == COMPRESSED_CONVERT_AC3_ASSOC) + formatMS11 = FORMAT_DOLBY_DIGITAL_PLUS_MAIN_ASSOC; + else + formatMS11 = FORMAT_DOLBY_DIGITAL_PLUS_MAIN; + } else + formatMS11 = FORMAT_DOLBY_PULSE_MAIN; + /* + set the use case to the MS11 decoder and open the stream for decoding + */ + if(ms11_set_usecase_and_open_stream_with_mode(out->ms11_decoder, + formatMS11, out->channels, out->sample_rate, + out->is_m11_file_mode)) { + ALOGE("SetUseCaseAndOpen MS11 failed"); + free_soft_ms11(out->ms11_decoder); + return EINVAL; + } + if(is_decoder_config_required(out) && out->dec_conf_buf && out->dec_conf_bufLength) { + if(ms11_set_aac_config(out->ms11_decoder, (unsigned char *)out->dec_conf_buf, + out->dec_conf_bufLength) == true) { + out->dec_conf_set = true; + } + } + + return 0; +} +#endif +/******************************************************************************* +Description: copy input to internal buffer +*******************************************************************************/ +void copy_bitstream_internal_buffer(struct audio_bitstream_sm *bitstrm, + char *buffer, size_t bytes) +{ + // copy bitstream to internal buffer + audio_bitstream_copy_to_internal_buffer(bitstrm, (char *)buffer, bytes); +#ifdef DEBUG + dumpInputOutput(INPUT, buffer, bytes, 0); +#endif +} + +/******************************************************************************* +Description: set decoder config +*******************************************************************************/ +//TODO: enable sw_decode if required +#if USE_SWDECODE +int setDecodeConfig(struct stream_out *out, char *buffer, size_t bytes) +{ + ALOGV("%s ", __func__); + + int main_format = out->format & AUDIO_FORMAT_MAIN_MASK; + if(!out->dec_conf_set) { + if(main_format == AUDIO_FORMAT_AAC || + main_format == AUDIO_FORMAT_HE_AAC_V1 || + main_format == AUDIO_FORMAT_AAC_ADIF || + main_format == AUDIO_FORMAT_HE_AAC_V2) { + if(out->ms11_decoder != NULL) { + if(ms11_set_aac_config(out->ms11_decoder,(unsigned char *)buffer, + bytes) == false) { + ALOGE("AAC decoder config fail"); + return 0; + } + } + } + + out->dec_conf_bufLength = bytes; + if(out->dec_conf_buf) + free(out->dec_conf_buf); + + out->dec_conf_buf = malloc(out->dec_conf_bufLength); + memcpy(out->dec_conf_buf, + buffer, + out->dec_conf_bufLength); + out->dec_conf_set = true; + } + out->dec_conf_set = true; + return bytes; +} +#endif + +//TODO: enable sw_decode if required +#if USE_SWDECODE +int validate_sw_free_space(struct stream_out* out, int bytes_consumed_in_decode, int *pcm_2ch_len, + int *pcm_mch_len, int *passthru_len, int *transcode_len, bool *wait_for_write_done) { + + struct alsa_handle *handle = NULL; + char *bufPtr; + int copy_output_buffer_size; + + *pcm_2ch_len = *pcm_mch_len = *passthru_len = *transcode_len = *wait_for_write_done = 0; + + if(out->decoder_type & SW_DECODE) { + bufPtr = audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, + PCM_2CH_OUT); + /*TODO: there is chance of illegale access if ms11 output exceeds bitstream + output buffer boudary */ + copy_output_buffer_size = ms11_copy_output_from_ms11buf(out->ms11_decoder, + PCM_2CH_OUT, + bufPtr); + handle = get_handle_by_route_format(out, ROUTE_UNCOMPRESSED); + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + return -EINVAL; + } + if(get_compress_available_space(handle) < copy_output_buffer_size) { + handle->cmd_pending = true; + *wait_for_write_done = true; + } + *pcm_2ch_len = copy_output_buffer_size; + + } + if(out->decoder_type & SW_DECODE_MCH) { + bufPtr=audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, + PCM_MCH_OUT); + copy_output_buffer_size = ms11_copy_output_from_ms11buf(out->ms11_decoder, + PCM_MCH_OUT, + bufPtr); + handle = get_handle_by_route_format(out, ROUTE_UNCOMPRESSED_MCH); + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + return -EINVAL; + } + + if(get_compress_available_space(handle) < copy_output_buffer_size) { + handle->cmd_pending = true; + *wait_for_write_done = true; + } + *pcm_mch_len = copy_output_buffer_size; + } + if(out->decoder_type & SW_PASSTHROUGH) { + bufPtr = audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, COMPRESSED_OUT); + copy_output_buffer_size = bytes_consumed_in_decode; + memcpy(bufPtr, audio_bitstream_get_input_buffer_ptr(out->bitstrm), copy_output_buffer_size); + + handle = get_handle_by_route_format(out, ROUTE_COMPRESSED); + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + return -EINVAL; + } + + if(get_compress_available_space(handle) < copy_output_buffer_size) { + handle->cmd_pending = true; + *wait_for_write_done = true; + } + *passthru_len = copy_output_buffer_size; + } + if(out->decoder_type & SW_TRANSCODE) { + bufPtr = audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, + TRANSCODE_OUT); + copy_output_buffer_size = ms11_copy_output_from_ms11buf(out->bitstrm, + COMPRESSED_OUT, + bufPtr); + handle = get_handle_by_route_format(out, ROUTE_SW_TRANSCODED_COMPRESSED); + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + return -EINVAL; + } + if(get_compress_available_space(handle) < copy_output_buffer_size) { + handle->cmd_pending = true; + *wait_for_write_done = true; + } + *transcode_len = copy_output_buffer_size; + } + return 0; +} +#endif + +int validate_hw_free_space(struct stream_out *out, int bytes_consumed_in_decode, int *pcm_2ch_len, + int *pcm_mch_len, int *passthru_len, int *transcode_len, bool *wait_for_write_done) { + + struct alsa_handle *handle = NULL; + char *bufPtr; + int copy_output_buffer_size; + *pcm_2ch_len = *pcm_mch_len = *passthru_len = *transcode_len = *wait_for_write_done = 0; + if(out->decoder_type & DSP_DECODE) { + ALOGVV("DSP_DECODE"); + bufPtr = audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, + PCM_MCH_OUT); + copy_output_buffer_size = bytes_consumed_in_decode; + memcpy(bufPtr, audio_bitstream_get_input_buffer_ptr(out->bitstrm), + copy_output_buffer_size); + ALOGVV("%s bytes_consumed %d out bufPtr %x, pcm_mch_out_buf_size%d", + __func__,bytes_consumed_in_decode,bufPtr, + out->bitstrm->pcm_mch_out_buf_size); + handle = get_handle_by_route_format(out, ROUTE_UNCOMPRESSED);/*TODO: revisit */ + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + return -EINVAL; + } + if(get_compress_available_space(handle) < copy_output_buffer_size) { + handle->cmd_pending = true; + *wait_for_write_done = true; + /*reset input buffer pointer as flinger will resend the data back */ + audio_bitstream_set_input_buffer_write_ptr(out->bitstrm, + -copy_output_buffer_size); + *pcm_mch_len = copy_output_buffer_size; + } + else + *pcm_mch_len = copy_output_buffer_size; + } + if(out->decoder_type & DSP_PASSTHROUGH) { + ALOGVV("DSP_PASSTHROUGH"); + bufPtr = audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, COMPRESSED_OUT); + copy_output_buffer_size = bytes_consumed_in_decode; + memcpy(bufPtr, audio_bitstream_get_input_buffer_ptr(out->bitstrm), copy_output_buffer_size); + handle = get_handle_by_route_format(out, ROUTE_COMPRESSED); + if(handle == NULL) { + ALOGE("%s Invalid handle", __func__); + return -EINVAL; + } + if(get_compress_available_space(handle) < copy_output_buffer_size) { + handle->cmd_pending = true; + *wait_for_write_done = true; + *passthru_len = copy_output_buffer_size; + /*reset input buffer pointer as flinger will resend the data back */ + audio_bitstream_set_input_buffer_ptr(out->bitstrm, -copy_output_buffer_size); + } + else + *passthru_len = copy_output_buffer_size; + } + /*TODO: handle DSP Transcode usecase */ + return 0; +} + +int update_bitstrm_pointers(struct stream_out *out, int pcm_2ch_len, + int pcm_mch_len, int passthru_len, int transcode_len) { + + if(out->decoder_type & SW_DECODE) { + audio_bitstream_set_output_buffer_write_ptr(out->bitstrm, PCM_2CH_OUT, + pcm_2ch_len); + + } + if(out->decoder_type & SW_DECODE_MCH || out->decoder_type & DSP_DECODE) { + audio_bitstream_set_output_buffer_write_ptr(out->bitstrm, PCM_MCH_OUT, pcm_mch_len); + } + if(out->decoder_type & SW_PASSTHROUGH || out->decoder_type & DSP_PASSTHROUGH) { + audio_bitstream_set_output_buffer_write_ptr(out->bitstrm, COMPRESSED_OUT, passthru_len); + } + if(out->decoder_type & SW_TRANSCODE) { + audio_bitstream_set_output_buffer_write_ptr(out->bitstrm, + TRANSCODE_OUT, + transcode_len); + } + return 0; +} + +/*TODO correct it */ +static int configure_compr(struct stream_out *out, + struct alsa_handle *handle) { + handle->compr_config.codec = (struct snd_codec *) + calloc(1, sizeof(struct snd_codec)); + handle->compr_config.codec->id = + get_snd_codec_id(out->format); /*TODO: correct this based on format*/ + handle->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + handle->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; + handle->compr_config.codec->sample_rate = + compress_get_alsa_rate(out->sample_rate); + handle->compr_config.codec->bit_rate = out->compr_config.codec->bit_rate; + handle->compr_config.codec->ch_in = + popcount(out->channel_mask); + handle->compr_config.codec->ch_out = handle->compr_config.codec->ch_in; + memcpy(&handle->compr_config.codec->options, + &out->compr_config.codec->options, + sizeof(union snd_codec_options)); + return 0; +} + +/*TODO: do we need to apply volume at the session open*/ +static int set_compress_volume(struct alsa_handle *handle, int left, int right) +{ + + struct audio_device *adev = handle->out->dev; + struct mixer_ctl *ctl; + int volume[2]; + + char mixer_ctl_name[44]; // max length of name is 44 as defined + char device_id[STRING_LENGTH_OF_INTEGER+1]; + + memset(mixer_ctl_name, 0, sizeof(mixer_ctl_name)); + strlcpy(mixer_ctl_name, "Compress Playback Volume", sizeof(mixer_ctl_name)); + + memset(device_id, 0, sizeof(device_id)); + snprintf(device_id, "%d", handle->device_id, sizeof(device_id)); + + strlcat(mixer_ctl_name, device_id, sizeof(mixer_ctl_name)); + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX); + volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX); + mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0])); + + return 0; + +} + +/******************************************************************************* +Description: software decode handling +*******************************************************************************/ +//TODO: enable sw_decode if required +#if USE_SWDECODE +static int sw_decode(struct stream_out *out, + char *buffer, + size_t bytes, + size_t *bytes_consumed, + bool *continueDecode) +{ + /* bytes pending to be decoded in current buffer*/ + bool wait_for_write_done = false; + int bytes_pending_for_decode = 0; + /* bytes consumed in current write buffer */ + int total_bytes_consumed = 0; + size_t copyBytesMS11 = 0; + size_t bytes_consumed_in_decode = 0; + size_t copy_output_buffer_size = 0; + uint32_t outSampleRate = out->sample_rate; + uint32_t outChannels = out->channels; + char * bufPtr; + int pcm_2ch_len, pcm_mch_len, passthru_len, transcode_len; + struct alsa_handle *handle = NULL; + + ALOGVV("sw Decode"); + // eos handling + if(bytes == 0) { + if(out->format == AUDIO_FORMAT_AAC_ADIF) + audio_bitstream_append_silence_internal_buffer(out->bitstrm, + out->min_bytes_req_to_dec,0x0); + else + return false; + } + /* + check for sync word, if present then configure MS11 for fileplayback mode + OFF. This is specifically done to handle Widevine usecase, in which the + ADTS HEADER is not stripped off by the Widevine parser + */ + if(out->first_bitstrm_buf == true) { + uint16_t uData = (*((char *)buffer) << 8) + *((char *)buffer + 1) ; + if(ADTS_HEADER_SYNC_RESULT == (uData & ADTS_HEADER_SYNC_MASK)) { + ALOGD("Sync word found hence configure MS11 in file_playback Mode OFF"); + free_soft_ms11(out->ms11_decoder); + out->is_m11_file_mode = false; + open_ms11_instance(out); + } + out->first_bitstrm_buf = false; + } + //decode + if(out->decoder_type == SW_PASSTHROUGH) { + /*TODO: check if correct */ + bytes_consumed_in_decode = audio_bitstream_get_size(out->bitstrm); + } else { + if(audio_bitstream_sufficient_buffer_to_decode(out->bitstrm, + out->min_bytes_req_to_dec) == true) { + bufPtr = audio_bitstream_get_input_buffer_ptr(out->bitstrm); + copyBytesMS11 = audio_bitstream_get_size(out->bitstrm); + ms11_copy_bitstream_to_ms11_inpbuf(out->ms11_decoder, bufPtr,copyBytesMS11); + bytes_consumed_in_decode = ms11_stream_decode(out->ms11_decoder, + &outSampleRate, &outChannels); + } + } + + if((out->sample_rate != outSampleRate) || (out->channels != outChannels)) { + ALOGD("Change in sample rate. New sample rate: %d", outSampleRate); + out->sample_rate = outSampleRate; + out->channels = outChannels; + handle = get_handle_by_route_format(out, ROUTE_UNCOMPRESSED); + if(handle !=NULL) { + configure_compr(out, handle); + handle->compr = compress_open(SOUND_CARD, handle->device_id, + COMPRESS_IN, &handle->compr_config); + if (handle->compr && !is_compress_ready(handle->compr)) { + ALOGE("%s: %s", __func__, compress_get_error(handle->compr)); + compress_close(handle->compr); + handle->compr = NULL; + } + if (out->offload_callback) + compress_nonblock(handle->compr, out->non_blocking); + + set_compress_volume(handle, out->left_volume, out->right_volume); + } + + handle = get_handle_by_route_format(out, ROUTE_UNCOMPRESSED_MCH); + if(handle !=NULL) { + configure_compr(out, handle); + handle->compr = compress_open(SOUND_CARD, handle->device_id, + COMPRESS_IN, &handle->compr_config); + if (handle->compr && !is_compress_ready(handle->compr)) { + ALOGE("%s: %s", __func__, compress_get_error(handle->compr)); + compress_close(handle->compr); + handle->compr = NULL; + } + if (out->offload_callback) + compress_nonblock(handle->compr, out->non_blocking); + set_compress_volume(handle, out->left_volume, out->right_volume); + out->channel_status_set = false; + } + } + + + validate_sw_free_space(out, bytes_consumed_in_decode, &pcm_2ch_len, &pcm_mch_len, + &passthru_len, &transcode_len, &wait_for_write_done); + + if(wait_for_write_done && out->non_blocking) { + send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); + *continueDecode = false; + *bytes_consumed = 0; + return 0; + } else { + update_bitstrm_pointers(out, pcm_2ch_len, pcm_mch_len, + passthru_len, transcode_len); + audio_bitstream_copy_residue_to_start(out->bitstrm, bytes_consumed_in_decode); + *bytes_consumed = bytes_consumed_in_decode; + } + + copy_output_buffer_size = pcm_2ch_len + pcm_mch_len + passthru_len + transcode_len; + if(copy_output_buffer_size && + audio_bitstream_sufficient_buffer_to_decode(out->bitstrm, out->min_bytes_req_to_dec) == true) { + *continueDecode = true; + return 0; + } + return 0; +} +#endif + +/******************************************************************************* +Description: dsp decode handling +*******************************************************************************/ +static bool dsp_decode(struct stream_out *out, char *buffer, size_t bytes, + size_t *bytes_consumed, bool *continueDecode) +{ + char *bufPtr; + size_t bytes_consumed_in_decode = 0; + + bool wait_for_write_done = false; + int pcm_2ch_len, pcm_mch_len, passthru_len, transcode_len; + + ALOGVV("dsp_decode"); + // decode + { + bytes_consumed_in_decode = audio_bitstream_get_size(out->bitstrm); + } + // handle change in sample rate + { + } + //TODO: check if the copy of the buffers can be avoided + /* can be removed as its not required for dsp decode usecase */ + *continueDecode = false; + validate_hw_free_space(out, bytes_consumed_in_decode, &pcm_2ch_len, &pcm_mch_len, + &passthru_len, &transcode_len, &wait_for_write_done); + + if(wait_for_write_done && out->non_blocking) { + send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); + *bytes_consumed = 0; + return 0; + } else { + update_bitstrm_pointers(out, pcm_2ch_len, pcm_mch_len, + passthru_len, transcode_len); + audio_bitstream_copy_residue_to_start(out->bitstrm, bytes_consumed_in_decode); + *bytes_consumed = bytes_consumed_in_decode; + ALOGV("%s bytes_consumed_in_decode =%d",__func__,bytes_consumed_in_decode); + } + + return 0; +} + +static bool decode(struct stream_out *out, char * buffer, size_t bytes, + size_t *bytes_consumed, bool *continuedecode) +{ + ALOGV("decode"); + bool continueDecode = false; + int ret = 0; + + // TODO: enable software decode if required + /*if (out->use_ms11_decoder) { + ret = sw_decode(out, buffer, bytes, + bytes_consumed, continuedecode); + + // set channel status + // Set the channel status after first frame decode/transcode + //TODO: set the SPDIF channel status bits + if(out->channel_status_set == false) + setSpdifchannel_status( + audio_bitstream_get_output_buffer_ptr(out->bitstrm, COMPRESSED_OUT), + bytes, AUDIO_PARSER_CODEC_AC3); + + } else */{ + ret = dsp_decode(out, buffer, bytes, + bytes_consumed, continuedecode); + // set channel status + // Set the channel status after first frame decode/transcode + //TODO: set the SPDIF channel status bits +/* if(out->channel_status_set == false) + setSpdifchannel_status( + audio_bitstream_get_output_buffer_ptr(out->bitstrm, COMPRESSED_OUT), + bytes, AUDIO_PARSER_CODEC_DTS); +*/ + } + return ret; +} + +/******************************************************************************* +Description: fixup sample rate and channel info based on format +*******************************************************************************/ +void fixupSampleRateChannelModeMS11Formats(struct stream_out *out) +{ + ALOGV("fixupSampleRateChannelModeMS11Formats"); + int main_format = out->format & AUDIO_FORMAT_MAIN_MASK; + int subFormat = out->format & AUDIO_FORMAT_SUB_MASK; +/* +NOTE: For AAC, the output of MS11 is 48000 for the sample rates greater than + 24000. The samples rates <= 24000 will be at their native sample rate + For AC3, the PCM output is at its native sample rate if the decoding is + single decode usecase for MS11. +*/ + if(main_format == AUDIO_FORMAT_AAC || + main_format == AUDIO_FORMAT_HE_AAC_V1 || + main_format == AUDIO_FORMAT_HE_AAC_V2 || + main_format == AUDIO_FORMAT_AAC_ADIF) { + out->sample_rate = out->sample_rate > 24000 ? 48000 : out->sample_rate; + out->channels = 6; + } else if (main_format == AUDIO_FORMAT_AC3 || + main_format == AUDIO_FORMAT_EAC3) { + /* transcode AC3/EAC3 44.1K to 48K AC3 for non dual-mono clips */ + if (out->sample_rate == 44100 && + (subFormat != AUDIO_FORMAT_DOLBY_SUB_DM) && + (out->spdif_format == COMPRESSED || + out->spdif_format == AUTO_DEVICE_FORMAT || + out->spdif_format == COMPRESSED_CONVERT_EAC3_AC3) && + (out->hdmi_format == UNCOMPRESSED || + out->hdmi_format == UNCOMPRESSED_MCH)) { + out->sample_rate = 48000; + out->spdif_format = COMPRESSED_CONVERT_AC3_ASSOC; + } else if (out->sample_rate == 44100) { + out->spdif_format = UNCOMPRESSED; + } + out->channels = 6; + } + ALOGD("ms11 format fixup: out->spdif_format %d, out->hdmi_format %d", + out->spdif_format, out->hdmi_format); +} static bool is_supported_format(audio_format_t format) { @@ -173,21 +1397,33 @@ static int send_offload_cmd_l(struct stream_out* out, int command) /* must be called iwth out->lock locked */ static void stop_compressed_output_l(struct stream_out *out) { + struct listnode *node; + struct alsa_handle *handle; + bool is_compr_out = false; + + ALOGV("%s", __func__); out->offload_state = OFFLOAD_STATE_IDLE; out->playback_started = 0; out->send_new_metadata = 1; - if (out->compr != NULL) { - compress_stop(out->compr); - while (out->offload_thread_blocked) { - pthread_cond_wait(&out->cond, &out->lock); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->compr != NULL) { + compress_stop(handle->compr); + is_compr_out = true; } } + if (is_compr_out) { + while (out->offload_thread_blocked) + pthread_cond_wait(&out->cond, &out->lock); + } } static void *offload_thread_loop(void *context) { struct stream_out *out = (struct stream_out *) context; struct listnode *item; + struct listnode *node; + struct alsa_handle *handle; out->offload_state = OFFLOAD_STATE_IDLE; out->playback_started = 0; @@ -217,15 +1453,15 @@ static void *offload_thread_loop(void *context) cmd = node_to_item(item, struct offload_cmd, node); list_remove(item); - ALOGVV("%s STATE %d CMD %d out->compr %p", - __func__, out->offload_state, cmd->cmd, out->compr); + ALOGVV("%s STATE %d CMD %d", + __func__, out->offload_state, cmd->cmd); if (cmd->cmd == OFFLOAD_CMD_EXIT) { free(cmd); break; } - if (out->compr == NULL) { + if (list_empty(&out->session_list)) { ALOGE("%s: Compress handle is NULL", __func__); pthread_cond_signal(&out->cond); continue; @@ -235,18 +1471,34 @@ static void *offload_thread_loop(void *context) send_callback = false; switch(cmd->cmd) { case OFFLOAD_CMD_WAIT_FOR_BUFFER: - compress_wait(out->compr, -1); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->compr && handle->cmd_pending) { + compress_wait(handle->compr, -1); + handle->cmd_pending = false; + } + } send_callback = true; event = STREAM_CBK_EVENT_WRITE_READY; break; case OFFLOAD_CMD_PARTIAL_DRAIN: - compress_next_track(out->compr); - compress_partial_drain(out->compr); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->compr) { + compress_next_track(handle->compr); + compress_partial_drain(handle->compr); + } + } send_callback = true; event = STREAM_CBK_EVENT_DRAIN_READY; break; case OFFLOAD_CMD_DRAIN: - compress_drain(out->compr); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->compr) { + compress_drain(handle->compr); + } + } send_callback = true; event = STREAM_CBK_EVENT_DRAIN_READY; break; @@ -373,18 +1625,18 @@ static int check_and_set_hdmi_channels(struct audio_device *adev, return 0; } -static int stop_output_stream(struct stream_out *out) +static int stop_output_stream(struct stream_out *out, struct alsa_handle *handle) { int i, ret = 0; struct audio_usecase *uc_info; struct audio_device *adev = out->dev; ALOGV("%s: enter: usecase(%d: %s)", __func__, - out->usecase, use_case_table[out->usecase]); - uc_info = get_usecase_from_list(adev, out->usecase); + handle->usecase, use_case_table[handle->usecase]); + uc_info = get_usecase_from_list(adev, handle->usecase); if (uc_info == NULL) { ALOGE("%s: Could not find the usecase (%d) in the list", - __func__, out->usecase); + __func__, handle->usecase); return -EINVAL; } @@ -409,63 +1661,66 @@ static int stop_output_stream(struct stream_out *out) return ret; } -int start_output_stream(struct stream_out *out) +int start_output_stream(struct stream_out *out, struct alsa_handle *handle) { int ret = 0; struct audio_usecase *uc_info; struct audio_device *adev = out->dev; ALOGV("%s: enter: usecase(%d: %s) devices(%#x)", - __func__, out->usecase, use_case_table[out->usecase], out->devices); - out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); - if (out->pcm_device_id < 0) { + __func__, handle->usecase, use_case_table[handle->usecase], handle->devices); + handle->device_id = platform_get_pcm_device_id(handle->usecase, PCM_PLAYBACK); + if (handle->device_id < 0) { ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", - __func__, out->pcm_device_id, out->usecase); + __func__, handle->device_id, handle->usecase); ret = -EINVAL; goto error_config; } uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); - uc_info->id = out->usecase; + uc_info->id = handle->usecase; + uc_info->handle = handle; uc_info->type = PCM_PLAYBACK; uc_info->stream.out = out; - uc_info->devices = out->devices; + uc_info->devices = handle->devices; uc_info->in_snd_device = SND_DEVICE_NONE; uc_info->out_snd_device = SND_DEVICE_NONE; /* This must be called before adding this usecase to the list */ - if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) - check_and_set_hdmi_channels(adev, out->config.channels); + //if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) + // check_and_set_hdmi_channels(adev, out->config.channels); list_add_tail(&adev->usecase_list, &uc_info->list); - select_devices(adev, out->usecase); + select_devices(adev, handle->usecase); ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", - __func__, 0, out->pcm_device_id); - if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { - out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id, - PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm && !pcm_is_ready(out->pcm)) { - ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); - pcm_close(out->pcm); - out->pcm = NULL; + __func__, 0, handle->device_id); + if (out->uc_strm_type != OFFLOAD_PLAYBACK_STREAM) { + handle->compr = NULL; + handle->pcm = pcm_open(SOUND_CARD, handle->device_id, + PCM_OUT | PCM_MONOTONIC, &handle->config); + if (handle->pcm && !pcm_is_ready(handle->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(handle->pcm)); + pcm_close(handle->pcm); + handle->pcm = NULL; ret = -EIO; goto error_open; } } else { - out->pcm = NULL; - out->compr = compress_open(SOUND_CARD, out->pcm_device_id, - COMPRESS_IN, &out->compr_config); - if (out->compr && !is_compress_ready(out->compr)) { - ALOGE("%s: %s", __func__, compress_get_error(out->compr)); - compress_close(out->compr); - out->compr = NULL; + handle->pcm = NULL; + configure_compr(out, handle); + handle->compr = compress_open(SOUND_CARD, handle->device_id, + COMPRESS_IN, &handle->compr_config); + if (handle->compr && !is_compress_ready(handle->compr)) { + ALOGE("%s: %s", __func__, compress_get_error(handle->compr)); + compress_close(handle->compr); + handle->compr = NULL; ret = -EIO; goto error_open; } if (out->offload_callback) - compress_nonblock(out->compr, out->non_blocking); + compress_nonblock(handle->compr, out->non_blocking); if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle); @@ -473,7 +1728,7 @@ int start_output_stream(struct stream_out *out) ALOGV("%s: exit", __func__); return 0; error_open: - stop_output_stream(out); + stop_output_stream(out, handle); error_config: return ret; } @@ -494,10 +1749,12 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + /*if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) return out->compr_config.fragment_size; + */ + return (size_t)out->buffer_size; - return out->config.period_size * audio_stream_frame_size(stream); + //return out->config.period_size * audio_stream_frame_size(stream); } static uint32_t out_get_channels(const struct audio_stream *stream) @@ -523,6 +1780,8 @@ static int out_standby(struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; + struct listnode *node; + struct alsa_handle *handle; ALOGV("%s: enter: usecase(%d: %s)", __func__, out->usecase, use_case_table[out->usecase]); @@ -538,21 +1797,21 @@ static int out_standby(struct audio_stream *stream) pthread_mutex_lock(&adev->lock); if (!out->standby) { out->standby = true; - if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { - if (out->pcm) { - pcm_close(out->pcm); - out->pcm = NULL; - } - } else { - stop_compressed_output_l(out); - out->gapless_mdata.encoder_delay = 0; - out->gapless_mdata.encoder_padding = 0; - if (out->compr != NULL) { - compress_close(out->compr); - out->compr = NULL; + stop_compressed_output_l(out); + out->gapless_mdata.encoder_delay = 0; + out->gapless_mdata.encoder_padding = 0; + + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->compr != NULL) { + compress_close(handle->compr); + handle->compr = NULL; + } else if (handle->pcm) { + pcm_close(handle->pcm); + handle->pcm = NULL; } + stop_output_stream(out, handle); } - stop_output_stream(out); } pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&out->lock); @@ -608,8 +1867,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int ret, val = 0; bool select_new_device = false; - ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", - __func__, out->usecase, use_case_table[out->usecase], kvpairs); + ALOGD("%s: enter: kvpairs: %s", __func__, kvpairs); parms = str_parms_create_str(kvpairs); ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); if (ret >= 0) { @@ -653,12 +1911,63 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if (!out->standby) select_devices(adev, out->usecase); } +//TODO: +//Get the device and device format mapping from the RoutingManager. +//Decide which streams need to be derouted and which need to opened/closed +//Update the respective device in each of the handles +#if 0 + if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) { + + /* TODO get format form routing manager */ + update_decode_type_and_routing_states(out); + + if(is_input_buffering_mode_reqd(out)) + audio_bitstream_start_input_buffering_mode(out->bitstrm); + else + audio_bitstream_stop_input_buffering_mode(out->bitstrm); + /* + For the runtime format change, close the device first to avoid any + concurrent PCM + Compressed sessions on the same device. + */ + close_handles_for_device_switch(out); + if(!out->mopen_dec_route) + handleCloseForDeviceSwitch(ROUTE_UNCOMPRESSED); + + if(!out->mopen_dec_mch_route) + handleCloseForDeviceSwitch(ROUTE_UNCOMPRESSED_MCH); + + if(!out->mopen_passt_route) + handleCloseForDeviceSwitch(ROUTE_COMPRESSED); + + if(!msw_open_trans_route) + handleCloseForDeviceSwitch(ROUTE_SW_TRANSCODED_COMPRESSED); + + if(!mhw_open_trans_route) + handleCloseForDeviceSwitch(ROUTE_DSP_TRANSCODED_COMPRESSED); + + if(out->mopen_dec_route) + handleSwitchAndOpenForDeviceSwitch(mdec_format_devices, + ROUTE_UNCOMPRESSED); + if(out->mopen_dec_mch_route) + handleSwitchAndOpenForDeviceSwitch(mdec_mch_format_devices, + ROUTE_UNCOMPRESSED_MCH); + if(out->mopen_passt_route) + handleSwitchAndOpenForDeviceSwitch(mpasst_format_devices, + ROUTE_COMPRESSED); + if(out->msw_open_trans_route) + handleSwitchAndOpenForDeviceSwitch(msw_trans_format_devices, + ROUTE_SW_TRANSCODED_COMPRESSED); + if(out->mhw_open_trans_route) + handleSwitchAndOpenForDeviceSwitch(mhw_trans_format_devices, + ROUTE_DSP_TRANSCODED_COMPRESSED); + } +#endif pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&out->lock); } - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) { parse_compress_metadata(out, parms); } @@ -695,54 +2004,218 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k } i++; } - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); - str = str_parms_to_str(reply); + str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); + str = str_parms_to_str(reply); + } + str_parms_destroy(query); + str_parms_destroy(reply); + ALOGV("%s: exit: returns - %s", __func__, str); + return str; +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + struct listnode *item; + struct alsa_handle *handle; + + //TODO: decide based on the clip properties + if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) + return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; + + item = list_head(&out->session_list); + handle = node_to_item(item, struct alsa_handle, list); + if(!handle) { + ALOGE("%s: error pcm handle NULL", __func__); + return -EINVAL; + } + + return (handle->config.period_count * handle->config.period_size * 1000) / + (handle->config.rate); +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + struct stream_out *out = (struct stream_out *)stream; + struct listnode *node; + struct alsa_handle *handle; + struct audio_device *adev = out->dev; + int ret = -ENOSYS; + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->pcm && (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH)){ + /* only take left channel into account: the API is for stereo anyway */ + out->muted = (left == 0.0f); + ret = 0; + } else if (handle->compr) { + + out->left_volume = left; + out->right_volume = right; + + //ret = set_compress_volume(handle, left, right); + } } - str_parms_destroy(query); - str_parms_destroy(reply); - ALOGV("%s: exit: returns - %s", __func__, str); - return str; + pthread_mutex_unlock(&out->lock); + + return ret; } -static uint32_t out_get_latency(const struct audio_stream_out *stream) -{ - struct stream_out *out = (struct stream_out *)stream; +static int write_data(struct stream_out *out, struct alsa_handle *handle, + const void *buffer, int bytes) { - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) - return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; + int ret = 0; + if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) { + ALOGV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); + + ret = compress_write(handle->compr, buffer, bytes); + ALOGV("%s: writing buffer (%d bytes) to compress device returned %d", + __func__, bytes, ret); + /* TODO:disnable this if ms12 */ + + if (ret >= 0 && ret < (ssize_t)bytes) { + send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); + } + return ret; + } else { + if (handle->pcm) { + if (out->muted) + memset((void *)buffer, 0, bytes); + ALOGV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); + ret = pcm_write(handle->pcm, (void *)buffer, bytes); + } + } - return (out->config.period_count * out->config.period_size * 1000) / - (out->config.rate); + if (ret != 0) { + if ((handle && handle->pcm)) + ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(handle->pcm)); + out_standby(&out->stream.common); + usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / + out_get_sample_rate(&out->stream.common)); + } + return bytes; } -static int out_set_volume(struct audio_stream_out *stream, float left, - float right) +/******************************************************************************* +Description: render +*******************************************************************************/ +size_t render_offload_data(struct stream_out *out, const void *buffer, size_t bytes) { - struct stream_out *out = (struct stream_out *)stream; - int volume[2]; + int ret =0; + uint32_t renderedPcmBytes = 0; + int fragment_size; + uint32_t availableSize; + int bytes_to_write = bytes; + int renderType; + /*int metadataLength = sizeof(out->output_meta_data);*/ + struct listnode *node; + struct alsa_handle *handle; - if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) { - /* only take left channel into account: the API is for stereo anyway */ - out->muted = (left == 0.0f); - return 0; - } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - const char *mixer_ctl_name = "Compress Playback Volume"; - struct audio_device *adev = out->dev; - struct mixer_ctl *ctl; - - ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; + ALOGV("%s", __func__); + + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (out->send_new_metadata) { + ALOGVV("send new gapless metadata"); + compress_set_gapless_metadata(handle->compr, &out->gapless_mdata); } - volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX); - volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX); - mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0])); - return 0; + + switch(handle->route_format) { + case ROUTE_UNCOMPRESSED: + ALOGVV("ROUTE_UNCOMPRESSED"); + renderType = PCM_2CH_OUT; + break; + case ROUTE_UNCOMPRESSED_MCH: + ALOGVV("ROUTE_UNCOMPRESSED_MCH"); + renderType = PCM_MCH_OUT; + break; + case ROUTE_COMPRESSED: + ALOGVV("ROUTE_COMPRESSED"); + renderType = COMPRESSED_OUT; + break; + case ROUTE_SW_TRANSCODED_COMPRESSED: + ALOGVV("ROUTE_SW_TRANSCODED_COMPRESSED"); + renderType = TRANSCODE_OUT; + break; + case ROUTE_DSP_TRANSCODED_COMPRESSED: + ALOGVV("ROUTE_DSP_TRANSCODED_COMPRESSED"); + continue; + default: + continue; + }; + + fragment_size = handle->compr_config.fragment_size; + /*TODO handle timestamp case */ +#if USE_SWDECODE + while(audio_bitstream_sufficient_sample_to_render(out->bitstrm, + renderType, 1) == true) { + availableSize = audio_bitstream_get_output_buffer_write_ptr(out->bitstrm, renderType) - + audio_bitstream_get_output_buffer_ptr(out->bitstrm, renderType); + buffer = audio_bitstream_get_output_buffer_ptr(out->bitstrm, renderType); + bytes_to_write = availableSize; + + TODO: meta data is only neded for TS mode + out->output_meta_data.metadataLength = metadataLength; + out->output_meta_data.bufferLength = (availableSize >= + (fragment_size - metadataLength)) ? + fragment_size - metadataLength : + availableSize; + bytes_to_write = metadataLength +out->output_meta_data.bufferLength; + out->output_meta_data.timestamp = 0; + memcpy(out->write_temp_buf, &out->output_meta_data, metadataLength); + memcpy(out->write_temp_buf+metadataLength, + audio_bitstream_get_output_buffer_ptr(out->bitstrm, renderType), + out->output_meta_data.bufferLength); + ret = write_data(out, handle, out->write_temp_buf, bytes_to_write); +#endif + + ret = write_data(out, handle, buffer, bytes_to_write); + ALOGD("write_data returned with %d", ret); + if(ret < 0) { + ALOGE("write_data returned ret < 0"); + return ret; + } else { + if (!out->playback_started) { + compress_start(handle->compr); + } + /*TODO:Do we need this + if(renderType == ROUTE_UNCOMPRESSED || + (renderType == ROUTE_UNCOMPRESSED_MCH && !out->open_dec_route)) { + mFrameCount++; + renderedPcmBytes += out->output_meta_data.bufferLength; + }*/ + renderedPcmBytes += ret; +#if USE_SWDECODE + /*iTODO: enable for MS11 + audio_bitstream_copy_residue_output_start(out->bitstrm, renderType, + bytes_to_write); + TODO:what if retplayback_started = 1; + out->offload_state = OFFLOAD_STATE_PLAYING; + out->send_new_metadata = 0; + return renderedPcmBytes; +} - return -ENOSYS; +size_t render_pcm_data(struct stream_out *out, const void *buffer, size_t bytes) +{ + ALOGV("%s", __func__); + size_t ret = 0; + struct listnode *node; + struct alsa_handle *handle; + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + ALOGV("%s handle is 0x%x", __func__,(uint32_t)handle); + ret = write_data(out, handle, buffer, bytes); + } + return ret; } static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, @@ -751,21 +2224,66 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; ssize_t ret = 0; + struct listnode *node; + bool continueDecode; + struct alsa_handle *handle; + size_t bytes_consumed; + size_t total_bytes_consumed = 0; + + ALOGV("%s bytes =%d", __func__, bytes); pthread_mutex_lock(&out->lock); + +//TODO: handle a2dp +/* if (mRouteAudioToA2dp && + mA2dpUseCase == AudioHardwareALSA::USECASE_NONE) { + a2dpRenderingControl(A2DP_RENDER_SETUP); + } +*/ + /* TODO: meta data comes in set_parameter it will be passed in compre_open + for all format exxce ms11 format + and for ms11 it will be set sdecode fucntion while opneing ms11 instance + hence below piece of code is no required*/ + /* + if(!out->dec_conf_set && is_decoder_config_required(out)) { + if (setDecodeConfig(out, (char *)buffer, bytes)) + ALOGD("decoder configuration set"); + } + */ + if (out->standby) { out->standby = false; - pthread_mutex_lock(&adev->lock); - ret = start_output_stream(out); - pthread_mutex_unlock(&adev->lock); - /* ToDo: If use case is compress offload should return 0 */ - if (ret != 0) { - out->standby = true; - goto exit; + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + pthread_mutex_lock(&adev->lock); + ret = start_output_stream(out, handle); + pthread_mutex_unlock(&adev->lock); + /* ToDo: If use case is compress offload should return 0 */ + if (ret != 0) { + out->standby = true; + goto exit; + } } } - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) { +#if USE_SWDECODE + //TODO: Enable for MS11 + copy_bitstream_internal_buffer(out->bitstrm, (char *)buffer, bytes); + //DO check if timestamp mode handle partial buffer + do { + + bytes_consumed = 0; + ret = decode(out, (char *)buffer, bytes, &bytes_consumed, &continueDecode); + if(ret < 0) + goto exit; + /*TODO: check for return size from write when ms11 is removed*/ + render_offload_data(out, continueDecode); + total_bytes_consumed += bytes_consumed; + + } while(continueDecode == true); +#endif +#if 0 ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); if (out->send_new_metadata) { ALOGVV("send new gapless metadata"); @@ -807,11 +2325,50 @@ exit: out_get_sample_rate(&out->stream.common)); } return bytes; +#endif + ret = render_offload_data(out, buffer, bytes); + total_bytes_consumed = ret; + } else { + ret = render_pcm_data(out, buffer, bytes); + total_bytes_consumed = ret; + } + +exit: + pthread_mutex_unlock(&out->lock); + ALOGV("total_bytes_consumed %d",total_bytes_consumed); + return total_bytes_consumed; } static int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) { + struct listnode *node; + struct alsa_handle *handle; + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + *dsp_frames = 0; + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + if ((out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) && (dsp_frames != NULL)) { + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if ((handle && handle->compr && + handle->route_format != ROUTE_DSP_TRANSCODED_COMPRESSED)){ + compress_get_tstamp(handle->compr, (unsigned long *)dsp_frames, + &out->sample_rate); + ALOGV("%s rendered frames %d sample_rate %d", + __func__, *dsp_frames, out->sample_rate); + } + pthread_mutex_unlock(&out->lock); + return 0; + } + } + else { + pthread_mutex_unlock(&out->lock); + return -EINVAL; + } + return 0; +#if 0 struct stream_out *out = (struct stream_out *)stream; *dsp_frames = 0; if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { @@ -826,6 +2383,7 @@ static int out_get_render_position(const struct audio_stream_out *stream, return 0; } else return -EINVAL; +#endif } static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) @@ -847,6 +2405,46 @@ static int out_get_next_write_timestamp(const struct audio_stream_out *stream, static int out_get_presentation_position(const struct audio_stream_out *stream, uint64_t *frames, struct timespec *timestamp) { + struct listnode *node; + struct alsa_handle *handle; + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + *frames = 0; + ALOGV("%s", __func__); + pthread_mutex_lock(&out->lock); + if ((frames != NULL)) { + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if ((handle && handle->compr && + handle->route_format != ROUTE_DSP_TRANSCODED_COMPRESSED)){ + compress_get_tstamp(handle->compr, (unsigned long *)frames, + &out->sample_rate); + clock_gettime(CLOCK_MONOTONIC, timestamp); + ALOGV("%s rendered frames %d sample_rate %d", + __func__, *frames, out->sample_rate); + } + else if (handle->pcm) { + size_t avail; + if (pcm_get_htimestamp(handle->pcm, &avail, timestamp) == 0) { + size_t kernel_buffer_size = handle->config.period_size * handle->config.period_count; + int64_t signed_frames = out->written - kernel_buffer_size + avail; + // This adjustment accounts for buffering after app processor. + // It is based on estimated DSP latency per use case, rather than exact. + signed_frames -= + (platform_render_latency(handle->usecase) * out->sample_rate / 1000000LL); + + // It would be unusual for this value to be negative, but check just in case ... + if (signed_frames >= 0) { + *frames = signed_frames; + } + } + } + + } + } + pthread_mutex_unlock(&out->lock); + return -EINVAL; +#if 0 struct stream_out *out = (struct stream_out *)stream; int ret = -1; unsigned long dsp_frames; @@ -887,6 +2485,7 @@ static int out_get_presentation_position(const struct audio_stream_out *stream, pthread_mutex_unlock(&out->lock); return ret; +#endif } static int out_set_callback(struct audio_stream_out *stream, @@ -904,64 +2503,84 @@ static int out_set_callback(struct audio_stream_out *stream, static int out_pause(struct audio_stream_out* stream) { + struct listnode *node; + struct alsa_handle *handle; struct stream_out *out = (struct stream_out *)stream; int status = -ENOSYS; ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - pthread_mutex_lock(&out->lock); - if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) { - status = compress_pause(out->compr); + pthread_mutex_lock(&out->lock); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + if (handle->compr != NULL && out->offload_state == + OFFLOAD_STATE_PLAYING) { + status = compress_pause(handle->compr); out->offload_state = OFFLOAD_STATE_PAUSED; } - pthread_mutex_unlock(&out->lock); } + pthread_mutex_unlock(&out->lock); return status; } static int out_resume(struct audio_stream_out* stream) { + struct listnode *node; + struct alsa_handle *handle; struct stream_out *out = (struct stream_out *)stream; int status = -ENOSYS; ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - status = 0; - pthread_mutex_lock(&out->lock); - if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) { - status = compress_resume(out->compr); - out->offload_state = OFFLOAD_STATE_PLAYING; - } - pthread_mutex_unlock(&out->lock); + pthread_mutex_lock(&out->lock); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + status = 0; + if (handle->compr != NULL && out->offload_state == + OFFLOAD_STATE_PAUSED) { + status = compress_resume(handle->compr); + out->offload_state = OFFLOAD_STATE_PLAYING; + } } + pthread_mutex_unlock(&out->lock); return status; } static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type ) { + struct listnode *node; + struct alsa_handle *handle; struct stream_out *out = (struct stream_out *)stream; int status = -ENOSYS; ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - pthread_mutex_lock(&out->lock); - if (type == AUDIO_DRAIN_EARLY_NOTIFY) - status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN); - else - status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN); - pthread_mutex_unlock(&out->lock); + pthread_mutex_lock(&out->lock); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + status = 0; + if (handle->compr != NULL) { + if (type == AUDIO_DRAIN_EARLY_NOTIFY) + status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN); + else + status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN); + } } + pthread_mutex_unlock(&out->lock); return status; } static int out_flush(struct audio_stream_out* stream) { + struct listnode *node; + struct alsa_handle *handle; struct stream_out *out = (struct stream_out *)stream; + int status = -ENOSYS; ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - pthread_mutex_lock(&out->lock); - stop_compressed_output_l(out); - pthread_mutex_unlock(&out->lock); - return 0; + pthread_mutex_lock(&out->lock); + list_for_each(node, &out->session_list) { + handle = node_to_item(node, struct alsa_handle, list); + status = 0; + if (handle->compr != NULL) { + stop_compressed_output_l(out); + } } - return -ENOSYS; + pthread_mutex_unlock(&out->lock); + return status; } int adev_open_output_stream(struct audio_hw_device *dev, @@ -973,7 +2592,9 @@ int adev_open_output_stream(struct audio_hw_device *dev, { struct audio_device *adev = (struct audio_device *)dev; struct stream_out *out; - int i, ret; + struct alsa_handle *device_handle = NULL; + int i, ret, channels; + struct listnode *item; ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", __func__, config->sample_rate, config->channel_mask, devices, flags); @@ -982,7 +2603,9 @@ int adev_open_output_stream(struct audio_hw_device *dev, if (devices == AUDIO_DEVICE_NONE) devices = AUDIO_DEVICE_OUT_SPEAKER; + list_init(&out->session_list); + reset_out_parameters(out); out->flags = flags; out->devices = devices; out->dev = adev; @@ -990,59 +2613,58 @@ int adev_open_output_stream(struct audio_hw_device *dev, out->sample_rate = config->sample_rate; out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; + out->config = config; out->handle = handle; +//*TODO: get hdmi/spdif format/channels from routing manager and intialize out->spdif_format & out->hdmi_format*/ /* Init use case and pcm_config */ - if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT && - out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - pthread_mutex_lock(&adev->lock); - ret = read_hdmi_channel_masks(out); - pthread_mutex_unlock(&adev->lock); - if (ret != 0) - goto error_open; + out->hdmi_format = UNCOMPRESSED; + out->spdif_format = UNCOMPRESSED; + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + out->stream.get_presentation_position = out_get_presentation_position; - if (config->sample_rate == 0) - config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; - if (config->channel_mask == 0) - config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1; - - out->channel_mask = config->channel_mask; - out->sample_rate = config->sample_rate; - out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH; - out->config = pcm_config_hdmi_multi; - out->config.rate = config->sample_rate; - out->config.channels = popcount(out->channel_mask); - out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); - } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + out->standby = 1; + /* out->muted = false; by calloc() */ + /* out->written = 0; by calloc() */ + + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + + if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + ALOGE("%s: Usecase is OFFLOAD", __func__); if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { ALOGE("%s: Unsupported Offload information", __func__); ret = -EINVAL; goto error_open; } + if (!is_supported_format(config->offload_info.format)) { ALOGE("%s: Unsupported audio format", __func__); ret = -EINVAL; goto error_open; } - out->compr_config.codec = (struct snd_codec *) - calloc(1, sizeof(struct snd_codec)); - - out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; - if (config->offload_info.channel_mask) - out->channel_mask = config->offload_info.channel_mask; - else if (config->channel_mask) - out->channel_mask = config->channel_mask; + calloc(1, sizeof(struct snd_codec)); + //Session/clip config. out->format = config->offload_info.format; out->sample_rate = config->offload_info.sample_rate; - - out->stream.set_callback = out_set_callback; - out->stream.pause = out_pause; - out->stream.resume = out_resume; - out->stream.drain = out_drain; - out->stream.flush = out_flush; - out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; @@ -1055,6 +2677,44 @@ int adev_open_output_stream(struct audio_hw_device *dev, popcount(config->channel_mask); out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + if (config->offload_info.channel_mask) + out->channel_mask = config->offload_info.channel_mask; + else if (config->channel_mask) + out->channel_mask = config->channel_mask; + out->uc_strm_type = OFFLOAD_PLAYBACK_STREAM; + + //Initialize the handles + /* ------------------------------------------------------------------------ + Update use decoder type and routing flags and corresponding states + decoderType will cache the decode types such as decode/passthrough/transcode + and in s/w or dsp. Besides, the states to open decode/passthrough/transcode + handles with the corresponding devices and device formats are updated + -------------------------------------------------------------------------*/ + update_decode_type_and_routing_states(out); + + /* ------------------------------------------------------------------------ + Update rxHandle states + Based on the states, we open the driver and store the handle at appropriate + index + -------------------------------------------------------------------------*/ + update_alsa_handle_state(out); + + /* ------------------------------------------------------------------------ + setup routing + -------------------------------------------------------------------------*/ + ret = allocate_internal_buffers(out); + if(ret < 0) { + ALOGE("%s:Error %d",__func__, ret); + goto error_handle; + } + + //Callbacks + out->stream.set_callback = out_set_callback; + out->stream.pause = out_pause; + out->stream.resume = out_resume; + out->stream.drain = out_drain; + out->stream.flush = out_flush; + if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; @@ -1063,17 +2723,35 @@ int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); - } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { - out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; - out->config = pcm_config_low_latency; - out->sample_rate = out->config.rate; - } else { - out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; - out->config = pcm_config_deep_buffer; - out->sample_rate = out->config.rate; - } + } else { //if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { + ALOGE("%s: Usecase is DEEP_BUFFER", __func__); + if((device_handle = get_alsa_handle())== NULL) + goto error_handle; + list_add_tail(&out->session_list, &device_handle->list); + device_handle->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER; + device_handle->config = pcm_config_deep_buffer; + device_handle->out = out; + device_handle->cmd_pending = false; + out->sample_rate = device_handle->config.rate; + out->uc_strm_type = DEEP_BUFFER_PLAYBACK_STREAM; + out->buffer_size = device_handle->config.period_size * + audio_stream_frame_size(&out->stream.common); + }/* else { + if((device_handle = get_alsa_handle())== NULL) + goto error_handle; + list_add_tail(&out->session_list, &device_handle->list); + device_handle->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; + device_handle->config = pcm_config_low_latency; + device_handle->sample_rate = device_handle->config.rate; + device_handle->out = out; + device_handle->cmd_pending = false; + out->uc_strm_type = LOW_LATENCY_PLAYBACK_STREAM; + out->buffer_size = device_handle->config.period_size * + audio_stream_frame_size(&out->stream.common); + }*/ if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { + ALOGE("%s: Usecase is primary ", __func__); if(adev->primary_output == NULL) adev->primary_output = out; else { @@ -1085,39 +2763,20 @@ int adev_open_output_stream(struct audio_hw_device *dev, /* Check if this usecase is already existing */ pthread_mutex_lock(&adev->lock); - if (get_usecase_from_list(adev, out->usecase) != NULL) { - ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase); - pthread_mutex_unlock(&adev->lock); - ret = -EEXIST; - goto error_open; + if (out->uc_strm_type != OFFLOAD_PLAYBACK_STREAM) { + if (get_usecase_from_list(adev, device_handle->usecase) != NULL) { + ALOGE("%s: Usecase (%d) is already present", __func__, + device_handle->usecase); + pthread_mutex_unlock(&adev->lock); + ret = -EEXIST; + goto error_open; + } } pthread_mutex_unlock(&adev->lock); - out->stream.common.get_sample_rate = out_get_sample_rate; - out->stream.common.set_sample_rate = out_set_sample_rate; - out->stream.common.get_buffer_size = out_get_buffer_size; - out->stream.common.get_channels = out_get_channels; - out->stream.common.get_format = out_get_format; - out->stream.common.set_format = out_set_format; - out->stream.common.standby = out_standby; - out->stream.common.dump = out_dump; - out->stream.common.set_parameters = out_set_parameters; - out->stream.common.get_parameters = out_get_parameters; - out->stream.common.add_audio_effect = out_add_audio_effect; - out->stream.common.remove_audio_effect = out_remove_audio_effect; - out->stream.get_latency = out_get_latency; - out->stream.set_volume = out_set_volume; - out->stream.write = out_write; - out->stream.get_render_position = out_get_render_position; - out->stream.get_next_write_timestamp = out_get_next_write_timestamp; - out->stream.get_presentation_position = out_get_presentation_position; - out->standby = 1; /* out->muted = false; by calloc() */ - /* out->written = 0; by calloc() */ - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); config->format = out->stream.common.get_format(&out->stream.common); config->channel_mask = out->stream.common.get_channels(&out->stream.common); @@ -1127,6 +2786,17 @@ int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: exit", __func__); return 0; +error_handle: + ret = -EINVAL; + ALOGE("%s: exit: error handle %d", __func__, ret); + while (!list_empty(&out->session_list)) { + item = list_head(&out->session_list); + list_remove(item); + device_handle = node_to_item(item, struct alsa_handle, list); + platform_free_usecase(device_handle->usecase); + free_alsa_handle(device_handle); + } + error_open: free(out); *stream_out = NULL; @@ -1139,17 +2809,28 @@ void adev_close_output_stream(struct audio_hw_device *dev, { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; - int ret = 0; + struct listnode *item; + struct alsa_handle *handle; - ALOGV("%s: enter", __func__); - out_standby(&stream->common); + ALOGV("%s", __func__); - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + out_standby(&stream->common); + if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) { destroy_offload_callback_thread(out); - if (out->compr_config.codec != NULL) - free(out->compr_config.codec); + while (!list_empty(&out->session_list)) { + item = list_head(&out->session_list); + list_remove(item); + handle = node_to_item(item, struct alsa_handle, list); + if(handle->compr_config.codec != NULL) + free(handle->compr_config.codec); + platform_free_usecase(handle->usecase); + free_alsa_handle(handle); + } + free(out->compr_config.codec); } + + free_internal_buffers(out); pthread_cond_destroy(&out->cond); pthread_mutex_destroy(&out->lock); free(stream); diff --git a/hal_mpq/mpq8092/platform.c b/hal_mpq/mpq8092/platform.c index d7d67d593..3c1b4f7a8 100644 --- a/hal_mpq/mpq8092/platform.c +++ b/hal_mpq/mpq8092/platform.c @@ -91,20 +91,39 @@ struct platform_data { struct csd_data *csd; }; -static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { - [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE, - DEEP_BUFFER_PCM_DEVICE}, - [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, - LOWLATENCY_PCM_DEVICE}, - [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE, - MULTIMEDIA2_PCM_DEVICE}, +static int pcm_device_table[AUDIO_USECASE_MAX][4] = { + [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {USECASE_AUDIO_PLAYBACK_DEEP_BUFFER, + DEEP_BUFFER_PCM_DEVICE, + DEEP_BUFFER_PCM_DEVICE, 0}, + [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {USECASE_AUDIO_PLAYBACK_LOW_LATENCY, + LOWLATENCY_PCM_DEVICE, + LOWLATENCY_PCM_DEVICE, 0}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {USECASE_AUDIO_PLAYBACK_MULTI_CH, + MULTIMEDIA2_PCM_DEVICE, + MULTIMEDIA2_PCM_DEVICE, 0}, + [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {USECASE_AUDIO_PLAYBACK_MULTI_CH, + MULTI_CHANNEL_PCM_DEVICE, + MULTI_CHANNEL_PCM_DEVICE, 0}, [USECASE_AUDIO_PLAYBACK_OFFLOAD] = - {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE}, - [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, - [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE}, - [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, - LOWLATENCY_PCM_DEVICE}, - [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE, + {USECASE_AUDIO_PLAYBACK_OFFLOAD, PLAYBACK_OFFLOAD_DEVICE1, + PLAYBACK_OFFLOAD_DEVICE1, 0}, + [USECASE_AUDIO_PLAYBACK_OFFLOAD1] = {USECASE_AUDIO_PLAYBACK_OFFLOAD, + PLAYBACK_OFFLOAD_DEVICE2, + PLAYBACK_OFFLOAD_DEVICE2, 0}, + [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = {USECASE_AUDIO_PLAYBACK_OFFLOAD, + PLAYBACK_OFFLOAD_DEVICE3, + PLAYBACK_OFFLOAD_DEVICE3, 0}, + [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = {USECASE_AUDIO_PLAYBACK_OFFLOAD, + PLAYBACK_OFFLOAD_DEVICE4, + PLAYBACK_OFFLOAD_DEVICE4, 0}, + [USECASE_AUDIO_RECORD] = {USECASE_AUDIO_RECORD, AUDIO_RECORD_PCM_DEVICE, + AUDIO_RECORD_PCM_DEVICE, 0}, + [USECASE_AUDIO_RECORD_COMPRESS] = {USECASE_AUDIO_RECORD_COMPRESS, COMPRESS_CAPTURE_DEVICE, + COMPRESS_CAPTURE_DEVICE, 0}, + [USECASE_AUDIO_RECORD_LOW_LATENCY] = {USECASE_AUDIO_RECORD_LOW_LATENCY, + LOWLATENCY_PCM_DEVICE, + LOWLATENCY_PCM_DEVICE, 0}, + /* [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {, MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, @@ -124,6 +143,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { INCALL_MUSIC_UPLINK2_PCM_DEVICE}, [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1}, [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE}, +*/ }; /* Array to store sound devices */ @@ -593,12 +613,39 @@ int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) { int device_id; if (device_type == PCM_PLAYBACK) - device_id = pcm_device_table[usecase][0]; - else device_id = pcm_device_table[usecase][1]; + else + device_id = pcm_device_table[usecase][2]; return device_id; } +audio_usecase_t platform_get_usecase( + audio_usecase_stream_type_t uc_type) +{ + int i = 0; + for(i =0;i= AUDIO_USECASE_MAX) { + ALOGV("%s: enter: invalid usecase(%d)", __func__, uc_id); + return -EINVAL; + } + pcm_device_table[uc_id][3] = 0; + return 0; +} + int platform_send_audio_calibration(void *platform, snd_device_t snd_device) { struct platform_data *my_data = (struct platform_data *)platform; diff --git a/hal_mpq/mpq8092/platform.h b/hal_mpq/mpq8092/platform.h index 7559258a7..2a81df511 100644 --- a/hal_mpq/mpq8092/platform.h +++ b/hal_mpq/mpq8092/platform.h @@ -26,6 +26,7 @@ enum { FLUENCE_QUAD_MIC = 0x2, }; +#include /* * Below are the devices for which is back end is same, SLIMBUS_0_RX. * All these devices are handled by the internal HW codec. We can @@ -34,6 +35,8 @@ enum { #define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \ (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \ AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE) +/*TODO remove this once define in audio.h */ +#define AUDIO_DEVICE_OUT_SPDIF 0x4000 /* Sound devices specific to the platform * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound @@ -154,6 +157,16 @@ enum { #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 +/******************************************************************************* +ADTS HEADER PARSING +*******************************************************************************/ +//Required for ADTS Header Parsing +#define ADTS_HEADER_SYNC_RESULT 0xfff0 +#define ADTS_HEADER_SYNC_MASK 0xfff6 +/******************************************************************************* +HDMI and SPDIF Device Output format control +*******************************************************************************/ + #define HDMI_MULTI_PERIOD_SIZE 336 #define HDMI_MULTI_PERIOD_COUNT 8 #define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6 @@ -174,8 +187,14 @@ enum { #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 22 -#define PLAYBACK_OFFLOAD_DEVICE 9 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3 +#define MULTI_CHANNEL_PCM_DEVICE 1 +#define VOICE_CALL_PCM_DEVICE 2 +//TODO: update the device number as per the dai links +#define PLAYBACK_OFFLOAD_DEVICE1 2 +#define PLAYBACK_OFFLOAD_DEVICE2 3 +#define PLAYBACK_OFFLOAD_DEVICE3 4 +#define PLAYBACK_OFFLOAD_DEVICE4 19 #define LOWLATENCY_PCM_DEVICE 15 #define COMPRESS_CAPTURE_DEVICE 19 @@ -235,10 +254,47 @@ void hw_info_deinit(void *hw_info); void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, char *device_name); -#define SAMPLES_PER_CHANNEL 1536*2 +/******************************************************************************* +USECASES AND THE CORRESPONDING DEVICE FORMATS THAT WE SUPPORT IN HAL +*******************************************************************************/ +/* +In general max of 2 for pass through. Additional 1 for handling transcode +as the existence of transcode is with a PCM handle followed by transcode handle +So, a (AC3/EAC3) pass through + trancode require - 1 for pas through, 1 - pcm and +1 - transcode +*/ +#define NUM_DEVICES_SUPPORT_COMPR_DATA 2+1 +#define NUM_SUPPORTED_CODECS 16 +#define NUM_COLUMN_FOR_INDEXING 2 +#define NUM_STATES_FOR_EACH_DEVICE_FMT 3 +#define DECODER_TYPE_IDX 0 +#define ROUTE_FORMAT_IDX 1 + +#define MIN_SIZE_FOR_METADATA 64 +#define NUM_OF_PERIODS 8 +/*Period size to be a multiple of chanels * bitwidth, +So min period size = LCM (1,2...8) * 4*/ +#define PERIOD_SIZE_COMPR 3360 +#define MS11_INPUT_BUFFER_SIZE 1536 +/*Max Period size which is exposed by the compr driver +The value needs to be modified when the period size is modified*/ +#define PLAYBACK_MAX_PERIOD_SIZE (160 * 1024) + +#define COMPR_INPUT_BUFFER_SIZE (PERIOD_SIZE_COMPR - MIN_SIZE_FOR_METADATA) +#define PCM_16_BITS_PER_SAMPLE 2 +#define PCM_24_BITS_PER_SAMPLE 3 +#define AC3_PERIOD_SIZE 1536 * PCM_16_BITS_PER_SAMPLE +#define TIME_PER_BUFFER 40 //Time duration in ms +#define SAMPLES_PER_CHANNEL 32*1024 //1536*2 /*TODO:correct it #define MAX_INPUT_CHANNELS_SUPPORTED 8 #define FACTOR_FOR_BUFFERING 2 #define STEREO_CHANNELS 2 +#define MAX_OUTPUT_CHANNELS_SUPPORTED 8 +#define PCM_BLOCK_PER_CHANNEL_MS11 1536*2 +#define AAC_BLOCK_PER_CHANNEL_MS11 768 +#define NUMBER_BITS_IN_A_BYTE 8 +#define AC3_BUFFER_SIZE 1920*2 + #define MAX_OUTPUT_CHANNELS_SUPPORTED 8 #define PCM_2CH_OUT 0 @@ -248,6 +304,333 @@ void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device, #define TRANSCODE_OUT 3 #define FACTOR_FOR_BUFFERING 2 +#define NUM_DEVICES_SUPPORT_COMPR_DATA 2+1 +#define NUM_SUPPORTED_CODECS 16 +#define NUM_COLUMN_FOR_INDEXING 2 +#define NUM_STATES_FOR_EACH_DEVICE_FMT 3 +#define DECODER_TYPE_IDX 0 +#define ROUTE_FORMAT_IDX 1 +#define NUM_OF_PERIODS 8 + +enum { + LPCM, + MULTI_CH_PCM, + COMPR, + TRANSCODE +}; + + +/* +List of indexes of the supported formats +Redundant formats such as (AAC-LC, HEAAC) are removed from the indexes as they +are treated with the AAC format +*/ +enum { + PCM_IDX = 0, + AAC_IDX, + AC3_IDX, + EAC3_IDX, + DTS_IDX, + DTS_LBR_IDX, + MP3_IDX, + WMA_IDX, + WMA_PRO_IDX, + MP2_IDX, + ALL_FORMATS_IDX +}; +/* +List of pass through's supported in the current usecases +*/ +enum { + NO_PASSTHROUGH = 0, + AC3_PASSTHR, + EAC3_PASSTHR, + DTS_PASSTHR +}; +/* +List of transcoder's supported in the current usecases +*/ +enum { + NO_TRANSCODER = 0, + AC3_TRANSCODER, + DTS_TRANSCODER +}; +/* +Requested end device format by user/app through set parameters +*/ +enum { + UNCOMPRESSED = 0, + COMPRESSED, + COMPRESSED_CONVERT_EAC3_AC3, + COMPRESSED_CONVERT_ANY_AC3, + COMPRESSED_CONVERT_ANY_DTS, + AUTO_DEVICE_FORMAT, + UNCOMPRESSED_MCH, /* not to be exposed, internal use only */ + COMPRESSED_CONVERT_AC3_ASSOC, /* not to be exposed, internal use only */ + ALL_DEVICE_FORMATS +}; +/* +List of type of data routed on end device +*/ +typedef enum { + ROUTE_NONE = 0x0, + ROUTE_UNCOMPRESSED = 0x1, + ROUTE_COMPRESSED = 0x2, + ROUTE_SW_TRANSCODED = 0x10, //route sub-format, not to be used directly + ROUTE_DSP_TRANSCODED = 0x20, //route sub-format, not to be used directly + ROUTE_MCH = 0x40, //route sub-format, not to be used directly + ROUTE_UNCOMPRESSED_MCH = (ROUTE_UNCOMPRESSED | ROUTE_MCH), + ROUTE_SW_TRANSCODED_COMPRESSED = (ROUTE_COMPRESSED | ROUTE_SW_TRANSCODED), + ROUTE_DSP_TRANSCODED_COMPRESSED = (ROUTE_COMPRESSED | ROUTE_DSP_TRANSCODED) +}route_format_t; +/* +List of end device formats +*/ +enum { + FORMAT_INVALID = -1, + FORMAT_PCM, + FORMAT_COMPR +}; +/* +Below are the only different types of decode that we perform +*/ +enum { + DSP_DECODE = 1, // render uncompressed + DSP_PASSTHROUGH = 2, // render compressed + DSP_TRANSCODE = 4, // render as compressed + SW_DECODE = 8, // render as uncompressed + SW_DECODE_MCH = 16, // render as uncompressed + SW_PASSTHROUGH = 32, // render compressed + SW_TRANSCODE = 64, // render compressed + NUM_DECODE_PATH = 7 +}; +/* +Modes of buffering that we can support +As of now, we only support input buffering to an extent specified by usecase +*/ +enum { + NO_BUFFERING_MODE = 0, + INPUT_BUFFERING_MODE, + OUTPUT_BUFFEING_MODE +}; +/* +playback controls +*/ +enum { + PLAY = 1, + PAUSE = (1<<1), + RESUME = (1<<2), + SEEK = (1<<3), + EOS = (1<<4), + STOP = (1<<5), + STANDBY = (1<<6), + INIT = (1<<7), +}; +/* +Multiple instance of use case +*/ +enum { + STEREO_DRIVER = 0, + MULTI_CHANNEL_DRIVER, + COMRPESSED_DRIVER, +}; +/* +Instance bits +*/ +enum { + MULTI_CHANNEL_1_BIT = 1<<4, + MULTI_CHANNEL_2_BIT = 1<<5, + MULTI_CHANNEL_3_BIT = 1<<6, + COMPRESSED_1_BIT = 1<<12, + COMPRESSED_2_BIT = 1<<13, + COMPRESSED_3_BIT = 1<<14, + COMPRESSED_4_BIT = 1<<15, + COMPRESSED_5_BIT = 1<<16, + COMPRESSED_6_BIT = 1<<17 +}; + +/* +List of support formats configured from frameworks +*/ +static const int supportedFormats[NUM_SUPPORTED_CODECS] = { + AUDIO_FORMAT_PCM_16_BIT, + AUDIO_FORMAT_PCM_24_BIT, + AUDIO_FORMAT_AAC, + AUDIO_FORMAT_HE_AAC_V1, + AUDIO_FORMAT_HE_AAC_V2, + AUDIO_FORMAT_AAC_ADIF, + AUDIO_FORMAT_AC3, + AUDIO_FORMAT_AC3_DM, + AUDIO_FORMAT_EAC3, + AUDIO_FORMAT_EAC3_DM, + AUDIO_FORMAT_DTS, + AUDIO_FORMAT_DTS_LBR, + AUDIO_FORMAT_MP3, + AUDIO_FORMAT_WMA, + AUDIO_FORMAT_WMA_PRO, + AUDIO_FORMAT_MP2 +}; +/* +we can only have 6 types of decoder type stored with bit masks. +*/ +static const int route_to_driver[NUM_DECODE_PATH][NUM_COLUMN_FOR_INDEXING] = { + {DSP_DECODE, ROUTE_UNCOMPRESSED_MCH}, + {DSP_PASSTHROUGH, ROUTE_COMPRESSED}, + {DSP_TRANSCODE, ROUTE_DSP_TRANSCODED_COMPRESSED}, + {SW_DECODE, ROUTE_UNCOMPRESSED}, + {SW_DECODE_MCH, ROUTE_UNCOMPRESSED_MCH}, + {SW_PASSTHROUGH, ROUTE_COMPRESSED}, + {SW_TRANSCODE, ROUTE_SW_TRANSCODED_COMPRESSED} +}; +/* +table to query index based on the format +*/ +static const int format_index[NUM_SUPPORTED_CODECS][NUM_COLUMN_FOR_INDEXING] = { +/*--------------------------------------------- +| FORMAT | INDEX | +----------------------------------------------*/ + {AUDIO_FORMAT_PCM_16_BIT, PCM_IDX}, + {AUDIO_FORMAT_PCM_24_BIT, PCM_IDX}, + {AUDIO_FORMAT_AAC, AAC_IDX}, + {AUDIO_FORMAT_HE_AAC_V1, AAC_IDX}, + {AUDIO_FORMAT_HE_AAC_V2, AAC_IDX}, + {AUDIO_FORMAT_AAC_ADIF, AAC_IDX}, + {AUDIO_FORMAT_AC3, AC3_IDX}, + {AUDIO_FORMAT_AC3_DM, AC3_IDX}, + {AUDIO_FORMAT_EAC3, EAC3_IDX}, + {AUDIO_FORMAT_EAC3_DM, EAC3_IDX}, + {AUDIO_FORMAT_DTS, DTS_IDX}, + {AUDIO_FORMAT_DTS_LBR, DTS_LBR_IDX}, + {AUDIO_FORMAT_MP3, MP3_IDX}, + {AUDIO_FORMAT_WMA, WMA_IDX}, + {AUDIO_FORMAT_WMA_PRO, WMA_PRO_IDX}, + {AUDIO_FORMAT_MP2, MP2_IDX} +}; + +/* +Table to query non HDMI and SPDIF devices and their states such as type of +decode, type of data routed to end device and type of transcoding needed +*/ +static const int usecase_decode_format[ALL_FORMATS_IDX*NUM_STATES_FOR_EACH_DEVICE_FMT] = { +/*----------------- +| UNCOMPR | +-----------------*/ +/* PCM */ + DSP_DECODE, //PCM_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + SW_DECODE, // AAC_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + SW_DECODE, //AC3_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + SW_DECODE, //EAC3_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + DSP_DECODE, //DTS_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + DSP_DECODE, //DTS_LBR_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + DSP_DECODE, //MP3_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + DSP_DECODE, //WMA_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + DSP_DECODE, //WMA_PRO_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER,//TRANSCODE_FORMAT +/* PCM */ + DSP_DECODE, //MP2_IDX + FORMAT_PCM, //ROUTE_FORMAT + NO_TRANSCODER//TRANSCODE_FORMAT +}; +/* +Table to query HDMI and SPDIF devices and their states such as type of +decode, type of data routed to end device and type of transcoding needed +*/ +static const int usecase_docode_hdmi_spdif[ALL_FORMATS_IDX*NUM_STATES_FOR_EACH_DEVICE_FMT] + [ALL_DEVICE_FORMATS] = { +/*------------------------------------------------------------------------------------------------------------------------------------------------------- +| UNCOMPRESSED | COMPR | COMPR_CONV | COMPR_CONV | COMPR_CONV | AUTO | UNCOMPR_MCH | AC3_AC3 | +| | | EAC3_AC3 | ANY_AC3 | ANY_DTS | | | | +--------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* PCM PCM PCM PCM PCM PCM PCM PCM */ + {DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE|DSP_TRANSCODE, DSP_DECODE, DSP_DECODE, DSP_DECODE}, //PCM_IDX + {FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, DTS_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM PCM PCM AC3 PCM PCM PCM PCM */ + {SW_DECODE, SW_DECODE, SW_DECODE, SW_TRANSCODE, DSP_DECODE, SW_DECODE, SW_DECODE_MCH, SW_DECODE}, //AAC_IDX + {FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, AC3_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM AC3 AC3 AC3 PCM AC3 PCM AC3 */ + {SW_DECODE, SW_PASSTHROUGH, SW_PASSTHROUGH, SW_PASSTHROUGH, DSP_DECODE, SW_PASSTHROUGH, SW_DECODE_MCH, SW_TRANSCODE}, //AC3_IDX + {FORMAT_PCM, FORMAT_COMPR, FORMAT_COMPR, FORMAT_COMPR, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_COMPR}, //ROUTE_FORMAT + {NO_TRANSCODER, AC3_PASSTHR, AC3_PASSTHR, AC3_PASSTHR, NO_TRANSCODER, AC3_PASSTHR, NO_TRANSCODER, AC3_TRANSCODER}, //TRANSCODE_FMT +/* PCM EAC3 AC3 AC3 PCM EAC3 PCM PCM */ + {SW_DECODE, SW_PASSTHROUGH, SW_TRANSCODE, SW_TRANSCODE, DSP_DECODE, SW_PASSTHROUGH, SW_DECODE_MCH, SW_TRANSCODE}, //EAC3_IDX + {FORMAT_PCM, FORMAT_COMPR, FORMAT_COMPR, FORMAT_COMPR, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_COMPR}, //ROUTE_FORMAT + {NO_TRANSCODER, EAC3_PASSTHR, AC3_TRANSCODER, AC3_TRANSCODER, NO_TRANSCODER, EAC3_PASSTHR, NO_TRANSCODER, AC3_TRANSCODER}, //TRANSCODE_FMT +/* PCM DTS PCM PCM DTS DTS PCM PCM */ + {DSP_DECODE, DSP_PASSTHROUGH, DSP_DECODE, DSP_DECODE, DSP_PASSTHROUGH, DSP_PASSTHROUGH, DSP_DECODE, DSP_DECODE},//DTS_IDX + {FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, DTS_PASSTHR, NO_TRANSCODER, NO_TRANSCODER, DTS_PASSTHR, DTS_PASSTHR, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM DTS_LBR PCM PCM DTS DTS PCM PCM */ + {DSP_DECODE, DSP_PASSTHROUGH, DSP_DECODE, DSP_DECODE, DSP_PASSTHROUGH, DSP_PASSTHROUGH, DSP_DECODE, DSP_DECODE},//DTS_LBR_IDX + {FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, DTS_PASSTHR, NO_TRANSCODER, NO_TRANSCODER, DTS_PASSTHR, DTS_PASSTHR, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM PCM PCM PCM DTS PCM PCM PCM */ + {DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE|DSP_TRANSCODE, DSP_DECODE, DSP_DECODE, DSP_DECODE}, //MP3_IDX + {FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, DTS_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM PCM PCM PCM DTS PCM PCM PCM */ + {DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE|DSP_TRANSCODE, DSP_DECODE, DSP_DECODE, DSP_DECODE}, //WMA_IDX + {FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, DTS_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM PCM PCM PCM DTS PCM PCM PCM */ + {DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE|DSP_TRANSCODE, DSP_DECODE, DSP_DECODE, DSP_DECODE}, //WMA_PRO_IDX + {FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, DTS_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER}, //TRANSCODE_FMT +/* PCM PCM PCM PCM DTS PCM PCM PCM */ + {DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE, DSP_DECODE|DSP_TRANSCODE, DSP_DECODE, DSP_DECODE, DSP_DECODE}, //MP2_IDX + {FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM, FORMAT_COMPR, FORMAT_PCM, FORMAT_PCM, FORMAT_PCM}, //ROUTE_FORMAT + {NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, DTS_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER, NO_TRANSCODER} //TRANSCODE_FMT +}; +/* +List of decoders which require config as part of first buffer +*/ +static const int decodersRequireConfig[] = { + AUDIO_FORMAT_AAC, + AUDIO_FORMAT_HE_AAC_V1, + AUDIO_FORMAT_HE_AAC_V2, + AUDIO_FORMAT_AAC_ADIF, + AUDIO_FORMAT_WMA, + AUDIO_FORMAT_WMA_PRO +}; +/* +List of enum that are used in Broadcast. +NOTE: Need to be removed once broadcast is moved with updated states as above +*/ +enum { + INVALID_FORMAT = -1, + PCM_FORMAT = 0, + COMPRESSED_FORMAT = 1, + COMPRESSED_FORCED_PCM_FORMAT = 2, + COMPRESSED_PASSTHROUGH_FORMAT = 3 +}; + + struct audio_bitstream_sm { int buffering_factor; int buffering_factor_cnt; @@ -255,18 +638,33 @@ struct audio_bitstream_sm { char *inp_buf; char *inp_buf_curr_ptr; char *inp_buf_write_ptr; + uint32_t inp_buf_size; char *enc_out_buf; char *enc_out_buf_write_ptr; + uint32_t enc_out_buf_size; char *pcm_2_out_buf; char *pcm_2_out_buf_write_ptr; + uint32_t pcm_2_out_buf_size; char *pcm_mch_out_buf; char *pcm_mch_out_buf_write_ptr; + uint32_t pcm_mch_out_buf_size; char *passt_out_buf; char *passt_out_buf_write_ptr; + uint32_t passt_out_buf_size; +}; + +/* +Meta data structure for handling compressed output +*/ +struct output_metadata { + uint32_t metadataLength; + uint32_t bufferLength; + uint64_t timestamp; + uint32_t reserved[12]; }; #endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal_mpq/platform_api.h b/hal_mpq/platform_api.h index 44ad7905d..955aa3ba5 100644 --- a/hal_mpq/platform_api.h +++ b/hal_mpq/platform_api.h @@ -51,5 +51,7 @@ int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id) /* returns the latency for a usecase in Us */ int64_t platform_render_latency(audio_usecase_t usecase); int platform_update_usecase_from_source(int source, audio_usecase_t usecase); +audio_usecase_t platform_get_usecase(audio_usecase_stream_type_t uc_type); +int platform_free_usecase(audio_usecase_t uc_id); #endif // QCOM_AUDIO_PLATFORM_API_H -- GitLab From 5a553e4210ba739469d97c5e78e4d489c5a16843 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 3 Dec 2013 23:06:49 +0530 Subject: [PATCH 128/298] audio: mpq: Add WMA, PCM and MP2 format for tunnel decode Add WMA, PCM and MP2 as supported format for tunnel decode Change-Id: I874305c17c1ac31ab89412bd5f05503b7844deea --- hal_mpq/Android.mk | 6 +-- hal_mpq/audio_stream_out.c | 83 +++++++++++++++++++++++++++++++++----- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/hal_mpq/Android.mk b/hal_mpq/Android.mk index 683de7a68..1cb7e601d 100644 --- a/hal_mpq/Android.mk +++ b/hal_mpq/Android.mk @@ -44,9 +44,9 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, audio-effects) \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true) - LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED -endif + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) diff --git a/hal_mpq/audio_stream_out.c b/hal_mpq/audio_stream_out.c index 5e9eb74f3..7ef325593 100644 --- a/hal_mpq/audio_stream_out.c +++ b/hal_mpq/audio_stream_out.c @@ -1043,6 +1043,7 @@ static int configure_compr(struct stream_out *out, handle->compr_config.codec->ch_in = popcount(out->channel_mask); handle->compr_config.codec->ch_out = handle->compr_config.codec->ch_in; + handle->compr_config.codec->format = out->compr_config.codec->format; memcpy(&handle->compr_config.codec->options, &out->compr_config.codec->options, sizeof(union snd_codec_options)); @@ -1328,9 +1329,18 @@ NOTE: For AAC, the output of MS11 is 48000 for the sample rates greater than static bool is_supported_format(audio_format_t format) { - if (format == AUDIO_FORMAT_MP3 || - format == AUDIO_FORMAT_AAC) + switch (format) { + case AUDIO_FORMAT_PCM_16_BIT: + case AUDIO_FORMAT_MP3: + case AUDIO_FORMAT_AAC: + case AUDIO_FORMAT_WMA: + case AUDIO_FORMAT_WMA_PRO: + case AUDIO_FORMAT_MP2: return true; + default: + ALOGE("%s: Unsupported audio format: %x", __func__, format); + break; + } return false; } @@ -1340,14 +1350,26 @@ static int get_snd_codec_id(audio_format_t format) int id = 0; switch (format) { + case AUDIO_FORMAT_PCM_16_BIT: + id = SND_AUDIOCODEC_PCM; + break; case AUDIO_FORMAT_MP3: id = SND_AUDIOCODEC_MP3; break; case AUDIO_FORMAT_AAC: id = SND_AUDIOCODEC_AAC; break; + case AUDIO_FORMAT_WMA: + id = SND_AUDIOCODEC_WMA; + break; + case AUDIO_FORMAT_WMA_PRO: + id = SND_AUDIOCODEC_WMA_PRO; + break; + case AUDIO_FORMAT_MP2: + id = SND_AUDIOCODEC_MP2; + break; default: - ALOGE("%s: Unsupported audio format", __func__); + ALOGE("%s: Unsupported audio format %x", __func__, format); } return id; @@ -1829,6 +1851,7 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par int ret = 0; char value[32]; struct compr_gapless_mdata tmp_mdata; + bool gapless_meta_set = true; if (!out || !parms) { return -EINVAL; @@ -1838,21 +1861,61 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par if (ret >= 0) { tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? } else { - return -EINVAL; + gapless_meta_set = false; } ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); if (ret >= 0) { tmp_mdata.encoder_padding = atoi(value); } else { - return -EINVAL; + gapless_meta_set = false; } - out->gapless_mdata = tmp_mdata; - out->send_new_metadata = 1; - ALOGV("%s new encoder delay %u and padding %u", __func__, - out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); + if (gapless_meta_set) { + out->gapless_mdata = tmp_mdata; + out->send_new_metadata = 1; + ALOGV("%s new encoder delay %u and padding %u", __func__, + out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); + } + if(out->format == AUDIO_FORMAT_WMA || out->format == AUDIO_FORMAT_WMA_PRO) { + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->format = atoi(value); + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.wma.super_block_align = atoi(value); + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.wma.bits_per_sample = atoi(value); + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.wma.channelmask = atoi(value); + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.wma.encodeopt = atoi(value); + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.wma.encodeopt1 = atoi(value); + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.wma.encodeopt2 = atoi(value); + } + ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x", + out->compr_config.codec->format, + out->compr_config.codec->options.wma.super_block_align, + out->compr_config.codec->options.wma.bits_per_sample, + out->compr_config.codec->options.wma.channelmask, + out->compr_config.codec->options.wma.encodeopt, + out->compr_config.codec->options.wma.encodeopt1, + out->compr_config.codec->options.wma.encodeopt2); + } return 0; } @@ -1968,7 +2031,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) { - parse_compress_metadata(out, parms); + ret = parse_compress_metadata(out, parms); } str_parms_destroy(parms); -- GitLab From 834543bcfa7329a423b3f652a12649a5841cdc6c Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Mon, 30 Dec 2013 15:52:43 -0800 Subject: [PATCH 129/298] hal: remove assertion for unsupported sound card - Remove CHECK(0) for unsupported sound card to avoid boot up failure with USB headsets. Change-Id: Ib41c48e2b50de042fe94a4c1db0890a39b6a03e2 CRs-Fixed: 580226 --- hal/msm8974/hw_info.c | 3 +-- hal_mpq/mpq8092/hw_info.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index fd943bac2..128e4afe2 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -261,8 +261,7 @@ void *hw_info_init(const char *snd_card_name) ALOGV("8084 - variant soundcard"); update_hardware_info_8084(hw_info, snd_card_name); } else { - ALOGE("%s: Unupported target %s:",__func__, snd_card_name); - CHECK(0); + ALOGE("%s: Unsupported target %s:",__func__, snd_card_name); free(hw_info); hw_info = NULL; } diff --git a/hal_mpq/mpq8092/hw_info.c b/hal_mpq/mpq8092/hw_info.c index 97b78045d..2a0231fec 100644 --- a/hal_mpq/mpq8092/hw_info.c +++ b/hal_mpq/mpq8092/hw_info.c @@ -285,8 +285,7 @@ void *hw_info_init(const char *snd_card_name) ALOGV("8084 - variant soundcard"); update_hardware_info_8084(hw_info, snd_card_name); } else { - ALOGE("%s: Unupported target %s:",__func__, snd_card_name); - CHECK(0); + ALOGE("%s: Unsupported target %s:",__func__, snd_card_name); free(hw_info); hw_info = NULL; } -- GitLab From 8f84e9f2d37d0385d2ec234254aafa8091f78381 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Mon, 30 Dec 2013 19:30:46 +0530 Subject: [PATCH 130/298] hal: Correct pcm device ID for QCHAT session Correct QCHAT pcm device ID of 8x10 as per the machine driver. Change-Id: I7f782d08584f95941e6041c0b5e1661a4398c20e --- hal/msm8974/platform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index e7980d60f..bb1f7875d 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -204,8 +204,8 @@ enum { #elif PLATFORM_MSM8610 #define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 13 -#define VOLTE_CALL_PCM_DEVICE 14 -#define QCHAT_CALL_PCM_DEVICE 20 +#define VOLTE_CALL_PCM_DEVICE 15 +#define QCHAT_CALL_PCM_DEVICE 14 #else #define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 22 -- GitLab From f93084982fda665355d1cf069939a6bce4584117 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Thu, 12 Dec 2013 12:18:09 -0800 Subject: [PATCH 131/298] hal: add support for all_call_states key Add support for all_call_states which can be queried by applications to know call states. Change-Id: I5ba66186e9d9f6d5769a814f4c1e0627c6f6dd74 --- hal/audio_hw.c | 4 +-- hal/voice.c | 7 ++++++ hal/voice.h | 2 ++ hal/voice_extn/voice_extn.c | 50 +++++++++++++++++++++++++++++++------ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fefbfa455..98e191214 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1992,7 +1992,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, { struct audio_device *adev = (struct audio_device *)dev; struct stream_out *out; - int i, ret; + int i, ret = 0; ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", __func__, config->sample_rate, config->channel_mask, devices, flags); @@ -2316,7 +2316,7 @@ static char* adev_get_parameters(const struct audio_hw_device *dev, pthread_mutex_lock(&adev->lock); audio_extn_get_parameters(adev, query, reply); - voice_extn_get_parameters(adev, query, reply); + voice_get_parameters(adev, query, reply); platform_get_parameters(adev->platform, query, reply); str = str_parms_to_str(reply); str_parms_destroy(query); diff --git a/hal/voice.c b/hal/voice.c index cbf895641..32bb8fda3 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -351,6 +351,13 @@ int voice_stop_call(struct audio_device *adev) return ret; } +void voice_get_parameters(struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply) +{ + voice_extn_get_parameters(adev, query, reply); +} + int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) { char *str; diff --git a/hal/voice.h b/hal/voice.h index eeb65dc1c..38b304e85 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -72,6 +72,8 @@ enum { int voice_start_call(struct audio_device *adev); int voice_stop_call(struct audio_device *adev); int voice_set_parameters(struct audio_device *adev, struct str_parms *parms); +void voice_get_parameters(struct audio_device *adev, struct str_parms *query, + struct str_parms *reply); void voice_init(struct audio_device *adev); bool voice_is_in_call(struct audio_device *adev); int voice_set_mic_mute(struct audio_device *dev, bool state); diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 989a87156..18bb59c84 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -18,7 +18,7 @@ */ #define LOG_TAG "voice_extn" -/*#define LOG_NDEBUG 0*/ +#define LOG_NDEBUG 0 #define LOG_NDDEBUG 0 #include @@ -34,8 +34,12 @@ #include "platform_api.h" #include "voice_extn.h" -#define AUDIO_PARAMETER_KEY_VSID "vsid" -#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state" +#define AUDIO_PARAMETER_KEY_VSID "vsid" +#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state" +#define AUDIO_PARAMETER_KEY_AUDIO_MODE "audio_mode" +#define AUDIO_PARAMETER_KEY_ALL_CALL_STATES "all_call_states" + +#define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256 #define VOICE2_VSID 0x10DC1000 #define VOLTE_VSID 0x10C02000 @@ -432,7 +436,7 @@ int voice_extn_set_parameters(struct audio_device *adev, goto done; } } else { - ALOGD("%s: Not handled here", __func__); + ALOGV("%s: Not handled here", __func__); } done: @@ -440,21 +444,51 @@ done: return ret; } +int get_all_call_states_str(const struct audio_device *adev, + char *value) +{ + int ret = 0; + char *cur_ptr = value; + int i, len=0; + + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len, + "%d:%d,",adev->voice.session[i].vsid, + adev->voice.session[i].state.current); + len = strlen(cur_ptr); + cur_ptr = cur_ptr + len; + } + ALOGV("%s:value=%s", __func__, value); + return ret; +} + void voice_extn_get_parameters(const struct audio_device *adev, struct str_parms *query, struct str_parms *reply) { int ret; - char value[32]={0}; + char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0}; char *str = NULL; - ret = str_parms_get_str(query, "audio_mode", value, + ALOGV("%s: enter %s", __func__, str_parms_to_str(query)); + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value, sizeof(value)); if (ret >= 0) { - str_parms_add_int(reply, "audio_mode", adev->mode); + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode); } - ALOGV("%s: returns %s", __func__, str_parms_to_str(reply)); + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, + value, sizeof(value)); + if (ret >= 0) { + ret = get_all_call_states_str(adev, value); + if (ret) { + ALOGE("%s: Error fetching call states, err:%d", __func__, ret); + return; + } + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value); + } + ALOGV("%s: exit: returns \"%s\"", __func__, str_parms_to_str(reply)); } void voice_extn_out_get_parameters(struct stream_out *out, -- GitLab From 3e064fdd0fdfcd8ee04faa00011df9a71f4a224b Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Mon, 16 Dec 2013 15:54:40 -0800 Subject: [PATCH 132/298] hal: fix set_parameter() returning -2 error When setparameters() is called and if the known keys are not found, the implementation returns -2 error.Fix this by setting error only when keys are found and there is an error while executing corresponding implemention. CRs-fixed: 589280 Change-Id: If5544d6fdeac47ddfc1f7e8e18bfa81e2ef5cbc2 --- hal/audio_hw.c | 54 +++++++++++++++++++--------------- hal/msm8974/platform.c | 18 ++++++------ hal/voice.c | 23 +++++++++------ hal/voice_extn/compress_voip.c | 32 +++++++++++--------- hal/voice_extn/voice_extn.c | 18 ++++++------ hal/voice_extn/voice_extn.h | 9 +++--- 6 files changed, 85 insertions(+), 69 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 98e191214..ae8bc87b0 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1341,14 +1341,14 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) struct listnode *node; struct str_parms *parms; char value[32]; - int ret, val = 0; + int ret = 0, val = 0, err; bool select_new_device = false; ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s", __func__, out->usecase, use_case_table[out->usecase], kvpairs); parms = str_parms_create_str(kvpairs); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { + err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (err >= 0) { val = atoi(value); pthread_mutex_lock(&out->lock); pthread_mutex_lock(&adev->lock); @@ -1392,18 +1392,18 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if ((adev->mode == AUDIO_MODE_IN_CALL) && !voice_is_in_call(adev) && (out == adev->primary_output)) { - voice_start_call(adev); + ret = voice_start_call(adev); } else if ((adev->mode == AUDIO_MODE_IN_CALL) && voice_is_in_call(adev) && (out == adev->primary_output)) { - select_devices(adev, get_voice_usecase_id_from_list(adev)); + ret = select_devices(adev, get_voice_usecase_id_from_list(adev)); } } if ((adev->mode == AUDIO_MODE_NORMAL) && voice_is_in_call(adev) && (out == adev->primary_output)) { - voice_stop_call(adev); + ret = voice_stop_call(adev); } pthread_mutex_unlock(&adev->lock); @@ -1821,16 +1821,16 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) struct str_parms *parms; char *str; char value[32]; - int ret, val = 0; + int ret = 0, val = 0, err; ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs); parms = str_parms_create_str(kvpairs); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); - pthread_mutex_lock(&in->lock); pthread_mutex_lock(&adev->lock); - if (ret >= 0) { + + err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); + if (err >= 0) { val = atoi(value); /* no audio source uses val == 0 */ if ((in->source != val) && (val != 0)) { @@ -1838,8 +1838,8 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) } } - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { + err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (err >= 0) { val = atoi(value); if ((in->device != val) && (val != 0)) { in->device = val; @@ -2236,18 +2236,23 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) char *str; char value[32]; int val; - int ret; + int ret = 0, err; ALOGD("%s: enter: %s", __func__, kvpairs); pthread_mutex_lock(&adev->lock); parms = str_parms_create_str(kvpairs); - voice_set_parameters(adev, parms); - platform_set_parameters(adev->platform, parms); + ret = voice_set_parameters(adev, parms); + if (ret != 0) + goto done; - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); - if (ret >= 0) { + ret = platform_set_parameters(adev->platform, parms); + if (ret != 0) + goto done; + + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); + if (err >= 0) { /* When set to false, HAL should disable EC and NS * But it is currently not supported. */ @@ -2257,16 +2262,16 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->bluetooth_nrec = false; } - ret = str_parms_get_str(parms, "screen_state", value, sizeof(value)); - if (ret >= 0) { + err = str_parms_get_str(parms, "screen_state", value, sizeof(value)); + if (err >= 0) { if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) adev->screen_off = false; else adev->screen_off = true; } - ret = str_parms_get_int(parms, "rotation", &val); - if (ret >= 0) { + err = str_parms_get_int(parms, "rotation", &val); + if (err >= 0) { bool reverse_speakers = false; switch(val) { // FIXME: note that the code below assumes that the speakers are in the correct placement @@ -2298,8 +2303,9 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) } audio_extn_set_parameters(adev, parms); - str_parms_destroy(parms); +done: + str_parms_destroy(parms); pthread_mutex_unlock(&adev->lock); ALOGV("%s: exit with code(%d)", __func__, ret); return ret; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 9ba3b94e0..0976c1c92 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1358,12 +1358,12 @@ int platform_set_parameters(void *platform, struct str_parms *parms) char *str; char value[256] = {0}; int val; - int ret = 0; + int ret = 0, err; ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); - ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val); - if (ret >= 0) { + err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val); + if (err >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO); my_data->btsco_sample_rate = val; if (val == SAMPLE_RATE_16KHZ) { @@ -1373,8 +1373,8 @@ int platform_set_parameters(void *platform, struct str_parms *parms) } } - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value)); - if (ret >= 0) { + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value)); + if (err >= 0) { bool state = false; if (!strncmp("true", value, sizeof("true"))) { state = true; @@ -1386,9 +1386,9 @@ int platform_set_parameters(void *platform, struct str_parms *parms) ALOGE("%s: Failed to set slow talk err: %d", __func__, ret); } - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST, + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value, sizeof(value)); - if (ret >= 0) { + if (err >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST); if (my_data->acdb_reload_vocvoltable == NULL) { diff --git a/hal/voice.c b/hal/voice.c index 32bb8fda3..74d197836 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -363,15 +363,20 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) char *str; char value[32]; int val; - int ret = 0; + int ret = 0, err; ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); - voice_extn_set_parameters(adev, parms); - voice_extn_compress_voip_set_parameters(adev, parms); + ret = voice_extn_set_parameters(adev, parms); + if (ret != 0) + goto done; + + ret = voice_extn_compress_voip_set_parameters(adev, parms); + if (ret != 0) + goto done; - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); - if (ret >= 0) { + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); + if (err >= 0) { int tty_mode; str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE); if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0) @@ -396,9 +401,9 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) } } - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC, + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC, value, sizeof(value)); - if (ret >= 0) { + if (err >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC); if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0) platform_start_incall_music_usecase(adev->platform); diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index ee9fd309f..d119ff59a 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -400,53 +400,57 @@ error_start_voip: return ret; } -void voice_extn_compress_voip_set_parameters(struct audio_device *adev, +int voice_extn_compress_voip_set_parameters(struct audio_device *adev, struct str_parms *parms) { char *str; char value[32]={0}; - int ret, rate; + int ret = 0, err, rate; int min_rate, max_rate; bool flag; ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE, + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE, value, sizeof(value)); - if (ret >= 0) { + if (err >= 0) { rate = atoi(value); voip_set_rate(adev, rate); voip_set_evrc_min_max_rate(adev, rate, rate); } memset(value, 0, sizeof(value)); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN, + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN, value, sizeof(value)); - if (ret >= 0) { + if (err >= 0) { min_rate = atoi(value); str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN); memset(value, 0, sizeof(value)); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX, + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX, value, sizeof(value)); - if (ret >= 0) { + if (err >= 0) { max_rate = atoi(value); voip_set_evrc_min_max_rate(adev, min_rate, max_rate); - } - else + } else { ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__); + ret = -EINVAL; + goto done; + } } memset(value, 0, sizeof(value)); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE, + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE, value, sizeof(value)); - if (ret >= 0) { + if (err >= 0) { flag = false; if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0) flag = true; voip_set_dtx(adev, flag); } +done: ALOGV("%s: exit", __func__); + return ret; } void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 18bb59c84..12fce09f3 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ */ #define LOG_TAG "voice_extn" -#define LOG_NDEBUG 0 +/*#define LOG_NDEBUG 0*/ #define LOG_NDDEBUG 0 #include @@ -409,17 +409,17 @@ int voice_extn_set_parameters(struct audio_device *adev, { char *str; int value; - int ret = 0; + int ret = 0, err; ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); - ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value); - if (ret >= 0) { + err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value); + if (err >= 0) { str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID); - int vsid = value; + uint32_t vsid = value; int call_state = -1; - ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value); - if (ret >= 0) { + err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value); + if (err >= 0) { call_state = value; } else { ALOGE("%s: call_state key not found", __func__); diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index 0ca23863c..adee9398b 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,7 +128,7 @@ int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume) int voice_extn_compress_voip_select_devices(struct audio_device *adev, snd_device_t *out_snd_device, snd_device_t *in_snd_device); -void voice_extn_compress_voip_set_parameters(struct audio_device *adev, +int voice_extn_compress_voip_set_parameters(struct audio_device *adev, struct str_parms *parms); void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, @@ -210,10 +210,11 @@ static int voice_extn_compress_voip_select_devices(struct audio_device *adev, return -ENOSYS; } -static void voice_extn_compress_voip_set_parameters(struct audio_device *adev, +static int voice_extn_compress_voip_set_parameters(struct audio_device *adev, struct str_parms *parms) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); + return -ENOSYS; } static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, -- GitLab From 47e64854578ddf8a3061789ba9aef8c4a71f3365 Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Fri, 20 Dec 2013 13:23:39 -0800 Subject: [PATCH 133/298] hal: HFP support for setting sampling rate - Add support for setting sampling rate using setparameter. This is to support 8000 or 16000 sampling rate set from BT Change-Id: Ia6c7e530df0ba0226e492937e1c9acc70f6c6d13 --- hal/audio_extn/hfp.c | 28 ++++++++++++++++++++++++---- hal/audio_hw.c | 1 + hal/audio_hw.h | 1 + hal/msm8974/platform.c | 1 + 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index 6b0546a3b..4eb9d3728 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -42,6 +42,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ #ifdef HFP_ENABLED #define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable" +#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate" static int32_t start_hfp(struct audio_device *adev, struct str_parms *parms); @@ -55,6 +56,7 @@ struct hfp_module { struct pcm *hfp_pcm_tx; bool is_hfp_running; int hfp_volume; + audio_usecase_t ucid; }; static struct hfp_module hfpmod = { @@ -64,6 +66,7 @@ static struct hfp_module hfpmod = { .hfp_pcm_tx = NULL, .hfp_volume = 0, .is_hfp_running = 0, + .ucid = USECASE_AUDIO_HFP_SCO, }; static struct pcm_config pcm_config_hfp = { .channels = 1, @@ -86,7 +89,7 @@ static int32_t start_hfp(struct audio_device *adev, ALOGD("%s: enter", __func__); uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); - uc_info->id = USECASE_AUDIO_HFP_SCO; + uc_info->id = hfpmod.ucid; uc_info->type = PCM_HFP_CALL; uc_info->stream.out = adev->primary_output; uc_info->devices = adev->primary_output->devices; @@ -95,7 +98,7 @@ static int32_t start_hfp(struct audio_device *adev, list_add_tail(&adev->usecase_list, &uc_info->list); - select_devices(adev, USECASE_AUDIO_HFP_SCO); + select_devices(adev, hfpmod.ucid); pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK); pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE); @@ -193,10 +196,10 @@ static int32_t stop_hfp(struct audio_device *adev) hfpmod.hfp_pcm_tx = NULL; } - uc_info = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + uc_info = get_usecase_from_list(adev, hfpmod.ucid); if (uc_info == NULL) { ALOGE("%s: Could not find the usecase (%d) in the list", - __func__, USECASE_AUDIO_HFP_SCO); + __func__, hfpmod.ucid); return -EINVAL; } @@ -217,6 +220,7 @@ static int32_t stop_hfp(struct audio_device *adev) void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) { int ret; + int rate; char value[32]={0}; ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, @@ -227,5 +231,21 @@ void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms * else stop_hfp(adev); } + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value, + sizeof(value)); + if (ret >= 0) { + rate = atoi(value); + if (rate == 8000){ + hfpmod.ucid = USECASE_AUDIO_HFP_SCO; + pcm_config_hfp.rate = rate; + } + else if (rate == 16000){ + hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB; + pcm_config_hfp.rate = rate; + } + else + ALOGE("Unsupported rate.."); + } } #endif /*HFP_ENABLED*/ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fefbfa455..da128b3f4 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -113,6 +113,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record", [USECASE_AUDIO_PLAYBACK_FM] = "play-fm", [USECASE_AUDIO_HFP_SCO] = "hfp-sco", + [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb", [USECASE_VOICE_CALL] = "voice-call", [USECASE_VOICE2_CALL] = "voice2-call", diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 73575e89c..205977b47 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -65,6 +65,7 @@ typedef enum { /* HFP Use case*/ USECASE_AUDIO_HFP_SCO, + USECASE_AUDIO_HFP_SCO_WB, /* Capture usecases */ USECASE_AUDIO_RECORD, diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 9ba3b94e0..ff9aeaa88 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -120,6 +120,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE}, [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX}, + [USECASE_AUDIO_HFP_SCO_WB] = {HFP_PCM_RX, HFP_SCO_RX}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, -- GitLab From 37b4a1cd95ed0576a4707bbea576383a3d1ff7f0 Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Tue, 7 Jan 2014 16:47:47 -0800 Subject: [PATCH 134/298] hal: avoid audio rerouting to different device when hfp is active - when hfp is active we make sure we do not reroute anything new to different device with same backend. CRs-Fixed: 592390 Change-Id: I75e69916a8fe7e711b326cf82b206e3e16508b60 --- hal/audio_extn/audio_extn.h | 6 ++++++ hal/audio_extn/hfp.c | 11 +++++++++++ hal/audio_hw.c | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index e17aa6ba3..72f8642da 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -165,4 +165,10 @@ int audio_extn_dolby_get_snd_codec_id(audio_format_t format); int audio_extn_dolby_set_DMID(struct audio_device *adev); #endif +#ifndef HFP_ENABLED +#define audio_extn_hfp_is_active(adev) (0) +#else +bool audio_extn_hfp_is_active(struct audio_device *adev); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index 6b0546a3b..8414ee272 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -214,6 +214,17 @@ static int32_t stop_hfp(struct audio_device *adev) return ret; } +bool audio_extn_hfp_is_active(struct audio_device *adev) +{ + struct audio_usecase *hfp_usecase = NULL; + hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + + if (hfp_usecase != NULL) + return true; + else + return false; +} + void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) { int ret; diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fefbfa455..f73f5fe81 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -593,6 +593,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) struct audio_usecase *usecase = NULL; struct audio_usecase *vc_usecase = NULL; struct audio_usecase *voip_usecase = NULL; + struct audio_usecase *hfp_usecase = NULL; struct listnode *node; int status = 0; @@ -631,6 +632,12 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) in_snd_device = voip_usecase->in_snd_device; out_snd_device = voip_usecase->out_snd_device; } + } else if (audio_extn_hfp_is_active(adev)) { + hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + in_snd_device = hfp_usecase->in_snd_device; + out_snd_device = hfp_usecase->out_snd_device; + } } if (usecase->type == PCM_PLAYBACK) { usecase->devices = usecase->stream.out->devices; -- GitLab From 21e5c767f7e38392af7a071f5482a9c19212f241 Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Wed, 8 Jan 2014 14:10:09 -0800 Subject: [PATCH 135/298] hal: audio routing enable in hfp case - When hfp is enabled make sure to reroute during device switch CRs-Fixed: 595541 Change-Id: I680b4198a2d3baf257ae4bcfaf0c955eb62df3d9 --- hal/audio_extn/hfp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index 4eb9d3728..30d206750 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -221,6 +221,7 @@ void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms * { int ret; int rate; + int val; char value[32]={0}; ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, @@ -247,5 +248,16 @@ void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms * else ALOGE("Unsupported rate.."); } + + if(hfpmod.is_hfp_running) { + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, + value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + if(val > 0) + select_devices(adev, hfpmod.ucid); + } + } } #endif /*HFP_ENABLED*/ -- GitLab From b165a8aa28a9aa173bed3e37e76fcd96fd5cba41 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Tue, 7 Jan 2014 11:25:51 -0800 Subject: [PATCH 136/298] hal: Disable gapless offload playback by default. -Set the property-audio.offload.gapless.enabled to true to enable gapless playback by default. -Set mixer control to the driver to decide if gapless playback needs to be used or not -If gapless playback is not enabled then partial drain from HAL is treated as full drain. Change-Id: Id7f4967fe528bab9097c3f609058276ec02174e1 --- hal/audio_hw.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ee68a8f98..118239d50 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2013-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -153,6 +153,7 @@ static unsigned int audio_device_ref_count; static int set_voice_volume_l(struct audio_device *adev, float volume); static uint32_t get_offload_buffer_size(); +static int set_gapless_mode(struct audio_device *adev); static bool is_supported_format(audio_format_t format) { @@ -2138,6 +2139,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } } + //Decide if we need to use gapless mode by default + set_gapless_mode(adev); + } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { ret = voice_check_and_set_incall_music_usecase(adev, out); if (ret != 0) { @@ -2688,6 +2692,33 @@ static uint32_t get_offload_buffer_size() return fragment_size; } +static int set_gapless_mode(struct audio_device *adev) { + + + char value[PROPERTY_VALUE_MAX] = {0}; + bool gapless_enabled = false; + const char *mixer_ctl_name = "Compress Gapless Playback"; + struct mixer_ctl *ctl; + + ALOGV("%s:", __func__); + property_get("audio.offload.gapless.enabled", value, NULL); + gapless_enabled = atoi(value) || !strncmp("true", value, 4); + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + + if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) { + ALOGE("%s: Could not set gapless mode %d", + __func__, gapless_enabled); + return -EINVAL; + } + return 0; + +} static struct hw_module_methods_t hal_module_methods = { .open = adev_open, }; -- GitLab From fdb08f41da991aa2823d3c222a403a897381a60b Mon Sep 17 00:00:00 2001 From: Aviral Gupta Date: Sat, 21 Dec 2013 00:33:47 -0800 Subject: [PATCH 137/298] hal_mpq: Fix the underrun issue in the offload playback The cmd_pending variable was not updated correctly leading to the underrun Change-Id: Ic5a779c2caf737da097ce9165242f1bdbfa737aa --- hal_mpq/audio_stream_out.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hal_mpq/audio_stream_out.c b/hal_mpq/audio_stream_out.c index 7ef325593..c475a1e3b 100644 --- a/hal_mpq/audio_stream_out.c +++ b/hal_mpq/audio_stream_out.c @@ -2139,6 +2139,7 @@ static int write_data(struct stream_out *out, struct alsa_handle *handle, /* TODO:disnable this if ms12 */ if (ret >= 0 && ret < (ssize_t)bytes) { + handle->cmd_pending = true; send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); } return ret; -- GitLab From 80ac628638ee91334afdc183ed38f1c43134168a Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Fri, 20 Dec 2013 18:56:15 -0800 Subject: [PATCH 138/298] hal: fix no audio when switching devices in voice concurrency When voip usecase is active and voice call is recieved, voip usecase will go to standby causing devices to be disabled resulting no audio in voice call. CRs-fixed: 589353, 592531 Change-Id: I6d5e2f9c5dd72438affd82799333d7227c72533f Conflicts: hal/audio_hw.c --- hal/audio_hw.c | 83 +++++++++++++++----------------------------------- 1 file changed, 25 insertions(+), 58 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ff33b7d73..21b430926 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -370,7 +370,7 @@ static void check_usecases_codec_backend(struct audio_device *adev, list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == PCM_PLAYBACK && + if (usecase->type != PCM_CAPTURE && usecase != uc_info && usecase->out_snd_device != snd_device && usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { @@ -414,8 +414,6 @@ static void check_usecases_codec_backend(struct audio_device *adev, enable_audio_route(adev, usecase, false); } } - - audio_route_update_mixer(adev->audio_route); } } @@ -443,7 +441,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == PCM_CAPTURE && + if (usecase->type != PCM_PLAYBACK && usecase != uc_info && usecase->in_snd_device != snd_device) { ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", @@ -463,6 +461,12 @@ static void check_and_route_capture_usecases(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { disable_snd_device(adev, usecase->in_snd_device, false); + } + } + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (switch_device[usecase->id]) { enable_snd_device(adev, snd_device, false); } } @@ -480,55 +484,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, enable_audio_route(adev, usecase, false); } } - - audio_route_update_mixer(adev->audio_route); - } -} - -static int disable_all_usecases_of_type(struct audio_device *adev, - usecase_type_t usecase_type, - bool update_mixer) -{ - struct audio_usecase *usecase; - struct listnode *node; - int ret = 0; - - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == usecase_type) { - ALOGV("%s: usecase id %d", __func__, usecase->id); - ret = disable_audio_route(adev, usecase, update_mixer); - if (ret) { - ALOGE("%s: Failed to disable usecase id %d", - __func__, usecase->id); - } - } - } - - return ret; -} - -static int enable_all_usecases_of_type(struct audio_device *adev, - usecase_type_t usecase_type, - bool update_mixer) -{ - struct audio_usecase *usecase; - struct listnode *node; - int ret = 0; - - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == usecase_type) { - ALOGV("%s: usecase id %d", __func__, usecase->id); - ret = enable_audio_route(adev, usecase, update_mixer); - if (ret) { - ALOGE("%s: Failed to enable usecase id %d", - __func__, usecase->id); - } - } } - - return ret; } /* must be called with hw device mutex locked */ @@ -559,6 +515,21 @@ static int read_hdmi_channel_masks(struct stream_out *out) return ret; } +static void update_devices_for_all_voice_usecases(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == VOICE_CALL) { + ALOGV("%s: updating device for usecase:%s", __func__, + use_case_table[usecase->id]); + select_devices(adev, usecase->id); + } + } +} + static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev) { struct audio_usecase *usecase; @@ -678,7 +649,6 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) */ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) { status = platform_switch_voice_call_device_pre(adev->platform); - disable_all_usecases_of_type(adev, VOICE_CALL, true); } /* Disable current sound devices */ @@ -714,10 +684,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) usecase->in_snd_device = in_snd_device; usecase->out_snd_device = out_snd_device; - if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) - enable_all_usecases_of_type(adev, usecase->type, true); - else - enable_audio_route(adev, usecase, true); + enable_audio_route(adev, usecase, true); /* Applicable only on the targets that has external modem. * Enable device command should be sent to modem only after @@ -1411,7 +1378,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } else if ((adev->mode == AUDIO_MODE_IN_CALL) && voice_is_in_call(adev) && (out == adev->primary_output)) { - ret = select_devices(adev, get_voice_usecase_id_from_list(adev)); + update_devices_for_all_voice_usecases(adev); } } -- GitLab From 4a72d65cef0f42c3ac37bfa42fa8f02aa9f06066 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Fri, 3 Jan 2014 18:54:18 -0800 Subject: [PATCH 139/298] hal: handle combo output devices for voice call - Issues: camera shutter sound is not heard on speaker when wired headset is connected. - Rootcause: combo output devices are not updated properly for voice call use cases. - Fix: update combo devices before voice call use cases in platform_get_output_snd_device. CRs-Fixed: 591822 Change-Id: Ic2e75a4ce25f77499c07b4a8a32af774cdea16c2 --- hal/msm8974/platform.c | 60 +++++++++++++++---------------- policy_hal/AudioPolicyManager.cpp | 4 +-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index f32ec94b5..807ede4f4 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -871,6 +871,36 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi goto exit; } + if (popcount(devices) == 2) { + if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + if (audio_extn_get_anc_enabled()) + snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET; + else + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; + } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; + } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | + AUDIO_DEVICE_OUT_SPEAKER)) { + snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET; + } else { + ALOGE("%s: Invalid combo device(%#x)", __func__, devices); + goto exit; + } + if (snd_device != SND_DEVICE_NONE) { + goto exit; + } + } + + if (popcount(devices) != 1) { + ALOGE("%s: Invalid output devices(%#x)", __func__, devices); + goto exit; + } + if ((mode == AUDIO_MODE_IN_CALL) || voice_extn_compress_voip_is_active(adev)) { if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || @@ -922,36 +952,6 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi } } - if (popcount(devices) == 2) { - if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; - } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_SPEAKER)) { - if (audio_extn_get_anc_enabled()) - snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET; - else - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES; - } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI; - } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_SPEAKER)) { - snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET; - } else { - ALOGE("%s: Invalid combo device(%#x)", __func__, devices); - goto exit; - } - if (snd_device != SND_DEVICE_NONE) { - goto exit; - } - } - - if (popcount(devices) != 1) { - ALOGE("%s: Invalid output devices(%#x)", __func__, devices); - goto exit; - } - if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) { if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index d44a251dc..f64bbfe84 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2009 The Android Open Source Project @@ -590,7 +590,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate case STRATEGY_MEDIA: { uint32_t device2 = AUDIO_DEVICE_NONE; - if (isInCall()) { + if (isInCall() && (device == AUDIO_DEVICE_NONE)) { // when in call, get the device for Phone strategy device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); break; -- GitLab From 8911f280057ba2b3aabc99e202d976ce7f859562 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Fri, 10 Jan 2014 15:56:19 -0800 Subject: [PATCH 140/298] hal: fix incorrectly updated copyrights for source files Fix incorrectly updated copyrights for source files. Change-Id: If321f8fb0489f3088e867d4f200c6d1581ed9f57 --- hal/audio_hw.c | 2 +- hal/msm8974/platform.c | 2 +- hal/voice.c | 2 +- hal/voice_extn/compress_voip.c | 2 +- hal/voice_extn/voice_extn.c | 2 +- hal/voice_extn/voice_extn.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index ff33b7d73..bd5f34d27 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2,7 +2,7 @@ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index f32ec94b5..19ad5d51f 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -2,7 +2,7 @@ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/hal/voice.c b/hal/voice.c index 74d197836..6aff1f117 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -2,7 +2,7 @@ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index d119ff59a..a89ec2dc0 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -2,7 +2,7 @@ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 12fce09f3..719dd2ed5 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -2,7 +2,7 @@ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index adee9398b..03118f78e 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -2,7 +2,7 @@ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. -- GitLab From 07a9ea232c89b45d69683a8cfb98c9dfcbfc5c98 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Mon, 6 Jan 2014 14:53:52 -0800 Subject: [PATCH 141/298] hal: fix no audio in qchat call with speaker as default device HAL doesnt let voice calls start if the device is set to speaker as voice calls generally start on devices other than speaker. However QCHAT calls start by calling setForceUse and setting the device to speaker. Fix by updating a flag whenever device routing happens when AUDIO_MODE_IN_CALL. Reset the flag when mode is AUDIO_MODE_NORMAL. CRs-fixed: 596074 Change-Id: I546959d2b0123828562dba1f6439aa494a365c3f --- hal/voice.c | 1 + hal/voice.h | 3 ++- hal/voice_extn/voice_extn.c | 25 +++++++++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/hal/voice.c b/hal/voice.c index 74d197836..cc546f586 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -424,6 +424,7 @@ void voice_init(struct audio_device *adev) adev->voice.tty_mode = TTY_MODE_OFF; adev->voice.volume = 1.0f; adev->voice.mic_mute = false; + adev->voice.voice_device_set = false; for (i = 0; i < MAX_VOICE_SESSIONS; i++) { adev->voice.session[i].pcm_rx = NULL; adev->voice.session[i].pcm_tx = NULL; diff --git a/hal/voice.h b/hal/voice.h index 38b304e85..a7733b1fd 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -60,6 +60,7 @@ struct voice { int tty_mode; bool mic_mute; float volume; + bool voice_device_set; }; enum { diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 12fce09f3..a840fcd40 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -143,6 +143,7 @@ static int update_calls(struct audio_device *adev) struct voice_session *session = NULL; int fd = 0; int ret = 0; + bool is_in_call = false; ALOGD("%s: enter:", __func__); @@ -202,6 +203,10 @@ static int update_calls(struct audio_device *adev) ALOGE("%s: voice_end_call() failed for usecase: %d\n", __func__, usecase_id); } else { + voice_extn_is_in_call(adev, &is_in_call); + if (!is_in_call) { + adev->voice.voice_device_set = false; + } session->state.current = session->state.new; } break; @@ -274,6 +279,7 @@ static int update_call_states(struct audio_device *adev, struct voice_session *session = NULL; int i = 0; bool is_in_call; + int no_of_calls_active = 0; for (i = 0; i < MAX_VOICE_SESSIONS; i++) { if (vsid == adev->voice.session[i].vsid) { @@ -282,17 +288,27 @@ static int update_call_states(struct audio_device *adev, } } + for (i = 0; i < MAX_VOICE_SESSIONS; i++) { + if (CALL_INACTIVE != adev->voice.session[i].state.current) + no_of_calls_active++; + } + + /* When there is only one call active, wait for audio policy manager to set + * the mode to AUDIO_MODE_NORMAL and trigger routing to end the last call. + */ + if (no_of_calls_active == 1 && call_state == CALL_INACTIVE) + return 0; + if (session) { session->state.new = call_state; voice_extn_is_in_call(adev, &is_in_call); - ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode); + ALOGD("%s is_in_call:%d voice_device_set:%d, mode:%d\n", + __func__, is_in_call, adev->voice.voice_device_set, adev->mode); /* Dont start voice call before device routing for voice usescases has * occured, otherwise voice calls will be started unintendedly on * speaker. */ - if (is_in_call || - (adev->mode == AUDIO_MODE_IN_CALL && - adev->primary_output->devices != AUDIO_DEVICE_OUT_SPEAKER)) { + if (is_in_call || adev->voice.voice_device_set) { /* Device routing is not triggered for voice calls on the subsequent * subs, Hence update the call states if voice call is already * active on other sub. @@ -377,6 +393,7 @@ int voice_extn_start_call(struct audio_device *adev) * udpated. */ ALOGV("%s: enter:", __func__); + adev->voice.voice_device_set = true; return update_calls(adev); } -- GitLab From 707e7518139c25a8ce17dc833df06ca0a10c92df Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Fri, 10 Jan 2014 10:18:13 -0800 Subject: [PATCH 142/298] hal: add support for voip_out_stream_count key in get_parameters Add support for voip_out_stream_count in get_parameters which will be queried by Audio Track to decide whether to open direct output or not in case of VoIP. Change-Id: Ic0d058dff32d9002cd452689636f342e748a7fe5 --- hal/voice_extn/compress_voip.c | 23 ++++++++++++++++++++++- hal/voice_extn/voice_extn.c | 2 ++ hal/voice_extn/voice_extn.h | 10 ++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index d119ff59a..27daf8039 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -60,6 +60,7 @@ struct voip_data { struct pcm *pcm_tx; struct stream_out *out_stream; int ref_count; + int out_stream_count; }; #define MODE_IS127 0x2 @@ -76,12 +77,14 @@ struct voip_data { #define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE "dtx_on" #define AUDIO_PARAMETER_VALUE_VOIP_TRUE "true" #define AUDIO_PARAMETER_KEY_VOIP_CHECK "voip_flag" +#define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT "voip_out_stream_count" static struct voip_data voip_data = { .pcm_rx = NULL, .pcm_tx = NULL, .out_stream = NULL, - .ref_count = 0 + .ref_count = 0, + .out_stream_count = 0 }; static int voip_set_volume(struct audio_device *adev, int volume); @@ -453,6 +456,22 @@ done: return ret; } +void voice_extn_compress_voip_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply) +{ + int ret; + char value[32]={0}; + char *str = NULL; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT, + value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT, + voip_data.out_stream_count); + } +} + void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, struct str_parms *query, struct str_parms *reply) @@ -554,6 +573,7 @@ int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) ret = voip_stop_call(adev); voip_data.out_stream = NULL; + voip_data.out_stream_count--; ALOGV("%s: exit: status(%d)", __func__, ret); return ret; @@ -574,6 +594,7 @@ int voice_extn_compress_voip_open_output_stream(struct stream_out *out) out->config = pcm_config_voip_nb; voip_data.out_stream = out; + voip_data.out_stream_count++; ret = voip_set_mode(out->dev, out->format); diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 12fce09f3..138a7043a 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -488,6 +488,8 @@ void voice_extn_get_parameters(const struct audio_device *adev, } str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value); } + voice_extn_compress_voip_get_parameters(adev, query, reply); + ALOGV("%s: exit: returns \"%s\"", __func__, str_parms_to_str(reply)); } diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index adee9398b..73d8901f9 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -130,6 +130,9 @@ int voice_extn_compress_voip_select_devices(struct audio_device *adev, snd_device_t *in_snd_device); int voice_extn_compress_voip_set_parameters(struct audio_device *adev, struct str_parms *parms); +void voice_extn_compress_voip_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply); void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, struct str_parms *query, @@ -217,6 +220,13 @@ static int voice_extn_compress_voip_set_parameters(struct audio_device *adev, return -ENOSYS; } +static void voice_extn_compress_voip_get_parameters(const struct audio_device *adev, + struct str_parms *query, + struct str_parms *reply) +{ + ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); +} + static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, struct str_parms *query, struct str_parms *reply) -- GitLab From 7a9e59d8eddbaee21bef0fea8d5da613677397bb Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Mon, 6 Jan 2014 10:36:27 -0800 Subject: [PATCH 143/298] hal: Fix compilation issue seen when a feature flag is defined This change is needed to fix a compilation warning in Compress VoIP code when the feature flag "AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS" is defined. Change-Id: Ie19f542dc71705bc27a7278c83236904782f3a5e CRs-Fixed: 590219 --- hal/voice_extn/voice_extn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index 03118f78e..cae1efbb6 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -166,7 +166,7 @@ static int voice_extn_compress_voip_open_input_stream(struct stream_in *in) return -ENOSYS; } -static int voice_extn_compress_voip_out_get_buffer_size(struct audio_stream *stream) +static int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *stream) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; -- GitLab From 156f6b9f71c8c3846588a97df21966d039f28bf5 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Fri, 10 Jan 2014 15:56:19 -0800 Subject: [PATCH 144/298] hal: fix incorrectly updated copyrights for source files Fix incorrectly updated copyrights for source files. Change-Id: If321f8fb0489f3088e867d4f200c6d1581ed9f57 -- GitLab From 788431a4316dad36c3d6023802e2b8d20307367f Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Thu, 16 Jan 2014 16:51:43 -0800 Subject: [PATCH 145/298] post_proc: Enable effects param in DSP to start effect -During switch to tunnel playback, offload effects-flags remain disabled. This stops effects being applied on tunnel playback. -Send effects enable params to DSP to start effects during switch. Change-Id: Ibe1e50b41ca25b51537e4a0ad80dbd5184379133 CRs-Fixed: 593509 --- post_proc/bass_boost.c | 5 +++++ post_proc/equalizer.c | 5 +++++ post_proc/virtualizer.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c index c64ba6bc4..c724b5822 100644 --- a/post_proc/bass_boost.c +++ b/post_proc/bass_boost.c @@ -239,6 +239,11 @@ int bassboost_start(effect_context_t *context, output_context_t *output) ALOGV("%s", __func__); bass_ctxt->ctl = output->ctl; ALOGV("output->ctl: %p", output->ctl); + if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); return 0; } diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c index e31d2b943..7c7ced2cf 100644 --- a/post_proc/equalizer.c +++ b/post_proc/equalizer.c @@ -491,6 +491,11 @@ int equalizer_start(effect_context_t *context, output_context_t *output) ALOGV("%s: %p", __func__, output->ctl); eq_ctxt->ctl = output->ctl; + if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) + if (eq_ctxt->ctl) + offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_BANDS_LEVEL); return 0; } diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c index 2f0ca6b87..e9eb728cc 100644 --- a/post_proc/virtualizer.c +++ b/post_proc/virtualizer.c @@ -237,6 +237,11 @@ int virtualizer_start(effect_context_t *context, output_context_t *output) ALOGV("%s", __func__); virt_ctxt->ctl = output->ctl; + if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG | + OFFLOAD_SEND_VIRTUALIZER_STRENGTH); return 0; } -- GitLab From e0a07125f3c024c494a8e25e27d8350be42764a7 Mon Sep 17 00:00:00 2001 From: Subhash Chandra Bose Naripeddy Date: Sat, 14 Dec 2013 00:34:53 -0800 Subject: [PATCH 146/298] hal: Send device based parameters for DAP and DDP Send device based parameters for DAP and DDP Change-Id: I2cb977a573a3065f121d7aa096355ebda15f5948 --- hal/Android.mk | 9 + hal/audio_extn/audio_extn.c | 59 +---- hal/audio_extn/audio_extn.h | 29 ++- hal/audio_extn/dolby.c | 456 ++++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 26 +- 5 files changed, 503 insertions(+), 76 deletions(-) create mode 100644 hal/audio_extn/dolby.c diff --git a/hal/Android.mk b/hal/Android.mk index 037be5681..41f712cf7 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -97,8 +97,17 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true) LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + LOCAL_SRC_FILES += audio_extn/dolby.c endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DAP)),true) + LOCAL_CFLAGS += -DDS1_DOLBY_DAP_ENABLED +ifeq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true) + LOCAL_SRC_FILES += audio_extn/dolby.c +endif +endif + + LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 80ce0631b..89903ba25 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -29,8 +29,6 @@ #include "audio_hw.h" #include "audio_extn.h" -#include "sound/compress_params.h" - #define MAX_SLEEP_RETRY 100 #define WIFI_INIT_WAIT_SLEEP 50 @@ -321,6 +319,7 @@ void audio_extn_set_parameters(struct audio_device *adev, audio_extn_fm_set_parameters(adev, parms); audio_extn_listen_set_parameters(adev, parms); audio_extn_hfp_set_parameters(adev, parms); + audio_extn_ddp_set_parameters(adev, parms); } void audio_extn_get_parameters(const struct audio_device *adev, @@ -359,57 +358,3 @@ int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card, return 0; } #endif /* AUXPCM_BT_ENABLED */ - - -#ifdef DS1_DOLBY_DDP_ENABLED - -bool audio_extn_dolby_is_supported_format(audio_format_t format) -{ - if (format == AUDIO_FORMAT_AC3 || - format == AUDIO_FORMAT_EAC3) - return true; - else - return false; -} - -int audio_extn_dolby_get_snd_codec_id(audio_format_t format) -{ - int id = 0; - - switch (format) { - case AUDIO_FORMAT_AC3: - id = SND_AUDIOCODEC_AC3; - break; - case AUDIO_FORMAT_EAC3: - id = SND_AUDIOCODEC_EAC3; - break; - default: - ALOGE("%s: Unsupported audio format :%x", __func__, format); - } - - return id; -} - -int audio_extn_dolby_set_DMID(struct audio_device *adev) -{ - struct mixer_ctl *ctl; - const char *mixer_ctl_name = "DS1 Security"; - char c_dmid[128] = {0}; - int i_dmid, ret; - - property_get("dmid",c_dmid,"0"); - i_dmid = atoi(c_dmid); - - ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid); - ret = mixer_ctl_set_value(ctl, 0, i_dmid); - - return ret; -} -#endif /* DS1_DOLBY_DDP_ENABLED */ - diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 72f8642da..fb428db9e 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -155,14 +155,31 @@ size_t audio_extn_compr_cap_read(struct stream_in *in, void audio_extn_compr_cap_deinit(); #endif +#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS1_DOLBY_DAP_ENABLED) +void audio_extn_dolby_set_dmid(struct audio_device *adev); +#else +#define audio_extn_dolby_set_dmid(adev) (0) +#endif + +#ifndef DS1_DOLBY_DDP_ENABLED +#define audio_extn_dolby_set_endpoint() (0) +#else +void audio_extn_dolby_set_endpoint(struct audio_device *adev); +#endif + #ifndef DS1_DOLBY_DDP_ENABLED -#define audio_extn_dolby_is_supported_format(format) (0) +#define audio_extn_ddp_set_parameters(adev, parms) (0) +#define audio_extn_is_dolby_format(format) (0) #define audio_extn_dolby_get_snd_codec_id(format) (0) -#define audio_extn_dolby_set_DMID(adev) (0) +#define audio_extn_dolby_send_ddp_endp_params(adev) (0) #else -bool audio_extn_dolby_is_supported_format(audio_format_t format); -int audio_extn_dolby_get_snd_codec_id(audio_format_t format); -int audio_extn_dolby_set_DMID(struct audio_device *adev); +bool audio_extn_is_dolby_format(audio_format_t format); +int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev, + struct stream_out *out, + audio_format_t format); +void audio_extn_ddp_set_parameters(struct audio_device *adev, + struct str_parms *parms); +void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev); #endif #ifndef HFP_ENABLED diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c new file mode 100644 index 000000000..bcc7381cb --- /dev/null +++ b/hal/audio_extn/dolby.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2010 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "audio_hw_dolby" +/*#define LOG_NDEBUG 0*/ +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include + +#include "audio_hw.h" +#include "platform.h" +#include "platform_api.h" +#include "audio_extn.h" +#include "sound/compress_params.h" + +#ifdef DS1_DOLBY_DDP_ENABLED + +#define AUDIO_PARAMETER_DDP_DEV "ddp_device" +#define AUDIO_PARAMETER_DDP_CH_CAP "ddp_chancap" +#define AUDIO_PARAMETER_DDP_MAX_OUT_CHAN "ddp_maxoutchan" +#define AUDIO_PARAMETER_DDP_OUT_MODE "ddp_outmode" +#define AUDIO_PARAMETER_DDP_OUT_LFE_ON "ddp_outlfeon" +#define AUDIO_PARAMETER_DDP_COMP_MODE "ddp_compmode" +#define AUDIO_PARAMETER_DDP_STEREO_MODE "ddp_stereomode" + +#define PARAM_ID_MAX_OUTPUT_CHANNELS 0x00010DE2 +#define PARAM_ID_CTL_RUNNING_MODE 0x0 +#define PARAM_ID_CTL_ERROR_CONCEAL 0x00010DE3 +#define PARAM_ID_CTL_ERROR_MAX_RPTS 0x00010DE4 +#define PARAM_ID_CNV_ERROR_CONCEAL 0x00010DE5 +#define PARAM_ID_CTL_SUBSTREAM_SELECT 0x00010DE6 +#define PARAM_ID_CTL_INPUT_MODE 0x0 +#define PARAM_ID_OUT_CTL_OUTMODE 0x00010DE0 +#define PARAM_ID_OUT_CTL_OUTLFE_ON 0x00010DE1 +#define PARAM_ID_OUT_CTL_COMPMODE 0x00010D74 +#define PARAM_ID_OUT_CTL_STEREO_MODE 0x00010D76 +#define PARAM_ID_OUT_CTL_DUAL_MODE 0x00010D75 +#define PARAM_ID_OUT_CTL_DRCSCALE_HIGH 0x00010D7A +#define PARAM_ID_OUT_CTL_DRCSCALE_LOW 0x00010D79 +#define PARAM_ID_OUT_CTL_OUT_PCMSCALE 0x00010D78 +#define PARAM_ID_OUT_CTL_MDCT_BANDLIMIT 0x00010DE7 +#define PARAM_ID_OUT_CTL_DRC_SUPPRESS 0x00010DE8 + +/* DS1-DDP Endp Params */ +#define DDP_ENDP_NUM_PARAMS 17 +#define DDP_ENDP_NUM_DEVICES 22 +static int ddp_endp_params_id[DDP_ENDP_NUM_PARAMS] = { + PARAM_ID_MAX_OUTPUT_CHANNELS, PARAM_ID_CTL_RUNNING_MODE, + PARAM_ID_CTL_ERROR_CONCEAL, PARAM_ID_CTL_ERROR_MAX_RPTS, + PARAM_ID_CNV_ERROR_CONCEAL, PARAM_ID_CTL_SUBSTREAM_SELECT, + PARAM_ID_CTL_INPUT_MODE, PARAM_ID_OUT_CTL_OUTMODE, + PARAM_ID_OUT_CTL_OUTLFE_ON, PARAM_ID_OUT_CTL_COMPMODE, + PARAM_ID_OUT_CTL_STEREO_MODE, PARAM_ID_OUT_CTL_DUAL_MODE, + PARAM_ID_OUT_CTL_DRCSCALE_HIGH, PARAM_ID_OUT_CTL_DRCSCALE_LOW, + PARAM_ID_OUT_CTL_OUT_PCMSCALE, PARAM_ID_OUT_CTL_MDCT_BANDLIMIT, + PARAM_ID_OUT_CTL_DRC_SUPPRESS +}; + +static struct ddp_endp_params { + int device; + int dev_ch_cap; + int param_val[DDP_ENDP_NUM_PARAMS]; + bool is_param_valid[DDP_ENDP_NUM_PARAMS]; +} ddp_endp_params[DDP_ENDP_NUM_DEVICES] = { + {AUDIO_DEVICE_OUT_EARPIECE, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 } }, + {AUDIO_DEVICE_OUT_SPEAKER, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_WIRED_HEADSET, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_WIRED_HEADPHONE, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_BLUETOOTH_SCO, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_AUX_DIGITAL, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_AUX_DIGITAL, 6, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_AUX_DIGITAL, 8, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_USB_ACCESSORY, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_USB_DEVICE, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_FM, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_FM_TX, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_ANC_HEADSET, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_ANC_HEADPHONE, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_PROXY, 2, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, +}; + +int update_ddp_endp_table(int device, int dev_ch_cap, int param_id, + int param_val) +{ + int idx = 0; + int param_idx = 0; + ALOGV("%s: dev 0x%x dev_ch_cap %d param_id 0x%x param_val %d", + __func__, device, dev_ch_cap , param_id, param_val); + + for(idx=0; idx=DDP_ENDP_NUM_DEVICES) { + ALOGE("%s: device not available in DDP endp config table", __func__); + return -EINVAL; + } + + for(param_idx=0; param_idx=DDP_ENDP_NUM_PARAMS) { + ALOGE("param not available in DDP endp config table"); + return -EINVAL; + } + + ALOGV("ddp_endp_params[%d].param_val[%d] = %d", idx, param_idx, param_val); + ddp_endp_params[idx].param_val[param_idx] = param_val; + return 0; +} + +void send_ddp_endp_params_stream(struct stream_out *out, + int device, int dev_ch_cap, + bool set_cache) +{ + int idx, i; + int ddp_endp_params_data[2*DDP_ENDP_NUM_PARAMS + 1]; + int length = 0; + for(idx=0; idx=DDP_ENDP_NUM_DEVICES) { + ALOGE("device not available in DDP endp config table"); + return; + } + + length += 1; /* offset 0 is for num of parameter. increase offset by 1 */ + for (i=0; idev; + struct mixer_ctl *ctl; + int pcm_device_id = platform_get_pcm_device_id(out->usecase, + PCM_PLAYBACK); + snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), + "Audio Stream %d Dec Params", pcm_device_id); + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return; + } + mixer_ctl_set_array(ctl, ddp_endp_params_data, length); + } + return; +} + +void send_ddp_endp_params(struct audio_device *adev, + int ddp_dev, int dev_ch_cap) +{ + struct listnode *node; + struct audio_usecase *usecase; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if ((usecase->type == PCM_PLAYBACK) && + (usecase->devices & ddp_dev) && + (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && + ((usecase->stream.out->format == AUDIO_FORMAT_AC3) || + (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) { + send_ddp_endp_params_stream(usecase->stream.out, ddp_dev, + dev_ch_cap, false /* set cache */); + } + } +} + +void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if ((usecase->type == PCM_PLAYBACK) && + (usecase->devices & AUDIO_DEVICE_OUT_ALL) && + (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && + ((usecase->stream.out->format == AUDIO_FORMAT_AC3) || + (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) { + send_ddp_endp_params_stream(usecase->stream.out, usecase->devices, + usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? + adev->cur_hdmi_channels : 2, false /* set cache */); + } + } +} + +void audio_extn_ddp_set_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + int ddp_dev, dev_ch_cap; + int val, ret; + char value[32]={0}; + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_DEV, value, + sizeof(value)); + if (ret >= 0) { + ddp_dev = atoi(value); + if (!(AUDIO_DEVICE_OUT_ALL & ddp_dev)) + return; + } else + return; + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_CH_CAP, value, + sizeof(value)); + if (ret >= 0) { + dev_ch_cap = atoi(value); + if ((dev_ch_cap != 2) && (dev_ch_cap != 6) && (dev_ch_cap != 8)) + return; + } else + return; + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_MAX_OUT_CHAN, value, + sizeof(value)); + if (ret >= 0) { + val = atoi(value); + update_ddp_endp_table(ddp_dev, dev_ch_cap, + PARAM_ID_MAX_OUTPUT_CHANNELS, val); + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_OUT_MODE, value, + sizeof(value)); + if (ret >= 0) { + val = atoi(value); + update_ddp_endp_table(ddp_dev, dev_ch_cap, + PARAM_ID_OUT_CTL_OUTMODE, val); + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_OUT_LFE_ON, value, + sizeof(value)); + if (ret >= 0) { + val = atoi(value); + update_ddp_endp_table(ddp_dev, dev_ch_cap, + PARAM_ID_OUT_CTL_OUTLFE_ON, val); + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_COMP_MODE, value, + sizeof(value)); + if (ret >= 0) { + val = atoi(value); + update_ddp_endp_table(ddp_dev, dev_ch_cap, + PARAM_ID_OUT_CTL_COMPMODE, val); + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_DDP_STEREO_MODE, value, + sizeof(value)); + if (ret >= 0) { + val = atoi(value); + update_ddp_endp_table(ddp_dev, dev_ch_cap, + PARAM_ID_OUT_CTL_STEREO_MODE, val); + } + + send_ddp_endp_params(adev, ddp_dev, dev_ch_cap); +} + +int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev, + struct stream_out *out, + audio_format_t format) +{ + int id = 0; + + switch (format) { + case AUDIO_FORMAT_AC3: + id = SND_AUDIOCODEC_AC3; + send_ddp_endp_params_stream(out, out->devices, + out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? + adev->cur_hdmi_channels : 2, true /* set_cache */); +#ifndef DS1_DOLBY_DAP_ENABLED + audio_extn_dolby_set_dmid(adev); +#endif + break; + case AUDIO_FORMAT_EAC3: + id = SND_AUDIOCODEC_EAC3; + send_ddp_endp_params_stream(out, out->devices, + out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? + adev->cur_hdmi_channels : 2, true /* set_cache */); +#ifndef DS1_DOLBY_DAP_ENABLED + audio_extn_dolby_set_dmid(adev); +#endif + break; + default: + ALOGE("%s: Unsupported audio format :%x", __func__, format); + } + + return id; +} + +bool audio_extn_is_dolby_format(audio_format_t format) +{ + if (format == AUDIO_FORMAT_AC3 || + format == AUDIO_FORMAT_EAC3) + return true; + else + return false; +} + +#endif /* DS1_DOLBY_DDP_ENABLED */ + +#ifdef DS1_DOLBY_DAP_ENABLED +void audio_extn_dolby_set_endpoint(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "DS1 DAP Endpoint"; + int endpoint = 0, ret; + bool send = false; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if ((usecase->type == PCM_PLAYBACK) && + (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) { + endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL; + send = true; + } + } + if (!send) + return; + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return; + } + ret = mixer_ctl_set_value(ctl, 0, endpoint); + if (ret) + ALOGE("%s: Dolby set endpint cannot be set error:%d",__func__, ret); + + return; +} +#endif /* DS1_DOLBY_DAP_ENABLED */ + + +#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS1_DOLBY_DAP_ENABLED) +void audio_extn_dolby_set_dmid(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "DS1 Security"; + char c_dmid[128] = {0}; + int i_dmid, ret; + bool send = false; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if ((usecase->type == PCM_PLAYBACK) && + (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) + send = true; + } + if (!send) + return; + + property_get("dmid",c_dmid,"0"); + i_dmid = atoi(c_dmid); + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return; + } + ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid); + ret = mixer_ctl_set_value(ctl, 0, i_dmid); + if (ret) + ALOGE("%s: Dolby DMID cannot be set error:%d",__func__, ret); + + return; +} +#endif /* DS1_DOLBY_DDP_ENABLED || DS1_DOLBY_DAP_ENABLED */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 19fdda254..09b9beae5 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -199,6 +199,10 @@ int enable_audio_route(struct audio_device *adev, else snd_device = usecase->out_snd_device; +#ifdef DS1_DOLBY_DAP_ENABLED + audio_extn_dolby_set_dmid(adev); + audio_extn_dolby_set_endpoint(adev); +#endif strcpy(mixer_path, use_case_table[usecase->id]); platform_add_backend_name(mixer_path, snd_device); ALOGV("%s: apply mixer path: %s", __func__, mixer_path); @@ -1116,6 +1120,11 @@ int start_output_stream(struct stream_out *out) if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); +#ifdef DS1_DOLBY_DDP_ENABLED + if (audio_extn_is_dolby_format(out->format)) + audio_extn_dolby_send_ddp_endp_params(adev); +#endif + if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle, out->pcm_device_id); if (adev->offload_effects_start_output != NULL) @@ -2053,7 +2062,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, goto error_open; } if (!is_supported_format(config->offload_info.format) && - !audio_extn_dolby_is_supported_format(config->offload_info.format)) { + !audio_extn_is_dolby_format(config->offload_info.format)) { ALOGE("%s: Unsupported audio format", __func__); ret = -EINVAL; goto error_open; @@ -2076,9 +2085,10 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.drain = out_drain; out->stream.flush = out_flush; - if (audio_extn_dolby_is_supported_format(config->offload_info.format)) + if (audio_extn_is_dolby_format(config->offload_info.format)) out->compr_config.codec->id = - audio_extn_dolby_get_snd_codec_id(config->offload_info.format); + audio_extn_dolby_get_snd_codec_id(adev, out, + config->offload_info.format); else out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); @@ -2103,16 +2113,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); - - if (audio_extn_dolby_is_supported_format(out->format)) { - ret = audio_extn_dolby_set_DMID(adev); - if (ret != 0) { - ALOGE("%s: Dolby DMID cannot be set error:%d", - __func__, ret); - goto error_open; - } - } - //Decide if we need to use gapless mode by default set_gapless_mode(adev); -- GitLab From e5149f68326ff140f706c03ee4840a4c6211a8e3 Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Thu, 23 Jan 2014 19:31:38 -0800 Subject: [PATCH 147/298] audio: update the vifeedback pcm device id Due to changes in machine driver pcm device id has changed. Change updates pcm device id for vifeedback usecase. Change-Id: I75323f80b07fda9cf21d9aef09e4849d767c11b9 CRs-fixed: 602026 --- hal/msm8974/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index bb1f7875d..78fd91a95 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -174,7 +174,7 @@ enum { #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 -#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22 +#define SPKR_PROT_CALIB_TX_PCM_DEVICE 25 #define PLAYBACK_OFFLOAD_DEVICE 9 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3 -- GitLab From 9d1632fb654a73c00ac9516dfda7771b8a180b4f Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Thu, 9 Jan 2014 12:45:31 -0800 Subject: [PATCH 148/298] hal: Add static internal function at the top of the file -Add check_and_set_gapless_mode and get_offload_buffer_size functions at the begining of hal file. Change-Id: I134dffac4aa81ed52fc6a2668cb53fbda60103ca --- hal/audio_hw.c | 102 ++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 19fdda254..de672fc21 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -152,8 +152,55 @@ static pthread_mutex_t adev_init_lock; static unsigned int audio_device_ref_count; static int set_voice_volume_l(struct audio_device *adev, float volume); -static uint32_t get_offload_buffer_size(); -static int set_gapless_mode(struct audio_device *adev); + +/* Read offload buffer size from a property. + * If value is not power of 2 round it to + * power of 2. + */ +static uint32_t get_offload_buffer_size() +{ + char value[PROPERTY_VALUE_MAX] = {0}; + uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + if((property_get("audio.offload.buffer.size.kb", value, "")) && + atoi(value)) { + fragment_size = atoi(value) * 1024; + //ring buffer size needs to be 4k aligned. + CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096)); + } + if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + ALOGVV("%s: fragment_size %d", __func__, fragment_size); + return fragment_size; +} + +static int check_and_set_gapless_mode(struct audio_device *adev) { + + + char value[PROPERTY_VALUE_MAX] = {0}; + bool gapless_enabled = false; + const char *mixer_ctl_name = "Compress Gapless Playback"; + struct mixer_ctl *ctl; + + ALOGV("%s:", __func__); + property_get("audio.offload.gapless.enabled", value, NULL); + gapless_enabled = atoi(value) || !strncmp("true", value, 4); + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + + if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) { + ALOGE("%s: Could not set gapless mode %d", + __func__, gapless_enabled); + return -EINVAL; + } + return 0; +} static bool is_supported_format(audio_format_t format) { @@ -2114,7 +2161,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } //Decide if we need to use gapless mode by default - set_gapless_mode(adev); + check_and_set_gapless_mode(adev); } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { ret = voice_check_and_set_incall_music_usecase(adev, out); @@ -2650,55 +2697,6 @@ static int adev_open(const hw_module_t *module, const char *name, return 0; } -/* Read offload buffer size from a property. - * If value is not power of 2 round it to - * power of 2. - */ -static uint32_t get_offload_buffer_size() -{ - char value[PROPERTY_VALUE_MAX] = {0}; - uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; - if((property_get("audio.offload.buffer.size.kb", value, "")) && - atoi(value)) { - fragment_size = atoi(value) * 1024; - //ring buffer size needs to be 4k aligned. - CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096)); - } - if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE) - fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE; - else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE) - fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; - ALOGVV("%s: fragment_size %d", __func__, fragment_size); - return fragment_size; -} - -static int set_gapless_mode(struct audio_device *adev) { - - - char value[PROPERTY_VALUE_MAX] = {0}; - bool gapless_enabled = false; - const char *mixer_ctl_name = "Compress Gapless Playback"; - struct mixer_ctl *ctl; - - ALOGV("%s:", __func__); - property_get("audio.offload.gapless.enabled", value, NULL); - gapless_enabled = atoi(value) || !strncmp("true", value, 4); - - ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - - if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) { - ALOGE("%s: Could not set gapless mode %d", - __func__, gapless_enabled); - return -EINVAL; - } - return 0; - -} static struct hw_module_methods_t hal_module_methods = { .open = adev_open, }; -- GitLab From 4408bb4af6d42aa0a9344a3a586b3c6c4ecb8401 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Tue, 14 Jan 2014 13:51:33 -0800 Subject: [PATCH 149/298] hal: Reduce the deep buffer period count. -Deep buffer period count in the driver is 8. This adds to latency of 160ms. This also results in the common block to have 8 buffers. -The total latency used for AV sync is 320ms. AV sync issues are seen due to this big latency -Reduce the deep buffer cound from 8 to 4. This would reduce the latency. CRs-Fixed: 598792 Change-Id: I1c057ee9d7c8a8cb747661e3dc62c9f44bf9ee79 --- hal/msm8974/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index bb1f7875d..ca8469ac5 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -147,7 +147,7 @@ enum { * the buffer size of an input/output stream */ #define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960 -#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8 +#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4 #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2 -- GitLab From 0fe78f0b597f66f0df4daa982a6dd9e13786b062 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Mon, 6 Jan 2014 18:33:58 -0800 Subject: [PATCH 150/298] hal : Send drain to the driver if next track returns error -Partial drain is send to the driver after next track ioctl. -If next track times out or returns any error then call drain. -Partial drain will not be executed if next track fails. CRs-Fixed: 594977 Change-Id: I0665f21a5ea01f7776408b5155344f542021c299 --- hal/audio_hw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 19fdda254..434b431b1 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -831,6 +831,7 @@ static void *offload_thread_loop(void *context) { struct stream_out *out = (struct stream_out *) context; struct listnode *item; + int ret = 0; setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); set_sched_policy(0, SP_FOREGROUND); @@ -880,8 +881,14 @@ static void *offload_thread_loop(void *context) event = STREAM_CBK_EVENT_WRITE_READY; break; case OFFLOAD_CMD_PARTIAL_DRAIN: - compress_next_track(out->compr); - compress_partial_drain(out->compr); + ret = compress_next_track(out->compr); + if(ret == 0) + compress_partial_drain(out->compr); + else if(ret == -ETIMEDOUT) + compress_drain(out->compr); + else + ALOGE("%s: Next track returned error %d",__func__, ret); + send_callback = true; event = STREAM_CBK_EVENT_DRAIN_READY; break; -- GitLab From b5d116f246d0a43037eeb8d12c28db01b8d6af00 Mon Sep 17 00:00:00 2001 From: wjiang Date: Wed, 22 Jan 2014 13:24:26 +0800 Subject: [PATCH 151/298] post_proc: disable adsp reverb when preset is 'None' Audio HAL set corresponding preset id into adsp, but doesn't disabe reverb explicitly when 'None' preset is chosen. However, preset=0 means custom preset in adsp, so adsp won't stop reverb processing. Change-Id: I0c42dd13c09579a6bd3bef2141b857477ec65f2e CRs-Fixed: 604982 --- post_proc/reverb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/post_proc/reverb.c b/post_proc/reverb.c index 4fc8c8380..d1040737f 100644 --- a/post_proc/reverb.c +++ b/post_proc/reverb.c @@ -236,9 +236,14 @@ void reverb_set_density(reverb_context_t *context, int16_t density) void reverb_set_preset(reverb_context_t *context, int16_t preset) { + bool enable; ALOGV("%s: preset: %d", __func__, preset); context->next_preset = preset; offload_reverb_set_preset(&(context->offload_reverb), preset); + + enable = (preset == REVERB_PRESET_NONE) ? false: true; + offload_reverb_set_enable_flag(&(context->offload_reverb), enable); + if (context->ctl) offload_reverb_send_params(context->ctl, context->offload_reverb, OFFLOAD_SEND_REVERB_ENABLE_FLAG | -- GitLab From 8fa9eab909b04bc3e7011051471023e43a88f21e Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Tue, 7 Jan 2014 16:47:47 -0800 Subject: [PATCH 152/298] hal: avoid audio rerouting to different device when hfp is active - when hfp is active we make sure we do not reroute anything new to different device with same backend. CRs-Fixed: 592390 Change-Id: I75e69916a8fe7e711b326cf82b206e3e16508b60 --- hal/audio_extn/audio_extn.h | 6 ++++++ hal/audio_hw.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index fb428db9e..df7fd444f 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -188,4 +188,10 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev); bool audio_extn_hfp_is_active(struct audio_device *adev); #endif +#ifndef HFP_ENABLED +#define audio_extn_hfp_is_active(adev) (0) +#else +bool audio_extn_hfp_is_active(struct audio_device *adev); +#endif + #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1b008dbe0..556f2e355 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -662,6 +662,12 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) in_snd_device = hfp_usecase->in_snd_device; out_snd_device = hfp_usecase->out_snd_device; } + } else if (audio_extn_hfp_is_active(adev)) { + hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + in_snd_device = hfp_usecase->in_snd_device; + out_snd_device = hfp_usecase->out_snd_device; + } } if (usecase->type == PCM_PLAYBACK) { usecase->devices = usecase->stream.out->devices; -- GitLab From b0668ee1a3df6c711d709f7a248b73faff817cd7 Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Fri, 24 Jan 2014 15:33:23 -0800 Subject: [PATCH 153/298] hal: add input source check to open compress voip input Compress voip input requires input source type to be of AUDIO_SOURCE_VOICE_COMMUNICATION. Move the opening of compress voip input to in_set_parameters() function which is the first place in HAL where the source type information is available. Change-Id: I3758eba6049ccd4f1a4465ef264420d9afb6a795 --- hal/audio_hw.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1b008dbe0..1a7b83e7b 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1889,6 +1889,18 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) /* no audio source uses val == 0 */ if ((in->source != val) && (val != 0)) { in->source = val; + if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) && + (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && + (voice_extn_compress_voip_is_format_supported(in->format)) && + (in->config.rate == 8000 || in->config.rate == 16000) && + (popcount(in->channel_mask) == 1)) { + ret = voice_extn_compress_voip_open_input_stream(in); + if (ret != 0) { + ALOGE("%s: Compress voip input cannot be opened, error:%d", + __func__, ret); + goto done; + } + } } } @@ -1903,6 +1915,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) } } +done: pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&in->lock); @@ -2502,16 +2515,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->config.rate = config->sample_rate; in->format = config->format; - if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && - (voice_extn_compress_voip_is_config_supported(config))) { - ret = voice_extn_compress_voip_open_input_stream(in); - if (ret != 0) - { - ALOGE("%s: Compress voip input cannot be opened, error:%d", - __func__, ret); - goto err_open; - } - } else if (channel_count == 6) { + if (channel_count == 6) { if(audio_extn_ssr_get_enabled()) { if(audio_extn_ssr_init(adev, in)) { ALOGE("%s: audio_extn_ssr_init failed", __func__); @@ -2523,7 +2527,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev, goto err_open; } } else if (audio_extn_compr_cap_enabled() && - audio_extn_compr_cap_format_supported(config->format)) { + audio_extn_compr_cap_format_supported(config->format) && + (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) { audio_extn_compr_cap_init(adev, in); } else { in->config.channels = channel_count; -- GitLab From 2e032359901c7912087e49e8f028ca64fb473c3b Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Wed, 29 Jan 2014 12:52:19 -0800 Subject: [PATCH 154/298] hal: fix a memeory leak caused by using str_parms_to_str() str_parms_to_str() requires the caller to free() the returned string. Free the memory pointed to by "str" before overwriting the "str" with the new pointer which is returned by strdup() function. Change-Id: I602ae37cce684e0c62b0ec310080bb0cd675e35a CRs-fixed: 608384 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1b008dbe0..58aa626d1 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1512,7 +1512,8 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k voice_extn_out_get_parameters(out, query, reply); str = str_parms_to_str(reply); if (!strncmp(str, "", sizeof(""))) { - str = strdup(keys); + free(str); + str = strdup(keys); } } str_parms_destroy(query); -- GitLab From f8a5d0a8705549636ecdb3114cb67525adafdbd7 Mon Sep 17 00:00:00 2001 From: Walter Yang Date: Fri, 17 Jan 2014 11:24:23 +0800 Subject: [PATCH 155/298] hal: Fix input device selection for stereo recording Only if the fluence type is dual mic or quad mic and the channel count is 2, the dmic device is selected as input device. Change-Id: I22f9d2f154e9b6348ef547ff68014b5e68ae7e5f CRs-fixed: 599947 --- hal/msm8974/platform.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c7896aedd..312c327d3 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1175,7 +1175,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) { if (audio_extn_ssr_get_enabled() && channel_count == 6) snd_device = SND_DEVICE_IN_QUAD_MIC; - else if (channel_count == 2) + else if (my_data->fluence_type & (FLUENCE_DUAL_MIC | FLUENCE_QUAD_MIC) && + channel_count == 2) snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC; else snd_device = SND_DEVICE_IN_HANDSET_MIC; -- GitLab From 8506a9832c64a31e86c45d5443b88a89789acfc7 Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Fri, 17 Jan 2014 13:10:09 -0800 Subject: [PATCH 156/298] policy_hal: Correct device selection in STRATEGY_ENFORCED_AUDIBLE - When strategy is STRATEGY_ENFORCED_AUDIBLE, do not select unsupported combo devices Proxy+Speaker, HDMI+Speaker, and FM_TX + Speaker. Change-Id: Icd4f6de74807a6efc5f6eb8258c020ad990aaf9b Crs-fixed: 600799 --- policy_hal/AudioPolicyManager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index f64bbfe84..69587dc76 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -632,7 +632,8 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (device2 == AUDIO_DEVICE_NONE) { device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; } - if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) { + if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) + && (device2 == AUDIO_DEVICE_NONE)) { // no sonification on aux digital (e.g. HDMI) device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; } @@ -642,12 +643,14 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; } #ifdef AUDIO_EXTN_FM_ENABLED - if ((strategy != STRATEGY_SONIFICATION) && (device2 == AUDIO_DEVICE_NONE)) { + if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) + && (device2 == AUDIO_DEVICE_NONE)) { device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX; } #endif #ifdef AUDIO_EXTN_AFE_PROXY_ENABLED - if ((strategy != STRATEGY_SONIFICATION) && (device2 == AUDIO_DEVICE_NONE)) { + if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) + && (device2 == AUDIO_DEVICE_NONE)) { // no sonification on WFD sink device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY; } -- GitLab From 301cc367c9961258c9b6b35feb54b26447de3fb0 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Fri, 31 Jan 2014 18:12:13 -0800 Subject: [PATCH 157/298] hal: Fix memory leak in HAL debug logs String returned from str_parms_to_str for set/get parameter in debug logs is not de-allocated. Fix is to make sure the memory allocated for set parameter key value pair is de-allocated. CRs-Fixed: 610079 Change-Id: I5027d8f1741c9e7223e7b4721f8d5473404998d3 --- hal/audio_extn/audio_extn.c | 5 ++++- hal/msm8974/platform.c | 9 +++++++-- hal/voice.c | 4 +++- hal/voice_extn/compress_voip.c | 9 +++++++-- hal/voice_extn/voice_extn.c | 13 +++++++++---- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 89903ba25..ad487b1c1 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -326,9 +326,12 @@ void audio_extn_get_parameters(const struct audio_device *adev, struct str_parms *query, struct str_parms *reply) { + char *kv_pairs = NULL; audio_extn_get_afe_proxy_parameters(query, reply); - ALOGD("%s: returns %s", __func__, str_parms_to_str(reply)); + kv_pairs = str_parms_to_str(reply); + ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs); + free(kv_pairs); } #ifdef AUXPCM_BT_ENABLED diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 312c327d3..b1f009f98 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1361,8 +1361,9 @@ int platform_set_parameters(void *platform, struct str_parms *parms) char value[256] = {0}; int val; int ret = 0, err; + char *kv_pairs = str_parms_to_str(parms); - ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val); if (err >= 0) { @@ -1407,6 +1408,7 @@ int platform_set_parameters(void *platform, struct str_parms *parms) } ALOGV("%s: exit with code(%d)", __func__, ret); + free(kv_pairs); return ret; } @@ -1505,6 +1507,7 @@ void platform_get_parameters(void *platform, char value[256] = {0}; int ret; int fluence_type; + char *kv_pairs = NULL; ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value, sizeof(value)); @@ -1540,7 +1543,9 @@ void platform_get_parameters(void *platform, str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value); } - ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply)); + kv_pairs = str_parms_to_str(reply); + ALOGV_IF(kv_pairs != NULL, "%s: exit: returns - %s", __func__, kv_pairs); + free(reply); } /* Delay in Us */ diff --git a/hal/voice.c b/hal/voice.c index 8783f010a..28d44db8f 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -364,8 +364,9 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) char value[32]; int val; int ret = 0, err; + char *kv_pairs = str_parms_to_str(parms); - ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); ret = voice_extn_set_parameters(adev, parms); if (ret != 0) @@ -413,6 +414,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) done: ALOGV("%s: exit with code(%d)", __func__, ret); + free(kv_pairs); return ret; } diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 5c87c9c50..4db46f6d9 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -411,8 +411,9 @@ int voice_extn_compress_voip_set_parameters(struct audio_device *adev, int ret = 0, err, rate; int min_rate, max_rate; bool flag; + char *kv_pairs = str_parms_to_str(parms); - ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE, value, sizeof(value)); @@ -453,6 +454,7 @@ int voice_extn_compress_voip_set_parameters(struct audio_device *adev, done: ALOGV("%s: exit", __func__); + free(kv_pairs); return ret; } @@ -499,6 +501,7 @@ void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, { int ret, val; char value[32]={0}; + char *kv_pairs = NULL; ALOGV("%s: enter", __func__); @@ -511,7 +514,9 @@ void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false); } - ALOGD("%s: exit: return - %s", __func__, str_parms_to_str(reply)); + kv_pairs = str_parms_to_str(reply); + ALOGD_IF(kv_pairs != NULL, "%s: exit: return - %s", __func__, kv_pairs); + free(kv_pairs); } int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out) diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index b8bc2df4f..5612e0c4d 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -427,8 +427,9 @@ int voice_extn_set_parameters(struct audio_device *adev, char *str; int value; int ret = 0, err; + char *kv_pairs = str_parms_to_str(parms); - ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value); if (err >= 0) { @@ -458,6 +459,7 @@ int voice_extn_set_parameters(struct audio_device *adev, done: ALOGV("%s: exit with code(%d)", __func__, ret); + free(kv_pairs); return ret; } @@ -485,9 +487,10 @@ void voice_extn_get_parameters(const struct audio_device *adev, { int ret; char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0}; - char *str = NULL; + char *str = str_parms_to_str(query); - ALOGV("%s: enter %s", __func__, str_parms_to_str(query)); + ALOGV_IF(str != NULL, "%s: enter %s", __func__, str); + free(str); ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value, sizeof(value)); @@ -507,7 +510,9 @@ void voice_extn_get_parameters(const struct audio_device *adev, } voice_extn_compress_voip_get_parameters(adev, query, reply); - ALOGV("%s: exit: returns \"%s\"", __func__, str_parms_to_str(reply)); + str = str_parms_to_str(reply); + ALOGV_IF(str != NULL, "%s: exit: returns \"%s\"", __func__, str); + free(str); } void voice_extn_out_get_parameters(struct stream_out *out, -- GitLab From fe916e1781287faff8742f65bbf7c2d568f3ac59 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Fri, 31 Jan 2014 17:41:16 -0800 Subject: [PATCH 158/298] hal: Fix memory leak in listen module String returned from str_parms_to_str for set/get parameter key-value pair for listen module is not de-allocated. Fix is to make sure the memory allocated for key value pair is de-allocated. CRs-Fixed: 610083 Change-Id: I290e61168b8fd1569a7b89e13257e142aa5aa1ac --- hal/audio_extn/listen.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c index 9166f8eb5..4a1980b71 100644 --- a/hal/audio_extn/listen.c +++ b/hal/audio_extn/listen.c @@ -119,10 +119,13 @@ void audio_extn_listen_update_status(snd_device_t snd_device, void audio_extn_listen_set_parameters(struct audio_device *adev, struct str_parms *parms) { - ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms)); + ALOGV("%s: enter", __func__); if (listen_dev) { - listen_dev->listen_set_parameters(&adev->device, str_parms_to_str(parms)); + char *kv_pairs = str_parms_to_str(parms); + ALOGV_IF(kv_pairs != NULL, "%s: %s", __func__, kv_pairs); + listen_dev->listen_set_parameters(&adev->device, kv_pairs); + free(kv_pairs); } return; -- GitLab From 287b816c4bb242984c49c0d5b710aa025515ab1a Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Tue, 4 Feb 2014 16:23:52 -0800 Subject: [PATCH 159/298] hal: start voip driver independent of voip output stream - Voip driver requires voip output stream to be opened to start itself. But it is possible that some applications may use voip input and normal audio output. Code changes are done to handle this scenario. - It is possible that some applications may use different sample rates for voip input and voip output streams. It is handled now in such a way that, if the sample rate of the secondly opening stream does not match with that of the first one, the second stream will not be allowed to open voice path for VoIP. Change-Id: Id9d86181eeee2c4ea0aa49a723ca92c1961a559b CRs-fixed: 601785 --- hal/audio_hw.c | 7 ++-- hal/voice_extn/compress_voip.c | 66 ++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 4fbf5c42f..99cd2c944 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1895,11 +1895,10 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) (voice_extn_compress_voip_is_format_supported(in->format)) && (in->config.rate == 8000 || in->config.rate == 16000) && (popcount(in->channel_mask) == 1)) { - ret = voice_extn_compress_voip_open_input_stream(in); - if (ret != 0) { + err = voice_extn_compress_voip_open_input_stream(in); + if (err != 0) { ALOGE("%s: Compress voip input cannot be opened, error:%d", - __func__, ret); - goto done; + __func__, err); } } } diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 5c87c9c50..9a850416e 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -59,8 +59,9 @@ struct voip_data { struct pcm *pcm_rx; struct pcm *pcm_tx; struct stream_out *out_stream; - int ref_count; - int out_stream_count; + uint32_t out_stream_count; + uint32_t in_stream_count; + uint32_t sample_rate; }; #define MODE_IS127 0x2 @@ -78,13 +79,15 @@ struct voip_data { #define AUDIO_PARAMETER_VALUE_VOIP_TRUE "true" #define AUDIO_PARAMETER_KEY_VOIP_CHECK "voip_flag" #define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT "voip_out_stream_count" +#define AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE "voip_sample_rate" static struct voip_data voip_data = { .pcm_rx = NULL, .pcm_tx = NULL, .out_stream = NULL, - .ref_count = 0, - .out_stream_count = 0 + .out_stream_count = 0, + .in_stream_count = 0, + .sample_rate = 0 }; static int voip_set_volume(struct audio_device *adev, int volume); @@ -280,10 +283,10 @@ static int voip_stop_call(struct audio_device *adev) int i, ret = 0; struct audio_usecase *uc_info; - ALOGD("%s: enter, ref_count=%d", __func__, voip_data.ref_count); - voip_data.ref_count--; + ALOGD("%s: enter, out_stream_count=%d, in_stream_count=%d", + __func__, voip_data.out_stream_count, voip_data.in_stream_count); - if (!voip_data.ref_count) { + if (!voip_data.out_stream_count && !voip_data.in_stream_count) { uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); if (uc_info == NULL) { ALOGE("%s: Could not find the usecase (%d) in the list", @@ -310,8 +313,10 @@ static int voip_stop_call(struct audio_device *adev) list_remove(&uc_info->list); free(uc_info); + voip_data.sample_rate = 0; } else - ALOGV("%s: NO-OP because ref_count=%d", __func__, voip_data.ref_count); + ALOGV("%s: NO-OP because out_stream_count=%d, in_stream_count=%d", + __func__, voip_data.out_stream_count, voip_data.in_stream_count); ALOGV("%s: exit: status(%d)", __func__, ret); return ret; @@ -327,12 +332,15 @@ static int voip_start_call(struct audio_device *adev, ALOGD("%s: enter", __func__); uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); - if ((uc_info == NULL) && (voip_data.out_stream)) { + if (uc_info == NULL) { ALOGV("%s: voip usecase is added to the list", __func__); uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); uc_info->id = USECASE_COMPRESS_VOIP_CALL; uc_info->type = VOIP_CALL; - uc_info->stream.out = voip_data.out_stream; + if (voip_data.out_stream) + uc_info->stream.out = voip_data.out_stream; + else + uc_info->stream.out = adev->primary_output; uc_info->in_snd_device = SND_DEVICE_NONE; uc_info->out_snd_device = SND_DEVICE_NONE; @@ -388,12 +396,15 @@ static int voip_start_call(struct audio_device *adev, ALOGE("%s: error %d\n", __func__, ret); goto error_start_voip; } - voip_data.ref_count = 0; - } - else + } else { ALOGV("%s: voip usecase is already enabled", __func__); + if (voip_data.out_stream) + uc_info->stream.out = voip_data.out_stream; + else + uc_info->stream.out = adev->primary_output; + select_devices(adev, USECASE_COMPRESS_VOIP_CALL); + } - voip_data.ref_count++; return 0; error_start_voip: @@ -470,6 +481,13 @@ void voice_extn_compress_voip_get_parameters(const struct audio_device *adev, str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT, voip_data.out_stream_count); } + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE, + value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE, + voip_data.sample_rate); + } } void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, @@ -571,9 +589,9 @@ int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) ALOGD("%s: enter", __func__); + voip_data.out_stream_count--; ret = voip_stop_call(adev); voip_data.out_stream = NULL; - voip_data.out_stream_count--; ALOGV("%s: exit: status(%d)", __func__, ret); return ret; @@ -595,7 +613,7 @@ int voice_extn_compress_voip_open_output_stream(struct stream_out *out) voip_data.out_stream = out; voip_data.out_stream_count++; - + voip_data.sample_rate = out->sample_rate; ret = voip_set_mode(out->dev, out->format); ALOGV("%s: exit", __func__); @@ -610,6 +628,7 @@ int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) ALOGD("%s: enter", __func__); + voip_data.in_stream_count--; status = voip_stop_call(adev); ALOGV("%s: exit: status(%d)", __func__, status); @@ -625,15 +644,25 @@ int voice_extn_compress_voip_open_input_stream(struct stream_in *in) ALOGD("%s: enter", __func__); + if ((voip_data.sample_rate != 0) && + (voip_data.sample_rate != in->config.rate)) { + ret = -ENOTSUP; + goto done; + } else { + voip_data.sample_rate = in->config.rate; + } + in->usecase = USECASE_COMPRESS_VOIP_CALL; if (in->config.rate == 16000) in->config = pcm_config_voip_wb; else in->config = pcm_config_voip_nb; + voip_data.in_stream_count++; ret = voip_set_mode(in->dev, in->format); - ALOGV("%s: exit", __func__); +done: + ALOGV("%s: exit, ret=%d", __func__, ret); return ret; } @@ -729,7 +758,8 @@ bool voice_extn_compress_voip_is_config_supported(struct audio_config *config) if (ret) { if ((popcount(config->channel_mask) == 1) && (config->sample_rate == 8000 || config->sample_rate == 16000)) - ret = true; + ret = ((voip_data.sample_rate == 0) ? true: + (voip_data.sample_rate == config->sample_rate)); else ret = false; } -- GitLab From 1d2ed3c583c9d94d9de3ec5af2f13789f4108f3e Mon Sep 17 00:00:00 2001 From: Apoorv Raghuvanshi Date: Wed, 29 Jan 2014 15:31:32 -0800 Subject: [PATCH 160/298] hal: Minor usb stability fix - Adding buffer of one byte for the strstr usecase to make the passed string is NULL terminated. Change-Id: Ief8531e149b05f4020cb1338110bbfad4a74f7d0 Crs-fixed: 607454 --- hal/audio_extn/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c index 88e3cad00..699c3b7d3 100644 --- a/hal/audio_extn/usb.c +++ b/hal/audio_extn/usb.c @@ -152,7 +152,7 @@ static int usb_get_capability(char *type, int32_t *channels, file_size = st.st_size; - read_buf = (char *)calloc(1, USB_BUFF_SIZE); + read_buf = (char *)calloc(1, USB_BUFF_SIZE + 1); err = read(fd, read_buf, USB_BUFF_SIZE); str_start = strstr(read_buf, type); if (str_start == NULL) { -- GitLab From db712ed63f1768e31112dafe52d4c36205fd0837 Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Thu, 13 Feb 2014 11:44:31 -0800 Subject: [PATCH 161/298] hal: fix a bug introduced as part of changes done for fixing memroy leak The return value of platform_get_parameters() is getting freed up wrongly which is fixed now. This bug was introduced as part of the gerrit-id 611791. Change-Id: I61e4f5abc732fbe84702452e27cde7c1c36f77e6 --- hal/msm8974/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index b1f009f98..074633c3c 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1545,7 +1545,7 @@ void platform_get_parameters(void *platform, kv_pairs = str_parms_to_str(reply); ALOGV_IF(kv_pairs != NULL, "%s: exit: returns - %s", __func__, kv_pairs); - free(reply); + free(kv_pairs); } /* Delay in Us */ -- GitLab From e2a149dd3595bc32ccb19dd9de593201713fae6e Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Tue, 11 Feb 2014 15:59:58 +0530 Subject: [PATCH 162/298] hal: Add chipset specific HFP device IDs Different chipsets have different device IDs as the front end dai links are specific to chipsets. Ensure that the right device IDs are used based on the chipset. CRs-Fixed: 611132 Change-Id: If7d1a0de30653ed85d52bcb35fd13b0cc7282657 --- hal/msm8974/platform.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 3ea068dfb..314835597 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -168,8 +168,6 @@ enum { #define FM_PLAYBACK_PCM_DEVICE 5 #define FM_CAPTURE_PCM_DEVICE 6 #define HFP_PCM_RX 5 -#define HFP_SCO_RX 23 -#define HFP_ASM_RX_TX 24 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 @@ -213,6 +211,14 @@ enum { #define QCHAT_CALL_PCM_DEVICE 20 #endif +#ifdef PLATFORM_MSM8x26 +#define HFP_SCO_RX 21 +#define HFP_ASM_RX_TX 22 +#else +#define HFP_SCO_RX 23 +#define HFP_ASM_RX_TX 24 +#endif + #define LIB_CSD_CLIENT "libcsd-client.so" /* CSD-CLIENT related functions */ typedef int (*init_t)(); -- GitLab From 0c5668726fad9ffffd176c1cea78a1dc3216e556 Mon Sep 17 00:00:00 2001 From: ApurupaPattapu Date: Fri, 10 Jan 2014 14:46:02 -0800 Subject: [PATCH 163/298] hal: Add support for PCM in offload path - Translate PCM Offload format to pcm codec id - Set 16/24 sub format id in compress params format - Calculate offload fragment size for pcm - Move offload calculation functions to platform file - Update audio policy manager isOffloadSupported for pcm offload profile. Use audio.offload.pcm.enable Change-Id: I2064d646b66e8283fce2cc736e96fb93cba0a552 --- hal/audio_hw.c | 56 +++++++------- hal/msm8974/platform.c | 84 ++++++++++++++++++++ hal/platform_api.h | 6 +- policy_hal/AudioPolicyManager.cpp | 123 ++++++++++++++++++++++++++++++ policy_hal/AudioPolicyManager.h | 2 + 5 files changed, 241 insertions(+), 30 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 7589f0e5f..60b38a545 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -53,14 +53,14 @@ #include "voice_extn.h" #include "sound/compress_params.h" -#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024) -#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (8 * 1024) -#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) +#include "sound/asound.h" + #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 /* ToDo: Check and update a proper value in msec */ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 + #define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER struct pcm_config pcm_config_deep_buffer = { @@ -153,28 +153,6 @@ static unsigned int audio_device_ref_count; static int set_voice_volume_l(struct audio_device *adev, float volume); -/* Read offload buffer size from a property. - * If value is not power of 2 round it to - * power of 2. - */ -static uint32_t get_offload_buffer_size() -{ - char value[PROPERTY_VALUE_MAX] = {0}; - uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; - if((property_get("audio.offload.buffer.size.kb", value, "")) && - atoi(value)) { - fragment_size = atoi(value) * 1024; - //ring buffer size needs to be 4k aligned. - CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096)); - } - if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE) - fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE; - else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE) - fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; - ALOGVV("%s: fragment_size %d", __func__, fragment_size); - return fragment_size; -} - static int check_and_set_gapless_mode(struct audio_device *adev) { @@ -205,8 +183,10 @@ static int check_and_set_gapless_mode(struct audio_device *adev) { static bool is_supported_format(audio_format_t format) { if (format == AUDIO_FORMAT_MP3 || - format == AUDIO_FORMAT_AAC) - return true; + format == AUDIO_FORMAT_AAC || + format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || + format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) + return true; return false; } @@ -222,6 +202,10 @@ static int get_snd_codec_id(audio_format_t format) case AUDIO_FORMAT_AAC: id = SND_AUDIOCODEC_AAC; break; + case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: + case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: + id = SND_AUDIOCODEC_PCM; + break; default: ALOGE("%s: Unsupported audio format :%x", __func__, format); } @@ -2147,8 +2131,10 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; if (config->offload_info.channel_mask) out->channel_mask = config->offload_info.channel_mask; - else if (config->channel_mask) + else if (config->channel_mask) { out->channel_mask = config->channel_mask; + config->offload_info.channel_mask = config->channel_mask; + } out->format = config->offload_info.format; out->sample_rate = config->offload_info.sample_rate; @@ -2165,7 +2151,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, else out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); - out->compr_config.fragment_size = get_offload_buffer_size(); + + if (audio_is_offload_pcm(config->offload_info.format)) { + out->compr_config.fragment_size = + platform_get_pcm_offload_buffer_size(&config->offload_info); + } else { + out->compr_config.fragment_size = + platform_get_compress_offload_buffer_size(&config->offload_info); + } out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; out->compr_config.codec->sample_rate = compress_get_alsa_rate(config->offload_info.sample_rate); @@ -2175,6 +2168,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, popcount(config->channel_mask); out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) + out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; + else if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) + out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; + if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 074633c3c..f0d4c4a60 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -31,12 +31,30 @@ #include "platform.h" #include "audio_extn.h" #include "voice_extn.h" +#include "sound/compress_params.h" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" #define LIB_ACDB_LOADER "libacdbloader.so" #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" +#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024) +#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024) +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024) +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) + +/* Used in calculating fragment size for pcm offload */ +#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 2000 /* 2 secs */ +#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 100 /* 100 millisecs */ + +/* MAX PCM fragment size cannot be increased further due + * to flinger's cblk size of 1mb,and it has to be a multiple of + * 24 - lcm of channels supported by DSP + */ +#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024) +#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024) + +#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1))) /* * This file will have a maximum of 38 bytes: * @@ -1579,3 +1597,69 @@ bool platform_listen_update_status(snd_device_t snd_device) else return false; } + +/* Read offload buffer size from a property. + * If value is not power of 2 round it to + * power of 2. + */ +uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) +{ + char value[PROPERTY_VALUE_MAX] = {0}; + uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + if((property_get("audio.offload.buffer.size.kb", value, "")) && + atoi(value)) { + fragment_size = atoi(value) * 1024; + } + + if (info != NULL && info->has_video && info->is_streaming) { + fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING; + ALOGV("%s: offload fragment size reduced for AV streaming to %d", + __func__, out->compr_config.fragment_size); + } + + fragment_size = ALIGN( fragment_size, 1024); + + if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + ALOGV("%s: fragment_size %d", __func__, fragment_size); + return fragment_size; +} + +uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) +{ + uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; + uint32_t bits_per_sample = 16; + + if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { + bits_per_sample = 32; + } + + if (!info->has_video) { + fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; + + } else if (info->has_video && info->is_streaming) { + fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING + * info->sample_rate + * bits_per_sample + * popcount(info->channel_mask))/1000; + + } else if (info->has_video) { + fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV + * info->sample_rate + * bits_per_sample + * popcount(info->channel_mask))/1000; + } + + fragment_size = ALIGN( fragment_size, 1024); + + if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; + else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; + + ALOGV("%s: fragment_size %d", __func__, fragment_size); + return fragment_size; +} + diff --git a/hal/platform_api.h b/hal/platform_api.h index 4096ef02f..306aaadda 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -57,4 +57,8 @@ int platform_update_usecase_from_source(int source, audio_usecase_t usecase); bool platform_listen_update_status(snd_device_t snd_device); -#endif // QCOM_AUDIO_PLATFORM_API_H +struct audio_offload_info_t; +uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info); +uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info); + +#endif // AUDIO_PLATFORM_API_H diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 69587dc76..cb26ed645 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -881,6 +881,129 @@ float AudioPolicyManager::computeVolume(int stream, #endif return AudioPolicyManagerBase::computeVolume(stream, index, output, device); } + +// This function checks for the parameters which can be offloaded. +// This can be enhanced depending on the capability of the DSP and policy +// of the system. +bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo) +{ + ALOGV(" isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d," + " BitRate=%u, duration=%lld us, has_video=%d", + offloadInfo.sample_rate, offloadInfo.channel_mask, + offloadInfo.format, + offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, + offloadInfo.has_video); + +#ifdef VOICE_CONCURRENCY + if(isInCall()) + { + ALOGD("\n blocking compress offload on call mode\n"); + return false; + } +#endif + // Check if stream type is music, then only allow offload as of now. + if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC) + { + ALOGV("isOffloadSupported: stream_type != MUSIC, returning false"); + return false; + } + + char propValue[PROPERTY_VALUE_MAX]; + bool pcmOffload = false; + if (audio_is_offload_pcm(offloadInfo.format)) { + if(property_get("audio.offload.pcm.enable", propValue, NULL)) { + bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4); + if (prop_enabled) { + ALOGW("PCM offload property is enabled"); + pcmOffload = true; + } + } + if (!pcmOffload) { + ALOGV("PCM offload disabled by property audio.offload.pcm.enable"); + return false; + } + } + + if (!pcmOffload) { + // Check if offload has been disabled + if (property_get("audio.offload.disable", propValue, "0")) { + if (atoi(propValue) != 0) { + ALOGV("offload disabled by audio.offload.disable=%s", propValue ); + return false; + } + } + + //check if it's multi-channel AAC format + if (AudioSystem::popCount(offloadInfo.channel_mask) > 2 + && offloadInfo.format == AUDIO_FORMAT_AAC) { + ALOGV("offload disabled for multi-channel AAC format"); + return false; + } + + if (offloadInfo.has_video) + { + if(property_get("av.offload.enable", propValue, NULL)) { + bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4); + if (!prop_enabled) { + ALOGW("offload disabled by av.offload.enable = %s ", propValue ); + return false; + } + } else { + return false; + } + + if(offloadInfo.is_streaming) { + if (property_get("av.streaming.offload.enable", propValue, NULL)) { + bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4); + if (!prop_enabled) { + ALOGW("offload disabled by av.streaming.offload.enable = %s ", propValue ); + return false; + } + } else { + //Do not offload AV streamnig if the property is not defined + return false; + } + } + ALOGV("isOffloadSupported: has_video == true, property\ + set to enable offload"); + } + } + + //If duration is less than minimum value defined in property, return false + if (property_get("audio.offload.min.duration.secs", propValue, NULL)) { + if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) { + ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue); + return false; + } + } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) { + ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS); + //duration checks only valid for MP3/AAC formats, + //do not check duration for other audio formats, e.g. dolby AAC/AC3 and amrwb+ formats + if (offloadInfo.format == AUDIO_FORMAT_MP3 || offloadInfo.format == AUDIO_FORMAT_AAC || pcmOffload) + return false; + } + + // Do not allow offloading if one non offloadable effect is enabled. This prevents from + // creating an offloaded track and tearing it down immediately after start when audioflinger + // detects there is an active non offloadable effect. + // FIXME: We should check the audio session here but we do not have it in this context. + // This may prevent offloading in rare situations where effects are left active by apps + // in the background. + if (isNonOffloadableEffectEnabled()) { + return false; + } + + // See if there is a profile to support this. + // AUDIO_DEVICE_NONE + IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */, + offloadInfo.sample_rate, + offloadInfo.format, + offloadInfo.channel_mask, + AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT "); + return (profile != NULL); +} + extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) { return new AudioPolicyManager(clientInterface); diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 7a8cfa911..5defa24ea 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -48,6 +48,8 @@ public: uint32_t format, uint32_t channels, AudioSystem::audio_in_acoustics acoustics); + virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); + protected: // return the strategy corresponding to a given stream type static routing_strategy getStrategy(AudioSystem::stream_type stream); -- GitLab From 0d66128fd4f0fd3ec17b34be1c76482c8c11c0e4 Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Sat, 22 Feb 2014 14:59:09 +0530 Subject: [PATCH 164/298] hal: Change device IDs of HFP DAI links for HFP in the machine driver of 8x26 were changed. Match the IDs in HAL with those in the kernel. Change-Id: I8996e7d8a150bf6550bf3fbf207f76a6d1d311df --- hal/msm8974/platform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 314835597..4dea9670e 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -212,8 +212,8 @@ enum { #endif #ifdef PLATFORM_MSM8x26 -#define HFP_SCO_RX 21 -#define HFP_ASM_RX_TX 22 +#define HFP_SCO_RX 28 +#define HFP_ASM_RX_TX 29 #else #define HFP_SCO_RX 23 #define HFP_ASM_RX_TX 24 -- GitLab From b979c67ced3240b30ec117b8c1d82c117d59387d Mon Sep 17 00:00:00 2001 From: Walter Yang Date: Fri, 21 Feb 2014 11:12:58 +0800 Subject: [PATCH 165/298] hal: Add the missing sound device of voice_speaker 8x10 skuab uses lineout path instead of speaker. Add the missing voice_speaker device in the array so that hal can select the correct path for voice speaker in 8x10 skuab. CRs-fixed: 621807 Change-Id: I5509184e368121cb1825392fce3860af20a9fa44 --- hal/msm8974/hw_info.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index 128e4afe2..f32ee44d3 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -121,6 +121,7 @@ static const snd_device_t helicon_skuab_variant_devices[] = { SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, + SND_DEVICE_OUT_VOICE_SPEAKER, }; static void update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name) -- GitLab From a0d835637ef913ec2478b3d963580c6cb138837b Mon Sep 17 00:00:00 2001 From: Bharath Ramachandramurthy Date: Tue, 14 Jan 2014 07:59:41 -0800 Subject: [PATCH 166/298] hal: Updated APIs to support Listen Multisession Update open_listen_session API to add listen_open_params. Change-Id: I203ef38676332a3054933750d200f1df36f0d097 --- hal/audio_extn/listen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c index 4a1980b71..91bb04ffd 100644 --- a/hal/audio_extn/listen.c +++ b/hal/audio_extn/listen.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -64,6 +64,7 @@ typedef int (*create_listen_hw_t)(unsigned int snd_card, typedef void (*destroy_listen_hw_t)(); typedef int (*open_listen_session_t)(struct audio_hw_device *, + struct listen_open_params*, struct listen_session**); typedef int (*close_listen_session_t)(struct audio_hw_device *dev, @@ -119,7 +120,6 @@ void audio_extn_listen_update_status(snd_device_t snd_device, void audio_extn_listen_set_parameters(struct audio_device *adev, struct str_parms *parms) { - ALOGV("%s: enter", __func__); if (listen_dev) { char *kv_pairs = str_parms_to_str(parms); -- GitLab From daa708c5df26065a4e9618a5f5588daddc38c43b Mon Sep 17 00:00:00 2001 From: ApurupaPattapu Date: Wed, 18 Dec 2013 15:47:59 -0800 Subject: [PATCH 167/298] audio: Set the correct audio format for ADTS - Widevine sends ADTS data, set ADTS based on the parameter Change-Id: I4c2376408e2998354db583a9f54649476a880f01 --- hal/audio_hw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 60b38a545..348508a30 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1337,11 +1337,21 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par struct compr_gapless_mdata tmp_mdata; tmp_mdata.encoder_delay = 0; tmp_mdata.encoder_padding = 0; + if (!out || !parms) { ALOGE("%s: return invalid ",__func__); return -EINVAL; } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FORMAT, value, sizeof(value)); + if (ret >= 0) { + if (atoi(value) == SND_AUDIOSTREAMFORMAT_MP4ADTS) { + out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS; + ALOGV("ADTS format is set in offload mode"); + } + out->send_new_metadata = 1; + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value)); if(ret >= 0) is_meta_data_params = true; @@ -2167,6 +2177,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->ch_in = popcount(config->channel_mask); out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; -- GitLab From c9965bb68c5b2ebd5742fd3ec7c429a7ece62bbe Mon Sep 17 00:00:00 2001 From: Avinash Vaish Date: Wed, 26 Feb 2014 17:26:48 +0530 Subject: [PATCH 168/298] hal: select LCH tone playback device based on platform -There was failure of LCH tone playback on some targets. -Required DAI Links were missing in the machine driver. -Make right selection of device for SCH tone playback on sub2 based on the platform. Change-Id: I04ab076a333725f98fb3f47eb6f1856cbcfe429c CRs-Fixed: 616154 CRs-Fixed: 571380 --- hal/msm8974/platform.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 4dea9670e..4a52b51c4 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -170,7 +170,6 @@ enum { #define HFP_PCM_RX 5 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 -#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 25 #define PLAYBACK_OFFLOAD_DEVICE 9 @@ -219,6 +218,12 @@ enum { #define HFP_ASM_RX_TX 24 #endif +#ifdef PLATFORM_MSM8610 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 15 +#else +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 +#endif + #define LIB_CSD_CLIENT "libcsd-client.so" /* CSD-CLIENT related functions */ typedef int (*init_t)(); -- GitLab From 3ed162b237b95ed623c9ef23ba04f638d5987d24 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Mon, 24 Feb 2014 17:56:01 -0800 Subject: [PATCH 169/298] hal: Fix for down-mixing of multi-ch offload playback - Check if multi-ch playback in offload path is active before re-configuring the HDMI channels Change-Id: If3639ffbbbc56083f9d09257ea4fafdc2b204e76 CRs-Fixed: 622339 --- hal/audio_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 60b38a545..fca3bd456 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1009,6 +1009,12 @@ static bool allow_hdmi_channel_config(struct audio_device *adev) "no change in HDMI channels", __func__); ret = false; break; + } else if (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD && + popcount(usecase->stream.out->channel_mask) > 2) { + ALOGD("%s: multi-channel(%x) compress offload playback is active, " + "no change in HDMI channels", __func__, usecase->stream.out->channel_mask); + ret = false; + break; } } } -- GitLab From 95a0943d4181a360a06e28b758aea142ad9336dd Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Tue, 25 Feb 2014 13:34:07 -0800 Subject: [PATCH 170/298] hal: set Dolby DMID for low latency playback - Remove additional check to set Dolby DMID for low latency playback. DMID should be set for all playback use cases. Change-Id: Ia93e1b13cc61145148a1bf520a222f8e480b3e2b CRs-Fixed: 620246 --- hal/audio_extn/dolby.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c index bcc7381cb..094f07712 100644 --- a/hal/audio_extn/dolby.c +++ b/hal/audio_extn/dolby.c @@ -430,8 +430,7 @@ void audio_extn_dolby_set_dmid(struct audio_device *adev) list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); - if ((usecase->type == PCM_PLAYBACK) && - (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) + if (usecase->type == PCM_PLAYBACK) send = true; } if (!send) -- GitLab From 739e7152580eb7daff0f957c8a15f906c8d008bf Mon Sep 17 00:00:00 2001 From: Vimal Puthanveed Date: Thu, 23 Jan 2014 15:56:53 -0800 Subject: [PATCH 171/298] hal: Check hfp usecase to differenciate between nb and wb - Need to check if the hfp session is WB or not before setting the device to avoid rerouting. CRs-Fixed: 605465 Change-Id: Ice6fd2776b89e5358004071b011ac304f35dbf58 --- hal/audio_extn/audio_extn.h | 2 ++ hal/audio_extn/hfp.c | 7 ++++++- hal/audio_hw.c | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index df7fd444f..3af95c795 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -184,8 +184,10 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev); #ifndef HFP_ENABLED #define audio_extn_hfp_is_active(adev) (0) +#define audio_extn_hfp_get_usecase() (0) #else bool audio_extn_hfp_is_active(struct audio_device *adev); +audio_usecase_t audio_extn_hfp_get_usecase(); #endif #ifndef HFP_ENABLED diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index 2d6e1e0cf..c48049068 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -220,7 +220,7 @@ static int32_t stop_hfp(struct audio_device *adev) bool audio_extn_hfp_is_active(struct audio_device *adev) { struct audio_usecase *hfp_usecase = NULL; - hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid); if (hfp_usecase != NULL) return true; @@ -228,6 +228,11 @@ bool audio_extn_hfp_is_active(struct audio_device *adev) return false; } +audio_usecase_t audio_extn_hfp_get_usecase() +{ + return hfpmod.ucid; +} + void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) { int ret; diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 60b38a545..7f8f73474 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -602,6 +602,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) struct audio_usecase *vc_usecase = NULL; struct audio_usecase *voip_usecase = NULL; struct audio_usecase *hfp_usecase = NULL; + audio_usecase_t hfp_ucid; struct listnode *node; int status = 0; @@ -641,7 +642,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) out_snd_device = voip_usecase->out_snd_device; } } else if (audio_extn_hfp_is_active(adev)) { - hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO); + hfp_ucid = audio_extn_hfp_get_usecase(); + hfp_usecase = get_usecase_from_list(adev, hfp_ucid); if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { in_snd_device = hfp_usecase->in_snd_device; out_snd_device = hfp_usecase->out_snd_device; -- GitLab From 111aeb3ab50b63c04bcb4cc748f54aa6715caf24 Mon Sep 17 00:00:00 2001 From: Vicky Sehrawat Date: Wed, 12 Feb 2014 17:58:59 -0800 Subject: [PATCH 172/298] hal: Add support for VoWLAN feature Add VoWLAN pcm id, usecase to enable voice over WLAN feature. Change-Id: I2d10ff06342bfcbef15a4769ba90deaeb4218107 --- hal/audio_hw.c | 1 + hal/audio_hw.h | 1 + hal/msm8974/platform.c | 1 + hal/msm8974/platform.h | 4 ++++ hal/voice.h | 2 +- hal/voice_extn/voice_extn.c | 14 +++++++++++++- 6 files changed, 21 insertions(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 7589f0e5f..49b209e8c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -119,6 +119,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_VOICE2_CALL] = "voice2-call", [USECASE_VOLTE_CALL] = "volte-call", [USECASE_QCHAT_CALL] = "qchat-call", + [USECASE_VOWLAN_CALL] = "vowlan-call", [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call", [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink", [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink", diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 205977b47..a6824c1b6 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -80,6 +80,7 @@ typedef enum { USECASE_VOICE2_CALL, USECASE_VOLTE_CALL, USECASE_QCHAT_CALL, + USECASE_VOWLAN_CALL, USECASE_COMPRESS_VOIP_CALL, USECASE_INCALL_REC_UPLINK, diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 074633c3c..10d034d28 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -125,6 +125,7 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE}, [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE}, + [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE}, [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE}, [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 3ea068dfb..83ead26b8 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -196,21 +196,25 @@ enum { #define VOICE2_CALL_PCM_DEVICE 14 #define VOLTE_CALL_PCM_DEVICE 17 #define QCHAT_CALL_PCM_DEVICE 18 +#define VOWLAN_CALL_PCM_DEVICE 30 #elif PLATFORM_APQ8084 #define VOICE_CALL_PCM_DEVICE 20 #define VOICE2_CALL_PCM_DEVICE 13 #define VOLTE_CALL_PCM_DEVICE 21 #define QCHAT_CALL_PCM_DEVICE 06 +#define VOWLAN_CALL_PCM_DEVICE -1 #elif PLATFORM_MSM8610 #define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 13 #define VOLTE_CALL_PCM_DEVICE 15 #define QCHAT_CALL_PCM_DEVICE 14 +#define VOWLAN_CALL_PCM_DEVICE -1 #else #define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 22 #define VOLTE_CALL_PCM_DEVICE 14 #define QCHAT_CALL_PCM_DEVICE 20 +#define VOWLAN_CALL_PCM_DEVICE -1 #endif #define LIB_CSD_CLIENT "libcsd-client.so" diff --git a/hal/voice.h b/hal/voice.h index a7733b1fd..5e4ce7fa2 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -24,7 +24,7 @@ #define VOICE_SESS_IDX (BASE_SESS_IDX) #ifdef MULTI_VOICE_SESSION_ENABLED -#define MAX_VOICE_SESSIONS 4 +#define MAX_VOICE_SESSIONS 5 #else #define MAX_VOICE_SESSIONS 1 #endif diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 5612e0c4d..f2dc6bc78 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -44,12 +44,14 @@ #define VOICE2_VSID 0x10DC1000 #define VOLTE_VSID 0x10C02000 #define QCHAT_VSID 0x10803000 +#define VOWLAN_VSID 0x10002000 #define ALL_VSID 0xFFFFFFFF /* Voice Session Indices */ #define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1) #define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2) #define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3) +#define VOWLAN_SESS_IDX (VOICE_SESS_IDX + 4) /* Call States */ #define CALL_HOLD (BASE_CALL_STATE + 2) @@ -83,7 +85,8 @@ static bool is_valid_vsid(uint32_t vsid) if (vsid == VOICE_VSID || vsid == VOICE2_VSID || vsid == VOLTE_VSID || - vsid == QCHAT_VSID) + vsid == QCHAT_VSID || + vsid == VOWLAN_VSID) return true; else return false; @@ -110,6 +113,10 @@ static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index) usecase_id = USECASE_QCHAT_CALL; break; + case VOWLAN_SESS_IDX: + usecase_id = USECASE_VOWLAN_CALL; + break; + default: ALOGE("%s: Invalid voice session index\n", __func__); } @@ -353,6 +360,7 @@ void voice_extn_init(struct audio_device *adev) adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID; adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID; adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID; + adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID; } int voice_extn_get_session_from_use_case(struct audio_device *adev, @@ -378,6 +386,10 @@ int voice_extn_get_session_from_use_case(struct audio_device *adev, *session = &adev->voice.session[QCHAT_SESS_IDX]; break; + case USECASE_VOWLAN_CALL: + *session = &adev->voice.session[VOWLAN_SESS_IDX]; + break; + default: ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id); *session = NULL; -- GitLab From 9b7e96b5afdbd4dbcf566b3854e6fef44cf92259 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Fri, 14 Feb 2014 14:45:49 -0800 Subject: [PATCH 173/298] hal: Update the correct channel count for dolby configuration -Wfd supports both 5.1 and stereo. Based on the sink capabilities update the correct channel count for dolby configuration for wfd. CRs-Fixed: 609429 Change-Id: I85b81ba7db7134a6781007393f0f3c2adb5ea138 --- hal/audio_extn/audio_extn.c | 8 +++++--- hal/audio_extn/dolby.c | 36 +++++++++++++++++++++++++++--------- hal/audio_hw.c | 1 + hal/audio_hw.h | 1 + 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index ad487b1c1..5530f5f50 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -131,7 +131,7 @@ void audio_extn_set_anc_parameters(struct audio_device *adev, #endif /* ANC_HEADSET_ENABLED */ #ifndef AFE_PROXY_ENABLED -#define audio_extn_set_afe_proxy_parameters(parms) (0) +#define audio_extn_set_afe_proxy_parameters(adev, parms) (0) #define audio_extn_get_afe_proxy_parameters(query, reply) (0) #else /* Front left channel. */ @@ -247,7 +247,8 @@ int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) return ret; } -void audio_extn_set_afe_proxy_parameters(struct str_parms *parms) +void audio_extn_set_afe_proxy_parameters(struct audio_device *adev, + struct str_parms *parms) { int ret, val; char value[32]={0}; @@ -257,6 +258,7 @@ void audio_extn_set_afe_proxy_parameters(struct str_parms *parms) if (ret >= 0) { val = atoi(value); aextnmod.proxy_channel_num = val; + adev->cur_wfd_channels = val; ALOGD("%s: channel capability set to: %d", __func__, aextnmod.proxy_channel_num); } @@ -315,7 +317,7 @@ void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms) { audio_extn_set_anc_parameters(adev, parms); - audio_extn_set_afe_proxy_parameters(parms); + audio_extn_set_afe_proxy_parameters(adev, parms); audio_extn_fm_set_parameters(adev, parms); audio_extn_listen_set_parameters(adev, parms); audio_extn_hfp_set_parameters(adev, parms); diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c index 094f07712..99fa2b7b4 100644 --- a/hal/audio_extn/dolby.c +++ b/hal/audio_extn/dolby.c @@ -64,7 +64,7 @@ /* DS1-DDP Endp Params */ #define DDP_ENDP_NUM_PARAMS 17 -#define DDP_ENDP_NUM_DEVICES 22 +#define DDP_ENDP_NUM_DEVICES 23 static int ddp_endp_params_id[DDP_ENDP_NUM_PARAMS] = { PARAM_ID_MAX_OUTPUT_CHANNELS, PARAM_ID_CTL_RUNNING_MODE, PARAM_ID_CTL_ERROR_CONCEAL, PARAM_ID_CTL_ERROR_MAX_RPTS, @@ -147,7 +147,10 @@ static struct ddp_endp_params { {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, {AUDIO_DEVICE_OUT_PROXY, 2, - {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, + {AUDIO_DEVICE_OUT_PROXY, 6, + {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, }; @@ -264,9 +267,16 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev) (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && ((usecase->stream.out->format == AUDIO_FORMAT_AC3) || (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) { + /* + * Use wfd /hdmi sink channel cap for dolby params if device is wfd + * or hdmi. Otherwise use stereo configuration + */ + int channel_cap = usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? + adev->cur_hdmi_channels : + usecase->devices & AUDIO_DEVICE_OUT_PROXY ? + adev->cur_wfd_channels : 2; send_ddp_endp_params_stream(usecase->stream.out, usecase->devices, - usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? - adev->cur_hdmi_channels : 2, false /* set cache */); + channel_cap, false /* set cache */); } } } @@ -334,7 +344,9 @@ void audio_extn_ddp_set_parameters(struct audio_device *adev, update_ddp_endp_table(ddp_dev, dev_ch_cap, PARAM_ID_OUT_CTL_STEREO_MODE, val); } - + /* TODO: Do we need device channel caps here? + * We dont have that information as this is from dolby modules + */ send_ddp_endp_params(adev, ddp_dev, dev_ch_cap); } @@ -343,13 +355,20 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev, audio_format_t format) { int id = 0; + /* + * Use wfd /hdmi sink channel cap for dolby params if device is wfd + * or hdmi. Otherwise use stereo configuration + */ + int channel_cap = out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? + adev->cur_hdmi_channels : + out->devices & AUDIO_DEVICE_OUT_PROXY ? + adev->cur_wfd_channels : 2; switch (format) { case AUDIO_FORMAT_AC3: id = SND_AUDIOCODEC_AC3; send_ddp_endp_params_stream(out, out->devices, - out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? - adev->cur_hdmi_channels : 2, true /* set_cache */); + channel_cap, true /* set_cache */); #ifndef DS1_DOLBY_DAP_ENABLED audio_extn_dolby_set_dmid(adev); #endif @@ -357,8 +376,7 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev, case AUDIO_FORMAT_EAC3: id = SND_AUDIOCODEC_EAC3; send_ddp_endp_params_stream(out, out->devices, - out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ? - adev->cur_hdmi_channels : 2, true /* set_cache */); + channel_cap, true /* set_cache */); #ifndef DS1_DOLBY_DAP_ENABLED audio_extn_dolby_set_dmid(adev); #endif diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fca3bd456..33e20fb04 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2665,6 +2665,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); voice_init(adev); list_init(&adev->usecase_list); + adev->cur_wfd_channels = 2; /* Loads platform specific libraries dynamically */ adev->platform = platform_init(adev); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 205977b47..21b77909e 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -223,6 +223,7 @@ struct audio_device { bool speaker_lr_swap; struct voice voice; unsigned int cur_hdmi_channels; + unsigned int cur_wfd_channels; int snd_card; void *platform; -- GitLab From 8267074a96ed1b1f1a51da07f45331b3c9444477 Mon Sep 17 00:00:00 2001 From: wjiang Date: Mon, 24 Feb 2014 22:19:43 +0800 Subject: [PATCH 174/298] post_proc: send ENABLE_FLAG directly to offload effect driver Enable flag should be sent directly through offload effect driver to adsp whenever bundle receives EFFECT_CMD_ENABLE. Otherwise enablement will only take effect in adsp after subsequent parameters being set, and that's not expected. Change-Id: I5a8f936095b5667f0e04b9109b67eaa0faec3a69 --- post_proc/bass_boost.c | 9 +++++++-- post_proc/virtualizer.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c index c724b5822..53ec77f00 100644 --- a/post_proc/bass_boost.c +++ b/post_proc/bass_boost.c @@ -211,9 +211,14 @@ int bassboost_enable(effect_context_t *context) bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; ALOGV("%s", __func__); - - if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) + if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); + if (bass_ctxt->ctl && bass_ctxt->strength) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + } return 0; } diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c index e9eb728cc..3f65f0062 100644 --- a/post_proc/virtualizer.c +++ b/post_proc/virtualizer.c @@ -210,9 +210,14 @@ int virtualizer_enable(effect_context_t *context) virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; ALOGV("%s", __func__); - - if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) + if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); + if (virt_ctxt->ctl && virt_ctxt->strength) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + } return 0; } -- GitLab From d797e17dd0726581e3ffe2a51095bccd573ad3cb Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Mon, 27 Jan 2014 16:52:50 -0800 Subject: [PATCH 175/298] mm-audio: Update bitrate based on profile and samplerate As per AAC specification bitrate is a function of profile and sample rate. Change ensures that bitrate will be programmed as per the specification. Change-Id: I188f7155c50c32b7c9945036c0ad0ef3f5ee164a CRs-fixed: 606251 --- mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h | 8 ++- mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp | 51 ++++++++++++++++++-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h index 276eaa351..623caa863 100644 --- a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h +++ b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h @@ -1,5 +1,5 @@ /*-------------------------------------------------------------------------- -Copyright (c) 2010, The Linux Foundation. All rights reserved. +Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -358,7 +358,10 @@ private: OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7 }; - + #define MIN_BITRATE 24000 + #define MAX_BITRATE 192000 + #define MAX_BITRATE_MULFACTOR 12 + #define BITRATE_DIVFACTOR 2 typedef Map input_buffer_map; @@ -619,6 +622,7 @@ private: OMX_U8 num_bits_reqd, OMX_U32 value, OMX_U16 *hdr_bit_index); + int get_updated_bit_rate(int bitrate); }; #endif diff --git a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp index 52aa915fb..652126588 100644 --- a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp +++ b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp @@ -1,5 +1,5 @@ /*-------------------------------------------------------------------------- -Copyright (c) 2010, The Linux Foundation. All rights reserved. +Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -1438,10 +1438,12 @@ OMX_ERRORTYPE omx_aac_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, } drv_aac_enc_config.channels = m_aac_param.nChannels; drv_aac_enc_config.sample_rate = m_aac_param.nSampleRate; - drv_aac_enc_config.bit_rate = m_aac_param.nBitRate; - DEBUG_PRINT("aac config %lu,%lu,%lu %d\n", + drv_aac_enc_config.bit_rate = + get_updated_bit_rate(m_aac_param.nBitRate); + DEBUG_PRINT("aac config %lu,%lu,%lu %d updated bitrate %d\n", m_aac_param.nChannels,m_aac_param.nSampleRate, - m_aac_param.nBitRate,m_aac_param.eAACStreamFormat); + m_aac_param.nBitRate,m_aac_param.eAACStreamFormat, + drv_aac_enc_config.bit_rate); switch(m_aac_param.eAACStreamFormat) { @@ -5014,3 +5016,44 @@ void omx_aac_aenc::audaac_rec_install_mp4ff_header_variable (OMX_U16 byte_num, } +int omx_aac_aenc::get_updated_bit_rate(int bitrate) +{ + int updated_rate, min_bitrate, max_bitrate; + + max_bitrate = m_aac_param.nSampleRate * + MAX_BITRATE_MULFACTOR; + switch(m_aac_param.eAACProfile) + { + case OMX_AUDIO_AACObjectLC: + min_bitrate = m_aac_param.nSampleRate; + if (m_aac_param.nChannels == 1) { + min_bitrate = min_bitrate/BITRATE_DIVFACTOR; + max_bitrate = max_bitrate/BITRATE_DIVFACTOR; + } + break; + case OMX_AUDIO_AACObjectHE: + min_bitrate = MIN_BITRATE; + if (m_aac_param.nChannels == 1) + max_bitrate = max_bitrate/BITRATE_DIVFACTOR; + break; + case OMX_AUDIO_AACObjectHE_PS: + min_bitrate = MIN_BITRATE; + break; + default: + return bitrate; + break; + } + /* Update MIN and MAX values*/ + if (min_bitrate > MIN_BITRATE) + min_bitrate = MIN_BITRATE; + if (max_bitrate > MAX_BITRATE) + max_bitrate = MAX_BITRATE; + /* Update the bitrate in the range */ + if (bitrate < min_bitrate) + updated_rate = min_bitrate; + else if(bitrate > max_bitrate) + updated_rate = max_bitrate; + else + updated_rate = bitrate; + return updated_rate; +} -- GitLab From b0dabd28b2873969603dd1fee8b5e4ea38de64df Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Mon, 10 Mar 2014 14:56:04 +0530 Subject: [PATCH 176/298] audio: Disabled excessive logging in OMX AACEncoder - Too many debug logs are enabled in AAC Encoder by default - Fix is to disable all the logs except the error messages and logs indicating loading and unloading of the encoder Change-Id: If4b37fb654b1c70796bfdc1c839839fab3ea20dc CRs-Fixed: 619677 --- mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h index 72bfebed2..9bc72009e 100644 --- a/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h +++ b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h @@ -60,7 +60,7 @@ extern "C" { #endif #define DEBUG_PRINT_ERROR LOGE -#define DEBUG_PRINT LOGI +#define DEBUG_PRINT LOGV #define DEBUG_DETAIL LOGV typedef void (*message_func)(void* client_data, unsigned char id); -- GitLab From 5bdb70534aa4474c0f6400a7f6528cb3068a6b38 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Wed, 5 Mar 2014 17:45:03 -0800 Subject: [PATCH 177/298] hal: update playback channel mapping for USB headset - Set proper USB headset channel mapping before starting playback. - Update audio_extn_set_afe_proxy_channel_mixer to handle channel mapping based on channel count. CRs-Fixed: 620828 Change-Id: I9660e3088bc747c30891b0aa7ec8d22096dd0fa2 --- hal/audio_extn/audio_extn.c | 30 +++++++++++++++++++++--------- hal/audio_extn/audio_extn.h | 10 +++++++--- hal/msm8974/platform.c | 7 +++++-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 5530f5f50..3bc72de1a 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -168,6 +168,10 @@ static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev, ALOGV("%s channel_count:%d",__func__, channel_count); switch (channel_count) { + case 2: + set_values[0] = PCM_CHANNEL_FL; + set_values[1] = PCM_CHANNEL_FR; + break; case 6: set_values[0] = PCM_CHANNEL_FL; set_values[1] = PCM_CHANNEL_FR; @@ -205,7 +209,8 @@ static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev, return ret; } -int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) +int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev, + int channel_count) { int32_t ret = 0; const char *channel_cnt_str = NULL; @@ -216,9 +221,8 @@ int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) /* use the existing channel count set by hardware params to configure the back end for stereo as usb/a2dp would be stereo by default */ - ALOGD("%s: channels = %d", __func__, - aextnmod.proxy_channel_num); - switch (aextnmod.proxy_channel_num) { + ALOGD("%s: channels = %d", __func__, channel_count); + switch (channel_count) { case 8: channel_cnt_str = "Eight"; break; case 7: channel_cnt_str = "Seven"; break; case 6: channel_cnt_str = "Six"; break; @@ -228,7 +232,7 @@ int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) default: channel_cnt_str = "Two"; break; } - if(aextnmod.proxy_channel_num >= 2 && aextnmod.proxy_channel_num < 8) { + if(channel_count >= 2 && channel_count <= 8) { ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { ALOGE("%s: could not get ctl for mixer cmd - %s", @@ -238,10 +242,12 @@ int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev) } mixer_ctl_set_enum_by_string(ctl, channel_cnt_str); - if (aextnmod.proxy_channel_num == 6 || - aextnmod.proxy_channel_num == 8) - ret = afe_proxy_set_channel_mapping(adev, - aextnmod.proxy_channel_num); + if (channel_count == 6 || channel_count == 8 || channel_count == 2) { + ret = afe_proxy_set_channel_mapping(adev, channel_count); + } else { + ALOGE("%s: set unsupported channel count(%d)", __func__, channel_count); + ret = -EINVAL; + } ALOGD("%s: exit", __func__); return ret; @@ -311,6 +317,12 @@ int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out) } return ret; } + +int32_t audio_extn_get_afe_proxy_channel_count() +{ + return aextnmod.proxy_channel_num; +} + #endif /* AFE_PROXY_ENABLED */ void audio_extn_set_parameters(struct audio_device *adev, diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 3af95c795..af0b2856c 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -40,11 +40,15 @@ bool audio_extn_should_use_handset_anc(int in_channels); #endif #ifndef AFE_PROXY_ENABLED -#define audio_extn_set_afe_proxy_channel_mixer(adev) (0) -#define audio_extn_read_afe_proxy_channel_masks(out) (0) +#define audio_extn_set_afe_proxy_channel_mixer(adev,channel_count) (0) +#define audio_extn_read_afe_proxy_channel_masks(out) (0) +#define audio_extn_get_afe_proxy_channel_count() (0) #else -int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev); +int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev, + int channel_count); int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out); +int32_t audio_extn_get_afe_proxy_channel_count(); + #endif #ifndef USB_HEADSET_ENABLED diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index fb45c28f7..5842ed446 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -996,14 +996,17 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_HDMI ; } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { + ALOGD("%s: setting USB hadset channel capability(2) for Proxy", __func__); + audio_extn_set_afe_proxy_channel_mixer(adev, 2); snd_device = SND_DEVICE_OUT_USB_HEADSET; } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { snd_device = SND_DEVICE_OUT_HANDSET; } else if (devices & AUDIO_DEVICE_OUT_PROXY) { - ALOGD("%s: setting sink capability for Proxy", __func__); - audio_extn_set_afe_proxy_channel_mixer(adev); + channel_count = audio_extn_get_afe_proxy_channel_count(); + ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count); + audio_extn_set_afe_proxy_channel_mixer(adev, channel_count); snd_device = SND_DEVICE_OUT_AFE_PROXY; } else { ALOGE("%s: Unknown device(s) %#x", __func__, devices); -- GitLab From cae30b12ad0b257cfc55c7e0c968b86734324e01 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Fri, 7 Feb 2014 17:03:21 -0800 Subject: [PATCH 178/298] hal: HFP support for setting volume -Add support for setting volume using setparameter. Change-Id: Id614d719324ab6b280116fd952c3fa73844ce1b0 --- hal/audio_extn/hfp.c | 63 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index c48049068..57d1f0c5c 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -1,5 +1,5 @@ /* hfp.c -Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -43,6 +43,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ #ifdef HFP_ENABLED #define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable" #define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate" +#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume" static int32_t start_hfp(struct audio_device *adev, struct str_parms *parms); @@ -55,7 +56,7 @@ struct hfp_module { struct pcm *hfp_pcm_rx; struct pcm *hfp_pcm_tx; bool is_hfp_running; - int hfp_volume; + float hfp_volume; audio_usecase_t ucid; }; @@ -79,6 +80,46 @@ static struct pcm_config pcm_config_hfp = { .avail_min = 0, }; +static int32_t hfp_set_volume(struct audio_device *adev, float value) +{ + int32_t vol, ret = 0; + struct mixer_ctl *ctl; + const char *mixer_ctl_name = "Internal HFP RX Volume"; + + ALOGV("%s: entry", __func__); + ALOGD("%s: (%f)\n", __func__, value); + + if (value < 0.0) { + ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value); + value = 0.0; + } else { + value = ((value > 15.000000) ? 1.0 : (value / 15)); + ALOGW("%s: Volume brought with in range (%f)\n", __func__, value); + } + vol = lrint((value * 0x2000) + 0.5); + hfpmod.hfp_volume = value; + + if (!hfpmod.is_hfp_running) { + ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__); + return -EIO; + } + + ALOGD("%s: Setting HFP volume to %d \n", __func__, vol); + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + if(mixer_ctl_set_value(ctl, 0, vol) < 0) { + ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol); + return -EINVAL; + } + + ALOGV("%s: exit", __func__); + return ret; +} + static int32_t start_hfp(struct audio_device *adev, struct str_parms *parms) { @@ -158,8 +199,8 @@ static int32_t start_hfp(struct audio_device *adev, pcm_start(hfpmod.hfp_pcm_rx); pcm_start(hfpmod.hfp_pcm_tx); - hfpmod.is_hfp_running = true; + hfp_set_volume(adev, hfpmod.hfp_volume); ALOGD("%s: exit: status(%d)", __func__, ret); return 0; @@ -238,6 +279,7 @@ void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms * int ret; int rate; int val; + float vol; char value[32]={0}; ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, @@ -275,5 +317,20 @@ void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms * select_devices(adev, hfpmod.ucid); } } + + memset(value, 0, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME, + value, sizeof(value)); + if (ret >= 0) { + if (sscanf(value, "%f", &vol) != 1){ + ALOGE("%s: error in retrieving hfp volume", __func__); + ret = -EIO; + goto exit; + } + ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol); + hfp_set_volume(adev, vol); + } +exit: + ALOGV("%s Exit",__func__); } #endif /*HFP_ENABLED*/ -- GitLab From 28261e9eb1ec9da7f38d20be1287ea54040acbe3 Mon Sep 17 00:00:00 2001 From: ApurupaPattapu Date: Wed, 5 Mar 2014 11:13:32 -0800 Subject: [PATCH 179/298] hal: Fix error in log message - Fix a compilation error in verbose log message Change-Id: I2a977f1af7fd568372988f30c5b51b45619f65c3 --- hal/msm8974/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index fb45c28f7..6514c9689 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1615,7 +1615,7 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) if (info != NULL && info->has_video && info->is_streaming) { fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING; ALOGV("%s: offload fragment size reduced for AV streaming to %d", - __func__, out->compr_config.fragment_size); + __func__, fragment_size); } fragment_size = ALIGN( fragment_size, 1024); -- GitLab From 31cf24c69e7855005f25e898bda5a91c1ec139e1 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Fri, 7 Mar 2014 11:40:24 -0800 Subject: [PATCH 180/298] hal: Add support for EC in regular audio recording - Ensure EC reference is set when the source is MIC and fluence is enabled in the regular audio recording path. Change-Id: I6648f41fcc578ded13e4fecdb7ef35bc6b0579d4 CRs-Fixed: 628085 --- hal/msm8974/platform.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 37dea7d53..1f4e3d576 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1176,8 +1176,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC && channel_count == 1 ) { if(my_data->fluence_type & FLUENCE_DUAL_MIC && - my_data->fluence_in_audio_rec) + my_data->fluence_in_audio_rec) { snd_device = SND_DEVICE_IN_HANDSET_DMIC; + set_echo_reference(adev->mixer, EC_REF_RX); + } } } else if (source == AUDIO_SOURCE_FM_RX || source == AUDIO_SOURCE_FM_RX_A2DP) { -- GitLab From 575c155665e2a3df31d99e62238521b264ea3d95 Mon Sep 17 00:00:00 2001 From: Shiv Maliyappanahalli Date: Fri, 7 Mar 2014 15:31:55 -0800 Subject: [PATCH 181/298] hal: add support for device mute Add support for muting the RX and TX devices without affecting the voice stream. This feature is added to enable voice call quality testing by carriers. CRs-Fixed: 634690 Change-Id: I4d0f599e44ae24ce02d29333f496ef18f889ac55 --- hal/msm8960/platform.c | 6 ++++++ hal/msm8974/platform.c | 38 +++++++++++++++++++++++++++++++++++++ hal/platform_api.h | 1 + hal/voice_extn/voice_extn.c | 33 ++++++++++++++++++++++++++++++-- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 298c60d8f..dacf68e40 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -551,6 +551,12 @@ int platform_set_mic_mute(void *platform, bool state) return ret; } +int platform_set_device_mute(void *platform, bool state, char *dir) +{ + LOGE("%s: Not implemented", __func__); + return -ENOSYS; +} + snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices) { struct platform_data *my_data = (struct platform_data *)platform; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1f4e3d576..1188c231e 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -872,6 +872,44 @@ int platform_set_mic_mute(void *platform, bool state) return ret; } +int platform_set_device_mute(void *platform, bool state, char *dir) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + struct mixer_ctl *ctl; + char *mixer_ctl_name = NULL; + int ret = 0; + uint32_t set_values[ ] = {0, + ALL_SESSION_VSID, + 0}; + if(dir == NULL) { + ALOGE("%s: Invalid direction:%s", __func__, dir); + return -EINVAL; + } + + if (!strncmp("rx", dir, sizeof("rx"))) { + mixer_ctl_name = "Voice Rx Device Mute"; + } else if (!strncmp("tx", dir, sizeof("tx"))) { + mixer_ctl_name = "Voice Tx Device Mute"; + } else { + return -EINVAL; + } + + set_values[0] = state; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + + ALOGV("%s: Setting device mute state: %d, mixer ctrl:%s", + __func__,state, mixer_ctl_name); + mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values)); + + return ret; +} + snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices) { struct platform_data *my_data = (struct platform_data *)platform; diff --git a/hal/platform_api.h b/hal/platform_api.h index 306aaadda..9e8727534 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -39,6 +39,7 @@ int platform_start_voice_call(void *platform, uint32_t vsid); int platform_stop_voice_call(void *platform, uint32_t vsid); int platform_set_voice_volume(void *platform, int volume); int platform_set_mic_mute(void *platform, bool state); +int platform_set_device_mute(void *platform, bool state, char *dir); snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices); snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device); int platform_set_hdmi_channels(void *platform, int channel_count); diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index f2dc6bc78..f6083f3d1 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -38,6 +38,8 @@ #define AUDIO_PARAMETER_KEY_CALL_STATE "call_state" #define AUDIO_PARAMETER_KEY_AUDIO_MODE "audio_mode" #define AUDIO_PARAMETER_KEY_ALL_CALL_STATES "all_call_states" +#define AUDIO_PARAMETER_KEY_DEVICE_MUTE "device_mute" +#define AUDIO_PARAMETER_KEY_DIRECTION "direction" #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256 @@ -440,6 +442,7 @@ int voice_extn_set_parameters(struct audio_device *adev, int value; int ret = 0, err; char *kv_pairs = str_parms_to_str(parms); + char str_value[256] = {0}; ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); @@ -465,8 +468,34 @@ int voice_extn_set_parameters(struct audio_device *adev, ret = -EINVAL; goto done; } - } else { - ALOGV("%s: Not handled here", __func__); + } + + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE, str_value, + sizeof(str_value)); + if (err >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE); + bool mute = false; + + if (!strncmp("true", str_value, sizeof("true"))) { + mute = true; + } + + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DIRECTION, str_value, + sizeof(str_value)); + if (err >= 0) { + str_parms_del(parms, AUDIO_PARAMETER_KEY_DIRECTION); + } else { + ALOGE("%s: direction key not found", __func__); + ret = -EINVAL; + goto done; + } + + ret = platform_set_device_mute(adev->platform, mute, str_value); + if (ret != 0) { + ALOGE("%s: Failed to set mute err:%d", __func__, ret); + ret = -EINVAL; + goto done; + } } done: -- GitLab From 52abe0b44e74cbe9b38735ccf0ff4ad7a1f7154b Mon Sep 17 00:00:00 2001 From: Avinash Vaish Date: Fri, 14 Mar 2014 21:04:19 +0530 Subject: [PATCH 182/298] hal: add incall music uplink2 pcm id - There is no LCH tone playback on sub2 since the pcm ID and the DAI links are missing for 8974. - Add pcm id for 8974. Change-Id: I45dec8af4f384c00e015ad0229d4dce550a8a371 CRs-Fixed: 626562 --- hal/msm8974/platform.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index b71ae297b..0ea57ae52 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -170,6 +170,17 @@ enum { #define HFP_PCM_RX 5 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1 + +#ifdef PLATFORM_MSM8610 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 15 +#elif PLATFORM_MSM8x26 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 +#elif PLATFORM_MSM8974 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 35 +#else +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE -1 +#endif + #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 25 #define PLAYBACK_OFFLOAD_DEVICE 9 @@ -222,12 +233,6 @@ enum { #define HFP_ASM_RX_TX 24 #endif -#ifdef PLATFORM_MSM8610 -#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 15 -#else -#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 -#endif - #define LIB_CSD_CLIENT "libcsd-client.so" /* CSD-CLIENT related functions */ typedef int (*init_t)(); -- GitLab From e6fff40e4e2674e8fc8305d68514ff74004c4293 Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Wed, 12 Mar 2014 14:13:09 -0700 Subject: [PATCH 183/298] hal: Clear VI feedback cal after VI capture path is started When speaker protection is enabled, afe TX common calibration will be pointing to VI feedback calibration. If any TX capture usecase is started by passing HAL(tinycap), recording will fail. Speaker protection module will set the afe tx common cal block to handset mic once VI feedback path is started. This will ensure that capture usecases can be supported with speaker protection enabled and HAL by passed. Change-Id: I1716d66aa87591b7a7e456ed059c2f75de8a5f84 CRs-fixed: 620979 --- hal/audio_extn/spkr_protection.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c index 5ec7ebaf1..6c0eec0b7 100644 --- a/hal/audio_extn/spkr_protection.c +++ b/hal/audio_extn/spkr_protection.c @@ -633,7 +633,11 @@ int audio_extn_spkr_prot_start_processing(snd_device_t snd_device) ret = -EINVAL; } } + exit: + /* Clear VI feedback cal and replace with handset MIC */ + platform_send_audio_calibration(adev->platform, + SND_DEVICE_IN_HANDSET_MIC); if (ret) { if (handle.pcm_tx) pcm_close(handle.pcm_tx); -- GitLab From c9bf40d3769c14fe13046165de2b3bd9634273e9 Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Thu, 6 Feb 2014 14:05:14 -0800 Subject: [PATCH 184/298] hal: apply TTY mode change for all voice use cases Update devices for Voice2, VoLTE and QCHAT sessions based on the TTY mode. This change is needed to support enabling/disabling and switching TTY mode during voice call. Change-Id: I4f1fde8ce6b20fad0d24e0cd963e2c3709ff25d5 CRs-fixed: 608183 --- hal/audio_hw.c | 17 +---------------- hal/voice.c | 18 ++++++++++++++++-- hal/voice.h | 1 + 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index f0b745b63..c0d47d925 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -551,21 +551,6 @@ static int read_hdmi_channel_masks(struct stream_out *out) return ret; } -static void update_devices_for_all_voice_usecases(struct audio_device *adev) -{ - struct listnode *node; - struct audio_usecase *usecase; - - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == VOICE_CALL) { - ALOGV("%s: updating device for usecase:%s", __func__, - use_case_table[usecase->id]); - select_devices(adev, usecase->id); - } - } -} - static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev) { struct audio_usecase *usecase; @@ -1457,7 +1442,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } else if ((adev->mode == AUDIO_MODE_IN_CALL) && voice_is_in_call(adev) && (out == adev->primary_output)) { - update_devices_for_all_voice_usecases(adev); + voice_update_devices_for_all_voice_usecases(adev); } } diff --git a/hal/voice.c b/hal/voice.c index 28d44db8f..82813f6a8 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -397,8 +397,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) adev->voice.tty_mode = tty_mode; adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode; if (voice_is_in_call(adev)) - //todo: what about voice2, volte and qchat usecases? - select_devices(adev, USECASE_VOICE_CALL); + voice_update_devices_for_all_voice_usecases(adev); } } @@ -438,4 +437,19 @@ void voice_init(struct audio_device *adev) voice_extn_init(adev); } +void voice_update_devices_for_all_voice_usecases(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == VOICE_CALL) { + ALOGV("%s: updating device for usecase:%s", __func__, + use_case_table[usecase->id]); + select_devices(adev, usecase->id); + } + } +} + diff --git a/hal/voice.h b/hal/voice.h index 5e4ce7fa2..d160569d8 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -86,4 +86,5 @@ int voice_check_and_set_incall_music_usecase(struct audio_device *adev, struct stream_out *out); int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev, struct stream_in *in); +void voice_update_devices_for_all_voice_usecases(struct audio_device *adev); #endif //VOICE_H -- GitLab From 0c9194fe77c8a9b3b35c5711f9dbbbebdc2ff30d Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Fri, 21 Mar 2014 17:33:03 -0700 Subject: [PATCH 185/298] hal: Fix compilation issue when Dolby DS1 feature is disabled Correct the input arguments to fix the compile time issue when the Dolby DS1 feature is disabled. Change-Id: I85e77d8b6549a98b9635640820cfa78dd3c89df4 CRs-Fixed: 636548 --- hal/audio_extn/audio_extn.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index af0b2856c..96e8a5fae 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -166,7 +166,7 @@ void audio_extn_dolby_set_dmid(struct audio_device *adev); #endif #ifndef DS1_DOLBY_DDP_ENABLED -#define audio_extn_dolby_set_endpoint() (0) +#define audio_extn_dolby_set_endpoint(adev) (0) #else void audio_extn_dolby_set_endpoint(struct audio_device *adev); #endif @@ -174,7 +174,7 @@ void audio_extn_dolby_set_endpoint(struct audio_device *adev); #ifndef DS1_DOLBY_DDP_ENABLED #define audio_extn_ddp_set_parameters(adev, parms) (0) #define audio_extn_is_dolby_format(format) (0) -#define audio_extn_dolby_get_snd_codec_id(format) (0) +#define audio_extn_dolby_get_snd_codec_id(adev, out, format) (0) #define audio_extn_dolby_send_ddp_endp_params(adev) (0) #else bool audio_extn_is_dolby_format(audio_format_t format); -- GitLab From 120b9ea1200d344d8b0d2362bc6e6ea1a00063f0 Mon Sep 17 00:00:00 2001 From: wjiang Date: Tue, 18 Mar 2014 06:43:48 +0800 Subject: [PATCH 186/298] post_proc: reverb preset id is not mapped correctly Array index is not correct and causes uninitialized value being used when 'Plate' is chosen. Correct index to retrieve the right preset id. Change-Id: I2ad058bc7dc5d9b74882da2f5d4c0e3570f9e952 CRs-Fixed: 630429 --- post_proc/effect_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c index a2e4f45fe..570ca8b51 100644 --- a/post_proc/effect_api.c +++ b/post_proc/effect_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -391,7 +391,7 @@ void offload_reverb_set_preset(struct reverb_params *reverb, int preset) { ALOGV("%s", __func__); if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED)) - reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset][1]; + reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset-1][1]; } void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix) -- GitLab From 36f75bce542dcc492a6c38035b303247f4e0587d Mon Sep 17 00:00:00 2001 From: wjiang Date: Tue, 18 Mar 2014 06:49:46 +0800 Subject: [PATCH 187/298] post_proc: disable Bassboost and Virtualizer for certain devices WFD, Hdmi and usb audio are not intended to be applied with SA+ bassboost and virtualizer, so add into invalid device list. Change-Id: Ifcf9cdffb6657cf82bf903d16d4a3ae8471590f0 CRs-Fixed: 630408 --- post_proc/bass_boost.c | 7 +++++-- post_proc/virtualizer.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c index c64ba6bc4..e0d1cd2a3 100644 --- a/post_proc/bass_boost.c +++ b/post_proc/bass_boost.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -153,7 +153,10 @@ int bassboost_set_device(effect_context_t *context, uint32_t device) bass_ctxt->device = device; if((device == AUDIO_DEVICE_OUT_SPEAKER) || (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || - (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) { + (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) || + (device == AUDIO_DEVICE_OUT_PROXY) || + (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) || + (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) { if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); bass_ctxt->temp_disabled = true; diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c index 2f0ca6b87..d79f31fad 100644 --- a/post_proc/virtualizer.c +++ b/post_proc/virtualizer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -153,7 +153,10 @@ int virtualizer_set_device(effect_context_t *context, uint32_t device) virt_ctxt->device = device; if((device == AUDIO_DEVICE_OUT_SPEAKER) || (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || - (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) { + (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) || + (device == AUDIO_DEVICE_OUT_PROXY) || + (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) || + (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) { if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); virt_ctxt->temp_disabled = true; -- GitLab From 62afce41ccdfe02a0114a0fd668bc09d8c611f4f Mon Sep 17 00:00:00 2001 From: wjiang Date: Mon, 24 Mar 2014 23:43:09 +0800 Subject: [PATCH 188/298] post_proc: Enable reverb in DSP to start effect During switch to tunnel playback, reverb enable command is not sent to DSP and causes reverb effect not applied continuously. Send reverb enable params to DSP to start effects during switch. Change-Id: I6e8bbdf4c1e5933be9a37413a4c4f1b7106fe6ba CRs-Fixed: 637016 --- post_proc/reverb.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/post_proc/reverb.c b/post_proc/reverb.c index d1040737f..60750b06d 100644 --- a/post_proc/reverb.c +++ b/post_proc/reverb.c @@ -309,6 +309,7 @@ int reverb_get_parameter(effect_context_t *context, effect_param_t *p, return -EINVAL; *(uint16_t *)value = reverb_ctxt->next_preset; ALOGV("get REVERB_PARAM_PRESET, preset %d", reverb_ctxt->next_preset); + return 0; } switch (param) { case REVERB_PARAM_ROOM_LEVEL: @@ -464,6 +465,7 @@ int reverb_set_parameter(effect_context_t *context, effect_param_t *p, return -EINVAL; } reverb_set_preset(reverb_ctxt, preset); + return 0; } switch (param) { case REVERB_PARAM_PROPERTIES: @@ -603,6 +605,14 @@ int reverb_start(effect_context_t *context, output_context_t *output) ALOGV("%s", __func__); reverb_ctxt->ctl = output->ctl; + if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) { + if (reverb_ctxt->ctl && reverb_ctxt->preset) { + offload_reverb_send_params(reverb_ctxt->ctl, reverb_ctxt->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_PRESET); + } + } + return 0; } -- GitLab From 9c38b18191387c96c381370d9c654ca5d0069475 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Thu, 27 Mar 2014 17:39:57 +0530 Subject: [PATCH 189/298] hal: Add support for turning fluence on/off - To turn on/off fluence we need to change the build prop file and changes will take effect after reboot. There is no option to turn it on/off without rebooting the target. - Add set_params support to turn it on and off. An option is given to user to select the dualmic fluence based on which set_parms is invoked. Change-Id: I51d580af820d8e0b1bd1384c941ffba3f96813ca CRs-Fixed: 605087 --- hal/Android.mk | 4 ++ hal/audio_extn/audio_extn.c | 58 +++++++++++++++++++++++++++ hal/audio_extn/audio_extn.h | 10 +++++ hal/audio_hw.h | 16 ++++---- hal/msm8974/platform.c | 80 ++++++++++++++++++++++++++++--------- hal/platform_api.h | 2 + 6 files changed, 144 insertions(+), 26 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index 41f712cf7..c4534b639 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -34,6 +34,10 @@ ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true) LOCAL_CFLAGS += -DANC_HEADSET_ENABLED endif +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FLUENCE)),true) + LOCAL_CFLAGS += -DFLUENCE_ENABLED +endif + ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAFE_PROXY_ENABLED endif diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 3bc72de1a..b641bdbd4 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -28,6 +28,8 @@ #include "audio_hw.h" #include "audio_extn.h" +#include "platform.h" +#include "platform_api.h" #define MAX_SLEEP_RETRY 100 #define WIFI_INIT_WAIT_SLEEP 50 @@ -130,6 +132,60 @@ void audio_extn_set_anc_parameters(struct audio_device *adev, } #endif /* ANC_HEADSET_ENABLED */ +#ifndef FLUENCE_ENABLED +#define audio_extn_set_fluence_parameters(adev, parms) (0) +#define audio_extn_get_fluence_parameters(adev, query, reply) (0) +#else +void audio_extn_set_fluence_parameters(struct audio_device *adev, + struct str_parms *parms) +{ + int ret = 0, err; + char value[32]; + struct listnode *node; + struct audio_usecase *usecase; + + err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FLUENCE, + value, sizeof(value)); + ALOGV_IF(err >= 0, "%s: Set Fluence Type to %s", __func__, value); + if (err >= 0) { + ret = platform_set_fluence_type(adev->platform, value); + if (ret != 0) { + ALOGE("platform_set_fluence_type returned error: %d", ret); + } else { + /* + *If the fluence is manually set/reset, devices + *need to get updated for all the usecases + *i.e. audio and voice. + */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + select_devices(adev, usecase->id); + } + } + } +} + +int audio_extn_get_fluence_parameters(struct audio_device *adev, + struct str_parms *query, struct str_parms *reply) +{ + int ret = 0, err; + char value[256] = {0}; + + err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE, value, + sizeof(value)); + if (err >= 0) { + ret = platform_get_fluence_type(adev->platform, value, sizeof(value)); + if (ret >= 0) { + ALOGV("%s: Fluence Type is %s", __func__, value); + str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE, value); + } else + goto done; + } +done: + return ret; +} +#endif /* FLUENCE_ENABLED */ + #ifndef AFE_PROXY_ENABLED #define audio_extn_set_afe_proxy_parameters(adev, parms) (0) #define audio_extn_get_afe_proxy_parameters(query, reply) (0) @@ -329,6 +385,7 @@ void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms) { audio_extn_set_anc_parameters(adev, parms); + audio_extn_set_fluence_parameters(adev, parms); audio_extn_set_afe_proxy_parameters(adev, parms); audio_extn_fm_set_parameters(adev, parms); audio_extn_listen_set_parameters(adev, parms); @@ -342,6 +399,7 @@ void audio_extn_get_parameters(const struct audio_device *adev, { char *kv_pairs = NULL; audio_extn_get_afe_proxy_parameters(query, reply); + audio_extn_get_fluence_parameters(adev, query, reply); kv_pairs = str_parms_to_str(reply); ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs); diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 96e8a5fae..fcb78cb6e 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -39,6 +39,16 @@ bool audio_extn_should_use_fb_anc(void); bool audio_extn_should_use_handset_anc(int in_channels); #endif +#ifndef FLUENCE_ENABLED +#define audio_extn_set_fluence_parameters(adev, parms) (0) +#define audio_extn_get_fluence_parameters(adev, query, reply) (0) +#else +void audio_extn_set_fluence_parameters(struct audio_device *adev, + struct str_parms *parms); +int audio_extn_get_fluence_parameters(struct audio_device *adev, + struct str_parms *query, struct str_parms *reply); +#endif + #ifndef AFE_PROXY_ENABLED #define audio_extn_set_afe_proxy_channel_mixer(adev,channel_count) (0) #define audio_extn_read_afe_proxy_channel_masks(out) (0) diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 2108a0097..e1172ef6f 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -32,13 +32,15 @@ #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so" /* Flags used to initialize acdb_settings variable that goes to ACDB library */ -#define DMIC_FLAG 0x00000002 -#define QMIC_FLAG 0x00000004 -#define TTY_MODE_OFF 0x00000010 -#define TTY_MODE_FULL 0x00000020 -#define TTY_MODE_VCO 0x00000040 -#define TTY_MODE_HCO 0x00000080 -#define TTY_MODE_CLEAR 0xFFFFFF0F +#define NONE_FLAG 0x00000000 +#define DMIC_FLAG 0x00000002 +#define QMIC_FLAG 0x00000004 +#define TTY_MODE_OFF 0x00000010 +#define TTY_MODE_FULL 0x00000020 +#define TTY_MODE_VCO 0x00000040 +#define TTY_MODE_HCO 0x00000080 +#define TTY_MODE_CLEAR 0xFFFFFF0F +#define FLUENCE_MODE_CLEAR 0xFFFFFFF0 #define ACDB_DEV_TYPE_OUT 1 #define ACDB_DEV_TYPE_IN 2 diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1188c231e..3ade91f27 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -106,6 +106,7 @@ struct platform_data { bool fluence_in_voice_rec; bool fluence_in_audio_rec; int fluence_type; + char fluence_cap[PROPERTY_VALUE_MAX]; int btsco_sample_rate; bool slowtalk; /* Audio calibration related functions */ @@ -522,10 +523,10 @@ void *platform_init(struct audio_device *adev) my_data->fluence_in_audio_rec = false; my_data->fluence_type = FLUENCE_NONE; - property_get("ro.qc.sdk.audio.fluencetype", value, ""); - if (!strncmp("fluencepro", value, sizeof("fluencepro"))) { + property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, ""); + if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) { my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC; - } else if (!strncmp("fluence", value, sizeof("fluence"))) { + } else if (!strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) { my_data->fluence_type = FLUENCE_DUAL_MIC; } else { my_data->fluence_type = FLUENCE_NONE; @@ -688,6 +689,63 @@ int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) return device_id; } +int platform_set_fluence_type(void *platform, char *value) +{ + int ret = 0; + int fluence_type = FLUENCE_NONE; + int fluence_flag = NONE_FLAG; + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_device *adev = my_data->adev; + + ALOGV("%s: fluence type:%d", __func__, my_data->fluence_type); + + /* only dual mic turn on and off is supported as of now through setparameters */ + if (!strncmp(AUDIO_PARAMETER_VALUE_DUALMIC,value, sizeof(AUDIO_PARAMETER_VALUE_DUALMIC))) { + if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro")) || + !strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) { + ALOGV("fluence dualmic feature enabled \n"); + fluence_type = FLUENCE_DUAL_MIC; + fluence_flag = DMIC_FLAG; + } else { + ALOGE("%s: Failed to set DUALMIC", __func__); + ret = -1; + goto done; + } + } else if (!strncmp(AUDIO_PARAMETER_KEY_NO_FLUENCE, value, sizeof(AUDIO_PARAMETER_KEY_NO_FLUENCE))) { + ALOGV("fluence disabled"); + fluence_type = FLUENCE_NONE; + } else { + ALOGE("Invalid fluence value : %s",value); + ret = -1; + goto done; + } + + if (fluence_type != my_data->fluence_type) { + ALOGV("%s: Updating fluence_type to :%d", __func__, fluence_type); + my_data->fluence_type = fluence_type; + adev->acdb_settings = (adev->acdb_settings & FLUENCE_MODE_CLEAR) | fluence_flag; + } +done: + return ret; +} + +int platform_get_fluence_type(void *platform, char *value, uint32_t len) +{ + int ret = 0; + struct platform_data *my_data = (struct platform_data *)platform; + + if (my_data->fluence_type == FLUENCE_QUAD_MIC) { + strlcpy(value, "quadmic", len); + } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) { + strlcpy(value, "dualmic", len); + } else if (my_data->fluence_type == FLUENCE_NONE) { + strlcpy(value, "none", len); + } else + ret = -1; + + return ret; +} + int platform_send_audio_calibration(void *platform, snd_device_t snd_device) { struct platform_data *my_data = (struct platform_data *)platform; @@ -1568,24 +1626,8 @@ void platform_get_parameters(void *platform, char *str = NULL; char value[256] = {0}; int ret; - int fluence_type; char *kv_pairs = NULL; - ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, - value, sizeof(value)); - if (ret >= 0) { - if (my_data->fluence_type & FLUENCE_QUAD_MIC) { - strlcpy(value, "fluencepro", sizeof(value)); - } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) { - strlcpy(value, "fluence", sizeof(value)); - } else { - strlcpy(value, "none", sizeof(value)); - } - - str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value); - } - - memset(value, 0, sizeof(value)); ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value)); if (ret >= 0) { diff --git a/hal/platform_api.h b/hal/platform_api.h index 9e8727534..7c4171d5b 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -27,6 +27,8 @@ int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device, char *device_name); void platform_add_backend_name(char *mixer_path, snd_device_t snd_device); int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type); +int platform_set_fluence_type(void *platform, char *value); +int platform_get_fluence_type(void *platform, char *value, uint32_t len); int platform_send_audio_calibration(void *platform, snd_device_t snd_device); int platform_switch_voice_call_device_pre(void *platform); int platform_switch_voice_call_device_post(void *platform, -- GitLab From 50a3feee86329443824cbc28cf56ba753847dc9d Mon Sep 17 00:00:00 2001 From: wjiang Date: Fri, 28 Mar 2014 12:29:58 +0800 Subject: [PATCH 190/298] post_proc: disable effect immediately when routed to invalid devices Offload effect is still perceived when invalid output device is connected. We should send disable command immediately once phone is routed to unexpected device and forbid effect enablement during temporary disabled state. Change-Id: I26d4ccfd77037a879622b0437ae3916ff0071a69 CRs-Fixed: 630408 --- post_proc/bass_boost.c | 12 +++++++++++- post_proc/virtualizer.c | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c index 221bbc42a..2061cd062 100644 --- a/post_proc/bass_boost.c +++ b/post_proc/bass_boost.c @@ -160,12 +160,20 @@ int bassboost_set_device(effect_context_t *context, uint32_t device) if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); bass_ctxt->temp_disabled = true; + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); } } else { if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) && bass_ctxt->temp_disabled) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); bass_ctxt->temp_disabled = false; + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); } } offload_bassboost_set_device(&(bass_ctxt->offload_bass), device); @@ -214,7 +222,9 @@ int bassboost_enable(effect_context_t *context) bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; ALOGV("%s", __func__); - if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { + + if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) && + !(bass_ctxt->temp_disabled)) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); if (bass_ctxt->ctl && bass_ctxt->strength) offload_bassboost_send_params(bass_ctxt->ctl, diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c index 3d6f908dc..8f6d00069 100644 --- a/post_proc/virtualizer.c +++ b/post_proc/virtualizer.c @@ -160,12 +160,20 @@ int virtualizer_set_device(effect_context_t *context, uint32_t device) if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); virt_ctxt->temp_disabled = true; + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); } } else { if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) && virt_ctxt->temp_disabled) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); virt_ctxt->temp_disabled = false; + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); } } offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device); @@ -213,7 +221,9 @@ int virtualizer_enable(effect_context_t *context) virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; ALOGV("%s", __func__); - if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { + + if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) && + !(virt_ctxt->temp_disabled)) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); if (virt_ctxt->ctl && virt_ctxt->strength) offload_virtualizer_send_params(virt_ctxt->ctl, -- GitLab From e33427d579b0fe64d3305b60a2ec0e3cd5379530 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Mon, 24 Mar 2014 17:11:50 +0530 Subject: [PATCH 191/298] audio: primary desc check for sonification - Audio glitches on alarm expiry if alarm starts on screen lock/standby mode - On alarm expiry alarm tone will start play on combo device &screen unlock tone try to play on headset which results multiple device switch, as a result audio glitches are audible - Fix is to treat all non-music streams as sonification if sonfication strategy is used by primary desc which will avoid device switch Change-Id: I54a2880f5b9dbc39746b20485f0aea9d9c3a39d7 CRs-Fixed: 514467 Crs-Fixed: 626722 --- policy_hal/AudioPolicyManager.cpp | 341 +++++++++++++++++++++++++++++- policy_hal/AudioPolicyManager.h | 11 + 2 files changed, 347 insertions(+), 5 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index cb26ed645..0722aed2c 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -261,6 +261,130 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, return BAD_VALUE; } +void AudioPolicyManager::setPhoneState(int state) +{ + ALOGV("setPhoneState() state %d", state); + audio_devices_t newDevice = AUDIO_DEVICE_NONE; + if (state < 0 || state >= AudioSystem::NUM_MODES) { + ALOGW("setPhoneState() invalid state %d", state); + return; + } + + if (state == mPhoneState ) { + ALOGW("setPhoneState() setting same state %d", state); + return; + } + + // if leaving call state, handle special case of active streams + // pertaining to sonification strategy see handleIncallSonification() + if (isInCall()) { + ALOGV("setPhoneState() in call state management: new state is %d", state); + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + handleIncallSonification(stream, false, true); + } + } + + // store previous phone state for management of sonification strategy below + int oldState = mPhoneState; + mPhoneState = state; + bool force = false; + + // are we entering or starting a call + if (!isStateInCall(oldState) && isStateInCall(state)) { + ALOGV(" Entering call in setPhoneState()"); + // force routing command to audio hardware when starting a call + // even if no device change is needed + force = true; + for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { + mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] = + sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]; + } + } else if (isStateInCall(oldState) && !isStateInCall(state)) { + ALOGV(" Exiting call in setPhoneState()"); + // force routing command to audio hardware when exiting a call + // even if no device change is needed + force = true; + for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { + mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] = + sVolumeProfiles[AUDIO_STREAM_DTMF][j]; + } + } else if (isStateInCall(state) && (state != oldState)) { + ALOGV(" Switching between telephony and VoIP in setPhoneState()"); + // force routing command to audio hardware when switching between telephony and VoIP + // even if no device change is needed + force = true; + } + + // check for device and output changes triggered by new phone state + newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); + checkA2dpSuspend(); + checkOutputForAllStrategies(); + updateDevicesAndOutputs(); + + AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); + + // force routing command to audio hardware when ending call + // even if no device change is needed + if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) { + newDevice = hwOutputDesc->device(); + } + + int delayMs = 0; + if (isStateInCall(state)) { + nsecs_t sysTime = systemTime(); + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + // mute media and sonification strategies and delay device switch by the largest + // latency of any output where either strategy is active. + // This avoid sending the ring tone or music tail into the earpiece or headset. + if ((desc->isStrategyActive(STRATEGY_MEDIA, + SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime) || + desc->isStrategyActive(STRATEGY_SONIFICATION, + SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime)) && + (delayMs < (int)desc->mLatency*2)) { + delayMs = desc->mLatency*2; + } + setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); + setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, + getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); + setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i)); + setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS, + getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/)); + } + } + + // change routing is necessary + setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); + + //update device for all non-primary outputs + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t output = mOutputs.keyAt(i); + if (output != mPrimaryOutput) { + newDevice = getNewDevice(output, false /*fromCache*/); + setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + } + } + + // if entering in call state, handle special case of active streams + // pertaining to sonification strategy see handleIncallSonification() + if (isStateInCall(state)) { + ALOGV("setPhoneState() in call state management: new state is %d", state); + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + handleIncallSonification(stream, true, true); + } + } + + // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE + if (state == AudioSystem::MODE_RINGTONE && + isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) { + mLimitRingtoneVolume = true; + } else { + mLimitRingtoneVolume = false; + } +} + void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) { ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); @@ -351,6 +475,193 @@ void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem:: } +status_t AudioPolicyManager::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) +{ + ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("startOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + + // increment usage count for this stream on the requested output: + // NOTE that the usage count is the same for duplicated output and hardware output which is + // necessary for a correct control of hardware output routing by startOutput() and stopOutput() + outputDesc->changeRefCount(stream, 1); + + if (outputDesc->mRefCount[stream] == 1) { + audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + routing_strategy strategy = getStrategy(stream); + bool shouldWait = (strategy == STRATEGY_SONIFICATION) || + (strategy == STRATEGY_SONIFICATION_RESPECTFUL); + uint32_t waitMs = 0; + bool force = false; + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (desc != outputDesc) { + // force a device change if any other output is managed by the same hw + // module and has a current device selection that differs from selected device. + // In this case, the audio HAL must receive the new device selection so that it can + // change the device currently selected by the other active output. + if (outputDesc->sharesHwModuleWith(desc) && + desc->device() != newDevice) { + force = true; + } + // wait for audio on other active outputs to be presented when starting + // a notification so that audio focus effect can propagate. + uint32_t latency = desc->latency(); + if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) { + waitMs = latency; + } + } + } + uint32_t muteWaitMs = setOutputDevice(output, newDevice, force); + + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, true, false); + } + + // apply volume rules for current stream and device if necessary + checkAndSetVolume(stream, + mStreams[stream].getVolumeIndex(newDevice), + output, + newDevice); + + // update the outputs if starting an output with a stream that can affect notification + // routing + handleNotificationRoutingForStream(stream); + if (waitMs > muteWaitMs) { + usleep((waitMs - muteWaitMs) * 2 * 1000); + } + } +#ifdef DOLBY_UDC + // It is observed that in some use-cases where both outputs are present eg. bluetooth and headphone, + // the output for particular stream type is decided in this routine. Hence we must call + // getDeviceForStrategy in order to get the current active output for this stream type and update + // the dolby system property. + if (stream == AudioSystem::MUSIC) + { + audio_devices_t audioOutputDevice = getDeviceForStrategy(getStrategy(AudioSystem::MUSIC), true); + DolbySystemProperty::set(audioOutputDevice); + } +#endif // DOLBY_END + return NO_ERROR; +} + + +status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) +{ + ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("stopOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, false, false); + } + + if (outputDesc->mRefCount[stream] > 0) { + // decrement usage count of this stream on the output + outputDesc->changeRefCount(stream, -1); + // store time at which the stream was stopped - see isStreamActive() + if (outputDesc->mRefCount[stream] == 0) { + outputDesc->mStopTime[stream] = systemTime(); + audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + // delay the device switch by twice the latency because stopOutput() is executed when + // the track stop() command is received and at that time the audio track buffer can + // still contain data that needs to be drained. The latency only covers the audio HAL + // and kernel buffers. Also the latency does not always include additional delay in the + // audio path (audio DSP, CODEC ...) + setOutputDevice(output, newDevice, false, outputDesc->mLatency*2); + + // force restoring the device selection on other active outputs if it differs from the + // one being selected for this output + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t curOutput = mOutputs.keyAt(i); + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (curOutput != output && + desc->isActive() && + outputDesc->sharesHwModuleWith(desc) && + (newDevice != desc->device())) { + setOutputDevice(curOutput, + getNewDevice(curOutput, false /*fromCache*/), + true, + outputDesc->mLatency*2); + } + } + // update the outputs if stopping one with a stream that can affect notification routing + handleNotificationRoutingForStream(stream); + } + return NO_ERROR; + } else { + ALOGW("stopOutput() refcount is already 0 for output %d", output); + return INVALID_OPERATION; + } +} + +audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache) +{ + audio_devices_t device = AUDIO_DEVICE_NONE; + + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + AudioOutputDescriptor *primaryOutputDesc = mOutputs.valueFor(mPrimaryOutput); + // check the following by order of priority to request a routing change if necessary: + // 1: the strategy enforced audible is active on the output: + // use device for strategy enforced audible + // 2: we are in call or the strategy phone is active on the output: + // use device for strategy phone + // 3: the strategy sonification is active on the output: + // use device for strategy sonification + // 4: the strategy "respectful" sonification is active on the output: + // use device for strategy "respectful" sonification + // 5: the strategy media is active on the output: + // use device for strategy media + // 6: the strategy DTMF is active on the output: + // use device for strategy DTMF + if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) { + device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); + } else if (isInCall() || + outputDesc->isStrategyActive(STRATEGY_PHONE)) { + device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)|| + (primaryOutputDesc->isStrategyActive(STRATEGY_SONIFICATION)&& !primaryOutputDesc->isStrategyActive(STRATEGY_MEDIA))){ + device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) { + device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) { + device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); + } + + ALOGV("getNewDevice() selected device %x", device); + return device; +} + +//private function, no changes from AudioPolicyManagerBase +void AudioPolicyManager::handleNotificationRoutingForStream(AudioSystem::stream_type stream) { + switch(stream) { + case AudioSystem::MUSIC: + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + updateDevicesAndOutputs(); + break; + default: + break; + } +} + audio_io_handle_t AudioPolicyManager::getInput(int inputSource, uint32_t samplingRate, uint32_t format, @@ -418,12 +729,32 @@ audio_io_handle_t AudioPolicyManager::getInput(int inputSource, AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(AudioSystem::stream_type stream) { -#ifdef QCOM_INCALL_MUSIC_ENABLED - if (stream == AudioSystem::INCALL_MUSIC) - return STRATEGY_MEDIA; + // stream to strategy mapping + switch (stream) { + case AudioSystem::VOICE_CALL: + case AudioSystem::BLUETOOTH_SCO: + return STRATEGY_PHONE; + case AudioSystem::RING: + case AudioSystem::ALARM: + return STRATEGY_SONIFICATION; + case AudioSystem::NOTIFICATION: + return STRATEGY_SONIFICATION_RESPECTFUL; + case AudioSystem::DTMF: + return STRATEGY_DTMF; + default: + ALOGE("unknown stream type"); + case AudioSystem::SYSTEM: + // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs + // while key clicks are played produces a poor result + case AudioSystem::TTS: + case AudioSystem::MUSIC: +#ifdef AUDIO_EXTN_INCALL_MUSIC_ENABLED + case AudioSystem::INCALL_MUSIC: #endif - - return getStrategy(stream); + return STRATEGY_MEDIA; + case AudioSystem::ENFORCED_AUDIBLE: + return STRATEGY_ENFORCED_AUDIBLE; + } } audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 5defa24ea..8ef1cabd2 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -49,6 +49,13 @@ public: uint32_t channels, AudioSystem::audio_in_acoustics acoustics); virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); + virtual void setPhoneState(int state); + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); protected: // return the strategy corresponding to a given stream type @@ -77,8 +84,12 @@ protected: // check that volume change is permitted, compute and send new volume to audio hardware status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); + audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache); // returns the category the device belongs to with regard to volume curve management static device_category getDeviceCategory(audio_devices_t device); +private: + void handleNotificationRoutingForStream(AudioSystem::stream_type stream); + }; }; -- GitLab From 2aae77d5710fb1c685ad0918e11c562b65e8a002 Mon Sep 17 00:00:00 2001 From: Karthik Reddy Katta Date: Tue, 1 Apr 2014 20:26:34 +0530 Subject: [PATCH 192/298] hal: Fix for no LCH tone playback in DSDA - Incorrect PCM device ID is being selected for incall music delivery usecase. - Select proper PCM device for incall music uplink-2. Change-Id: Ic53495790fbd4bf7eac3f45811f2a8973ea3c6d9 CRs-Fixed: 642160 --- hal/msm8974/platform.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 0ea57ae52..f119fcd2f 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -175,10 +175,8 @@ enum { #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 15 #elif PLATFORM_MSM8x26 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16 -#elif PLATFORM_MSM8974 -#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 35 #else -#define INCALL_MUSIC_UPLINK2_PCM_DEVICE -1 +#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 35 #endif #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 -- GitLab From c47c86fd0752bee8b42cd0c917e8e1f1ba2e8a87 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Wed, 2 Apr 2014 19:22:53 +0530 Subject: [PATCH 193/298] hal: Update EC support for HPF usecase - Ensure reference device is set if audio is routed to speaker/headset during HFP usecase. Change-Id: Ia404aaa8ec8b80e9f4be14840dfef3bf9afef435 CRs-Fixed: 641513 --- hal/msm8974/platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 1f4e3d576..896b53ad2 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1072,6 +1072,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; + set_echo_reference(adev->mixer, EC_REF_RX); } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; @@ -1090,6 +1091,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else { snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; + set_echo_reference(adev->mixer, EC_REF_RX); } } } else if (source == AUDIO_SOURCE_CAMCORDER) { -- GitLab From f6d3c5564bae4c85d3cc98a8660fbfc159d7fbac Mon Sep 17 00:00:00 2001 From: Satish Babu Patakokila Date: Wed, 26 Mar 2014 15:02:12 +0530 Subject: [PATCH 194/298] hal/usb: Add initial volume setting for USB headset Some USB headsets start at 0 volume because of this even if the Media Player volume is maximum cannot hear any audio. Initialize device volume before starting the playback. Change-Id: Ie6940fae6fd7946ce0a90a142aaf110d829eea8f CRs-Fixed: 639168 --- hal/audio_extn/audio_extn.h | 1 + hal/audio_extn/usb.c | 40 ++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index fcb78cb6e..aecef3662 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -71,6 +71,7 @@ int32_t audio_extn_get_afe_proxy_channel_count(); #define audio_extn_usb_set_proxy_sound_card(sndcard_idx) (0) #define audio_extn_usb_is_proxy_inuse() (0) #else +void initPlaybackVolume(); void audio_extn_usb_init(void *adev); void audio_extn_usb_deinit(); void audio_extn_usb_start_playback(void *adev); diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c index 699c3b7d3..281b445fc 100644 --- a/hal/audio_extn/usb.c +++ b/hal/audio_extn/usb.c @@ -96,6 +96,42 @@ static void usb_alloc() usbmod = calloc(1, sizeof(struct usb_module)); } +// Some USB audio accessories have a really low default volume set. Look for a suitable +// volume control and set the volume to default volume level. +static void initPlaybackVolume() { + ALOGD("initPlaybackVolume"); + struct mixer *usbMixer = mixer_open(1); + + if (usbMixer) { + struct mixer_ctl *ctl = NULL; + unsigned int usbPlaybackVolume; + unsigned int i; + unsigned int num_ctls = mixer_get_num_ctls(usbMixer); + + // Look for the first control named ".*Playback Volume" that isn't for a microphone + for (i = 0; i < num_ctls; i++) { + ctl = mixer_get_ctl(usbMixer, i); + if (strstr((const char *)mixer_ctl_get_name(ctl), "Playback Volume") && + !strstr((const char *)mixer_ctl_get_name(ctl), "Mic")) { + break; + } + } + if (ctl != NULL) { + ALOGD("Found a volume control for USB: %s", mixer_ctl_get_name(ctl) ); + usbPlaybackVolume = mixer_ctl_get_value(ctl, 0); + ALOGD("Value got from mixer_ctl_get is:%u", usbPlaybackVolume); + if (mixer_ctl_set_value(ctl,0,usbPlaybackVolume) < 0) { + ALOGE("Failed to set volume; default volume might be used"); + } + } else { + ALOGE("No playback volume control found; default volume will be used"); + } + mixer_close(usbMixer); + } else { + ALOGE("Failed to open mixer for card 1"); + } +} + static int usb_get_numof_rates(char *rates_str) { int i, size = 0; @@ -340,7 +376,7 @@ static int32_t usb_playback_entry(void *adev) pcm_config_usbmod.channels = usbmod->channels_playback; pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT; usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE; - ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__, + ALOGD("%s: proxy device %u:period %u:channels %u:sample", __func__, pcm_config_usbmod.period_size, pcm_config_usbmod.channels, pcm_config_usbmod.rate); @@ -375,6 +411,8 @@ static int32_t usb_playback_entry(void *adev) ALOGD("%s: PROXY configured for playback", __func__); pthread_mutex_unlock(&usbmod->usb_playback_lock); + ALOGD("Init USB volume"); + initPlaybackVolume(); /* main loop to read from proxy and write to usb */ while (usbmod->is_playback_running) { /* read data from proxy */ -- GitLab From 11fe3530a8c27708fc193f06df20a20c08a76531 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Thu, 3 Apr 2014 00:31:55 -0700 Subject: [PATCH 195/298] mm-audio: aenc: timestamp fixes Save timestamp of first ETB as anchor time and use it as reference in calculating timestamp for all future FBDs Change-Id: Id937ac169c878fccf7d6f8fa660cb9ec321d4afa CRs-Fixed: 639731 --- mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h | 1 + mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h index 623caa863..98afa718a 100644 --- a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h +++ b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h @@ -457,6 +457,7 @@ private: unsigned int m_flags; //encapsulate the waiting states. OMX_U64 nTimestamp; OMX_U64 ts; + uint32_t m_frame_count; unsigned int frameduration; unsigned int pcm_input; //tunnel or non-tunnel unsigned int m_inp_act_buf_count; // Num of Input Buffers diff --git a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp index 652126588..33892b55b 100644 --- a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp +++ b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp @@ -1072,6 +1072,7 @@ OMX_ERRORTYPE omx_aac_aenc::component_init(OMX_STRING role) nTimestamp = 0; ts = 0; + m_frame_count = 0; frameduration = 0; nNumInputBuf = 0; nNumOutputBuf = 0; @@ -4097,6 +4098,11 @@ OMX_ERRORTYPE omx_aac_aenc::empty_this_buffer_proxy DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags); } + if (ts == 0) { + DEBUG_PRINT("Anchor time %lld", buffer->nTimeStamp); + ts = buffer->nTimeStamp; + } + memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen); write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN)); pthread_mutex_lock(&m_state_lock); @@ -4207,11 +4213,8 @@ OMX_ERRORTYPE omx_aac_aenc::fill_this_buffer_proxy } meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char)); - buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+ - meta_out->lsw_ts); - - ts += frameduration; - buffer->nTimeStamp = ts; + buffer->nTimeStamp = ts + (frameduration * m_frame_count); + ++m_frame_count; nTimestamp = buffer->nTimeStamp; buffer->nFlags |= meta_out->nflags; buffer->nOffset = meta_out->offset_to_frame + 1; -- GitLab From 0c097d5344dbdd06e4b6bb09e0ba078ab89c170d Mon Sep 17 00:00:00 2001 From: ApurupaPattapu Date: Tue, 8 Apr 2014 10:41:07 -0700 Subject: [PATCH 196/298] hal: Correct PCM offload fragment size - Correct the fragment size to use bytes instead of bits per sample - Use 80ms as pcm offload buffer duration for video streaming usecases and 1 sec for video + audio usecases Change-Id: Iec8e24c2b158368742a55710a46da94ce5d3c170 --- hal/msm8974/platform.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 3ade91f27..0d73d0f59 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -44,15 +44,15 @@ #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) /* Used in calculating fragment size for pcm offload */ -#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 2000 /* 2 secs */ -#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 100 /* 100 millisecs */ +#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */ +#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */ /* MAX PCM fragment size cannot be increased further due * to flinger's cblk size of 1mb,and it has to be a multiple of * 24 - lcm of channels supported by DSP */ #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024) -#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024) +#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024) #define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1))) /* @@ -1728,16 +1728,23 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) } else if (info->has_video && info->is_streaming) { fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING * info->sample_rate - * bits_per_sample + * (bits_per_sample >> 3) * popcount(info->channel_mask))/1000; } else if (info->has_video) { fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV * info->sample_rate - * bits_per_sample + * (bits_per_sample >> 3) * popcount(info->channel_mask))/1000; } + char value[PROPERTY_VALUE_MAX] = {0}; + if((property_get("audio.offload.pcm.buffer.size", value, "")) && + atoi(value)) { + fragment_size = atoi(value) * 1024; + ALOGV("Using buffer size from sys prop %d", fragment_size); + } + fragment_size = ALIGN( fragment_size, 1024); if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE) -- GitLab From 95072ba17595f54dd52ed744f8337b69cba2eefe Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Mon, 14 Apr 2014 21:18:52 +0530 Subject: [PATCH 197/298] hal: msm8974: Fix echo reference port for msm8x10 Echo cancellation is not working in VoIP calls. Echo reference port is set as I2S_RX which inturn sets PRIMARY_I2S_RX as echo reference port while configuring ADM is causing the issue. 8x10 is using SECONDARY_I2S_RX port in Rx path. Update the EC reference port accordingly. CRs-Fixed: 646310 Change-Id: If949c6c7487c36a02e5bcedb3c779f502592ce64 --- hal/msm8974/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index f119fcd2f..be4f5d477 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -186,7 +186,7 @@ enum { #ifdef PLATFORM_MSM8610 #define LOWLATENCY_PCM_DEVICE 12 -#define EC_REF_RX "I2S_RX" +#define EC_REF_RX "SEC_I2S_RX" #else #define LOWLATENCY_PCM_DEVICE 15 #define EC_REF_RX "SLIM_RX" -- GitLab From 0d06c8e7c89a18eee365dd9e8eb44095f9868e9d Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Thu, 17 Apr 2014 20:00:41 -0700 Subject: [PATCH 198/298] hal: fix to handle voip issue when input stream starts first - adev_open_output_stream() fails if the use case is already enabled. Because of this, in case of VoIP, when the input stream is created and started before creating Audio Track, then the output stream creation fails. - Fix this issue by giving exception for VoIP use case. Change-Id: I5e7329d64075a09b99e5760a9050ace8c62a4e87 CRs-fixed: 651761 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c0d47d925..38223a8cc 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2224,7 +2224,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, /* Check if this usecase is already existing */ pthread_mutex_lock(&adev->lock); - if (get_usecase_from_list(adev, out->usecase) != NULL) { + if ((get_usecase_from_list(adev, out->usecase) != NULL) && + (out->usecase != USECASE_COMPRESS_VOIP_CALL)) { ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase); pthread_mutex_unlock(&adev->lock); ret = -EEXIST; -- GitLab From 523ae41684c59628fb33f415a7369550c204d732 Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Fri, 18 Apr 2014 22:26:56 +0530 Subject: [PATCH 199/298] Audio: Fix for audio loss on switching between speaker and USB headset - snd device reference count is not decremented when usb headset is unplugged, because touch tone is still active on usb headset. So when usb is plugged again device routing is not triggered as present and prev devices are same - Fix is to route audio to speaker as soon as usb headset is disconnected CRs-Fixed: 630425 Change-Id: Idfa37478fa19cd5a1c75c7e1d2f77b4dc02b311a --- hal/audio_hw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c0d47d925..c7f836567 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1400,13 +1400,14 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_lock(&adev->lock); /* - * When HDMI cable is unplugged the music playback is paused and - * the policy manager sends routing=0. But the audioflinger - * continues to write data until standby time (3sec). - * As the HDMI core is turned off, the write gets blocked. + * When HDMI cable is unplugged/usb hs is disconnected the + * music playback is paused and the policy manager sends routing=0 + * But the audioflingercontinues to write data until standby time + * (3sec). As the HDMI core is turned off, the write gets blocked. * Avoid this by routing audio to speaker until standby. */ - if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL && + if ((out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL || + out->devices == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) && val == AUDIO_DEVICE_NONE) { val = AUDIO_DEVICE_OUT_SPEAKER; } -- GitLab From bd1440c8aa2a80b490052ad0a1eac5d17ba45a51 Mon Sep 17 00:00:00 2001 From: Avinash Vaish Date: Mon, 21 Apr 2014 18:46:48 +0530 Subject: [PATCH 200/298] policy_hal: remove VGS check for BT volume -Currently voice volume is forced to MAX when VGS is set for BT. But VGS parameter is not used anymore in BT stack so it never set the value. -Removed VGS check as this is deprecated and keep the behavior same as default policy. CRs-Fixed: 645853 Change-Id: I69de60987835cc7bfbf26e6b89eb39447423fd9d --- policy_hal/AudioPolicyManager.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 0722aed2c..d18ae6663 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -1157,19 +1157,11 @@ status_t AudioPolicyManager::checkAndSetVolume(int stream, stream == AudioSystem::BLUETOOTH_SCO) { float voiceVolume; - voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; - - // Force voice volume to max when Vgs is set for bluetooth SCO as volume is managed by the headset - if (stream == AudioSystem::BLUETOOTH_SCO) { - String8 key ("bt_headset_vgs"); - mpClientInterface->getParameters(output,key); - AudioParameter result(mpClientInterface->getParameters(0,key)); - int value; - if (result.getInt(String8("isVGS"),value) == NO_ERROR) { - ALOGV("Use BT-SCO Voice Volume"); - voiceVolume = 1.0; - } - } + if (stream == AudioSystem::VOICE_CALL) + voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; + else + // Force voice volume to max for bluetooth SCO as volume is managed by the headset + voiceVolume = 1.0; if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); -- GitLab From 5856f9b61a70d42d41dfa2560c9a483162e7ee0a Mon Sep 17 00:00:00 2001 From: Narsinga Rao Chella Date: Fri, 11 Apr 2014 17:20:46 -0700 Subject: [PATCH 201/298] hal: fix BT device switch issue for audio playback during VoIP call - When VoIP call is active on non-BT device and if the music playback tries to switch to BT device, it will continue to route to non-BT device on which the VoIP call is active already. - Fix the issue by not selecting VoIP devices for audio playback when they are on different back ends. Change-Id: Iff9251fcf02f897d9b1cdc17fcf27c262518ada8 CRs-fixed: 652129 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c0d47d925..79d8ad811 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -623,7 +623,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) } } else if (voice_extn_compress_voip_is_active(adev)) { voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); - if (voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + if ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) && + (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) { in_snd_device = voip_usecase->in_snd_device; out_snd_device = voip_usecase->out_snd_device; } -- GitLab From c05cbdb4b1e48a594cf9230c210b9c593fab78f9 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Tue, 22 Apr 2014 15:19:13 -0700 Subject: [PATCH 202/298] hal: fm: Fix incorrect routing of fm audio to speaker - FM audio is enabled or disabled through set_parameters() API on primary output stream. The audio is routed to device of primary output stream. - If the routing is not updated before the enable command, the audio is routed to previous device of primary output. - Fix the issue by updating the primary output device with device from enable command. Change-Id: I67764b8b5d2cfaddef94ccfe555702289bf36f95 CRs-Fixed: 651821 --- hal/audio_extn/fm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c index a4157f8a5..249ae9e3c 100644 --- a/hal/audio_extn/fm.c +++ b/hal/audio_extn/fm.c @@ -230,9 +230,10 @@ void audio_extn_fm_set_parameters(struct audio_device *adev, ALOGD("%s: FM usecase", __func__); if (val != 0) { if(val & AUDIO_DEVICE_OUT_FM - && fmmod.is_fm_running == false) + && fmmod.is_fm_running == false) { + adev->primary_output->devices = val & ~AUDIO_DEVICE_OUT_FM; fm_start(adev); - else if (!(val & AUDIO_DEVICE_OUT_FM) + } else if (!(val & AUDIO_DEVICE_OUT_FM) && fmmod.is_fm_running == true) fm_stop(adev); } -- GitLab From 33de8143c0e24e0d4236b8061d9fd476ad5beb9d Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Thu, 24 Apr 2014 10:34:41 -0700 Subject: [PATCH 203/298] hal: Ensure all the mutexes are initialized - Ensure all the mutex locks are initialized before using them, to avoid native crashes. Change-Id: I7b6253f1d08a36a24d366d69004ce969d73c13e1 CRs-Fixed: 654375 --- hal/audio_extn/usb.c | 5 +++++ hal/audio_hw.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c index 281b445fc..0240d7c65 100644 --- a/hal/audio_extn/usb.c +++ b/hal/audio_extn/usb.c @@ -580,6 +580,11 @@ void audio_extn_usb_init(void *adev) usbmod->proxy_card = 0; usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE; usbmod->adev = (struct audio_device*)adev; + + pthread_mutex_init(&usbmod->usb_playback_lock, + (const pthread_mutexattr_t *) NULL); + pthread_mutex_init(&usbmod->usb_record_lock, + (const pthread_mutexattr_t *) NULL); } void audio_extn_usb_deinit() diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 752242693..bad1aed5f 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2499,6 +2499,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); + pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); + in->stream.common.get_sample_rate = in_get_sample_rate; in->stream.common.set_sample_rate = in_set_sample_rate; in->stream.common.get_buffer_size = in_get_buffer_size; @@ -2633,6 +2635,8 @@ static int adev_open(const hw_module_t *module, const char *name, adev = calloc(1, sizeof(struct audio_device)); + pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL); + adev->device.common.tag = HARDWARE_DEVICE_TAG; adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; adev->device.common.module = (struct hw_module_t *)module; -- GitLab From f930675069ee094544dc9bcaa13ff53df2a9dcbd Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Thu, 24 Apr 2014 11:53:44 -0700 Subject: [PATCH 204/298] audio: use of audio_route_{apply/reset}_and_update_path APIs 1) Update enable/disable device and route to use the new APIs. With this change, mixer controls will be updated in the order listed in mixer paths XML file. 2) update_mixer is now an unused var. Change-Id: Ic0a8874e4a2080347cfa0c2e66af606a08a207a7 CRs-Fixed: 581453 --- hal/audio_hw.c | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 752242693..47b0fb6ae 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -216,7 +216,7 @@ static int get_snd_codec_id(audio_format_t format) int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, - bool update_mixer) + bool __unused update_mixer) { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; @@ -237,18 +237,15 @@ int enable_audio_route(struct audio_device *adev, #endif strcpy(mixer_path, use_case_table[usecase->id]); platform_add_backend_name(mixer_path, snd_device); - ALOGV("%s: apply mixer path: %s", __func__, mixer_path); - audio_route_apply_path(adev->audio_route, mixer_path); - if (update_mixer) - audio_route_update_mixer(adev->audio_route); - + ALOGV("%s: apply mixer and update path: %s", __func__, mixer_path); + audio_route_apply_and_update_path(adev->audio_route, mixer_path); ALOGV("%s: exit", __func__); return 0; } int disable_audio_route(struct audio_device *adev, struct audio_usecase *usecase, - bool update_mixer) + bool __unused update_mixer) { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; @@ -263,18 +260,15 @@ int disable_audio_route(struct audio_device *adev, snd_device = usecase->out_snd_device; strcpy(mixer_path, use_case_table[usecase->id]); platform_add_backend_name(mixer_path, snd_device); - ALOGV("%s: reset mixer path: %s", __func__, mixer_path); - audio_route_reset_path(adev->audio_route, mixer_path); - if (update_mixer) - audio_route_update_mixer(adev->audio_route); - + ALOGV("%s: reset and update mixer path: %s", __func__, mixer_path); + audio_route_reset_and_update_path(adev->audio_route, mixer_path); ALOGV("%s: exit", __func__); return 0; } int enable_snd_device(struct audio_device *adev, snd_device_t snd_device, - bool update_mixer) + bool __unused update_mixer) { char device_name[DEVICE_NAME_MAX_SIZE] = {0}; @@ -321,17 +315,14 @@ int enable_snd_device(struct audio_device *adev, audio_extn_listen_update_status(snd_device, LISTEN_EVENT_SND_DEVICE_BUSY); - audio_route_apply_path(adev->audio_route, device_name); + audio_route_apply_and_update_path(adev->audio_route, device_name); } - if (update_mixer) - audio_route_update_mixer(adev->audio_route); - return 0; } int disable_snd_device(struct audio_device *adev, snd_device_t snd_device, - bool update_mixer) + bool __unused update_mixer) { char device_name[DEVICE_NAME_MAX_SIZE] = {0}; @@ -368,10 +359,7 @@ int disable_snd_device(struct audio_device *adev, audio_extn_spkr_prot_is_enabled()) { audio_extn_spkr_prot_stop_processing(); } else - audio_route_reset_path(adev->audio_route, device_name); - - if (update_mixer) - audio_route_update_mixer(adev->audio_route); + audio_route_reset_and_update_path(adev->audio_route, device_name); audio_extn_listen_update_status(snd_device, LISTEN_EVENT_SND_DEVICE_FREE); @@ -420,8 +408,7 @@ static void check_usecases_codec_backend(struct audio_device *adev, } if (num_uc_to_switch) { - /* Make sure all the streams are de-routed before disabling the device */ - audio_route_update_mixer(adev->audio_route); + /* All streams have been de-routed. Disable the device */ list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); @@ -490,8 +477,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, } if (num_uc_to_switch) { - /* Make sure all the streams are de-routed before disabling the device */ - audio_route_update_mixer(adev->audio_route); + /* All streams have been de-routed. Disable the device */ list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); @@ -716,8 +702,6 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) out_snd_device, in_snd_device); - audio_route_update_mixer(adev->audio_route); - usecase->in_snd_device = in_snd_device; usecase->out_snd_device = out_snd_device; -- GitLab From 9d2feb772a977454f9bf90373fff98d9fa29d5c0 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Tue, 29 Apr 2014 18:40:21 -0700 Subject: [PATCH 205/298] Revert "audio: primary desc check for sonification" This reverts commit 785b693a0fa89aebbec4137fc9cc52b2b160174f Change-Id: I70cb4e74eb47b6fd936f9ddd8afb602441a9ad7e CRs-Fixed: 656945 --- policy_hal/AudioPolicyManager.cpp | 187 ------------------------------ policy_hal/AudioPolicyManager.h | 19 +-- 2 files changed, 10 insertions(+), 196 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index d18ae6663..64842a164 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -475,193 +475,6 @@ void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem:: } -status_t AudioPolicyManager::startOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session) -{ - ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - ALOGW("startOutput() unknow output %d", output); - return BAD_VALUE; - } - - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - - // increment usage count for this stream on the requested output: - // NOTE that the usage count is the same for duplicated output and hardware output which is - // necessary for a correct control of hardware output routing by startOutput() and stopOutput() - outputDesc->changeRefCount(stream, 1); - - if (outputDesc->mRefCount[stream] == 1) { - audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); - routing_strategy strategy = getStrategy(stream); - bool shouldWait = (strategy == STRATEGY_SONIFICATION) || - (strategy == STRATEGY_SONIFICATION_RESPECTFUL); - uint32_t waitMs = 0; - bool force = false; - for (size_t i = 0; i < mOutputs.size(); i++) { - AudioOutputDescriptor *desc = mOutputs.valueAt(i); - if (desc != outputDesc) { - // force a device change if any other output is managed by the same hw - // module and has a current device selection that differs from selected device. - // In this case, the audio HAL must receive the new device selection so that it can - // change the device currently selected by the other active output. - if (outputDesc->sharesHwModuleWith(desc) && - desc->device() != newDevice) { - force = true; - } - // wait for audio on other active outputs to be presented when starting - // a notification so that audio focus effect can propagate. - uint32_t latency = desc->latency(); - if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) { - waitMs = latency; - } - } - } - uint32_t muteWaitMs = setOutputDevice(output, newDevice, force); - - // handle special case for sonification while in call - if (isInCall()) { - handleIncallSonification(stream, true, false); - } - - // apply volume rules for current stream and device if necessary - checkAndSetVolume(stream, - mStreams[stream].getVolumeIndex(newDevice), - output, - newDevice); - - // update the outputs if starting an output with a stream that can affect notification - // routing - handleNotificationRoutingForStream(stream); - if (waitMs > muteWaitMs) { - usleep((waitMs - muteWaitMs) * 2 * 1000); - } - } -#ifdef DOLBY_UDC - // It is observed that in some use-cases where both outputs are present eg. bluetooth and headphone, - // the output for particular stream type is decided in this routine. Hence we must call - // getDeviceForStrategy in order to get the current active output for this stream type and update - // the dolby system property. - if (stream == AudioSystem::MUSIC) - { - audio_devices_t audioOutputDevice = getDeviceForStrategy(getStrategy(AudioSystem::MUSIC), true); - DolbySystemProperty::set(audioOutputDevice); - } -#endif // DOLBY_END - return NO_ERROR; -} - - -status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session) -{ - ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - ALOGW("stopOutput() unknow output %d", output); - return BAD_VALUE; - } - - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - - // handle special case for sonification while in call - if (isInCall()) { - handleIncallSonification(stream, false, false); - } - - if (outputDesc->mRefCount[stream] > 0) { - // decrement usage count of this stream on the output - outputDesc->changeRefCount(stream, -1); - // store time at which the stream was stopped - see isStreamActive() - if (outputDesc->mRefCount[stream] == 0) { - outputDesc->mStopTime[stream] = systemTime(); - audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); - // delay the device switch by twice the latency because stopOutput() is executed when - // the track stop() command is received and at that time the audio track buffer can - // still contain data that needs to be drained. The latency only covers the audio HAL - // and kernel buffers. Also the latency does not always include additional delay in the - // audio path (audio DSP, CODEC ...) - setOutputDevice(output, newDevice, false, outputDesc->mLatency*2); - - // force restoring the device selection on other active outputs if it differs from the - // one being selected for this output - for (size_t i = 0; i < mOutputs.size(); i++) { - audio_io_handle_t curOutput = mOutputs.keyAt(i); - AudioOutputDescriptor *desc = mOutputs.valueAt(i); - if (curOutput != output && - desc->isActive() && - outputDesc->sharesHwModuleWith(desc) && - (newDevice != desc->device())) { - setOutputDevice(curOutput, - getNewDevice(curOutput, false /*fromCache*/), - true, - outputDesc->mLatency*2); - } - } - // update the outputs if stopping one with a stream that can affect notification routing - handleNotificationRoutingForStream(stream); - } - return NO_ERROR; - } else { - ALOGW("stopOutput() refcount is already 0 for output %d", output); - return INVALID_OPERATION; - } -} - -audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache) -{ - audio_devices_t device = AUDIO_DEVICE_NONE; - - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); - AudioOutputDescriptor *primaryOutputDesc = mOutputs.valueFor(mPrimaryOutput); - // check the following by order of priority to request a routing change if necessary: - // 1: the strategy enforced audible is active on the output: - // use device for strategy enforced audible - // 2: we are in call or the strategy phone is active on the output: - // use device for strategy phone - // 3: the strategy sonification is active on the output: - // use device for strategy sonification - // 4: the strategy "respectful" sonification is active on the output: - // use device for strategy "respectful" sonification - // 5: the strategy media is active on the output: - // use device for strategy media - // 6: the strategy DTMF is active on the output: - // use device for strategy DTMF - if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) { - device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); - } else if (isInCall() || - outputDesc->isStrategyActive(STRATEGY_PHONE)) { - device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); - } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)|| - (primaryOutputDesc->isStrategyActive(STRATEGY_SONIFICATION)&& !primaryOutputDesc->isStrategyActive(STRATEGY_MEDIA))){ - device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); - } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) { - device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); - } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) { - device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); - } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) { - device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); - } - - ALOGV("getNewDevice() selected device %x", device); - return device; -} - -//private function, no changes from AudioPolicyManagerBase -void AudioPolicyManager::handleNotificationRoutingForStream(AudioSystem::stream_type stream) { - switch(stream) { - case AudioSystem::MUSIC: - checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); - updateDevicesAndOutputs(); - break; - default: - break; - } -} - audio_io_handle_t AudioPolicyManager::getInput(int inputSource, uint32_t samplingRate, uint32_t format, diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 8ef1cabd2..6a2db85f8 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -50,13 +50,6 @@ public: AudioSystem::audio_in_acoustics acoustics); virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); virtual void setPhoneState(int state); - virtual status_t startOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session = 0); - virtual status_t stopOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session = 0); - protected: // return the strategy corresponding to a given stream type static routing_strategy getStrategy(AudioSystem::stream_type stream); @@ -84,12 +77,20 @@ protected: // check that volume change is permitted, compute and send new volume to audio hardware status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); - audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache); // returns the category the device belongs to with regard to volume curve management static device_category getDeviceCategory(audio_devices_t device); + static const char* HDMI_SPKR_STR; + + //parameter indicates of HDMI speakers disabled from the Qualcomm settings + bool mHdmiAudioDisabled; + + //parameter indicates if HDMI plug in/out detected + bool mHdmiAudioEvent; + private: - void handleNotificationRoutingForStream(AudioSystem::stream_type stream); + // Used for voip + voice concurrency usecase + int mPrevPhoneState; }; }; -- GitLab From ea098923e9e5dac1cd615bc124ddc6afe6de6921 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Thu, 24 Apr 2014 17:53:50 -0700 Subject: [PATCH 206/298] audio: Remove unused var 'update_mixer' Remove update_mixer (as its unused) and change function signatures wherever used. Change-Id: I465ddc4bfeba714a7f0d14a7e319a3d1ddc62dbb CRs-Fixed: 581453 --- hal/audio_extn/fm.c | 8 ++--- hal/audio_extn/hfp.c | 6 ++-- hal/audio_extn/spkr_protection.c | 34 +++++++++--------- hal/audio_hw.c | 60 +++++++++++++------------------- hal/audio_hw.h | 14 ++++---- hal/voice.c | 6 ++-- hal/voice_extn/compress_voip.c | 6 ++-- 7 files changed, 61 insertions(+), 73 deletions(-) diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c index 249ae9e3c..8a420bdc2 100644 --- a/hal/audio_extn/fm.c +++ b/hal/audio_extn/fm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -123,11 +123,11 @@ static int32_t fm_stop(struct audio_device *adev) } /* 2. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); + disable_audio_route(adev, uc_info); /* 3. Disable the rx and tx devices */ - disable_snd_device(adev, uc_info->out_snd_device, false); - disable_snd_device(adev, uc_info->in_snd_device, true); + disable_snd_device(adev, uc_info->out_snd_device); + disable_snd_device(adev, uc_info->in_snd_device); list_remove(&uc_info->list); free(uc_info); diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index 57d1f0c5c..add4a7c44 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -245,11 +245,11 @@ static int32_t stop_hfp(struct audio_device *adev) } /* 2. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); + disable_audio_route(adev, uc_info); /* 3. Disable the rx and tx devices */ - disable_snd_device(adev, uc_info->out_snd_device, false); - disable_snd_device(adev, uc_info->in_snd_device, true); + disable_snd_device(adev, uc_info->out_snd_device); + disable_snd_device(adev, uc_info->in_snd_device); list_remove(&uc_info->list); free(uc_info); diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c index 6c0eec0b7..f89fe861e 100644 --- a/hal/audio_extn/spkr_protection.c +++ b/hal/audio_extn/spkr_protection.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -227,8 +227,8 @@ static int spkr_calibrate(int t0) uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED; pthread_mutex_lock(&adev->lock); disable_rx = true; - enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED, true); - enable_audio_route(adev, uc_info_rx, true); + enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED); + enable_audio_route(adev, uc_info_rx); pthread_mutex_unlock(&adev->lock); pcm_dev_rx_id = platform_get_pcm_device_id(uc_info_rx->id, PCM_PLAYBACK); @@ -257,8 +257,8 @@ static int spkr_calibrate(int t0) pthread_mutex_lock(&adev->lock); disable_tx = true; - enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); - enable_audio_route(adev, uc_info_tx, true); + enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); + enable_audio_route(adev, uc_info_tx); pthread_mutex_unlock(&adev->lock); pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE); @@ -336,12 +336,12 @@ exit: handle.pcm_tx = NULL; pthread_mutex_lock(&adev->lock); if (disable_rx) { - disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED, true); - disable_audio_route(adev, uc_info_rx, true); + disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED); + disable_audio_route(adev, uc_info_rx); } if (disable_tx) { - disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); - disable_audio_route(adev, uc_info_tx, true); + disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); + disable_audio_route(adev, uc_info_tx); } pthread_mutex_unlock(&adev->lock); @@ -598,7 +598,7 @@ int audio_extn_spkr_prot_start_processing(snd_device_t snd_device) } ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED)); - audio_route_apply_path(adev->audio_route, + audio_route_apply_and_update_path(adev->audio_route, platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED)); pthread_mutex_lock(&handle.mutex_spkr_prot); @@ -610,8 +610,8 @@ int audio_extn_spkr_prot_start_processing(snd_device_t snd_device) uc_info_tx.out_snd_device = SND_DEVICE_NONE; handle.pcm_tx = NULL; - enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); - enable_audio_route(adev, &uc_info_tx, true); + enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); + enable_audio_route(adev, &uc_info_tx); pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx.id, PCM_CAPTURE); if (pcm_dev_tx_id < 0) { @@ -642,8 +642,8 @@ exit: if (handle.pcm_tx) pcm_close(handle.pcm_tx); handle.pcm_tx = NULL; - disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); - disable_audio_route(adev, &uc_info_tx, true); + disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); + disable_audio_route(adev, &uc_info_tx); } else handle.spkr_processing_state = SPKR_PROCESSING_IN_PROGRESS; pthread_mutex_unlock(&handle.mutex_spkr_prot); @@ -667,12 +667,12 @@ void audio_extn_spkr_prot_stop_processing() if (handle.pcm_tx) pcm_close(handle.pcm_tx); handle.pcm_tx = NULL; - disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true); - disable_audio_route(adev, &uc_info_tx, true); + disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK); + disable_audio_route(adev, &uc_info_tx); } handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE; pthread_mutex_unlock(&handle.mutex_spkr_prot); - audio_route_reset_path(adev->audio_route, + audio_route_reset_and_update_path(adev->audio_route, platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED)); ALOGV("%s: Exit", __func__); } diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 24cd787bf..eaf53d88d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -215,8 +215,7 @@ static int get_snd_codec_id(audio_format_t format) } int enable_audio_route(struct audio_device *adev, - struct audio_usecase *usecase, - bool __unused update_mixer) + struct audio_usecase *usecase) { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; @@ -244,8 +243,7 @@ int enable_audio_route(struct audio_device *adev, } int disable_audio_route(struct audio_device *adev, - struct audio_usecase *usecase, - bool __unused update_mixer) + struct audio_usecase *usecase) { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; @@ -267,8 +265,7 @@ int disable_audio_route(struct audio_device *adev, } int enable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool __unused update_mixer) + snd_device_t snd_device) { char device_name[DEVICE_NAME_MAX_SIZE] = {0}; @@ -321,8 +318,7 @@ int enable_snd_device(struct audio_device *adev, } int disable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool __unused update_mixer) + snd_device_t snd_device) { char device_name[DEVICE_NAME_MAX_SIZE] = {0}; @@ -401,7 +397,7 @@ static void check_usecases_codec_backend(struct audio_device *adev, ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", __func__, use_case_table[usecase->id], platform_get_snd_device_name(usecase->out_snd_device)); - disable_audio_route(adev, usecase, false); + disable_audio_route(adev, usecase); switch_device[usecase->id] = true; num_uc_to_switch++; } @@ -413,20 +409,17 @@ static void check_usecases_codec_backend(struct audio_device *adev, list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { - disable_snd_device(adev, usecase->out_snd_device, false); + disable_snd_device(adev, usecase->out_snd_device); } } list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { - enable_snd_device(adev, snd_device, false); + enable_snd_device(adev, snd_device); } } - /* Make sure new snd device is enabled before re-routing the streams */ - audio_route_update_mixer(adev->audio_route); - /* Re-route all the usecases on the shared backend other than the specified usecase to new snd devices */ list_for_each(node, &adev->usecase_list) { @@ -434,7 +427,7 @@ static void check_usecases_codec_backend(struct audio_device *adev, /* Update the out_snd_device only before enabling the audio route */ if (switch_device[usecase->id] ) { usecase->out_snd_device = snd_device; - enable_audio_route(adev, usecase, false); + enable_audio_route(adev, usecase); } } } @@ -470,7 +463,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", __func__, use_case_table[usecase->id], platform_get_snd_device_name(usecase->in_snd_device)); - disable_audio_route(adev, usecase, false); + disable_audio_route(adev, usecase); switch_device[usecase->id] = true; num_uc_to_switch++; } @@ -482,20 +475,17 @@ static void check_and_route_capture_usecases(struct audio_device *adev, list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { - disable_snd_device(adev, usecase->in_snd_device, false); + disable_snd_device(adev, usecase->in_snd_device); } } list_for_each(node, &adev->usecase_list) { usecase = node_to_item(node, struct audio_usecase, list); if (switch_device[usecase->id]) { - enable_snd_device(adev, snd_device, false); + enable_snd_device(adev, snd_device); } } - /* Make sure new snd device is enabled before re-routing the streams */ - audio_route_update_mixer(adev->audio_route); - /* Re-route all the usecases on the shared backend other than the specified usecase to new snd devices */ list_for_each(node, &adev->usecase_list) { @@ -503,7 +493,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev, /* Update the in_snd_device only before enabling the audio route */ if (switch_device[usecase->id] ) { usecase->in_snd_device = snd_device; - enable_audio_route(adev, usecase, false); + enable_audio_route(adev, usecase); } } } @@ -676,25 +666,25 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) /* Disable current sound devices */ if (usecase->out_snd_device != SND_DEVICE_NONE) { - disable_audio_route(adev, usecase, true); - disable_snd_device(adev, usecase->out_snd_device, false); + disable_audio_route(adev, usecase); + disable_snd_device(adev, usecase->out_snd_device); } if (usecase->in_snd_device != SND_DEVICE_NONE) { - disable_audio_route(adev, usecase, true); - disable_snd_device(adev, usecase->in_snd_device, false); + disable_audio_route(adev, usecase); + disable_snd_device(adev, usecase->in_snd_device); } /* Enable new sound devices */ if (out_snd_device != SND_DEVICE_NONE) { if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) check_usecases_codec_backend(adev, usecase, out_snd_device); - enable_snd_device(adev, out_snd_device, false); + enable_snd_device(adev, out_snd_device); } if (in_snd_device != SND_DEVICE_NONE) { check_and_route_capture_usecases(adev, usecase, in_snd_device); - enable_snd_device(adev, in_snd_device, false); + enable_snd_device(adev, in_snd_device); } if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) @@ -705,7 +695,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) usecase->in_snd_device = in_snd_device; usecase->out_snd_device = out_snd_device; - enable_audio_route(adev, usecase, true); + enable_audio_route(adev, usecase); /* Applicable only on the targets that has external modem. * Enable device command should be sent to modem only after @@ -740,10 +730,10 @@ static int stop_input_stream(struct stream_in *in) voice_check_and_stop_incall_rec_usecase(adev, in); /* 1. Disable stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); + disable_audio_route(adev, uc_info); /* 2. Disable the tx device */ - disable_snd_device(adev, uc_info->in_snd_device, true); + disable_snd_device(adev, uc_info->in_snd_device); list_remove(&uc_info->list); free(uc_info); @@ -1021,7 +1011,7 @@ static int check_and_set_hdmi_channels(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (usecase->type == PCM_PLAYBACK && usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - disable_audio_route(adev, usecase, true); + disable_audio_route(adev, usecase); } } @@ -1033,7 +1023,7 @@ static int check_and_set_hdmi_channels(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (usecase->type == PCM_PLAYBACK && usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - enable_audio_route(adev, usecase, true); + enable_audio_route(adev, usecase); } } @@ -1063,10 +1053,10 @@ static int stop_output_stream(struct stream_out *out) } /* 1. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); + disable_audio_route(adev, uc_info); /* 2. Disable the rx device */ - disable_snd_device(adev, uc_info->out_snd_device, true); + disable_snd_device(adev, uc_info->out_snd_device); list_remove(&uc_info->list); free(uc_info); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index e1172ef6f..e6ec012ec 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -242,17 +242,15 @@ struct audio_device { int select_devices(struct audio_device *adev, audio_usecase_t uc_id); int disable_audio_route(struct audio_device *adev, - struct audio_usecase *usecase, - bool update_mixer); + struct audio_usecase *usecase); int disable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool update_mixer); + snd_device_t snd_device); int enable_snd_device(struct audio_device *adev, - snd_device_t snd_device, - bool update_mixer); + snd_device_t snd_device); + int enable_audio_route(struct audio_device *adev, - struct audio_usecase *usecase, - bool update_mixer); + struct audio_usecase *usecase); + struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id); diff --git a/hal/voice.c b/hal/voice.c index 82813f6a8..9bde5708a 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -88,11 +88,11 @@ int stop_call(struct audio_device *adev, audio_usecase_t usecase_id) } /* 2. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); + disable_audio_route(adev, uc_info); /* 3. Disable the rx and tx devices */ - disable_snd_device(adev, uc_info->out_snd_device, false); - disable_snd_device(adev, uc_info->in_snd_device, true); + disable_snd_device(adev, uc_info->out_snd_device); + disable_snd_device(adev, uc_info->in_snd_device); list_remove(&uc_info->list); free(uc_info); diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 47ac2c882..deb3172c6 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -305,11 +305,11 @@ static int voip_stop_call(struct audio_device *adev) } /* 2. Get and set stream specific mixer controls */ - disable_audio_route(adev, uc_info, true); + disable_audio_route(adev, uc_info); /* 3. Disable the rx and tx devices */ - disable_snd_device(adev, uc_info->out_snd_device, false); - disable_snd_device(adev, uc_info->in_snd_device, true); + disable_snd_device(adev, uc_info->out_snd_device); + disable_snd_device(adev, uc_info->in_snd_device); list_remove(&uc_info->list); free(uc_info); -- GitLab From e293e173af7abcfa4ac2d276d7f67db7626b3b7f Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Fri, 2 May 2014 15:52:46 +0530 Subject: [PATCH 207/298] Audiod: Priority change for AudioDaemon - Device getting crash after preforming ADSP/LPASS SSR during compress playback - Due to continous compress write calls to compress driver audio daemon not getting schduled which results system crash - Change AudioDaemon priority from PRIORITY_AUDIO to PRIORITY_URGENT_AUDIO to make sure audio daemon scheduled prior to audio HAL Change-Id: I0d7dff30908d4e1f727c1eb6af9e66ed74095148 --- audiod/AudioDaemon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audiod/AudioDaemon.cpp b/audiod/AudioDaemon.cpp index 6c8d99128..610563579 100644 --- a/audiod/AudioDaemon.cpp +++ b/audiod/AudioDaemon.cpp @@ -48,7 +48,7 @@ namespace android { void AudioDaemon::onFirstRef() { ALOGV("Start audiod daemon"); - run("AudioDaemon", PRIORITY_AUDIO); + run("AudioDaemon", PRIORITY_URGENT_AUDIO); } void AudioDaemon::binderDied(const wp& who) -- GitLab From 6c34443ddad38fab392efc69033d495741c5e12f Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Thu, 1 May 2014 15:37:31 -0700 Subject: [PATCH 208/298] hal: configure HDMI channels based on sink capability. - configure output HDMI channel count based on sink capability when audio.use.hdmi.sink.cap is set to true CRs-Fixed: 656308 Change-Id: I3dd3226054c68a69a2c29f8bb2f9c27e429ad2dc --- hal/audio_hw.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index eaf53d88d..143c6dfb2 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1072,6 +1072,8 @@ static int stop_output_stream(struct stream_out *out) int start_output_stream(struct stream_out *out) { int ret = 0; + int sink_channels = 0; + char prop_value[PROPERTY_VALUE_MAX] = {0}; struct audio_usecase *uc_info; struct audio_device *adev = out->dev; @@ -1095,10 +1097,17 @@ int start_output_stream(struct stream_out *out) /* This must be called before adding this usecase to the list */ if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) - check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in); - else - check_and_set_hdmi_channels(adev, out->config.channels); + property_get("audio.use.hdmi.sink.cap", prop_value, NULL); + if (!strncmp("true", prop_value, 4)) { + sink_channels = platform_edid_get_max_channels(out->dev->platform); + ALOGD("%s: set HDMI channel count[%d] based on sink capability", __func__, sink_channels); + check_and_set_hdmi_channels(adev, sink_channels); + } else { + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) + check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in); + else + check_and_set_hdmi_channels(adev, out->config.channels); + } } list_add_tail(&adev->usecase_list, &uc_info->list); -- GitLab From 674837a6ea5d4446df763b1f66e8fb7fd8f70d15 Mon Sep 17 00:00:00 2001 From: Anish Kumar Date: Thu, 17 Apr 2014 12:42:20 -0700 Subject: [PATCH 209/298] hal: Set echo reference from mixer file Set echo reference from mixer file. Change-Id: I8b9d1209002ead0f82eb6052d41ab00ba41ce6a2 --- hal/msm8960/platform.c | 22 ++++++++-------------- hal/msm8974/platform.c | 30 ++++++++++++------------------ 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index dacf68e40..09f08ca72 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -193,20 +193,14 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) -static int set_echo_reference(struct mixer *mixer, const char* ec_ref) +static void set_echo_reference(struct audio_device *adev, bool enable) { - struct mixer_ctl *ctl; - const char *mixer_ctl_name = "EC_REF_RX"; + if (enable) + audio_route_apply_and_update_path(adev->audio_route, "echo-reference"); + else + audio_route_reset_and_update_path(adev->audio_route, "echo-reference"); - ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("Setting EC Reference: %s", ec_ref); - mixer_ctl_set_enum_by_string(ctl, ec_ref); - return 0; + ALOGV("Setting EC Reference: %d", enable); } void *platform_init(struct audio_device *adev) @@ -738,9 +732,9 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC; } - set_echo_reference(adev->mixer, "SLIM_RX"); + set_echo_reference(adev, true); } else - set_echo_reference(adev->mixer, "NONE"); + set_echo_reference(adev, false); } } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index b0cc5a7f6..3b5ef3b59 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -317,20 +317,14 @@ static const int acdb_device_table[SND_DEVICE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) -static int set_echo_reference(struct mixer *mixer, const char* ec_ref) +static void set_echo_reference(struct audio_device *adev, bool enable) { - struct mixer_ctl *ctl; - const char *mixer_ctl_name = "EC_REF_RX"; + if (enable) + audio_route_apply_and_update_path(adev->audio_route, "echo-reference"); + else + audio_route_reset_and_update_path(adev->audio_route, "echo-reference"); - ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name); - if (!ctl) { - ALOGE("%s: Could not get ctl for mixer cmd - %s", - __func__, mixer_ctl_name); - return -EINVAL; - } - ALOGV("Setting EC Reference: %s", ec_ref); - mixer_ctl_set_enum_by_string(ctl, ec_ref); - return 0; + ALOGV("Setting EC Reference: %d", enable); } static struct csd_data *open_csd_client() @@ -1161,7 +1155,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (my_data->fluence_type == FLUENCE_NONE || my_data->fluence_in_voice_call == false) { snd_device = SND_DEVICE_IN_HANDSET_MIC; - set_echo_reference(adev->mixer, EC_REF_RX); + set_echo_reference(adev, true); } else { snd_device = SND_DEVICE_IN_VOICE_DMIC; adev->acdb_settings |= DMIC_FLAG; @@ -1232,7 +1226,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; } - set_echo_reference(adev->mixer, EC_REF_RX); + set_echo_reference(adev, true); } else if (adev->active_input->enable_aec) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { if (my_data->fluence_type & FLUENCE_DUAL_MIC) { @@ -1249,7 +1243,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; } - set_echo_reference(adev->mixer, EC_REF_RX); + set_echo_reference(adev, true); } else if (adev->active_input->enable_ns) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { if (my_data->fluence_type & FLUENCE_DUAL_MIC) { @@ -1266,9 +1260,9 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE; } - set_echo_reference(adev->mixer, "NONE"); + set_echo_reference(adev, false); } else - set_echo_reference(adev->mixer, "NONE"); + set_echo_reference(adev, false); } } else if (source == AUDIO_SOURCE_MIC) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC && @@ -1276,7 +1270,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d if(my_data->fluence_type & FLUENCE_DUAL_MIC && my_data->fluence_in_audio_rec) { snd_device = SND_DEVICE_IN_HANDSET_DMIC; - set_echo_reference(adev->mixer, EC_REF_RX); + set_echo_reference(adev, true); } } } else if (source == AUDIO_SOURCE_FM_RX || -- GitLab From a1673712b85ebea5b6a292a95ef9422731d02547 Mon Sep 17 00:00:00 2001 From: Ben Romberger Date: Fri, 10 Jan 2014 13:49:02 -0800 Subject: [PATCH 210/298] hal: Add XML parser for platform info Add XML parser which parses the platform_info.xml on the device. That xml contains ACDB ID information and is populated from the device project folder to the /etc folder on the device. It is used to overwrite hardcoded ACDB ID's in platform.c. CRs-Fixed: 645819 Change-Id: I86419bf0f48bcf7f0125da58626adab1d23fa50a --- hal/Android.mk | 6 ++ hal/msm8960/platform.c | 7 +- hal/msm8974/platform.c | 22 ++++- hal/msm8974/platform_parser.c | 161 ++++++++++++++++++++++++++++++++++ hal/msm8974/platform_parser.h | 35 ++++++++ hal/platform_api.h | 7 +- 6 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 hal/msm8974/platform_parser.c create mode 100644 hal/msm8974/platform_parser.h diff --git a/hal/Android.mk b/hal/Android.mk index c4534b639..d4862f23f 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -129,6 +129,12 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/audio_extn \ $(LOCAL_PATH)/voice_extn +ifneq ($(filter msm8974,$(AUDIO_PLATFORM)),) + LOCAL_C_INCLUDES += external/expat/lib + LOCAL_SHARED_LIBRARIES += libexpat + LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/platform_parser.c +endif + ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true) LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-listen diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 09f08ca72..bbf85b0ef 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -385,6 +385,11 @@ int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) return device_id; } +int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id) +{ + return -ENODEV; +} + int platform_send_audio_calibration(void *platform, snd_device_t snd_device) { struct platform_data *my_data = (struct platform_data *)platform; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 3b5ef3b59..7d9c7bf72 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -32,6 +32,7 @@ #include "audio_extn.h" #include "voice_extn.h" #include "sound/compress_params.h" +#include "platform_parser.h" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" @@ -242,7 +243,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { }; /* ACDB IDs (audio DSP path configuration IDs) for each sound device */ -static const int acdb_device_table[SND_DEVICE_MAX] = { +static int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_NONE] = -1, [SND_DEVICE_OUT_HANDSET] = 7, [SND_DEVICE_OUT_SPEAKER] = 14, @@ -586,6 +587,9 @@ void *platform_init(struct audio_device *adev) my_data->acdb_init(); } + /* Initialize ACDB ID's */ + platform_info_init(); + /* If platform is apq8084 and baseband is MDM, load CSD Client specific * symbols. Voice call is handled by MDM and apps processor talks to * MDM through CSD Client @@ -723,6 +727,22 @@ done: return ret; } +int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id) +{ + int ret = 0; + + if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) { + ALOGE("%s: Invalid snd_device = %d", + __func__, snd_device); + ret = -EINVAL; + goto done; + } + + acdb_device_table[snd_device] = acdb_id; +done: + return ret; +} + int platform_get_fluence_type(void *platform, char *value, uint32_t len) { int ret = 0; diff --git a/hal/msm8974/platform_parser.c b/hal/msm8974/platform_parser.c new file mode 100644 index 000000000..8f86d9733 --- /dev/null +++ b/hal/msm8974/platform_parser.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "platform_parser" +#define LOG_NDDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include "platform.h" +#include "platform_parser.h" + +#define PLATFORM_XML_PATH "/system/etc/platform_info.xml" +#define BUF_SIZE 1024 + +static void process_device(void *userdata, const XML_Char **attr) +{ + unsigned int *snd_device_index = userdata; + + if (strcmp(attr[0], "name") != 0) + goto done; + + if (platform_get_snd_device_name(*snd_device_index) == NULL) + goto next; + if (strcmp(attr[1], platform_get_snd_device_name(*snd_device_index)) != 0) { + ALOGE("%s: %s in platform.h at index %d does not match %s, from %s no ACDB ID set!", + __func__, platform_get_snd_device_name(*snd_device_index), + *snd_device_index, attr[1], PLATFORM_XML_PATH); + goto done; + } + + if (strcmp(attr[2], "acdb_id") != 0) { + ALOGE("%s: Device %s at index %d in %s has no acdb_id, no ACDB ID set!", + __func__, attr[1], *snd_device_index, PLATFORM_XML_PATH); + goto done; + } + + if(platform_set_snd_device_acdb_id(*snd_device_index, + atoi((char *)attr[3])) != 0) + goto done; + +next: + (*snd_device_index)++; +done: + return; +} + +static void start_tag(void *userdata, const XML_Char *tag_name, + const XML_Char **attr) +{ + const XML_Char *attr_name = NULL; + const XML_Char *attr_value = NULL; + unsigned int i; + + if (strcmp(tag_name, "device") == 0) + process_device(userdata, attr); + + return; +} + +static void end_tag(void *userdata, const XML_Char *tag_name) +{ + +} + +int platform_info_init(void) +{ + XML_Parser parser; + FILE *file; + int ret = 0; + int bytes_read; + unsigned int snd_device_index = SND_DEVICE_MIN; + void *buf; + + file = fopen(PLATFORM_XML_PATH, "r"); + if (!file) { + ALOGD("%s: Failed to open %s, using defaults.", + __func__, PLATFORM_XML_PATH); + ret = -ENODEV; + goto done; + } + + parser = XML_ParserCreate(NULL); + if (!parser) { + ALOGE("%s: Failed to create XML parser!", __func__); + ret = -ENODEV; + goto err_close_file; + } + + XML_SetUserData(parser, &snd_device_index); + XML_SetElementHandler(parser, start_tag, end_tag); + + while (1) { + buf = XML_GetBuffer(parser, BUF_SIZE); + if (buf == NULL) { + ALOGE("%s: XML_GetBuffer failed", __func__); + ret = -ENOMEM; + goto err_free_parser; + } + + bytes_read = fread(buf, 1, BUF_SIZE, file); + if (bytes_read < 0) { + ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read); + ret = bytes_read; + goto err_free_parser; + } + + if (XML_ParseBuffer(parser, bytes_read, + bytes_read == 0) == XML_STATUS_ERROR) { + ALOGE("%s: XML_ParseBuffer failed, for %s", + __func__, PLATFORM_XML_PATH); + ret = -EINVAL; + goto err_free_parser; + } + + if (bytes_read == 0) + break; + } + + if (snd_device_index != SND_DEVICE_MAX) { + ALOGE("%s: Only %d/%d ACDB ID's set! Fix %s!", + __func__, snd_device_index, SND_DEVICE_MAX, PLATFORM_XML_PATH); + ret = -EINVAL; + } + +err_free_parser: + XML_ParserFree(parser); +err_close_file: + fclose(file); +done: + return ret; +} diff --git a/hal/msm8974/platform_parser.h b/hal/msm8974/platform_parser.h new file mode 100644 index 000000000..3e9193482 --- /dev/null +++ b/hal/msm8974/platform_parser.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AUDIO_PLATFORM_PARSER_H +#define AUDIO_PLATFORM_PARSER_H + +int platform_info_init(void); + +#endif // AUDIO_PLATFORM_PARSER_H diff --git a/hal/platform_api.h b/hal/platform_api.h index 7c4171d5b..913fd8270 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -17,8 +17,8 @@ * limitations under the License. */ -#ifndef QCOM_AUDIO_PLATFORM_API_H -#define QCOM_AUDIO_PLATFORM_API_H +#ifndef AUDIO_PLATFORM_API_H +#define AUDIO_PLATFORM_API_H void *platform_init(struct audio_device *adev); void platform_deinit(void *platform); @@ -29,6 +29,7 @@ void platform_add_backend_name(char *mixer_path, snd_device_t snd_device); int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type); int platform_set_fluence_type(void *platform, char *value); int platform_get_fluence_type(void *platform, char *value, uint32_t len); +int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id); int platform_send_audio_calibration(void *platform, snd_device_t snd_device); int platform_switch_voice_call_device_pre(void *platform); int platform_switch_voice_call_device_post(void *platform, -- GitLab From a1a9ee0cd00e67985f4542a597db4324a0657d5e Mon Sep 17 00:00:00 2001 From: kunleiz Date: Thu, 24 Apr 2014 18:46:22 +0800 Subject: [PATCH 211/298] hal: Fix VoIP Mute failure in SIP call during Voice call HOLD - Unable to apply the mute in MT SIP call during Voice call in CALL_HOLD. - Mute is only applied if the voice call state is INACTIVE. Thus when SIP call is made during Voice call in CALL_HOLD, the mute is not being reflected. - Fix this issue by checking voice stream type to allow the mute to be applied. Change-Id: I3af5225edd8e9a4123867b647de9405d5c4b9efc CRs-Fixed: 642893 --- hal/audio_hw.c | 2 +- hal/voice.c | 13 +++++++++++++ hal/voice.h | 1 + hal/voice_extn/voice_extn.c | 13 +++++++++++++ hal/voice_extn/voice_extn.h | 6 ++++++ 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index c0d47d925..1fb6fda39 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1977,7 +1977,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, * Instead of writing zeroes here, we could trust the hardware * to always provide zeroes when muted. */ - if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call(adev)) + if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in)) memset(buffer, 0, bytes); exit: diff --git a/hal/voice.c b/hal/voice.c index 82813f6a8..4417ecebc 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -189,6 +189,19 @@ bool voice_is_in_call(struct audio_device *adev) return in_call; } +bool voice_is_in_call_rec_stream(struct stream_in *in) +{ + bool in_call_rec = false; + int ret = 0; + + ret = voice_extn_is_in_call_rec_stream(in, &in_call_rec); + if (ret == -ENOSYS) { + in_call_rec = false; + } + + return in_call_rec; +} + uint32_t voice_get_active_session_id(struct audio_device *adev) { int ret = 0; diff --git a/hal/voice.h b/hal/voice.h index d160569d8..0098f944a 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -77,6 +77,7 @@ void voice_get_parameters(struct audio_device *adev, struct str_parms *query, struct str_parms *reply); void voice_init(struct audio_device *adev); bool voice_is_in_call(struct audio_device *adev); +bool voice_is_in_call_rec_stream(struct stream_in *in); int voice_set_mic_mute(struct audio_device *dev, bool state); bool voice_get_mic_mute(struct audio_device *dev); int voice_set_volume(struct audio_device *adev, float volume); diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index f6083f3d1..58a1f8bec 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -356,6 +356,19 @@ int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) return 0; } +int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec) +{ + *in_call_rec = false; + + if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK || + in->source == AUDIO_SOURCE_VOICE_UPLINK || + in->source == AUDIO_SOURCE_VOICE_CALL) { + *in_call_rec = true; + } + + return 0; +} + void voice_extn_init(struct audio_device *adev) { adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID; diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index f7d20e4ce..4a9c610fd 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -33,6 +33,7 @@ void voice_extn_get_parameters(const struct audio_device *adev, struct str_parms *query, struct str_parms *reply); int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); +int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec); int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id); void voice_extn_in_get_parameters(struct stream_in *in, @@ -80,6 +81,11 @@ static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) return -ENOSYS; } +static int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec) +{ + return -ENOSYS; +} + static int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id) { -- GitLab From 4673b151fc858123eefaf0706ad300981cc63221 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 6 May 2014 16:48:17 +0530 Subject: [PATCH 212/298] post_proc: disable Bassboost and Virtualizer for USB_ACCESSORY USB_ACCESSORY is not intended to be applied with SA+ bassboost and virtualizer, so add into invalid devices list. CRs-Fixed: 659191 Change-Id: If1f3421f9935ce624dc21895d9244d36d195b2bd --- post_proc/bass_boost.c | 1 + post_proc/virtualizer.c | 1 + 2 files changed, 2 insertions(+) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c index 2061cd062..bea1fbc23 100644 --- a/post_proc/bass_boost.c +++ b/post_proc/bass_boost.c @@ -156,6 +156,7 @@ int bassboost_set_device(effect_context_t *context, uint32_t device) (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) || (device == AUDIO_DEVICE_OUT_PROXY) || (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) || + (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) || (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) { if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c index 8f6d00069..484a7388c 100644 --- a/post_proc/virtualizer.c +++ b/post_proc/virtualizer.c @@ -156,6 +156,7 @@ int virtualizer_set_device(effect_context_t *context, uint32_t device) (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) || (device == AUDIO_DEVICE_OUT_PROXY) || (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) || + (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) || (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) { if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); -- GitLab From 34fb4cbdee4e14f9d48d5f3308263c6b14a92906 Mon Sep 17 00:00:00 2001 From: Vicky Sehrawat Date: Fri, 9 May 2014 16:28:40 -0700 Subject: [PATCH 213/298] hal: Add support for VoWLAN on MSM8974 Update the VoWLAN pcm id for MSM8974 CRs-fixed: 662362 Change-Id: Ia0894fa1347f05e55993af91da91272af3161f83 --- hal/msm8974/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index be4f5d477..2d6f854d1 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -220,7 +220,7 @@ enum { #define VOICE2_CALL_PCM_DEVICE 22 #define VOLTE_CALL_PCM_DEVICE 14 #define QCHAT_CALL_PCM_DEVICE 20 -#define VOWLAN_CALL_PCM_DEVICE -1 +#define VOWLAN_CALL_PCM_DEVICE 36 #endif #ifdef PLATFORM_MSM8x26 -- GitLab From 74ff5955621fb2dccc865448063b092392648be3 Mon Sep 17 00:00:00 2001 From: wjiang Date: Thu, 15 May 2014 19:38:26 +0800 Subject: [PATCH 214/298] post_proc: fix post and pre process KW issues KW issue fix includes: - handle memory allocation failure - array index boundary check Change-Id: I083952ba58d348a5b650601a83e6f492b0d686bb --- post_proc/bundle.c | 17 +++++++++++++++++ post_proc/effect_api.c | 5 +++-- visualizer/offload_visualizer.c | 9 +++++++++ voice_processing/voice_processing.c | 8 ++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/post_proc/bundle.c b/post_proc/bundle.c index 8e2bce8de..fa740c8d0 100644 --- a/post_proc/bundle.c +++ b/post_proc/bundle.c @@ -199,6 +199,11 @@ int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id output_context_t *out_ctxt = (output_context_t *) malloc(sizeof(output_context_t)); + if (!out_ctxt) { + ALOGE("%s fail to allocate for output context", __func__); + ret = -ENOMEM; + goto exit; + } out_ctxt->handle = output; out_ctxt->pcm_device_id = pcm_id; @@ -332,6 +337,9 @@ int effect_lib_create(const effect_uuid_t *uuid, sizeof(effect_uuid_t)) == 0) { equalizer_context_t *eq_ctxt = (equalizer_context_t *) calloc(1, sizeof(equalizer_context_t)); + if (eq_ctxt == NULL) { + return -ENOMEM; + } context = (effect_context_t *)eq_ctxt; context->ops.init = equalizer_init; context->ops.reset = equalizer_reset; @@ -349,6 +357,9 @@ int effect_lib_create(const effect_uuid_t *uuid, sizeof(effect_uuid_t)) == 0) { bassboost_context_t *bass_ctxt = (bassboost_context_t *) calloc(1, sizeof(bassboost_context_t)); + if (bass_ctxt == NULL) { + return -ENOMEM; + } context = (effect_context_t *)bass_ctxt; context->ops.init = bassboost_init; context->ops.reset = bassboost_reset; @@ -366,6 +377,9 @@ int effect_lib_create(const effect_uuid_t *uuid, sizeof(effect_uuid_t)) == 0) { virtualizer_context_t *virt_ctxt = (virtualizer_context_t *) calloc(1, sizeof(virtualizer_context_t)); + if (virt_ctxt == NULL) { + return -ENOMEM; + } context = (effect_context_t *)virt_ctxt; context->ops.init = virtualizer_init; context->ops.reset = virtualizer_reset; @@ -389,6 +403,9 @@ int effect_lib_create(const effect_uuid_t *uuid, sizeof(effect_uuid_t)) == 0)) { reverb_context_t *reverb_ctxt = (reverb_context_t *) calloc(1, sizeof(reverb_context_t)); + if (reverb_ctxt == NULL) { + return -ENOMEM; + } context = (effect_context_t *)reverb_ctxt; context->ops.init = reverb_init; context->ops.reset = reverb_reset; diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c index 570ca8b51..f17a4911c 100644 --- a/post_proc/effect_api.c +++ b/post_proc/effect_api.c @@ -311,8 +311,9 @@ int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, int *p_param_values = param_values; uint32_t i; - ALOGV("%s", __func__); - if (eq.config.preset_id < -1 ) { + ALOGV("%s: flags 0x%x", __func__, param_send_flags); + if ((eq.config.preset_id < -1) || + ((param_send_flags & OFFLOAD_SEND_EQ_PRESET) && (eq.config.preset_id == -1))) { ALOGV("No Valid preset to set"); return 0; } diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c index 95b468746..94c44a59b 100644 --- a/visualizer/offload_visualizer.c +++ b/visualizer/offload_visualizer.c @@ -431,6 +431,11 @@ int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) { } output_context_t *out_ctxt = (output_context_t *)malloc(sizeof(output_context_t)); + if (out_ctxt == NULL) { + ALOGE("%s fail to allocate memory", __func__); + ret = -ENOMEM; + goto exit; + } out_ctxt->handle = output; list_init(&out_ctxt->effects_list); @@ -927,6 +932,10 @@ int effect_lib_create(const effect_uuid_t *uuid, if (memcmp(uuid, &visualizer_descriptor.uuid, sizeof(effect_uuid_t)) == 0) { visualizer_context_t *visu_ctxt = (visualizer_context_t *)calloc(1, sizeof(visualizer_context_t)); + if (visu_ctxt == NULL) { + ALOGE("%s fail to allocate memory", __func__); + return -ENOMEM; + } context = (effect_context_t *)visu_ctxt; context->ops.init = visualizer_init; context->ops.reset = visualizer_reset; diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c index b8b1e1b0a..1d18a3d2c 100644 --- a/voice_processing/voice_processing.c +++ b/voice_processing/voice_processing.c @@ -408,6 +408,10 @@ static struct session_s *get_session(int32_t id, int32_t sessionId, int32_t io } session = (struct session_s *)calloc(1, sizeof(struct session_s)); + if (session == NULL) { + ALOGE("get_session() fail to allocate memory"); + return NULL; + } session_init(session); session->id = sessionId; session->io = ioId; @@ -682,6 +686,10 @@ static int lib_create(const effect_uuid_t *uuid, return -EINVAL; } id = uuid_to_id(&desc->type); + if (id >= NUM_ID) { + ALOGW("lib_create: fx not found type: %08x", desc->type.timeLow); + return -EINVAL; + } session = get_session(id, sessionId, ioId); -- GitLab From 5cf8c1a93863f7727d2781af18d30cdc0ecec57f Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Thu, 8 May 2014 12:22:16 +0530 Subject: [PATCH 215/298] hal: Fix teardown during back to back pause/play of WFD session - When an active WFD session is paused/played continuously from the WFDClient app, the session tears down after a few iterations if touch tones are enabled. - The output device is switched back and forth between speaker and proxy when the session is paused and played continuously. When this happens, sometimes, there is no backend to write the low latency output which results in pcm_write getting blocked. - Fix the issue by not routing the low latency output to speaker if the previous device is proxy. CRs-Fixed: 630234 Change-Id: I6bbe82badd3d5ee857e920430304c3a45c5b44c7 --- policy_hal/AudioPolicyManager.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 64842a164..949e4ffb9 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -193,8 +193,16 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, // do not force device change on duplicated output because if device is 0, it will // also force a device 0 for the two outputs it is duplicated to which may override // a valid device selection on those outputs. + audio_devices_t cachedDevice = getNewDevice(mOutputs.keyAt(i), true /*fromCache*/); + AudioOutputDescriptor *desc = mOutputs.valueFor(mOutputs.keyAt(i)); + if (cachedDevice == AUDIO_DEVICE_OUT_SPEAKER && + device == AUDIO_DEVICE_OUT_PROXY && + (desc->mFlags & AUDIO_OUTPUT_FLAG_FAST)) { + ALOGI("Avoid routing touch tone to spkr as proxy is being disconnected"); + break; + } setOutputDevice(mOutputs.keyAt(i), - getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), + cachedDevice, !mOutputs.valueAt(i)->isDuplicated(), 0); } -- GitLab From fa5187814c5b7f1241b3c47a159b229446235a92 Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Wed, 21 May 2014 14:45:28 +0530 Subject: [PATCH 216/298] hal: Fix no Tx issue during multi party HFP calls - When an incoming MT HFP call is accepted during an ongoing MO HFP call, the MO call goes to held state. Later, if this held call is rejected, Tx is not heard at the far end of the incoming call from that moment. - When the held call is rejected, the input device gets disabled due to which Tx samples are not captured. - Fix the issue by ensuring that the input device is not set to none when HFP is active. CRs-Fixed: 656928 Change-Id: Ie3f0886c0412bfdb3e450c54e9f4b651e992f84e --- hal/msm8974/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index d2e2466b6..e0f9df550 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1145,7 +1145,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d ALOGV("%s: enter: out_device(%#x) in_device(%#x)", __func__, out_device, in_device); if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) || - voice_extn_compress_voip_is_active(adev))) { + voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) { if ((adev->voice.tty_mode != TTY_MODE_OFF) && !voice_extn_compress_voip_is_active(adev)) { if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE || -- GitLab From b2c7ac1aa76410e3558ea83aee19e5b436399eb9 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 25 Mar 2014 17:41:44 +0530 Subject: [PATCH 217/298] post_proc: improve logging Make logs more meaningful and remove ones not necessary. Change-Id: I9562cf34a5dee406b1c0347a9004db08de9cd5df --- post_proc/bass_boost.c | 27 +++++++------- post_proc/bundle.c | 15 ++++---- post_proc/effect_api.c | 78 ++++++++++++++++++++++------------------- post_proc/equalizer.c | 50 ++++++++++---------------- post_proc/reverb.c | 70 +++++++++++++++--------------------- post_proc/virtualizer.c | 24 ++++++------- 6 files changed, 121 insertions(+), 143 deletions(-) diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c index bea1fbc23..4edd9af98 100644 --- a/post_proc/bass_boost.c +++ b/post_proc/bass_boost.c @@ -47,13 +47,14 @@ const effect_descriptor_t bassboost_descriptor = { int bassboost_get_strength(bassboost_context_t *context) { - ALOGV("%s: strength: %d", __func__, context->strength); + ALOGV("%s: ctxt %p, strength: %d", __func__, + context, context->strength); return context->strength; } int bassboost_set_strength(bassboost_context_t *context, uint32_t strength) { - ALOGV("%s: strength: %d", __func__, strength); + ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength); context->strength = strength; offload_bassboost_set_strength(&(context->offload_bass), strength); @@ -74,7 +75,7 @@ int bassboost_get_parameter(effect_context_t *context, effect_param_t *p, void *value = p->data + voffset; int i; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param); p->status = 0; @@ -100,12 +101,10 @@ int bassboost_get_parameter(effect_context_t *context, effect_param_t *p, switch (param) { case BASSBOOST_PARAM_STRENGTH_SUPPORTED: - ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__); *(uint32_t *)value = 1; break; case BASSBOOST_PARAM_STRENGTH: - ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__); *(int16_t *)value = bassboost_get_strength(bass_ctxt); break; @@ -127,13 +126,12 @@ int bassboost_set_parameter(effect_context_t *context, effect_param_t *p, int32_t param = *param_tmp++; uint32_t strength; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param); p->status = 0; switch (param) { case BASSBOOST_PARAM_STRENGTH: - ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__); strength = (uint32_t)(*(int16_t *)value); bassboost_set_strength(bass_ctxt, strength); break; @@ -149,7 +147,7 @@ int bassboost_set_device(effect_context_t *context, uint32_t device) { bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; - ALOGV("%s: device: %d", __func__, device); + ALOGV("%s: ctxt %p, device 0x%x", __func__, bass_ctxt, device); bass_ctxt->device = device; if((device == AUDIO_DEVICE_OUT_SPEAKER) || (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || @@ -165,6 +163,7 @@ int bassboost_set_device(effect_context_t *context, uint32_t device) offload_bassboost_send_params(bass_ctxt->ctl, bass_ctxt->offload_bass, OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); + ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt); } } else { if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) && @@ -192,7 +191,7 @@ int bassboost_init(effect_context_t *context) { bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, bass_ctxt); context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; @@ -222,7 +221,7 @@ int bassboost_enable(effect_context_t *context) { bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, strength %d", __func__, bass_ctxt, bass_ctxt->strength); if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) && !(bass_ctxt->temp_disabled)) { @@ -240,7 +239,7 @@ int bassboost_disable(effect_context_t *context) { bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, bass_ctxt); if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); if (bass_ctxt->ctl) @@ -255,9 +254,9 @@ int bassboost_start(effect_context_t *context, output_context_t *output) { bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, ctl %p, strength %d", __func__, bass_ctxt, + output->ctl, bass_ctxt->strength); bass_ctxt->ctl = output->ctl; - ALOGV("output->ctl: %p", output->ctl); if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) if (bass_ctxt->ctl) offload_bassboost_send_params(bass_ctxt->ctl, bass_ctxt->offload_bass, @@ -270,7 +269,7 @@ int bassboost_stop(effect_context_t *context, output_context_t *output) { bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, bass_ctxt); bass_ctxt->ctl = NULL; return 0; } diff --git a/post_proc/bundle.c b/post_proc/bundle.c index fa740c8d0..a0d9fcbd7 100644 --- a/post_proc/bundle.c +++ b/post_proc/bundle.c @@ -121,6 +121,7 @@ void add_effect_to_output(output_context_t * output, effect_context_t *context) { struct listnode *fx_node; + ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output); list_for_each(fx_node, &output->effects_list) { effect_context_t *fx_ctxt = node_to_item(fx_node, effect_context_t, @@ -139,6 +140,7 @@ void remove_effect_from_output(output_context_t * output, { struct listnode *fx_node; + ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output); list_for_each(fx_node, &output->effects_list) { effect_context_t *fx_ctxt = node_to_item(fx_node, effect_context_t, @@ -529,7 +531,7 @@ int effect_process(effect_handle_t self, effect_context_t * context = (effect_context_t *)self; int status = 0; - ALOGW("%s Called ?????", __func__); + ALOGW("%s: ctxt %p, Called ?????", __func__, context); pthread_mutex_lock(&lock); if (!effect_exists(context)) { @@ -562,6 +564,7 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, goto exit; } + ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode); if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) { status = -EINVAL; goto exit; @@ -615,7 +618,6 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, context->state = EFFECT_STATE_ACTIVE; if (context->ops.enable) context->ops.enable(context); - ALOGV("%s EFFECT_CMD_ENABLE", __func__); *(int *)pReplyData = 0; break; case EFFECT_CMD_DISABLE: @@ -630,7 +632,6 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, context->state = EFFECT_STATE_INITIALIZED; if (context->ops.disable) context->ops.disable(context); - ALOGV("%s EFFECT_CMD_DISABLE", __func__); *(int *)pReplyData = 0; break; case EFFECT_CMD_GET_PARAM: { @@ -640,7 +641,7 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t))) { status = -EINVAL; - ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d", + ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d", cmdSize, *replySize); goto exit; } @@ -660,7 +661,7 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, sizeof(uint16_t)) || pReplyData == NULL || *replySize != sizeof(int32_t)) { status = -EINVAL; - ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d", + ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d", cmdSize, *replySize); goto exit; } @@ -676,7 +677,7 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, ALOGV("\t EFFECT_CMD_SET_DEVICE start"); if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) { status = -EINVAL; - ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize); + ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize); goto exit; } device = *(uint32_t *)pCmdData; @@ -692,7 +693,7 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL || pReplyData == NULL || *replySize != sizeof(int)) { - ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__); + ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__); status = -EINVAL; break; } diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c index f17a4911c..2acf18e32 100644 --- a/post_proc/effect_api.c +++ b/post_proc/effect_api.c @@ -29,6 +29,12 @@ #define LOG_TAG "offload_effect_api" #define LOG_NDEBUG 0 +//#define VERY_VERY_VERBOSE_LOGGING +#ifdef VERY_VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif #include #include @@ -99,34 +105,34 @@ void offload_close_mixer(struct mixer *mixer) void offload_bassboost_set_device(struct bass_boost_params *bassboost, uint32_t device) { - ALOGV("%s", __func__); + ALOGVV("%s: device 0x%x", __func__, device); bassboost->device = device; } void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost, bool enable) { - ALOGV("%s", __func__); + ALOGVV("%s: enable=%d", __func__, (int)enable); bassboost->enable_flag = enable; } int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost) { - ALOGV("%s", __func__); + ALOGVV("%s: enable=%d", __func__, (int)bassboost->enable_flag); return bassboost->enable_flag; } void offload_bassboost_set_strength(struct bass_boost_params *bassboost, int strength) { - ALOGV("%s", __func__); + ALOGVV("%s: strength %d", __func__, strength); bassboost->strength = strength; } void offload_bassboost_set_mode(struct bass_boost_params *bassboost, int mode) { - ALOGV("%s", __func__); + ALOGVV("%s: mode %d", __func__, mode); bassboost->mode = mode; } @@ -137,7 +143,7 @@ int offload_bassboost_send_params(struct mixer_ctl *ctl, int param_values[128] = {0}; int *p_param_values = param_values; - ALOGV("%s", __func__); + ALOGV("%s: flags 0x%x", __func__, param_send_flags); *p_param_values++ = BASS_BOOST_MODULE; *p_param_values++ = bassboost.device; *p_param_values++ = 0; /* num of commands*/ @@ -175,41 +181,41 @@ int offload_bassboost_send_params(struct mixer_ctl *ctl, void offload_virtualizer_set_device(struct virtualizer_params *virtualizer, uint32_t device) { - ALOGV("%s", __func__); + ALOGVV("%s: device=0x%x", __func__, device); virtualizer->device = device; } void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer, bool enable) { - ALOGV("%s", __func__); + ALOGVV("%s: enable=%d", __func__, (int)enable); virtualizer->enable_flag = enable; } int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer) { - ALOGV("%s", __func__); + ALOGVV("%s: enabled %d", __func__, (int)virtualizer->enable_flag); return virtualizer->enable_flag; } void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer, int strength) { - ALOGV("%s", __func__); + ALOGVV("%s: strength %d", __func__, strength); virtualizer->strength = strength; } void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer, int out_type) { - ALOGV("%s", __func__); + ALOGVV("%s: out_type %d", __func__, out_type); virtualizer->out_type = out_type; } void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer, int gain_adjust) { - ALOGV("%s", __func__); + ALOGVV("%s: gain %d", __func__, gain_adjust); virtualizer->gain_adjust = gain_adjust; } @@ -220,7 +226,7 @@ int offload_virtualizer_send_params(struct mixer_ctl *ctl, int param_values[128] = {0}; int *p_param_values = param_values; - ALOGV("%s", __func__); + ALOGV("%s: flags 0x%x", __func__, param_send_flags); *p_param_values++ = VIRTUALIZER_MODULE; *p_param_values++ = virtualizer.device; *p_param_values++ = 0; /* num of commands*/ @@ -265,25 +271,25 @@ int offload_virtualizer_send_params(struct mixer_ctl *ctl, void offload_eq_set_device(struct eq_params *eq, uint32_t device) { - ALOGV("%s", __func__); + ALOGVV("%s: device 0x%x", __func__, device); eq->device = device; } void offload_eq_set_enable_flag(struct eq_params *eq, bool enable) { - ALOGV("%s", __func__); + ALOGVV("%s: enable=%d", __func__, (int)enable); eq->enable_flag = enable; } int offload_eq_get_enable_flag(struct eq_params *eq) { - ALOGV("%s", __func__); + ALOGVV("%s: enabled=%d", __func__, (int)eq->enable_flag); return eq->enable_flag; } void offload_eq_set_preset(struct eq_params *eq, int preset) { - ALOGV("%s", __func__); + ALOGVV("%s: preset %d", __func__, preset); eq->config.preset_id = preset; eq->config.eq_pregain = Q27_UNITY; } @@ -293,7 +299,7 @@ void offload_eq_set_bands_level(struct eq_params *eq, int num_bands, int *band_gain_list) { int i; - ALOGV("%s", __func__); + ALOGVV("%s", __func__); eq->config.num_bands = num_bands; for (i=0; iper_band_cfg[i].band_idx = i; @@ -366,110 +372,110 @@ int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device) { - ALOGV("%s", __func__); + ALOGVV("%s: device 0x%x", __func__, device); reverb->device = device; } void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable) { - ALOGV("%s", __func__); + ALOGVV("%s: enable=%d", __func__, (int)enable); reverb->enable_flag = enable; } int offload_reverb_get_enable_flag(struct reverb_params *reverb) { - ALOGV("%s", __func__); + ALOGVV("%s: enabled=%d", __func__, reverb->enable_flag); return reverb->enable_flag; } void offload_reverb_set_mode(struct reverb_params *reverb, int mode) { - ALOGV("%s", __func__); + ALOGVV("%s", __func__); reverb->mode = mode; } void offload_reverb_set_preset(struct reverb_params *reverb, int preset) { - ALOGV("%s", __func__); + ALOGVV("%s: preset %d", __func__, preset); if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED)) reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset-1][1]; } void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix) { - ALOGV("%s", __func__); + ALOGVV("%s: wet_mix %d", __func__, wet_mix); reverb->wet_mix = wet_mix; } void offload_reverb_set_gain_adjust(struct reverb_params *reverb, int gain_adjust) { - ALOGV("%s", __func__); + ALOGVV("%s: gain %d", __func__, gain_adjust); reverb->gain_adjust = gain_adjust; } void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level) { - ALOGV("%s", __func__); + ALOGVV("%s: level %d", __func__, room_level); reverb->room_level = room_level; } void offload_reverb_set_room_hf_level(struct reverb_params *reverb, int room_hf_level) { - ALOGV("%s", __func__); + ALOGVV("%s: level %d", __func__, room_hf_level); reverb->room_hf_level = room_hf_level; } void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time) { - ALOGV("%s", __func__); + ALOGVV("%s: decay time %d", __func__, decay_time); reverb->decay_time = decay_time; } void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb, int decay_hf_ratio) { - ALOGV("%s", __func__); + ALOGVV("%s: decay_hf_ratio %d", __func__, decay_hf_ratio); reverb->decay_hf_ratio = decay_hf_ratio; } void offload_reverb_set_reflections_level(struct reverb_params *reverb, int reflections_level) { - ALOGV("%s", __func__); + ALOGVV("%s: ref level %d", __func__, reflections_level); reverb->reflections_level = reflections_level; } void offload_reverb_set_reflections_delay(struct reverb_params *reverb, int reflections_delay) { - ALOGV("%s", __func__); + ALOGVV("%s: ref delay", __func__, reflections_delay); reverb->reflections_delay = reflections_delay; } void offload_reverb_set_reverb_level(struct reverb_params *reverb, int reverb_level) { - ALOGV("%s", __func__); + ALOGD("%s: reverb level %d", __func__, reverb_level); reverb->level = reverb_level; } void offload_reverb_set_delay(struct reverb_params *reverb, int delay) { - ALOGV("%s", __func__); + ALOGVV("%s: delay %d", __func__, delay); reverb->delay = delay; } void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion) { - ALOGV("%s", __func__); + ALOGVV("%s: diffusion %d", __func__, diffusion); reverb->diffusion = diffusion; } void offload_reverb_set_density(struct reverb_params *reverb, int density) { - ALOGV("%s", __func__); + ALOGVV("%s: density %d", __func__, density); reverb->density = density; } @@ -480,7 +486,7 @@ int offload_reverb_send_params(struct mixer_ctl *ctl, int param_values[128] = {0}; int *p_param_values = param_values; - ALOGV("%s", __func__); + ALOGV("%s: flags 0x%x", __func__, param_send_flags); *p_param_values++ = REVERB_MODULE; *p_param_values++ = reverb.device; *p_param_values++ = 0; /* num of commands*/ diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c index 7c7ced2cf..c635251ae 100644 --- a/post_proc/equalizer.c +++ b/post_proc/equalizer.c @@ -87,7 +87,7 @@ const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = { int equalizer_get_band_level(equalizer_context_t *context, int32_t band) { - ALOGV("%s: band: %d level: %d", __func__, band, + ALOGV("%s: ctxt %p, band: %d level: %d", __func__, context, band, context->band_levels[band] * 100); return context->band_levels[band] * 100; } @@ -95,7 +95,7 @@ int equalizer_get_band_level(equalizer_context_t *context, int32_t band) int equalizer_set_band_level(equalizer_context_t *context, int32_t band, int32_t level) { - ALOGV("%s: band: %d, level: %d", __func__, band, level); + ALOGV("%s: ctxt %p, band: %d, level: %d", __func__, context, band, level); if (level > 0) { level = (int)((level+50)/100); } else { @@ -118,7 +118,7 @@ int equalizer_set_band_level(equalizer_context_t *context, int32_t band, int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band) { - ALOGV("%s: band: %d", __func__, band); + ALOGV("%s: ctxt %p, band: %d", __func__, context, band); return (equalizer_band_freq_range[band][0] + equalizer_band_freq_range[band][1]) / 2; } @@ -126,7 +126,7 @@ int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band) int equalizer_get_band_freq_range(equalizer_context_t *context, int32_t band, uint32_t *low, uint32_t *high) { - ALOGV("%s: band: %d", __func__, band); + ALOGV("%s: ctxt %p, band: %d", __func__, context, band); *low = equalizer_band_freq_range[band][0]; *high = equalizer_band_freq_range[band][1]; return 0; @@ -136,7 +136,7 @@ int equalizer_get_band(equalizer_context_t *context, uint32_t freq) { int i; - ALOGV("%s: freq: %d", __func__, freq); + ALOGV("%s: ctxt %p, freq: %d", __func__, context, freq); for(i = 0; i < NUM_EQ_BANDS; i++) { if (freq <= equalizer_band_freq_range[i][1]) { return i; @@ -147,7 +147,7 @@ int equalizer_get_band(equalizer_context_t *context, uint32_t freq) int equalizer_get_preset(equalizer_context_t *context) { - ALOGV("%s: preset: %d", __func__, context->preset); + ALOGV("%s: ctxt %p, preset: %d", __func__, context, context->preset); return context->preset; } @@ -155,7 +155,7 @@ int equalizer_set_preset(equalizer_context_t *context, int preset) { int i; - ALOGV("%s: preset: %d", __func__, preset); + ALOGV("%s: ctxt %p, preset: %d", __func__, context, preset); context->preset = preset; for (i=0; iband_levels[i] = @@ -176,7 +176,8 @@ int equalizer_set_preset(equalizer_context_t *context, int preset) const char * equalizer_get_preset_name(equalizer_context_t *context, int32_t preset) { - ALOGV("%s: preset: %s", __func__, equalizer_preset_names[preset]); + ALOGV("%s: ctxt %p, preset: %s", __func__, context, + equalizer_preset_names[preset]); if (preset == PRESET_CUSTOM) { return "Custom"; } else { @@ -186,7 +187,7 @@ const char * equalizer_get_preset_name(equalizer_context_t *context, int equalizer_get_num_presets(equalizer_context_t *context) { - ALOGV("%s: presets_num: %d", __func__, + ALOGV("%s: ctxt %p, presets_num: %d", __func__, context, sizeof(equalizer_preset_names)/sizeof(char *)); return sizeof(equalizer_preset_names)/sizeof(char *); } @@ -203,7 +204,7 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, void *value = p->data + voffset; int i; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, eq_ctxt, param); p->status = 0; @@ -255,18 +256,15 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, switch (param) { case EQ_PARAM_NUM_BANDS: - ALOGV("%s: EQ_PARAM_NUM_BANDS", __func__); *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS; break; case EQ_PARAM_LEVEL_RANGE: - ALOGV("%s: EQ_PARAM_LEVEL_RANGE", __func__); *(int16_t *)value = -1500; *((int16_t *)value + 1) = 1500; break; case EQ_PARAM_BAND_LEVEL: - ALOGV("%s: EQ_PARAM_BAND_LEVEL", __func__); param2 = *param_tmp; if (param2 >= NUM_EQ_BANDS) { p->status = -EINVAL; @@ -276,7 +274,6 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, break; case EQ_PARAM_CENTER_FREQ: - ALOGV("%s: EQ_PARAM_CENTER_FREQ", __func__); param2 = *param_tmp; if (param2 >= NUM_EQ_BANDS) { p->status = -EINVAL; @@ -286,7 +283,6 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, break; case EQ_PARAM_BAND_FREQ_RANGE: - ALOGV("%s: EQ_PARAM_BAND_FREQ_RANGE", __func__); param2 = *param_tmp; if (param2 >= NUM_EQ_BANDS) { p->status = -EINVAL; @@ -297,25 +293,21 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, break; case EQ_PARAM_GET_BAND: - ALOGV("%s: EQ_PARAM_GET_BAND", __func__); param2 = *param_tmp; *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2); break; case EQ_PARAM_CUR_PRESET: - ALOGV("%s: EQ_PARAM_CUR_PRESET", __func__); *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt); break; case EQ_PARAM_GET_NUM_OF_PRESETS: - ALOGV("%s: EQ_PARAM_GET_NUM_OF_PRESETS", __func__); *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt); break; case EQ_PARAM_GET_PRESET_NAME: - ALOGV("%s: EQ_PARAM_GET_PRESET_NAME", __func__); param2 = *param_tmp; - ALOGV("param2: %d", param2); + ALOGV("%s: EQ_PARAM_GET_PRESET_NAME: param2: %d", __func__, param2); if (param2 >= equalizer_get_num_presets(eq_ctxt)) { p->status = -EINVAL; break; @@ -327,7 +319,6 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, break; case EQ_PARAM_PROPERTIES: { - ALOGV("%s: EQ_PARAM_PROPERTIES", __func__); int16_t *prop = (int16_t *)value; prop[0] = (int16_t)equalizer_get_preset(eq_ctxt); prop[1] = (int16_t)NUM_EQ_BANDS; @@ -357,13 +348,12 @@ int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, int32_t level; int i; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, eq_ctxt, param); p->status = 0; switch (param) { case EQ_PARAM_CUR_PRESET: - ALOGV("EQ_PARAM_CUR_PRESET"); preset = (int32_t)(*(uint16_t *)value); if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) { @@ -373,7 +363,6 @@ int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, equalizer_set_preset(eq_ctxt, preset); break; case EQ_PARAM_BAND_LEVEL: - ALOGV("EQ_PARAM_BAND_LEVEL"); band = *param_tmp; level = (int32_t)(*(int16_t *)value); if (band >= NUM_EQ_BANDS) { @@ -383,7 +372,6 @@ int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, equalizer_set_band_level(eq_ctxt, band, level); break; case EQ_PARAM_PROPERTIES: { - ALOGV("EQ_PARAM_PROPERTIES"); int16_t *prop = (int16_t *)value; if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) { p->status = -EINVAL; @@ -411,7 +399,7 @@ int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, int equalizer_set_device(effect_context_t *context, uint32_t device) { - ALOGV("%s: device: %d", __func__, device); + ALOGV("%s: ctxt %p, device: 0x%x", __func__, context, device); equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; eq_ctxt->device = device; offload_eq_set_device(&(eq_ctxt->offload_eq), device); @@ -427,7 +415,7 @@ int equalizer_reset(effect_context_t *context) int equalizer_init(effect_context_t *context) { - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, context); equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; @@ -459,7 +447,7 @@ int equalizer_enable(effect_context_t *context) { equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, context); if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true); @@ -475,7 +463,7 @@ int equalizer_disable(effect_context_t *context) { equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s:ctxt %p", __func__, eq_ctxt); if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false); if (eq_ctxt->ctl) @@ -489,7 +477,7 @@ int equalizer_start(effect_context_t *context, output_context_t *output) { equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; - ALOGV("%s: %p", __func__, output->ctl); + ALOGV("%s: ctxt %p, ctl %p", __func__, eq_ctxt, output->ctl); eq_ctxt->ctl = output->ctl; if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) if (eq_ctxt->ctl) @@ -503,7 +491,7 @@ int equalizer_stop(effect_context_t *context, output_context_t *output) { equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, eq_ctxt); eq_ctxt->ctl = NULL; return 0; } diff --git a/post_proc/reverb.c b/post_proc/reverb.c index 60750b06d..078c584bc 100644 --- a/post_proc/reverb.c +++ b/post_proc/reverb.c @@ -115,13 +115,13 @@ void reverb_preset_init(reverb_context_t *context) */ int16_t reverb_get_room_level(reverb_context_t *context) { - ALOGV("%s: room level: %d", __func__, context->reverb_settings.roomLevel); + ALOGV("%s: ctxt %p, room level: %d", __func__, context, context->reverb_settings.roomLevel); return context->reverb_settings.roomLevel; } void reverb_set_room_level(reverb_context_t *context, int16_t room_level) { - ALOGV("%s: room level: %d", __func__, room_level); + ALOGV("%s: ctxt %p, room level: %d", __func__, context, room_level); context->reverb_settings.roomLevel = room_level; offload_reverb_set_room_level(&(context->offload_reverb), room_level); if (context->ctl) @@ -132,14 +132,14 @@ void reverb_set_room_level(reverb_context_t *context, int16_t room_level) int16_t reverb_get_room_hf_level(reverb_context_t *context) { - ALOGV("%s: room hf level: %d", __func__, + ALOGV("%s: ctxt %p, room hf level: %d", __func__, context, context->reverb_settings.roomHFLevel); return context->reverb_settings.roomHFLevel; } void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level) { - ALOGV("%s: room hf level: %d", __func__, room_hf_level); + ALOGV("%s: ctxt %p, room hf level: %d", __func__, context, room_hf_level); context->reverb_settings.roomHFLevel = room_hf_level; offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level); if (context->ctl) @@ -150,13 +150,14 @@ void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level) uint32_t reverb_get_decay_time(reverb_context_t *context) { - ALOGV("%s: decay time: %d", __func__, context->reverb_settings.decayTime); + ALOGV("%s: ctxt %p, decay time: %d", __func__, context, + context->reverb_settings.decayTime); return context->reverb_settings.decayTime; } void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time) { - ALOGV("%s: decay_time: %d", __func__, decay_time); + ALOGV("%s: ctxt %p, decay_time: %d", __func__, context, decay_time); context->reverb_settings.decayTime = decay_time; offload_reverb_set_decay_time(&(context->offload_reverb), decay_time); if (context->ctl) @@ -167,14 +168,14 @@ void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time) int16_t reverb_get_decay_hf_ratio(reverb_context_t *context) { - ALOGV("%s: decay hf ratio: %d", __func__, + ALOGV("%s: ctxt %p, decay hf ratio: %d", __func__, context, context->reverb_settings.decayHFRatio); return context->reverb_settings.decayHFRatio; } void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio) { - ALOGV("%s: decay_hf_ratio: %d", __func__, decay_hf_ratio); + ALOGV("%s: ctxt %p, decay_hf_ratio: %d", __func__, context, decay_hf_ratio); context->reverb_settings.decayHFRatio = decay_hf_ratio; offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio); if (context->ctl) @@ -185,13 +186,14 @@ void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio int16_t reverb_get_reverb_level(reverb_context_t *context) { - ALOGV("%s: reverb level: %d", __func__, context->reverb_settings.reverbLevel); + ALOGV("%s: ctxt %p, reverb level: %d", __func__, context, + context->reverb_settings.reverbLevel); return context->reverb_settings.reverbLevel; } void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level) { - ALOGV("%s: reverb level: %d", __func__, reverb_level); + ALOGV("%s: ctxt %p, reverb level: %d", __func__, context, reverb_level); context->reverb_settings.reverbLevel = reverb_level; offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level); if (context->ctl) @@ -202,13 +204,14 @@ void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level) int16_t reverb_get_diffusion(reverb_context_t *context) { - ALOGV("%s: diffusion: %d", __func__, context->reverb_settings.diffusion); + ALOGV("%s: ctxt %p, diffusion: %d", __func__, context, + context->reverb_settings.diffusion); return context->reverb_settings.diffusion; } void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion) { - ALOGV("%s: diffusion: %d", __func__, diffusion); + ALOGV("%s: ctxt %p, diffusion: %d", __func__, context, diffusion); context->reverb_settings.diffusion = diffusion; offload_reverb_set_diffusion(&(context->offload_reverb), diffusion); if (context->ctl) @@ -219,13 +222,14 @@ void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion) int16_t reverb_get_density(reverb_context_t *context) { - ALOGV("%s: density: %d", __func__, context->reverb_settings.density); + ALOGV("%s: ctxt %p, density: %d", __func__, context, + context->reverb_settings.density); return context->reverb_settings.density; } void reverb_set_density(reverb_context_t *context, int16_t density) { - ALOGV("%s: density: %d", __func__, density); + ALOGV("%s: ctxt %p, density: %d", __func__, density, density); context->reverb_settings.density = density; offload_reverb_set_density(&(context->offload_reverb), density); if (context->ctl) @@ -237,7 +241,7 @@ void reverb_set_density(reverb_context_t *context, int16_t density) void reverb_set_preset(reverb_context_t *context, int16_t preset) { bool enable; - ALOGV("%s: preset: %d", __func__, preset); + ALOGV("%s: ctxt %p, preset: %d", __func__, context, preset); context->next_preset = preset; offload_reverb_set_preset(&(context->offload_reverb), preset); @@ -253,7 +257,7 @@ void reverb_set_preset(reverb_context_t *context, int16_t preset) void reverb_set_all_properties(reverb_context_t *context, reverb_settings_t *reverb_settings) { - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, context); context->reverb_settings.roomLevel = reverb_settings->roomLevel; context->reverb_settings.roomHFLevel = reverb_settings->roomHFLevel; context->reverb_settings.decayTime = reverb_settings->decayTime; @@ -300,7 +304,7 @@ int reverb_get_parameter(effect_context_t *context, effect_param_t *p, reverb_settings_t *reverb_settings; int i; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, reverb_ctxt, param); p->status = 0; @@ -378,7 +382,6 @@ int reverb_get_parameter(effect_context_t *context, effect_param_t *p, switch (param) { case REVERB_PARAM_PROPERTIES: - ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__); reverb_settings = (reverb_settings_t *)value; reverb_settings->roomLevel = reverb_get_room_level(reverb_ctxt); reverb_settings->roomHFLevel = reverb_get_room_hf_level(reverb_ctxt); @@ -392,43 +395,33 @@ int reverb_get_parameter(effect_context_t *context, effect_param_t *p, reverb_settings->density = reverb_get_density(reverb_ctxt); break; case REVERB_PARAM_ROOM_LEVEL: - ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__); *(int16_t *)value = reverb_get_room_level(reverb_ctxt); break; case REVERB_PARAM_ROOM_HF_LEVEL: - ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__); *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt); break; case REVERB_PARAM_DECAY_TIME: - ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__); *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt); break; case REVERB_PARAM_DECAY_HF_RATIO: - ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__); *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt); break; case REVERB_PARAM_REVERB_LEVEL: - ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__); *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt); break; case REVERB_PARAM_DIFFUSION: - ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__); *(int16_t *)value = reverb_get_diffusion(reverb_ctxt); break; case REVERB_PARAM_DENSITY: - ALOGV("%s: REVERB_PARAM_DENSITY", __func__); *(int16_t *)value = reverb_get_density(reverb_ctxt); break; case REVERB_PARAM_REFLECTIONS_LEVEL: - ALOGV("%s: REVERB_PARAM_REFLECTIONS_LEVEL", __func__); *(uint16_t *)value = 0; break; case REVERB_PARAM_REFLECTIONS_DELAY: - ALOGV("%s: REVERB_PARAM_REFLECTIONS_DELAY", __func__); *(uint32_t *)value = 0; break; case REVERB_PARAM_REVERB_DELAY: - ALOGV("%s: REVERB_PARAM_REVERB_DELAY", __func__); *(uint32_t *)value = 0; break; default: @@ -452,7 +445,7 @@ int reverb_set_parameter(effect_context_t *context, effect_param_t *p, int16_t ratio; uint32_t time; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, reverb_ctxt, param); p->status = 0; @@ -469,41 +462,33 @@ int reverb_set_parameter(effect_context_t *context, effect_param_t *p, } switch (param) { case REVERB_PARAM_PROPERTIES: - ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__); reverb_settings = (reverb_settings_t *)value; break; case REVERB_PARAM_ROOM_LEVEL: - ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__); level = *(int16_t *)value; reverb_set_room_level(reverb_ctxt, level); break; case REVERB_PARAM_ROOM_HF_LEVEL: - ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__); level = *(int16_t *)value; reverb_set_room_hf_level(reverb_ctxt, level); break; case REVERB_PARAM_DECAY_TIME: - ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__); time = *(uint32_t *)value; reverb_set_decay_time(reverb_ctxt, time); break; case REVERB_PARAM_DECAY_HF_RATIO: - ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__); ratio = *(int16_t *)value; reverb_set_decay_hf_ratio(reverb_ctxt, ratio); break; case REVERB_PARAM_REVERB_LEVEL: - ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__); level = *(int16_t *)value; reverb_set_reverb_level(reverb_ctxt, level); break; case REVERB_PARAM_DIFFUSION: - ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__); ratio = *(int16_t *)value; reverb_set_diffusion(reverb_ctxt, ratio); break; case REVERB_PARAM_DENSITY: - ALOGV("%s: REVERB_PARAM_DENSITY", __func__); ratio = *(int16_t *)value; reverb_set_density(reverb_ctxt, ratio); break; @@ -523,7 +508,7 @@ int reverb_set_device(effect_context_t *context, uint32_t device) { reverb_context_t *reverb_ctxt = (reverb_context_t *)context; - ALOGV("%s: device: %d", __func__, device); + ALOGV("%s: ctxt %p, device: 0x%x", __func__, reverb_ctxt, device); reverb_ctxt->device = device; offload_reverb_set_device(&(reverb_ctxt->offload_reverb), device); return 0; @@ -540,6 +525,7 @@ int reverb_init(effect_context_t *context) { reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; /* FIXME: channel mode is mono for auxiliary. is it needed for offload ? @@ -577,7 +563,7 @@ int reverb_enable(effect_context_t *context) { reverb_context_t *reverb_ctxt = (reverb_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true); @@ -588,7 +574,7 @@ int reverb_disable(effect_context_t *context) { reverb_context_t *reverb_ctxt = (reverb_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) { offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false); if (reverb_ctxt->ctl) @@ -603,7 +589,7 @@ int reverb_start(effect_context_t *context, output_context_t *output) { reverb_context_t *reverb_ctxt = (reverb_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, ctl %p", __func__, reverb_ctxt, output->ctl); reverb_ctxt->ctl = output->ctl; if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) { if (reverb_ctxt->ctl && reverb_ctxt->preset) { @@ -620,7 +606,7 @@ int reverb_stop(effect_context_t *context, output_context_t *output) { reverb_context_t *reverb_ctxt = (reverb_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); reverb_ctxt->ctl = NULL; return 0; } diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c index 484a7388c..6afbdfba4 100644 --- a/post_proc/virtualizer.c +++ b/post_proc/virtualizer.c @@ -47,13 +47,13 @@ const effect_descriptor_t virtualizer_descriptor = { int virtualizer_get_strength(virtualizer_context_t *context) { - ALOGV("%s: strength: %d", __func__, context->strength); + ALOGV("%s: ctxt %p, strength: %d", __func__, context, context->strength); return context->strength; } int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength) { - ALOGV("%s: strength: %d", __func__, strength); + ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength); context->strength = strength; offload_virtualizer_set_strength(&(context->offload_virt), strength); @@ -74,7 +74,7 @@ int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p, void *value = p->data + voffset; int i; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, virt_ctxt, param); p->status = 0; @@ -100,12 +100,10 @@ int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p, switch (param) { case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED: - ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH_SUPPORTED", __func__); *(uint32_t *)value = 1; break; case VIRTUALIZER_PARAM_STRENGTH: - ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH", __func__); *(int16_t *)value = virtualizer_get_strength(virt_ctxt); break; @@ -127,13 +125,12 @@ int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p, int32_t param = *param_tmp++; uint32_t strength; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, param %d", __func__, virt_ctxt, param); p->status = 0; switch (param) { case VIRTUALIZER_PARAM_STRENGTH: - ALOGV("%s VIRTUALIZER_PARAM_STRENGTH", __func__); strength = (uint32_t)(*(int16_t *)value); virtualizer_set_strength(virt_ctxt, strength); break; @@ -149,7 +146,7 @@ int virtualizer_set_device(effect_context_t *context, uint32_t device) { virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; - ALOGV("%s: device: %d", __func__, device); + ALOGV("%s: ctxt %p, device: 0x%x", __func__, virt_ctxt, device); virt_ctxt->device = device; if((device == AUDIO_DEVICE_OUT_SPEAKER) || (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || @@ -165,6 +162,7 @@ int virtualizer_set_device(effect_context_t *context, uint32_t device) offload_virtualizer_send_params(virt_ctxt->ctl, virt_ctxt->offload_virt, OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt); } } else { if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) && @@ -190,7 +188,7 @@ int virtualizer_reset(effect_context_t *context) int virtualizer_init(effect_context_t *context) { - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, context); virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; @@ -221,7 +219,7 @@ int virtualizer_enable(effect_context_t *context) { virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, strength %d", __func__, virt_ctxt, virt_ctxt->strength); if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) && !(virt_ctxt->temp_disabled)) { @@ -239,7 +237,7 @@ int virtualizer_disable(effect_context_t *context) { virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, virt_ctxt); if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); if (virt_ctxt->ctl) @@ -254,7 +252,7 @@ int virtualizer_start(effect_context_t *context, output_context_t *output) { virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p, ctl %p", __func__, virt_ctxt, output->ctl); virt_ctxt->ctl = output->ctl; if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) if (virt_ctxt->ctl) @@ -268,7 +266,7 @@ int virtualizer_stop(effect_context_t *context, output_context_t *output) { virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; - ALOGV("%s", __func__); + ALOGV("%s: ctxt %p", __func__, virt_ctxt); virt_ctxt->ctl = NULL; return 0; } -- GitLab From e4514fade5788122926207a5052d73739e847142 Mon Sep 17 00:00:00 2001 From: Sidipotu Ashok Date: Fri, 2 May 2014 16:21:50 +0530 Subject: [PATCH 218/298] hal: improve logging. -log to print open/close/standby of out/in streams -log to print the the device switches Change-Id: I1b3bf3d6ba19faa4df804f781fc15c0f96a5b80f --- hal/audio_hw.c | 41 +++++++++++++++++++++---------- policy_hal/AudioPolicyManager.cpp | 8 +++--- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 530f08f0d..93db1276b 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -706,6 +706,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) out_snd_device, in_snd_device); + ALOGD("%s: done",__func__); + return status; } @@ -750,7 +752,8 @@ int start_input_stream(struct stream_in *in) struct audio_device *adev = in->dev; in->usecase = platform_update_usecase_from_source(in->source,in->usecase); - ALOGV("%s: enter: usecase(%d)", __func__, in->usecase); + ALOGD("%s: enter: stream(%p)usecase(%d: %s)", + __func__, &in->stream, in->usecase, use_case_table[in->usecase]); /* Check if source matches incall recording usecase criteria */ ret = voice_check_and_set_incall_rec_usecase(adev, in); @@ -1077,8 +1080,9 @@ int start_output_stream(struct stream_out *out) struct audio_usecase *uc_info; struct audio_device *adev = out->dev; - ALOGV("%s: enter: usecase(%d: %s) devices(%#x)", - __func__, out->usecase, use_case_table[out->usecase], out->devices); + ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)", + __func__, &out->stream, out->usecase, use_case_table[out->usecase], + out->devices); out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); if (out->pcm_device_id < 0) { ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", @@ -1266,13 +1270,13 @@ static int out_standby(struct audio_stream *stream) struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; - ALOGV("%s: enter: usecase(%d: %s)", __func__, - out->usecase, use_case_table[out->usecase]); + ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__, + stream, out->usecase, use_case_table[out->usecase]); if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { /* Ignore standby in case of voip call because the voip output * stream is closed in adev_close_output_stream() */ - ALOGV("%s: Ignore Standby in VOIP call", __func__); + ALOGD("%s: Ignore Standby in VOIP call", __func__); return 0; } @@ -1817,7 +1821,9 @@ static int in_standby(struct audio_stream *stream) struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int status = 0; - ALOGV("%s: enter", __func__); + ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__, + stream, in->usecase, use_case_table[in->usecase]); + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { /* Ignore standby in case of voip call because the voip input @@ -1857,7 +1863,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) char value[32]; int ret = 0, val = 0, err; - ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs); + ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs); parms = str_parms_create_str(kvpairs); pthread_mutex_lock(&in->lock); @@ -2040,11 +2046,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, struct stream_out *out; int i, ret = 0; - ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", - __func__, config->sample_rate, config->channel_mask, devices, flags); *stream_out = NULL; out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\ + stream_handle(%p)",__func__, config->sample_rate, config->channel_mask, + devices, flags, &out->stream); + + if (!out) { return -ENOMEM; } @@ -2246,6 +2255,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); *stream_out = &out->stream; + ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream, + use_case_table[out->usecase]); ALOGV("%s: exit", __func__); return 0; @@ -2263,7 +2274,8 @@ static void adev_close_output_stream(struct audio_hw_device *dev, struct audio_device *adev = out->dev; int ret = 0; - ALOGV("%s: enter", __func__); + ALOGD("%s: enter:stream_handle(%p)",__func__, out); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { ret = voice_extn_compress_voip_close_output_stream(&stream->common); if(ret != 0) @@ -2475,12 +2487,15 @@ static int adev_open_input_stream(struct audio_hw_device *dev, int ret = 0, buffer_size, frame_size; int channel_count = popcount(config->channel_mask); - ALOGV("%s: enter", __func__); + *stream_in = NULL; if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) return -EINVAL; in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); + ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\ + stream_handle(%p)",__func__, config->sample_rate, config->channel_mask, + devices, &in->stream); pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); @@ -2551,7 +2566,7 @@ static void adev_close_input_stream(struct audio_hw_device *dev, { int ret; struct stream_in *in = (struct stream_in *)stream; - ALOGV("%s", __func__); + ALOGD("%s: enter:stream_handle(%p)",__func__, in); if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { ret = voice_extn_compress_voip_close_input_stream(&stream->common); diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 949e4ffb9..3c64c938f 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -51,7 +51,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, { SortedVector outputs; - ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); + ALOGD("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); // connect/disconnect only 1 device at a time if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; @@ -395,7 +395,7 @@ void AudioPolicyManager::setPhoneState(int state) void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) { - ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); + ALOGD("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); bool forceVolumeReeval = false; switch(usage) { @@ -492,7 +492,7 @@ audio_io_handle_t AudioPolicyManager::getInput(int inputSource, audio_io_handle_t input = 0; audio_devices_t device = getDeviceForInputSource(inputSource); - ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x", + ALOGD("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x", inputSource, samplingRate, format, channelMask, acoustics); if (device == AUDIO_DEVICE_NONE) { @@ -545,6 +545,8 @@ audio_io_handle_t AudioPolicyManager::getInput(int inputSource, return 0; } mInputs.add(input, inputDesc); + ALOGD("getInput() returns input %d", input); + return input; } -- GitLab From 3a0a6fd96b909b15c921cea22004253952e3c4cc Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Wed, 28 May 2014 13:11:51 -0700 Subject: [PATCH 219/298] hal: fix mutex unlock issue If a audio/voice usecase is active, hal should re-try the speaker calibration.Speaker portection mutex was not being unlocked for this usecase which causes ANR.Change unlocks the mutex which fixes the issue. CRs-fixed: 671620 Change-Id: Ic29697e29e96dba784941f4e29664b8c10f51e84 --- hal/audio_extn/spkr_protection.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c index f89fe861e..0c131cdbf 100644 --- a/hal/audio_extn/spkr_protection.c +++ b/hal/audio_extn/spkr_protection.c @@ -468,8 +468,11 @@ static void* spkr_calibration_thread(void *context) } goahead = true; } - if (!list_empty(&adev->usecase_list)) + if (!list_empty(&adev->usecase_list)) { + ALOGD("%s: Usecase active re-try calibration", __func__); goahead = false; + pthread_mutex_unlock(&handle.mutex_spkr_prot); + } if (goahead) { int status; status = spkr_calibrate(t0); -- GitLab From 521934f6e7c4a40b57a1d6145e789d74c6d79d37 Mon Sep 17 00:00:00 2001 From: Karthik Reddy Katta Date: Mon, 9 Jun 2014 12:39:37 +0530 Subject: [PATCH 220/298] alsa_sound: call voice volume api for direct output also - Voip volume is not applied on direct output and as a result volume cannot be adjusted for some voicemail applications which opens direct output stream with mode set to IN_CALL. - Voice volume is applied only for primary output and volume command is not sent to HAL for direct output. - Call voice volume api for direct output as well from policy manager. Change-Id: Iad6dc31ba628408958e4d693b99062f502210a56 CRs-Fixed: 676599 --- policy_hal/AudioPolicyManager.cpp | 14 +++++++++++++- policy_hal/AudioPolicyManager.h | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 3c64c938f..8f1ebf8ea 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -924,6 +924,17 @@ AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_ } } +bool AudioPolicyManager::isDirectOutput(audio_io_handle_t output) { + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t curOutput = mOutputs.keyAt(i); + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if ((curOutput == output) && (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { + return true; + } + } + return false; +} + status_t AudioPolicyManager::checkAndSetVolume(int stream, int index, audio_io_handle_t output, @@ -986,7 +997,8 @@ status_t AudioPolicyManager::checkAndSetVolume(int stream, // Force voice volume to max for bluetooth SCO as volume is managed by the headset voiceVolume = 1.0; - if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) { + if (voiceVolume != mLastVoiceVolume && ((output == mPrimaryOutput) || + isDirectOutput(output))) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 6a2db85f8..3b809777a 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -80,6 +80,9 @@ protected: // returns the category the device belongs to with regard to volume curve management static device_category getDeviceCategory(audio_devices_t device); + // returns true if give output is direct output + bool isDirectOutput(audio_io_handle_t output); + static const char* HDMI_SPKR_STR; //parameter indicates of HDMI speakers disabled from the Qualcomm settings -- GitLab From 61d3ae196ef4fbe0c6cdc5f1a8195ed9dcee0787 Mon Sep 17 00:00:00 2001 From: Preetam Singh Ranawat Date: Tue, 3 Jun 2014 13:11:00 +0530 Subject: [PATCH 221/298] policy_hal: Set the output devices in ascending order of outputs -volume related issues are seen with customer app while setting device forcefully -Set the output devices in ascending order of outputs to make the overridden setForceUse API's code inline with base function. Change-Id: I375b557de105be295c7bc246fe3f8325f55ce859 --- policy_hal/AudioPolicyManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 3c64c938f..410c4305b 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -458,7 +458,7 @@ void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem:: checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); - for (int i = mOutputs.size() -1; i >= 0; i--) { + for (int i = 0; i < mOutputs.size(); i++) { audio_io_handle_t output = mOutputs.keyAt(i); audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/); setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); -- GitLab From b692841c2c364d2c6df6530d7c2bc346872c34d5 Mon Sep 17 00:00:00 2001 From: Anish Kumar Date: Thu, 12 Jun 2014 23:16:32 -0700 Subject: [PATCH 222/298] hal: fix the set_echo_reference call sites Set_echo_reference definition is changed so fix all the call sites. Change-Id: I46a3b6fd8f4c5bcd5ab8de60132b7671719983bd --- hal/msm8974/platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index e0f9df550..629bd8c9a 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1182,7 +1182,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; - set_echo_reference(adev->mixer, EC_REF_RX); + set_echo_reference(adev, true); } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ) snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB; @@ -1201,7 +1201,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } } else { snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; - set_echo_reference(adev->mixer, EC_REF_RX); + set_echo_reference(adev, true); } } } else if (source == AUDIO_SOURCE_CAMCORDER) { -- GitLab From 9b69ba11cdc293ebc9f4aef2a7d2a3ae2fb0d8f4 Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Wed, 18 Jun 2014 14:45:29 +0530 Subject: [PATCH 223/298] hal: Fix compilation error when flag is not defined - HAL compilation fails if the flag HFP_ENABLED is not defined. - Fix the issue by changing the function prototype if the flag is undefined. CRs-Fixed: 678534 Change-Id: I7043082fd337604899666abc1f5a6c331a4421bc --- hal/audio_extn/audio_extn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index b641bdbd4..06bcac801 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -56,7 +56,7 @@ void audio_extn_fm_set_parameters(struct audio_device *adev, struct str_parms *parms); #endif #ifndef HFP_ENABLED -void audio_extn_hfp_set_parameters(adev, parms) (0) +#define audio_extn_hfp_set_parameters(adev, parms) (0) #else void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms); -- GitLab From 6a4c3371a53d1cbe0bffcb1edc01de5204f173bc Mon Sep 17 00:00:00 2001 From: Avinash Vaish Date: Wed, 25 Jun 2014 12:20:37 +0530 Subject: [PATCH 224/298] hal: Permit device switch for primary output in a voip call The device switch from speaker to earpiece or vice versa fails during a QQ voip call. Currently, we use the same devices for all usecases as that of voice/voip call and avoid switching the same for other usecases when a voip/voice call is active. At times, voip call has primary output which uses deep buffer path. With current design in place, we do not permit device switch on deep buffer path since voip call is active despite the rx on primary output. Do not select voip usecase devices if the output stream uses primary output or in effect permit switching. Change-Id: Ie61a7d7d8f27d55a393d173a724697045f66e1d6 CRs-Fixed: 685222 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 93db1276b..3b8351e33 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -600,7 +600,8 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) } else if (voice_extn_compress_voip_is_active(adev)) { voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); if ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) && - (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) { + (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) && + (voip_usecase->stream.out != adev->primary_output)) { in_snd_device = voip_usecase->in_snd_device; out_snd_device = voip_usecase->out_snd_device; } -- GitLab From ee73360895cdc83fabaf656c8f823c83ef10ffd2 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Thu, 3 Apr 2014 17:47:22 -0700 Subject: [PATCH 225/298] hal: add missing flags for extended features. - add missing feature flags to compile hal without extended features enabled. Change-Id: Idd43dfac20cb14798b20f4aa2bee5ff11a8da491 --- hal/audio_hw.c | 34 +++++++++++++++++++------ hal/msm8974/platform.c | 49 +++++++++++++++++++++++++------------ hal/voice_extn/voice_extn.c | 8 ++++++ mm-audio/Android.mk | 2 ++ policy_hal/Android.mk | 2 ++ post_proc/Android.mk | 4 ++- 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 3b8351e33..3faa045fa 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -115,7 +115,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_HFP_SCO] = "hfp-sco", [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb", [USECASE_VOICE_CALL] = "voice-call", - + [USECASE_VOICE2_CALL] = "voice2-call", [USECASE_VOLTE_CALL] = "volte-call", [USECASE_QCHAT_CALL] = "qchat-call", @@ -184,9 +184,11 @@ static int check_and_set_gapless_mode(struct audio_device *adev) { static bool is_supported_format(audio_format_t format) { if (format == AUDIO_FORMAT_MP3 || - format == AUDIO_FORMAT_AAC || +#ifdef EXTN_OFFLOAD_ENABLED format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || - format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) + format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD || +#endif + format == AUDIO_FORMAT_AAC) return true; return false; @@ -203,10 +205,12 @@ static int get_snd_codec_id(audio_format_t format) case AUDIO_FORMAT_AAC: id = SND_AUDIOCODEC_AAC; break; +#ifdef EXTN_OFFLOAD_ENABLED case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: id = SND_AUDIOCODEC_PCM; break; +#endif default: ALOGE("%s: Unsupported audio format :%x", __func__, format); } @@ -1326,6 +1330,7 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par return -EINVAL; } +#ifdef EXTN_OFFLOAD_ENABLED ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FORMAT, value, sizeof(value)); if (ret >= 0) { if (atoi(value) == SND_AUDIOSTREAMFORMAT_MP4ADTS) { @@ -1334,6 +1339,7 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par } out->send_new_metadata = 1; } +#endif ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value)); if(ret >= 0) @@ -2076,15 +2082,21 @@ static int adev_open_output_stream(struct audio_hw_device *dev, /* Init use case and pcm_config */ if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) && - (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL || - out->devices & AUDIO_DEVICE_OUT_PROXY)) { + ( +#ifdef AFE_PROXY_ENABLED + out->devices & AUDIO_DEVICE_OUT_PROXY || +#endif + out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { pthread_mutex_lock(&adev->lock); if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) ret = read_hdmi_channel_masks(out); +#ifdef AFE_PROXY_ENABLED if (out->devices & AUDIO_DEVICE_OUT_PROXY) ret = audio_extn_read_afe_proxy_channel_masks(out); +#endif + pthread_mutex_unlock(&adev->lock); if (ret != 0) goto error_open; @@ -2101,6 +2113,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->config.rate = config->sample_rate; out->config.channels = popcount(out->channel_mask); out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); +#ifdef COMPRESS_VOIP_ENABLED } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) && (voice_extn_compress_voip_is_config_supported(config))) { @@ -2110,6 +2123,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, __func__, ret); goto error_open; } +#endif } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version || config->offload_info.size != AUDIO_INFO_INITIALIZER.size) { @@ -2150,11 +2164,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev, else out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); - +#ifdef EXTN_OFFLOAD_ENABLED if (audio_is_offload_pcm(config->offload_info.format)) { out->compr_config.fragment_size = platform_get_pcm_offload_buffer_size(&config->offload_info); - } else { + } else +#endif + { out->compr_config.fragment_size = platform_get_compress_offload_buffer_size(&config->offload_info); } @@ -2168,10 +2184,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; +#ifdef EXTN_OFFLOAD_ENABLED if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; else if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; +#endif if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; @@ -2187,6 +2205,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, //Decide if we need to use gapless mode by default check_and_set_gapless_mode(adev); +#ifdef INCALL_MUSIC_ENABLED } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { ret = voice_check_and_set_incall_music_usecase(adev, out); if (ret != 0) { @@ -2194,6 +2213,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, __func__, ret); goto error_open; } +#endif } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 629bd8c9a..c6a310f42 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -687,6 +687,23 @@ int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) return device_id; } +int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id) +{ + int ret = 0; + + if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) { + ALOGE("%s: Invalid snd_device = %d", + __func__, snd_device); + ret = -EINVAL; + goto done; + } + + acdb_device_table[snd_device] = acdb_id; +done: + return ret; +} + +#ifdef FLUENCE_ENABLED int platform_set_fluence_type(void *platform, char *value) { int ret = 0; @@ -727,21 +744,6 @@ done: return ret; } -int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id) -{ - int ret = 0; - - if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) { - ALOGE("%s: Invalid snd_device = %d", - __func__, snd_device); - ret = -EINVAL; - goto done; - } - - acdb_device_table[snd_device] = acdb_id; -done: - return ret; -} int platform_get_fluence_type(void *platform, char *value, uint32_t len) { @@ -759,6 +761,7 @@ int platform_get_fluence_type(void *platform, char *value, uint32_t len) return ret; } +#endif int platform_send_audio_calibration(void *platform, snd_device_t snd_device) { @@ -1068,8 +1071,10 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET || devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { snd_device = SND_DEVICE_OUT_USB_HEADSET; +#ifdef FM_ENABLED } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; +#endif } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { if (audio_extn_should_use_handset_anc(channel_count)) snd_device = SND_DEVICE_OUT_ANC_HANDSET; @@ -1109,15 +1114,19 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi ALOGD("%s: setting USB hadset channel capability(2) for Proxy", __func__); audio_extn_set_afe_proxy_channel_mixer(adev, 2); snd_device = SND_DEVICE_OUT_USB_HEADSET; +#ifdef FM_ENABLED } else if (devices & AUDIO_DEVICE_OUT_FM_TX) { snd_device = SND_DEVICE_OUT_TRANSMISSION_FM; +#endif } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { snd_device = SND_DEVICE_OUT_HANDSET; +#ifdef AFE_PROXY_ENABLED } else if (devices & AUDIO_DEVICE_OUT_PROXY) { channel_count = audio_extn_get_afe_proxy_channel_count(); ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count); audio_extn_set_afe_proxy_channel_mixer(adev, channel_count); snd_device = SND_DEVICE_OUT_AFE_PROXY; +#endif } else { ALOGE("%s: Unknown device(s) %#x", __func__, devices); } @@ -1293,9 +1302,11 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d set_echo_reference(adev, true); } } +#ifdef FM_ENABLED } else if (source == AUDIO_SOURCE_FM_RX || source == AUDIO_SOURCE_FM_RX_A2DP) { snd_device = SND_DEVICE_IN_CAPTURE_FM; +#endif } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; } @@ -1330,8 +1341,10 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET || in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) { snd_device = SND_DEVICE_IN_USB_HEADSET_MIC; +#ifdef FM_ENABLED } else if (in_device & AUDIO_DEVICE_IN_FM_RX) { snd_device = SND_DEVICE_IN_CAPTURE_FM; +#endif } else { ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); ALOGW("%s: Using default handset-mic", __func__); @@ -1684,8 +1697,10 @@ int64_t platform_render_latency(audio_usecase_t usecase) int platform_update_usecase_from_source(int source, int usecase) { ALOGV("%s: input source :%d", __func__, source); +#ifdef FM_ENABLED if(source == AUDIO_SOURCE_FM_RX_A2DP) usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL; +#endif return usecase; } @@ -1693,7 +1708,9 @@ bool platform_listen_update_status(snd_device_t snd_device) { if ((snd_device >= SND_DEVICE_IN_BEGIN) && (snd_device < SND_DEVICE_IN_END) && +#ifdef FM_ENABLED (snd_device != SND_DEVICE_IN_CAPTURE_FM) && +#endif (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)) return true; else @@ -1734,9 +1751,11 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; uint32_t bits_per_sample = 16; +#ifdef EXTN_OFFLOAD_ENABLED if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { bits_per_sample = 32; } +#endif if (!info->has_video) { fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index 58a1f8bec..cd7270c89 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -186,11 +186,13 @@ static int update_calls(struct audio_device *adev) case CALL_LOCAL_HOLD: ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid); lch_mode = VOICE_LCH_STOP; +#ifdef PCM_IOCTL_ENABLED if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { ALOGE("LOCAL_HOLD -> ACTIVE failed"); } else { session->state.current = session->state.new; } +#endif break; default: @@ -238,11 +240,13 @@ static int update_calls(struct audio_device *adev) case CALL_LOCAL_HOLD: ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid); lch_mode = VOICE_LCH_STOP; +#ifdef PCM_IOCTL_ENABLED if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { ALOGE("LOCAL_HOLD -> HOLD failed"); } else { session->state.current = session->state.new; } +#endif break; default: @@ -260,11 +264,13 @@ static int update_calls(struct audio_device *adev) ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__, session->vsid); lch_mode = VOICE_LCH_START; +#ifdef PCM_IOCTL_ENABLED if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) { ALOGE("LOCAL_HOLD -> HOLD failed"); } else { session->state.current = session->state.new; } +#endif break; default: @@ -583,6 +589,7 @@ void voice_extn_in_get_parameters(struct stream_in *in, voice_extn_compress_voip_in_get_parameters(in, query, reply); } +#ifdef INCALL_MUSIC_ENABLED int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, struct stream_out *out) { @@ -604,4 +611,5 @@ int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, return 0; } +#endif diff --git a/mm-audio/Android.mk b/mm-audio/Android.mk index 5053e7d64..148f2058e 100644 --- a/mm-audio/Android.mk +++ b/mm-audio/Android.mk @@ -1 +1,3 @@ +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_EXTN_MM_AUDIO)),true) include $(call all-subdir-makefiles) +endif diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index b6a06e4c7..839fe06ea 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -1,3 +1,4 @@ +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_EXTN_APM)),true) ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true) LOCAL_PATH := $(call my-dir) @@ -33,3 +34,4 @@ endif include $(BUILD_SHARED_LIBRARY) endif +endif#endif for AUDIO_FEATURE_DISABLED_EXTN_APM diff --git a/post_proc/Android.mk b/post_proc/Android.mk index b6966e669..a363164dd 100644 --- a/post_proc/Android.mk +++ b/post_proc/Android.mk @@ -1,4 +1,4 @@ - +ifneq ($(strip $(AUDIO_FEATURE_DISABLED_EXTN_POST_PROC)),true) LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -29,3 +29,5 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, audio-effects) include $(BUILD_SHARED_LIBRARY) + +endif -- GitLab From 7854128f68f88c0d557402c872fad85572adedba Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Fri, 16 May 2014 12:10:55 -0700 Subject: [PATCH 226/298] hal: update audio feature flags - update audio feature flags to use AUDIO_FEATURE_ENABLED_XXX instead of AUDIO_FEATURE_DISABLED_XXX. - These feature flags are defined by target board config file Conflicts: hal/Android.mk hal/audio_extn/audio_extn.h policy_hal/Android.mk post_proc/Android.mk Conflicts: mm-audio/Android.mk policy_hal/Android.mk post_proc/Android.mk Change-Id: Iba482d8b72bfa2675877d833d7abcb93d4cf4907 --- hal/Android.mk | 48 ++++++++++++++++++++++--------------- hal/audio_extn/audio_extn.h | 39 ++++++++++++++++++++++++++++++ mm-audio/Android.mk | 2 +- policy_hal/Android.mk | 23 +++++++++++++----- post_proc/Android.mk | 6 ++++- 5 files changed, 91 insertions(+), 27 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index d4862f23f..044e4e959 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -30,83 +30,93 @@ LOCAL_SRC_FILES := \ LOCAL_SRC_FILES += audio_extn/audio_extn.c -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true) + LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED +endif + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ANC_HEADSET)),true) LOCAL_CFLAGS += -DANC_HEADSET_ENABLED endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FLUENCE)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLUENCE)),true) LOCAL_CFLAGS += -DFLUENCE_ENABLED endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAFE_PROXY_ENABLED endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM)),true) LOCAL_CFLAGS += -DFM_ENABLED LOCAL_SRC_FILES += audio_extn/fm.c endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_USBAUDIO)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_USBAUDIO)),true) LOCAL_CFLAGS += -DUSB_HEADSET_ENABLED LOCAL_SRC_FILES += audio_extn/usb.c endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_HFP)),true) + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HFP)),true) LOCAL_CFLAGS += -DHFP_ENABLED LOCAL_SRC_FILES += audio_extn/hfp.c endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_SSR)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_CUSTOMSTEREO)),true) + LOCAL_CFLAGS += -DCUSTOM_STEREO_ENABLED +endif + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SSR)),true) LOCAL_CFLAGS += -DSSR_ENABLED LOCAL_SRC_FILES += audio_extn/ssr.c LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/surround_sound/ endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS)),true) LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED LOCAL_SRC_FILES += voice_extn/voice_extn.c LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr - -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_INCALL_MUSIC)),true) LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED endif - -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_VOIP)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_COMPRESS_VOIP)),true) LOCAL_CFLAGS += -DCOMPRESS_VOIP_ENABLED LOCAL_SRC_FILES += voice_extn/compress_voip.c endif endif -ifneq ($(strip, $(AUDIO_FEATURE_DISABLED_SPKR_PROTECTION)),true) -ifneq ($(filter msm8974,$(TARGET_BOARD_PLATFORM)),) + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FORMATS)),true) +LOCAL_CFLAGS += -DFORMATS_ENABLED +endif + +ifeq ($(strip, $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true) LOCAL_CFLAGS += -DSPKR_PROT_ENABLED LOCAL_SRC_FILES += audio_extn/spkr_protection.c LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr endif -endif ifdef MULTIPLE_HW_VARIANTS_ENABLED LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_CAPTURE)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_COMPRESS_CAPTURE)),true) LOCAL_CFLAGS += -DCOMPRESS_CAPTURE_ENABLED LOCAL_SRC_FILES += audio_extn/compress_capture.c endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true) +ifeq ($(strip $(DOLBY_DDP)),true) LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_SRC_FILES += audio_extn/dolby.c endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DAP)),true) +ifeq ($(strip $(DOLBY_DAP)),true) LOCAL_CFLAGS += -DDS1_DOLBY_DAP_ENABLED -ifeq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true) +ifneq ($(strip $(DOLBY_DDP)),true) LOCAL_SRC_FILES += audio_extn/dolby.c endif endif diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index aecef3662..5bf8a1fe4 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -22,6 +22,45 @@ #include +#ifndef PCM_OFFLOAD_ENABLED +#define AUDIO_FORMAT_PCM_OFFLOAD 0x17000000UL +#define AUDIO_FORMAT_PCM_16_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_16_BIT) +#define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT) +#define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format" +#define audio_is_offload_pcm(format) (0) +#endif + +#ifndef AFE_PROXY_ENABLED +#define AUDIO_DEVICE_OUT_PROXY 0x40000 +#endif + +#ifndef COMPRESS_VOIP_ENABLED +#define AUDIO_OUTPUT_FLAG_VOIP_RX 0x4000 +#endif + +#ifndef INCALL_MUSIC_ENABLED +#define AUDIO_OUTPUT_FLAG_INCALL_MUSIC 0x8000 +#endif + +#ifndef FLUENCE_ENABLED +#define AUDIO_PARAMETER_KEY_FLUENCE "fluence" +#define AUDIO_PARAMETER_VALUE_QUADMIC "quadmic" +#define AUDIO_PARAMETER_VALUE_DUALMIC "dualmic" +#define AUDIO_PARAMETER_KEY_NO_FLUENCE "none" +#endif + +#ifndef FM_ENABLED +#define AUDIO_DEVICE_OUT_FM 0x80000 +#define AUDIO_DEVICE_OUT_FM_TX 0x100000 +#define AUDIO_SOURCE_FM_RX 9 +#define AUDIO_SOURCE_FM_RX_A2DP 10 +#define AUDIO_DEVICE_IN_FM_RX (AUDIO_DEVICE_BIT_IN | 0x8000) +#define AUDIO_DEVICE_IN_FM_RX_A2DP (AUDIO_DEVICE_BIT_IN | 0x10000) +#endif + + +#define MAX_LENGTH_MIXER_CONTROL_IN_INT (128) + void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms); diff --git a/mm-audio/Android.mk b/mm-audio/Android.mk index 148f2058e..3885afc63 100644 --- a/mm-audio/Android.mk +++ b/mm-audio/Android.mk @@ -1,3 +1,3 @@ -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_EXTN_MM_AUDIO)),true) +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) include $(call all-subdir-makefiles) endif diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index 839fe06ea..b787130ef 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -1,5 +1,4 @@ -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_EXTN_APM)),true) -ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true) +ifeq ($(strip $(BOARD_USES_EXTN_AUDIO_POLICY_MANAGER)),true) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -21,17 +20,29 @@ LOCAL_MODULE := audio_policy.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_MODULE_TAGS := optional -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM)),true) LOCAL_CFLAGS += -DAUDIO_EXTN_FM_ENABLED endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED endif -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_INCALL_MUSIC)),true) LOCAL_CFLAGS += -DAUDIO_EXTN_INCALL_MUSIC_ENABLED endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_SPK)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_HDMI_SPK_ENABLED +endif + + +ifeq ($(strip $(TARGET_BOARD_PLATFORM)),msm8916) +LOCAL_CFLAGS += -DVOICE_CONCURRENCY +LOCAL_CFLAGS += -DWFD_CONCURRENCY +endif + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTIPLE_TUNNEL)), true) +LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED +endif include $(BUILD_SHARED_LIBRARY) endif -endif#endif for AUDIO_FEATURE_DISABLED_EXTN_APM diff --git a/post_proc/Android.mk b/post_proc/Android.mk index a363164dd..683588ed6 100644 --- a/post_proc/Android.mk +++ b/post_proc/Android.mk @@ -1,8 +1,12 @@ -ifneq ($(strip $(AUDIO_FEATURE_DISABLED_EXTN_POST_PROC)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_POST_PROC)),true) LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) + LOCAL_CFLAGS += -DAFE_PROXY_ENABLED +endif + LOCAL_SRC_FILES:= \ bundle.c \ equalizer.c \ -- GitLab From 9952f5260c3c258128ff13252225a170cc029e0e Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Fri, 11 Jul 2014 10:39:59 -0700 Subject: [PATCH 227/298] hal: add extended audio definitions in hal - Add audio_defs.h in hal for extended audio definitions. Change-Id: I7d574a222d405d8c62d8b833d9ef413708f19639 --- hal/audio_extn/audio_defs.h | 78 +++++++++++++++++++++++++++++++++++++ hal/audio_extn/audio_extn.h | 7 ---- hal/audio_hw.h | 1 + 3 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 hal/audio_extn/audio_defs.h diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h new file mode 100644 index 000000000..335a62951 --- /dev/null +++ b/hal/audio_extn/audio_defs.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AUDIO_DEFS_H +#define AUDIO_DEFS_H + + +/** + * extended audio codec parameters + */ + +#define AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG "music_offload_wma_format_tag" +#define AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN "music_offload_wma_block_align" +#define AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE "music_offload_wma_bit_per_sample" +#define AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK "music_offload_wma_channel_mask" +#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION "music_offload_wma_encode_option" +#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1 "music_offload_wma_encode_option1" +#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2 "music_offload_wma_encode_option2" +#define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format" +#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size" +#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size" +#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size" +#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size" + +/* Query handle fm parameter*/ +#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm" + +/* Query fm volume */ +#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume" + +/* Query Fluence type */ +#define AUDIO_PARAMETER_KEY_FLUENCE "fluence" +#define AUDIO_PARAMETER_VALUE_QUADMIC "quadmic" +#define AUDIO_PARAMETER_VALUE_DUALMIC "dualmic" +#define AUDIO_PARAMETER_KEY_NO_FLUENCE "none" + +/* Query if surround sound recording is supported */ +#define AUDIO_PARAMETER_KEY_SSR "ssr" + +/* Query if a2dp is supported */ +#define AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported" + +/* Query ADSP Status */ +#define AUDIO_PARAMETER_KEY_ADSP_STATUS "ADSP_STATUS" + +/* Query Sound Card Status */ +#define AUDIO_PARAMETER_KEY_SND_CARD_STATUS "SND_CARD_STATUS" + +/* Query if Proxy can be Opend */ +#define AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY "can_open_proxy" + +#endif /* AUDIO_DEFS_H */ diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 5bf8a1fe4..09bc0b6c4 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -42,13 +42,6 @@ #define AUDIO_OUTPUT_FLAG_INCALL_MUSIC 0x8000 #endif -#ifndef FLUENCE_ENABLED -#define AUDIO_PARAMETER_KEY_FLUENCE "fluence" -#define AUDIO_PARAMETER_VALUE_QUADMIC "quadmic" -#define AUDIO_PARAMETER_VALUE_DUALMIC "dualmic" -#define AUDIO_PARAMETER_KEY_NO_FLUENCE "none" -#endif - #ifndef FM_ENABLED #define AUDIO_DEVICE_OUT_FM 0x80000 #define AUDIO_DEVICE_OUT_FM_TX 0x100000 diff --git a/hal/audio_hw.h b/hal/audio_hw.h index e6ec012ec..51432c0ae 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -26,6 +26,7 @@ #include #include +#include "audio_defs.h" #include "voice.h" #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so" -- GitLab From 97f6d999e538e70924c2d4e620af01ee6163056f Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Mon, 2 Jun 2014 22:38:35 -0700 Subject: [PATCH 228/298] hal: remove ANC headset devices in hal - Remove AUDIO_DEVICE_OUT_ANC_HEADPHONE and AUDIO_DEVICE_OUT_ANC_HEADSET in hal. - These devices are not used Change-Id: Ib8692906edb3460a6325adcf3c3cce9ef4641120 --- hal/audio_extn/dolby.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c index 99fa2b7b4..cf07e11fc 100644 --- a/hal/audio_extn/dolby.c +++ b/hal/audio_extn/dolby.c @@ -64,7 +64,7 @@ /* DS1-DDP Endp Params */ #define DDP_ENDP_NUM_PARAMS 17 -#define DDP_ENDP_NUM_DEVICES 23 +#define DDP_ENDP_NUM_DEVICES 21 static int ddp_endp_params_id[DDP_ENDP_NUM_PARAMS] = { PARAM_ID_MAX_OUTPUT_CHANNELS, PARAM_ID_CTL_RUNNING_MODE, PARAM_ID_CTL_ERROR_CONCEAL, PARAM_ID_CTL_ERROR_MAX_RPTS, @@ -140,12 +140,6 @@ static struct ddp_endp_params { {AUDIO_DEVICE_OUT_FM_TX, 2, {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, - {AUDIO_DEVICE_OUT_ANC_HEADSET, 2, - {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, - {AUDIO_DEVICE_OUT_ANC_HEADPHONE, 2, - {8, 0, 0, 0, 0, 0, 0, 21, 1, 6, 0, 0, 0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, {AUDIO_DEVICE_OUT_PROXY, 2, {8, 0, 0, 0, 0, 0, 0, 21, 1, 2, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} }, -- GitLab From 90e2cd85988aab473e157a28ae594f247b4927d0 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Fri, 6 Jun 2014 17:11:23 -0700 Subject: [PATCH 229/298] hal: add support for pcm_ioctl() api - Tinyalsa doesn't expose an api to call ioctls exposed by the audio drivers. - Add pcm_ioctl() api to support pcm ioctl. Change-Id: I448252e8d3347257a73c56bc8ed341abc2dd2dab --- hal/audio_hw.c | 13 +++++++++++++ hal/audio_hw.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 3faa045fa..3b1228334 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2745,6 +2745,19 @@ static int adev_open(const hw_module_t *module, const char *name, return 0; } +int pcm_ioctl(struct pcm *pcm, int request, ...) +{ + va_list ap; + void * arg; + int pcm_fd = *(int*)pcm; + + va_start(ap, request); + arg = va_arg(ap, void *); + va_end(ap); + + return ioctl(pcm_fd, request, arg); +} + static struct hw_module_methods_t hal_module_methods = { .open = adev_open, }; diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 51432c0ae..0dbf2d72d 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -255,6 +255,8 @@ int enable_audio_route(struct audio_device *adev, struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id); +int pcm_ioctl(struct pcm *pcm, int request, ...); + #define LITERAL_TO_STRING(x) #x #define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\ __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ -- GitLab From 3e68db3947a4e1e9f6844841c4cfe79b27f7e736 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Thu, 7 Aug 2014 17:21:00 +0530 Subject: [PATCH 230/298] hal: Correcting syntax to check Speaker Protection Macro Change-Id: If5c97010479fca84a5f172c7a047813ee7c06e73 --- hal/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/Android.mk b/hal/Android.mk index 044e4e959..6695afdbf 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -90,7 +90,7 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FORMATS)),true) LOCAL_CFLAGS += -DFORMATS_ENABLED endif -ifeq ($(strip, $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true) LOCAL_CFLAGS += -DSPKR_PROT_ENABLED LOCAL_SRC_FILES += audio_extn/spkr_protection.c LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include -- GitLab From 654b0a677ff4bcd857ccb85da8b65762b4151743 Mon Sep 17 00:00:00 2001 From: Aviral Gupta Date: Fri, 14 Mar 2014 21:51:36 +0530 Subject: [PATCH 231/298] hal: update the vifeedback pcm device id Due to changes in machine driver pcm device id has changed, which causes the failure during the pcm_open. Fix by updating the pcm device_id for vifeedback usecase. Change-Id: I47a035f59ccaefe296ecd721d08670a6ffc57363 --- hal/msm8974/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 2d6f854d1..5c625e205 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -180,7 +180,7 @@ enum { #endif #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5 -#define SPKR_PROT_CALIB_TX_PCM_DEVICE 25 +#define SPKR_PROT_CALIB_TX_PCM_DEVICE 32 #define PLAYBACK_OFFLOAD_DEVICE 9 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3 -- GitLab From d1179ade2b6a001006298ec94083edcfc586534c Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Mon, 4 Aug 2014 15:49:24 -0700 Subject: [PATCH 232/298] hal: make file change to export audio_defs.h - copy audio_defs.h to out target so that it can be included in AOSP code. Change-Id: I84996dd8821a48a9ec71a1164764bf28b91cd390 --- hal/Android.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hal/Android.mk b/hal/Android.mk index 6695afdbf..5d4a9eeff 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -155,6 +155,9 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true) LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED endif +LOCAL_COPY_HEADERS_TO := mm-audio +LOCAL_COPY_HEADERS := audio_extn/audio_defs.h + LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -- GitLab From cff6e3e6c8151e3a232f5fb2aeed8f3ebaeda677 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Mon, 25 Aug 2014 20:36:25 +0530 Subject: [PATCH 233/298] hal: Update HAL to handle offload format with AAC profile info. -Framework now passes AAC profile information alongwith the format. -Check for the supported AAC profiles by HW decoder. Change-Id: I5c0625d53f07c1d3374f2cbdf4848ef438883b2d --- hal/audio_hw.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 3faa045fa..175c4e78c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -188,9 +188,11 @@ static bool is_supported_format(audio_format_t format) format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD || #endif - format == AUDIO_FORMAT_AAC) - return true; - + format == AUDIO_FORMAT_AAC_LC || + format == AUDIO_FORMAT_AAC_HE_V1 || + format == AUDIO_FORMAT_AAC_HE_V2 ){ + return true; + } return false; } @@ -198,7 +200,7 @@ static int get_snd_codec_id(audio_format_t format) { int id = 0; - switch (format) { + switch (format & AUDIO_FORMAT_MAIN_MASK) { case AUDIO_FORMAT_MP3: id = SND_AUDIOCODEC_MP3; break; @@ -206,8 +208,7 @@ static int get_snd_codec_id(audio_format_t format) id = SND_AUDIOCODEC_AAC; break; #ifdef EXTN_OFFLOAD_ENABLED - case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: - case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: + case AUDIO_FORMAT_PCM_OFFLOAD: id = SND_AUDIOCODEC_PCM; break; #endif -- GitLab From daf9c546e0c0ab2d04f5c301006b6a02724f4bf8 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Tue, 16 Sep 2014 17:41:33 -0700 Subject: [PATCH 234/298] hal: fix for open input failure while SSR is not enabled. - Do not return failure if SSR is not enabled. Change-Id: I49d1e47b700165f8d9fd073792eeef57b40a5cb4 --- hal/audio_hw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 175c4e78c..fa0ea9f32 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2557,8 +2557,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, goto err_open; } } else { - ret = -EINVAL; - goto err_open; + ALOGW("%s: surround sound recording is not supported", __func__); } } else if (audio_extn_compr_cap_enabled() && audio_extn_compr_cap_format_supported(config->format) && -- GitLab From 23b3af2ed67aac322a5f41f82793f0f767b5c16e Mon Sep 17 00:00:00 2001 From: Shreyas Nagasandra Chandrasekhar Date: Wed, 3 Sep 2014 19:10:01 +0530 Subject: [PATCH 235/298] audio:Set the input device for VOIP calls using audio path For Voip calls using audio path ,the input devices is not getting selected when output device is changed. Now,removed the source type check to select the input device when there is an active input and output device switch . Change-Id: Icc7e1c3085771526cde01ea0a06afca1ffd1278b --- hal/audio_hw.c | 5 ++--- hal/msm8974/platform.c | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fa0ea9f32..6aef6ff31 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -631,8 +631,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) out_snd_device = platform_get_output_snd_device(adev->platform, usecase->stream.out->devices); if (usecase->stream.out == adev->primary_output && - adev->active_input && - adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) { + adev->active_input ) { select_devices(adev, adev->active_input->usecase); } } @@ -640,7 +639,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) usecase->devices = usecase->stream.in->device; out_snd_device = SND_DEVICE_NONE; if (in_snd_device == SND_DEVICE_NONE) { - if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION && + if ((adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION || (adev->mode == AUDIO_MODE_IN_COMMUNICATION && adev->active_input->source == AUDIO_SOURCE_MIC)) && adev->primary_output && !adev->primary_output->standby) { in_snd_device = platform_get_input_snd_device(adev->platform, adev->primary_output->devices); diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c6a310f42..b3345e128 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1233,7 +1233,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_VOICE_REC_MIC; } } - } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) { + } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION || + (mode == AUDIO_MODE_IN_COMMUNICATION)) { if (out_device & AUDIO_DEVICE_OUT_SPEAKER) in_device = AUDIO_DEVICE_IN_BACK_MIC; if (adev->active_input) { -- GitLab From 27cf526276eee9e59b20c13afc80259f34872e98 Mon Sep 17 00:00:00 2001 From: Shreyas Nagasandra Chandrasekhar Date: Tue, 30 Sep 2014 15:16:21 +0530 Subject: [PATCH 236/298] audio: Changes to enable Local Hold for DSDA calls Local hold was not enabled for DSDA calls . Fixed the issue by enabling the macro. CRs-Fixed: 727221 Change-Id: Ib29a08fd52740919f0ca240f9506705977dcb521 --- hal/Android.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/Android.mk b/hal/Android.mk index 5d4a9eeff..22c01c154 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -155,6 +155,10 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true) LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED endif +ifeq ($(strip $(AUDIO_FEATURE_PCM_IOCTL_ENABLED)),true) + LOCAL_CFLAGS += -DPCM_IOCTL_ENABLED +endif + LOCAL_COPY_HEADERS_TO := mm-audio LOCAL_COPY_HEADERS := audio_extn/audio_defs.h -- GitLab From 4dfa075bcfdaff7bdc26d736f60e26115c3c2053 Mon Sep 17 00:00:00 2001 From: Rajshekar Eashwarappa Date: Thu, 2 Oct 2014 20:18:20 +0530 Subject: [PATCH 237/298] hal: Fix compilation error "audio_extn_usb_stop_capture()" method modified to fix compilation error. Change-Id: Ibea3eed2bef687ad328ff6a0f00bdb796bbf0036 --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index fa0ea9f32..22e3fde80 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -354,7 +354,7 @@ int disable_snd_device(struct audio_device *adev, /* exit usb capture thread */ if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) - audio_extn_usb_stop_capture(adev); + audio_extn_usb_stop_capture(); if (snd_device == SND_DEVICE_OUT_SPEAKER && audio_extn_spkr_prot_is_enabled()) { -- GitLab From 8005dc822d6a2c8e6e61eb005b61553a93561a42 Mon Sep 17 00:00:00 2001 From: Avinash Vaish Date: Thu, 24 Jul 2014 15:36:33 +0530 Subject: [PATCH 238/298] hal: Send voice cal data before routing voice usecases -The sound intensity is drastically reduced in a DSDA call when a particular device is re-selected after a device switch. It is observed that for the active sub, acdb data tables are registered to ADSP even before the right acdb tables are sent to the acdb driver. Therefore, the tables which are infact registered to the ADSP correspond to the previous device. - Load the acdb files into the kernel memory before routing voice usecases to prevent any incorrect tables being sent. CRs-Fixed: 694397 Change-Id: Id2f2a43c887d9b9e74cd98858013d1ef655a93e3 --- hal/audio_hw.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 601edcf3d..59b838064 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -219,6 +219,26 @@ static int get_snd_codec_id(audio_format_t format) return id; } +static int enable_audio_route_for_voice_usecases(struct audio_device *adev, + struct audio_usecase *uc_info) +{ + struct listnode *node; + struct audio_usecase *usecase; + + if (uc_info == NULL) + return -EINVAL; + + /* Re-route all voice usecases on the shared backend other than the + specified usecase to new snd devices */ + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if ((usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) && + (usecase != uc_info)) + enable_audio_route(adev, usecase); + } + return 0; +} + int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase) { @@ -432,7 +452,8 @@ static void check_usecases_codec_backend(struct audio_device *adev, /* Update the out_snd_device only before enabling the audio route */ if (switch_device[usecase->id] ) { usecase->out_snd_device = snd_device; - enable_audio_route(adev, usecase); + if (usecase->type != VOICE_CALL && usecase->type != VOIP_CALL) + enable_audio_route(adev, usecase); } } } @@ -498,7 +519,8 @@ static void check_and_route_capture_usecases(struct audio_device *adev, /* Update the in_snd_device only before enabling the audio route */ if (switch_device[usecase->id] ) { usecase->in_snd_device = snd_device; - enable_audio_route(adev, usecase); + if (usecase->type != VOICE_CALL && usecase->type != VOIP_CALL) + enable_audio_route(adev, usecase); } } } @@ -692,10 +714,12 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) enable_snd_device(adev, in_snd_device); } - if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) + if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) { status = platform_switch_voice_call_device_post(adev->platform, out_snd_device, in_snd_device); + enable_audio_route_for_voice_usecases(adev, usecase); + } usecase->in_snd_device = in_snd_device; usecase->out_snd_device = out_snd_device; -- GitLab From ab9b1ef5fa5bdd164a3ab20d1eefa3ac45693804 Mon Sep 17 00:00:00 2001 From: Divya Narayanan Poojary Date: Fri, 12 Sep 2014 15:52:36 +0530 Subject: [PATCH 239/298] hal: add support to send/receive voice call TX/RX audio Add support for routing voice calls to devices in other audio HALs by allowing playback and capture to/from AFE proxy Change-Id: Ifab6a0368710c2735f548d09df71e8f8416b8992 --- hal/audio_hw.c | 200 ++++++++++++++++++++++++++++++++--------- hal/audio_hw.h | 8 +- hal/msm8960/platform.h | 3 + hal/msm8974/platform.c | 20 ++++- hal/msm8974/platform.h | 5 ++ hal/voice.c | 5 +- 6 files changed, 196 insertions(+), 45 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 59b838064..770eb2ecd 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -60,6 +60,8 @@ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 +#define PROXY_OPEN_RETRY_COUNT 100 +#define PROXY_OPEN_WAIT_TIME 20 #define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER @@ -102,6 +104,37 @@ struct pcm_config pcm_config_audio_capture = { .format = PCM_FORMAT_S16_LE, }; +#define AFE_PROXY_CHANNEL_COUNT 2 +#define AFE_PROXY_SAMPLING_RATE 48000 + +#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768 +#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4 + +struct pcm_config pcm_config_afe_proxy_playback = { + .channels = AFE_PROXY_CHANNEL_COUNT, + .rate = AFE_PROXY_SAMPLING_RATE, + .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE, + .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE, + .stop_threshold = INT_MAX, + .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE, +}; + +#define AFE_PROXY_RECORD_PERIOD_SIZE 768 +#define AFE_PROXY_RECORD_PERIOD_COUNT 4 + +struct pcm_config pcm_config_afe_proxy_record = { + .channels = AFE_PROXY_CHANNEL_COUNT, + .rate = AFE_PROXY_SAMPLING_RATE, + .period_size = AFE_PROXY_RECORD_PERIOD_SIZE, + .period_count = AFE_PROXY_RECORD_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE, + .stop_threshold = INT_MAX, + .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE, +}; + const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback", [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback", @@ -132,6 +165,9 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2", [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib", [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record", + + [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback", + [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record", }; @@ -375,7 +411,6 @@ int disable_snd_device(struct audio_device *adev, /* exit usb capture thread */ if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device) audio_extn_usb_stop_capture(); - if (snd_device == SND_DEVICE_OUT_SPEAKER && audio_extn_spkr_prot_is_enabled()) { audio_extn_spkr_prot_stop_processing(); @@ -661,14 +696,14 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) usecase->devices = usecase->stream.in->device; out_snd_device = SND_DEVICE_NONE; if (in_snd_device == SND_DEVICE_NONE) { + audio_devices_t out_device = AUDIO_DEVICE_NONE; if ((adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION || (adev->mode == AUDIO_MODE_IN_COMMUNICATION && adev->active_input->source == AUDIO_SOURCE_MIC)) && adev->primary_output && !adev->primary_output->standby) { - in_snd_device = platform_get_input_snd_device(adev->platform, - adev->primary_output->devices); - } else { - in_snd_device = platform_get_input_snd_device(adev->platform, - AUDIO_DEVICE_NONE); + out_device = adev->primary_output->devices; + } else if(usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) { + out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX; } + in_snd_device = platform_get_input_snd_device(adev->platform, out_device); } } } @@ -812,16 +847,33 @@ int start_input_stream(struct stream_in *in) select_devices(adev, in->usecase); ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", - __func__, adev->snd_card, - in->pcm_device_id, in->config.channels); - in->pcm = pcm_open(adev->snd_card, - in->pcm_device_id, PCM_IN, &in->config); - if (in->pcm && !pcm_is_ready(in->pcm)) { - ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); - pcm_close(in->pcm); - in->pcm = NULL; - ret = -EIO; - goto error_open; + __func__, adev->snd_card, in->pcm_device_id, in->config.channels); + + unsigned int flags = PCM_IN; + unsigned int pcm_open_retry_entry_count = 0; + + if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) { + flags |= PCM_MMAP | PCM_NOIRQ; + pcm_open_retry_entry_count = PROXY_OPEN_RETRY_COUNT; + } + + while(1) { + in->pcm = pcm_open(adev->snd_card, in->pcm_device_id, + flags, &in->config); + if (in->pcm == NULL || !pcm_is_ready(in->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); + if (in->pcm != NULL) { + pcm_close(in->pcm); + in->pcm = NULL; + } + if (pcm_open_retry_entry_count-- == 0) { + ret = -EIO; + goto error_open; + } + usleep(PROXY_OPEN_WAIT_TIME * 1000); + continue; + } + break; } ALOGV("%s: exit", __func__); return ret; @@ -1150,15 +1202,31 @@ int start_output_stream(struct stream_out *out) ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)", __func__, 0, out->pcm_device_id); if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { - out->pcm = pcm_open(adev->snd_card, - out->pcm_device_id, - PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm && !pcm_is_ready(out->pcm)) { - ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); - pcm_close(out->pcm); - out->pcm = NULL; - ret = -EIO; - goto error_open; + unsigned int flags = PCM_OUT; + unsigned int pcm_open_retry_count = 0; + if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) { + flags |= PCM_MMAP | PCM_NOIRQ; + pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT; + } else + flags |= PCM_MONOTONIC; + + while (1) { + out->pcm = pcm_open(adev->snd_card, out->pcm_device_id, + flags, &out->config); + if (out->pcm && !pcm_is_ready(out->pcm)) { + ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); + if (out->pcm != NULL) { + pcm_close(out->pcm); + out->pcm = NULL; + } + if (pcm_open_retry_count-- == 0) { + ret = -EIO; + goto error_open; + } + usleep(PROXY_OPEN_WAIT_TIME * 1000); + continue; + } + break; } } else { out->pcm = NULL; @@ -1397,6 +1465,10 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par return 0; } +static bool output_drives_call(struct audio_device *adev, struct stream_out *out) +{ + return out == adev->primary_output || out == adev->voice_tx_output; +} static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { @@ -1431,6 +1503,13 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) val = AUDIO_DEVICE_OUT_SPEAKER; } + if ((adev->mode == AUDIO_MODE_NORMAL) && + voice_is_in_call(adev) && + output_drives_call(adev, out)) { + ret = voice_stop_call(adev); + adev->current_call_output = NULL; + } + /* * select_devices() call below switches all the usecases on the same * backend to the new device. Refer to check_usecases_codec_backend() in @@ -1456,20 +1535,14 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) select_devices(adev, out->usecase); if ((adev->mode == AUDIO_MODE_IN_CALL) && - !voice_is_in_call(adev) && - (out == adev->primary_output)) { - ret = voice_start_call(adev); - } else if ((adev->mode == AUDIO_MODE_IN_CALL) && - voice_is_in_call(adev) && - (out == adev->primary_output)) { - voice_update_devices_for_all_voice_usecases(adev); + output_drives_call(adev, out)) { + adev->current_call_output = out; + if (!voice_is_in_call(adev)) + ret = voice_start_call(adev); + else + voice_update_devices_for_all_voice_usecases(adev); } - } - if ((adev->mode == AUDIO_MODE_NORMAL) && - voice_is_in_call(adev) && - (out == adev->primary_output)) { - ret = voice_stop_call(adev); } pthread_mutex_unlock(&adev->lock); @@ -1629,7 +1702,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, if (out->muted) memset((void *)buffer, 0, bytes); ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes); - ret = pcm_write(out->pcm, (void *)buffer, bytes); + if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) + ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes); + else + ret = pcm_write(out->pcm, (void *)buffer, bytes); if (ret == 0) out->written += bytes / (out->config.channels * sizeof(short)); } @@ -1923,7 +1999,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); if (err >= 0) { val = atoi(value); - if ((in->device != val) && (val != 0)) { + if (((int)in->device != val) && (val != 0)) { in->device = val; /* If recording is in progress, change the tx device to new device */ if (!in->standby) @@ -1991,6 +2067,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, ret = audio_extn_ssr_read(stream, buffer, bytes); else if (audio_extn_compr_cap_usecase_supported(in->usecase)) ret = audio_extn_compr_cap_read(in, buffer, bytes); + else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) + ret = pcm_mmap_read(in->pcm, buffer, bytes); else ret = pcm_read(in->pcm, buffer, bytes); } @@ -2238,6 +2316,28 @@ static int adev_open_output_stream(struct audio_hw_device *dev, goto error_open; } #endif + } else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) { + if (config->sample_rate == 0) + config->sample_rate = AFE_PROXY_SAMPLING_RATE; + if (config->sample_rate != 48000 && config->sample_rate != 16000 && + config->sample_rate != 8000) { + config->sample_rate = AFE_PROXY_SAMPLING_RATE; + ret = -EINVAL; + goto error_open; + } + out->sample_rate = config->sample_rate; + out->config.rate = config->sample_rate; + if (config->format == AUDIO_FORMAT_DEFAULT) + config->format = AUDIO_FORMAT_PCM_16_BIT; + if (config->format != AUDIO_FORMAT_PCM_16_BIT) { + config->format = AUDIO_FORMAT_PCM_16_BIT; + ret = -EINVAL; + goto error_open; + } + out->format = config->format; + out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY; + out->config = pcm_config_afe_proxy_playback; + adev->voice_tx_output = out; } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; @@ -2572,7 +2672,27 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->config.rate = config->sample_rate; in->format = config->format; - if (channel_count == 6) { + if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) { + if (config->sample_rate == 0) + config->sample_rate = AFE_PROXY_SAMPLING_RATE; + if (config->sample_rate != 48000 && config->sample_rate != 16000 && + config->sample_rate != 8000) { + config->sample_rate = AFE_PROXY_SAMPLING_RATE; + ret = -EINVAL; + goto err_open; + } + if (config->format == AUDIO_FORMAT_DEFAULT) + config->format = AUDIO_FORMAT_PCM_16_BIT; + if (config->format != AUDIO_FORMAT_PCM_16_BIT) { + config->format = AUDIO_FORMAT_PCM_16_BIT; + ret = -EINVAL; + goto err_open; + } + in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY; + in->config = pcm_config_afe_proxy_record; + in->config.channels = channel_count; + in->config.rate = config->sample_rate; + } else if (channel_count == 6) { if(audio_extn_ssr_get_enabled()) { if(audio_extn_ssr_init(adev, in)) { ALOGE("%s: audio_extn_ssr_init failed", __func__); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 51432c0ae..62ae6d99f 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -98,6 +98,10 @@ typedef enum { USECASE_AUDIO_SPKR_CALIB_RX, USECASE_AUDIO_SPKR_CALIB_TX, + + USECASE_AUDIO_PLAYBACK_AFE_PROXY, + USECASE_AUDIO_RECORD_AFE_PROXY, + AUDIO_USECASE_MAX } audio_usecase_t; @@ -177,7 +181,7 @@ struct stream_in { int standby; int source; int pcm_device_id; - int device; + audio_devices_t device; audio_channel_mask_t channel_mask; audio_usecase_t usecase; bool enable_aec; @@ -218,6 +222,8 @@ struct audio_device { audio_devices_t out_device; struct stream_in *active_input; struct stream_out *primary_output; + struct stream_out *voice_tx_output; + struct stream_out *current_call_output; bool bluetooth_nrec; bool screen_off; int *snd_dev_ref_cnt; diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h index e38d801de..8faf9cae9 100644 --- a/hal/msm8960/platform.h +++ b/hal/msm8960/platform.h @@ -118,4 +118,7 @@ enum { #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20 #define AUDIO_CAPTURE_PERIOD_COUNT 2 +#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7 +#define AFE_PROXY_RECORD_PCM_DEVICE 8 + #endif // QCOM_AUDIO_PLATFORM_H diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index b3345e128..a23f87e51 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -165,6 +165,11 @@ static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { INCALL_MUSIC_UPLINK2_PCM_DEVICE}, [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1}, [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE}, + + [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE, + AFE_PROXY_RECORD_PCM_DEVICE}, + [USECASE_AUDIO_RECORD_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE, + AFE_PROXY_RECORD_PCM_DEVICE}, }; /* Array to store sound devices */ @@ -186,6 +191,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones", [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones", [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset", + [SND_DEVICE_OUT_VOICE_TX] = "voice-tx", [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy", [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones", [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones", @@ -229,6 +235,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic", + [SND_DEVICE_IN_VOICE_RX] = "voice-rx", [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic", [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic", [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef", @@ -260,6 +267,7 @@ static int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17, [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37, + [SND_DEVICE_OUT_VOICE_TX] = 45, [SND_DEVICE_OUT_AFE_PROXY] = 0, [SND_DEVICE_OUT_USB_HEADSET] = 0, [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14, @@ -302,6 +310,7 @@ static int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36, [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16, + [SND_DEVICE_IN_VOICE_RX] = 44, [SND_DEVICE_IN_VOICE_REC_MIC] = 4, [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107, [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34, @@ -662,6 +671,10 @@ void platform_add_backend_name(char *mixer_path, snd_device_t snd_device) strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI) strcat(mixer_path, " speaker-and-hdmi"); + else if (snd_device == SND_DEVICE_OUT_VOICE_TX) + strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH); + else if (snd_device == SND_DEVICE_IN_VOICE_RX) + strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_AFE_PROXY) strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH); else if (snd_device == SND_DEVICE_OUT_USB_HEADSET) @@ -1080,7 +1093,9 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_ANC_HANDSET; else snd_device = SND_DEVICE_OUT_VOICE_HANDSET; - } + } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX) + snd_device = SND_DEVICE_OUT_VOICE_TX; + if (snd_device != SND_DEVICE_NONE) { goto exit; } @@ -1212,7 +1227,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; set_echo_reference(adev, true); } - } + } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX) + snd_device = SND_DEVICE_IN_VOICE_RX; } else if (source == AUDIO_SOURCE_CAMCORDER) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC || in_device & AUDIO_DEVICE_IN_BACK_MIC) { diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 5c625e205..2dcfd8a13 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -60,6 +60,7 @@ enum { SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES, SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET, + SND_DEVICE_OUT_VOICE_TX, SND_DEVICE_OUT_AFE_PROXY, SND_DEVICE_OUT_USB_HEADSET, SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET, @@ -113,6 +114,7 @@ enum { SND_DEVICE_IN_VOICE_REC_MIC_NS, SND_DEVICE_IN_VOICE_REC_DMIC_STEREO, SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE, + SND_DEVICE_IN_VOICE_RX, SND_DEVICE_IN_USB_HEADSET_MIC, SND_DEVICE_IN_CAPTURE_FM, SND_DEVICE_IN_AANC_HANDSET_MIC, @@ -223,6 +225,9 @@ enum { #define VOWLAN_CALL_PCM_DEVICE 36 #endif +#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7 +#define AFE_PROXY_RECORD_PCM_DEVICE 8 + #ifdef PLATFORM_MSM8x26 #define HFP_SCO_RX 28 #define HFP_ASM_RX_TX 29 diff --git a/hal/voice.c b/hal/voice.c index 7cb448e3e..a2e3586b9 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -115,8 +115,8 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); uc_info->id = usecase_id; uc_info->type = VOICE_CALL; - uc_info->stream.out = adev->primary_output; - uc_info->devices = adev->primary_output->devices; + uc_info->stream.out = adev->current_call_output; + uc_info->devices = adev->current_call_output->devices; uc_info->in_snd_device = SND_DEVICE_NONE; uc_info->out_snd_device = SND_DEVICE_NONE; @@ -460,6 +460,7 @@ void voice_update_devices_for_all_voice_usecases(struct audio_device *adev) if (usecase->type == VOICE_CALL) { ALOGV("%s: updating device for usecase:%s", __func__, use_case_table[usecase->id]); + usecase->stream.out = adev->current_call_output; select_devices(adev, usecase->id); } } -- GitLab From bd9f33f6fc9e49710a8fa9d4778034c5c8b82f83 Mon Sep 17 00:00:00 2001 From: Divya Narayanan Poojary Date: Wed, 17 Sep 2014 17:35:59 +0530 Subject: [PATCH 240/298] hal: fix unused param warnings Fix unused param warnings. Take care of coding style issues. Change-Id: Ifc72472b487abee83ff85e21fd324cee938973e9 --- hal/audio_extn/audio_extn.c | 2 +- hal/audio_extn/audio_extn.h | 14 ++-- hal/audio_extn/compress_capture.c | 3 +- hal/audio_extn/dolby.c | 2 +- hal/audio_extn/hfp.c | 10 ++- hal/audio_extn/spkr_protection.c | 8 +-- hal/audio_extn/ssr.c | 3 +- hal/audio_hw.c | 71 ++++++++++++-------- hal/msm8960/platform.c | 24 ++++--- hal/msm8974/platform_parser.c | 3 +- hal/voice_extn/compress_voip.c | 2 +- hal/voice_extn/voice_extn.h | 104 +++++++++++++++--------------- 12 files changed, 132 insertions(+), 114 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 06bcac801..dbb29c0ee 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -165,7 +165,7 @@ void audio_extn_set_fluence_parameters(struct audio_device *adev, } } -int audio_extn_get_fluence_parameters(struct audio_device *adev, +int audio_extn_get_fluence_parameters(const struct audio_device *adev, struct str_parms *query, struct str_parms *reply) { int ret = 0, err; diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 09bc0b6c4..6beaa95e2 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -77,7 +77,7 @@ bool audio_extn_should_use_handset_anc(int in_channels); #else void audio_extn_set_fluence_parameters(struct audio_device *adev, struct str_parms *parms); -int audio_extn_get_fluence_parameters(struct audio_device *adev, +int audio_extn_get_fluence_parameters(const struct audio_device *adev, struct str_parms *query, struct str_parms *reply); #endif @@ -115,14 +115,13 @@ bool audio_extn_usb_is_proxy_inuse(); #endif #ifndef SSR_ENABLED -#define audio_extn_ssr_init(adev, in) (0) +#define audio_extn_ssr_init(in) (0) #define audio_extn_ssr_deinit() (0) #define audio_extn_ssr_update_enabled() (0) #define audio_extn_ssr_get_enabled() (0) #define audio_extn_ssr_read(stream, buffer, bytes) (0) #else -int32_t audio_extn_ssr_init(struct audio_device *adev, - struct stream_in *in); +int32_t audio_extn_ssr_init(struct stream_in *in); int32_t audio_extn_ssr_deinit(); void audio_extn_ssr_update_enabled(); bool audio_extn_ssr_get_enabled(); @@ -183,7 +182,7 @@ bool audio_extn_spkr_prot_is_enabled(); #endif #ifndef COMPRESS_CAPTURE_ENABLED -#define audio_extn_compr_cap_init(adev,in) (0) +#define audio_extn_compr_cap_init(in) (0) #define audio_extn_compr_cap_enabled() (0) #define audio_extn_compr_cap_format_supported(format) (0) #define audio_extn_compr_cap_usecase_supported(usecase) (0) @@ -191,8 +190,7 @@ bool audio_extn_spkr_prot_is_enabled(); #define audio_extn_compr_cap_read(in, buffer, bytes) (0) #define audio_extn_compr_cap_deinit() (0) #else -void audio_extn_compr_cap_init(struct audio_device *adev, - struct stream_in *in); +void audio_extn_compr_cap_init(struct stream_in *in); bool audio_extn_compr_cap_enabled(); bool audio_extn_compr_cap_format_supported(audio_format_t format); bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase); @@ -231,7 +229,7 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev); #ifndef HFP_ENABLED #define audio_extn_hfp_is_active(adev) (0) -#define audio_extn_hfp_get_usecase() (0) +#define audio_extn_hfp_get_usecase() (-1) #else bool audio_extn_hfp_is_active(struct audio_device *adev); audio_usecase_t audio_extn_hfp_get_usecase(); diff --git a/hal/audio_extn/compress_capture.c b/hal/audio_extn/compress_capture.c index 0a2de3601..b8722a3c9 100644 --- a/hal/audio_extn/compress_capture.c +++ b/hal/audio_extn/compress_capture.c @@ -51,8 +51,7 @@ static struct compress_in_module c_in_mod = { }; -void audio_extn_compr_cap_init(struct audio_device *adev, - struct stream_in *in) +void audio_extn_compr_cap_init(struct stream_in *in) { in->usecase = USECASE_AUDIO_RECORD_COMPRESS; in->config.channels = COMPRESS_IN_CONFIG_CHANNELS; diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c index cf07e11fc..2184947c6 100644 --- a/hal/audio_extn/dolby.c +++ b/hal/audio_extn/dolby.c @@ -187,7 +187,7 @@ int update_ddp_endp_table(int device, int dev_ch_cap, int param_id, void send_ddp_endp_params_stream(struct stream_out *out, int device, int dev_ch_cap, - bool set_cache) + bool set_cache __unused) { int idx, i; int ddp_endp_params_data[2*DDP_ENDP_NUM_PARAMS + 1]; diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index add4a7c44..0be8de840 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -46,7 +46,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ #define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume" static int32_t start_hfp(struct audio_device *adev, - struct str_parms *parms); + struct str_parms *parms __unused); static int32_t stop_hfp(struct audio_device *adev); @@ -121,7 +121,7 @@ static int32_t hfp_set_volume(struct audio_device *adev, float value) } static int32_t start_hfp(struct audio_device *adev, - struct str_parms *parms) + struct str_parms *parms __unused) { int32_t i, ret = 0; struct audio_usecase *uc_info; @@ -298,12 +298,10 @@ void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms * if (rate == 8000){ hfpmod.ucid = USECASE_AUDIO_HFP_SCO; pcm_config_hfp.rate = rate; - } - else if (rate == 16000){ + } else if (rate == 16000){ hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB; pcm_config_hfp.rate = rate; - } - else + } else ALOGE("Unsupported rate.."); } diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c index 0c131cdbf..810b43e87 100644 --- a/hal/audio_extn/spkr_protection.c +++ b/hal/audio_extn/spkr_protection.c @@ -111,7 +111,7 @@ struct speaker_prot_session { struct pcm *pcm_rx; struct pcm *pcm_tx; int (*client_register_callback) - (char *client_name, int (*callback)(int, void *, void *), void *data); + (char *client_name, int (*callback)(int), void *data); void (*thermal_client_unregister_callback)(int handle); int (*thermal_client_request)(char *client_name, int req_data); bool spkr_prot_enable; @@ -372,7 +372,7 @@ exit: return status.status; } -static void* spkr_calibration_thread(void *context) +static void* spkr_calibration_thread() { unsigned long sec = 0; int t0; @@ -499,7 +499,7 @@ static void* spkr_calibration_thread(void *context) return NULL; } -static int thermal_client_callback(int temp, void *user_data, void *reserved) +static int thermal_client_callback(int temp) { pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex); ALOGD("%s: spkr_prot set t0 %d and signal", __func__, temp); @@ -544,7 +544,7 @@ void audio_extn_spkr_prot_init(void *adev) } else { /*Query callback function symbol*/ handle.client_register_callback = - (int (*)(char *, int (*)(int, void *, void *),void *)) + (int (*)(char *, int (*)(int),void *)) dlsym(handle.thermal_handle, "thermal_client_register_callback"); handle.thermal_client_unregister_callback = (void (*)(int) ) diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c index ac6da8b7f..355059923 100644 --- a/hal/audio_extn/ssr.c +++ b/hal/audio_extn/ssr.c @@ -378,8 +378,7 @@ bool audio_extn_ssr_get_enabled() return (ssrmod.is_ssr_enabled ? true: false); } -int32_t audio_extn_ssr_init(struct audio_device *adev, - struct stream_in *in) +int32_t audio_extn_ssr_init(struct stream_in *in) { uint32_t ret; char c_multi_ch_dump[128] = {0}; diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 770eb2ecd..3038d44f9 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1326,7 +1326,8 @@ static uint32_t out_get_sample_rate(const struct audio_stream *stream) return out->sample_rate; } -static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +static int out_set_sample_rate(struct audio_stream *stream __unused, + uint32_t rate __unused) { return -ENOSYS; } @@ -1357,7 +1358,8 @@ static audio_format_t out_get_format(const struct audio_stream *stream) return out->format; } -static int out_set_format(struct audio_stream *stream, audio_format_t format) +static int out_set_format(struct audio_stream *stream __unused, + audio_format_t format __unused) { return -ENOSYS; } @@ -1403,7 +1405,8 @@ static int out_standby(struct audio_stream *stream) return 0; } -static int out_dump(const struct audio_stream *stream, int fd) +static int out_dump(const struct audio_stream *stream __unused, + int fd __unused) { return 0; } @@ -1743,18 +1746,20 @@ static int out_get_render_position(const struct audio_stream_out *stream, return -EINVAL; } -static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +static int out_add_audio_effect(const struct audio_stream *stream __unused, + effect_handle_t effect __unused) { return 0; } -static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +static int out_remove_audio_effect(const struct audio_stream *stream __unused, + effect_handle_t effect __unused) { return 0; } -static int out_get_next_write_timestamp(const struct audio_stream_out *stream, - int64_t *timestamp) +static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused, + int64_t *timestamp __unused) { return -EINVAL; } @@ -1887,7 +1892,8 @@ static uint32_t in_get_sample_rate(const struct audio_stream *stream) return in->config.rate; } -static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +static int in_set_sample_rate(struct audio_stream *stream __unused, + uint32_t rate __unused) { return -ENOSYS; } @@ -1918,7 +1924,8 @@ static audio_format_t in_get_format(const struct audio_stream *stream) return in->format; } -static int in_set_format(struct audio_stream *stream, audio_format_t format) +static int in_set_format(struct audio_stream *stream __unused, + audio_format_t format __unused) { return -ENOSYS; } @@ -1956,7 +1963,8 @@ static int in_standby(struct audio_stream *stream) return status; } -static int in_dump(const struct audio_stream *stream, int fd) +static int in_dump(const struct audio_stream *stream __unused, + int fd __unused) { return 0; } @@ -2036,7 +2044,8 @@ static char* in_get_parameters(const struct audio_stream *stream, return str; } -static int in_set_gain(struct audio_stream_in *stream, float gain) +static int in_set_gain(struct audio_stream_in *stream __unused, + float gain __unused) { return 0; } @@ -2092,7 +2101,7 @@ exit: return bytes; } -static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused) { return 0; } @@ -2149,7 +2158,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, audio_devices_t devices, audio_output_flags_t flags, struct audio_config *config, - struct audio_stream_out **stream_out) + struct audio_stream_out **stream_out, + const char *address __unused) { struct audio_device *adev = (struct audio_device *)dev; struct stream_out *out; @@ -2412,7 +2422,7 @@ error_open: return ret; } -static void adev_close_output_stream(struct audio_hw_device *dev, +static void adev_close_output_stream(struct audio_hw_device *dev __unused, struct audio_stream_out *stream) { struct stream_out *out = (struct stream_out *)stream; @@ -2546,7 +2556,7 @@ static char* adev_get_parameters(const struct audio_hw_device *dev, return str; } -static int adev_init_check(const struct audio_hw_device *dev) +static int adev_init_check(const struct audio_hw_device *dev __unused) { return 0; } @@ -2562,23 +2572,26 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) return ret; } -static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +static int adev_set_master_volume(struct audio_hw_device *dev __unused, + float volume __unused) { return -ENOSYS; } -static int adev_get_master_volume(struct audio_hw_device *dev, - float *volume) +static int adev_get_master_volume(struct audio_hw_device *dev __unused, + float *volume __unused) { return -ENOSYS; } -static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) +static int adev_set_master_mute(struct audio_hw_device *dev __unused, + bool muted __unused) { return -ENOSYS; } -static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) +static int adev_get_master_mute(struct audio_hw_device *dev __unused, + bool *muted __unused) { return -ENOSYS; } @@ -2613,7 +2626,7 @@ static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) return 0; } -static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused, const struct audio_config *config) { int channel_count = popcount(config->channel_mask); @@ -2622,10 +2635,13 @@ static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, } static int adev_open_input_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, + audio_io_handle_t handle __unused, audio_devices_t devices, struct audio_config *config, - struct audio_stream_in **stream_in) + struct audio_stream_in **stream_in, + audio_input_flags_t flags __unused, + const char *address __unused, + audio_source_t source __unused) { struct audio_device *adev = (struct audio_device *)dev; struct stream_in *in; @@ -2694,7 +2710,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->config.rate = config->sample_rate; } else if (channel_count == 6) { if(audio_extn_ssr_get_enabled()) { - if(audio_extn_ssr_init(adev, in)) { + if(audio_extn_ssr_init(in)) { ALOGE("%s: audio_extn_ssr_init failed", __func__); ret = -EINVAL; goto err_open; @@ -2705,7 +2721,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, } else if (audio_extn_compr_cap_enabled() && audio_extn_compr_cap_format_supported(config->format) && (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) { - audio_extn_compr_cap_init(adev, in); + audio_extn_compr_cap_init(in); } else { in->config.channels = channel_count; frame_size = audio_stream_frame_size((struct audio_stream *)in); @@ -2725,7 +2741,7 @@ err_open: return ret; } -static void adev_close_input_stream(struct audio_hw_device *dev, +static void adev_close_input_stream(struct audio_hw_device *dev __unused, struct audio_stream_in *stream) { int ret; @@ -2751,7 +2767,8 @@ static void adev_close_input_stream(struct audio_hw_device *dev, return; } -static int adev_dump(const audio_hw_device_t *device, int fd) +static int adev_dump(const audio_hw_device_t *device __unused, + int fd __unused) { return 0; } diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index bbf85b0ef..551498875 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -385,7 +385,8 @@ int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type) return device_id; } -int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id) +int platform_set_snd_device_acdb_id(snd_device_t snd_device __unused, + unsigned int acdb_id __unused) { return -ENODEV; } @@ -550,7 +551,8 @@ int platform_set_mic_mute(void *platform, bool state) return ret; } -int platform_set_device_mute(void *platform, bool state, char *dir) +int platform_set_device_mute(void *platform __unused, bool state __unused, + char *dir __unused) { LOGE("%s: Not implemented", __func__); return -ENOSYS; @@ -826,7 +828,7 @@ int platform_set_hdmi_channels(void *platform, int channel_count) return 0; } -int platform_edid_get_max_channels(void *platform) +int platform_edid_get_max_channels(void *platform __unused) { FILE *file; struct audio_block_header header; @@ -872,19 +874,22 @@ int platform_edid_get_max_channels(void *platform) return max_channels; } -void platform_get_parameters(void *platform, struct str_parms *query, - struct str_parms *reply) +void platform_get_parameters(void *platform __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { LOGE("%s: Not implemented", __func__); } -int platform_set_parameters(void *platform, struct str_parms *parms) +int platform_set_parameters(void *platform __unused, + struct str_parms *parms __unused) { LOGE("%s: Not implemented", __func__); return -ENOSYS; } -int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id) +int platform_set_incall_recoding_session_id(void *platform __unused, + uint32_t session_id __unused) { LOGE("%s: Not implemented", __func__); return -ENOSYS; @@ -903,13 +908,14 @@ int64_t platform_render_latency(audio_usecase_t usecase) } } -int platform_update_usecase_from_source(int source, int usecase) +int platform_update_usecase_from_source(int source __unused, + int usecase __unused) { ALOGV("%s: input source :%d", __func__, source); return usecase; } -bool platform_listen_update_status(snd_device_t snd_device) +bool platform_listen_update_status(snd_device_t snd_device __unused) { return false; } diff --git a/hal/msm8974/platform_parser.c b/hal/msm8974/platform_parser.c index 8f86d9733..2ccab1add 100644 --- a/hal/msm8974/platform_parser.c +++ b/hal/msm8974/platform_parser.c @@ -87,7 +87,8 @@ static void start_tag(void *userdata, const XML_Char *tag_name, return; } -static void end_tag(void *userdata, const XML_Char *tag_name) +static void end_tag(void *userdata __unused, + const XML_Char *tag_name __unused) { } diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index deb3172c6..5de5a2e1d 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -469,7 +469,7 @@ done: return ret; } -void voice_extn_compress_voip_get_parameters(const struct audio_device *adev, +void voice_extn_compress_voip_get_parameters(const struct audio_device *adev __unused, struct str_parms *query, struct str_parms *reply) { diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index 4a9c610fd..9bac8782e 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -43,74 +43,74 @@ void voice_extn_out_get_parameters(struct stream_out *out, struct str_parms *query, struct str_parms *reply); #else -static int voice_extn_start_call(struct audio_device *adev) +static int voice_extn_start_call(struct audio_device *adev __unused) { return -ENOSYS; } -static int voice_extn_stop_call(struct audio_device *adev) +static int voice_extn_stop_call(struct audio_device *adev __unused) { return -ENOSYS; } -static int voice_extn_get_session_from_use_case(struct audio_device *adev, - const audio_usecase_t usecase_id, - struct voice_session **session) +static int voice_extn_get_session_from_use_case(struct audio_device *adev __unused, + const audio_usecase_t usecase_id __unused, + struct voice_session **session __unused) { return -ENOSYS; } -static void voice_extn_init(struct audio_device *adev) +static void voice_extn_init(struct audio_device *adev __unused) { } -static int voice_extn_set_parameters(struct audio_device *adev, - struct str_parms *parms) +static int voice_extn_set_parameters(struct audio_device *adev __unused, + struct str_parms *parms __unused) { return -ENOSYS; } -static void voice_extn_get_parameters(const struct audio_device *adev, - struct str_parms *query, - struct str_parms *reply) +static void voice_extn_get_parameters(const struct audio_device *adev __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { } -static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) +static int voice_extn_is_in_call(struct audio_device *adev __unused, bool *in_call __unused) { return -ENOSYS; } -static int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec) +static int voice_extn_is_in_call_rec_stream(struct stream_in *in __unused, bool *in_call_rec __unused) { return -ENOSYS; } -static int voice_extn_get_active_session_id(struct audio_device *adev, - uint32_t *session_id) +static int voice_extn_get_active_session_id(struct audio_device *adev __unused, + uint32_t *session_id __unused) { return -ENOSYS; } -static void voice_extn_in_get_parameters(struct stream_in *in, - struct str_parms *query, - struct str_parms *reply) +static void voice_extn_in_get_parameters(struct stream_in *in __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { } -static void voice_extn_out_get_parameters(struct stream_out *out, - struct str_parms *query, - struct str_parms *reply) +static void voice_extn_out_get_parameters(struct stream_out *out __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { } #endif #ifdef INCALL_MUSIC_ENABLED -int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, - struct stream_out *out); +int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev __unused, + struct stream_out *out __unused); #else -static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev, - struct stream_out *out) +static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev __unused, + struct stream_out *out __unused) { return -ENOSYS; } @@ -151,98 +151,98 @@ bool voice_extn_compress_voip_is_active(struct audio_device *adev); bool voice_extn_compress_voip_is_format_supported(audio_format_t format); bool voice_extn_compress_voip_is_config_supported(struct audio_config *config); #else -static int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) +static int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_open_output_stream(struct stream_out *out) +static int voice_extn_compress_voip_open_output_stream(struct stream_out *out __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) +static int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_open_input_stream(struct stream_in *in) +static int voice_extn_compress_voip_open_input_stream(struct stream_in *in __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *stream) +static int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *stream __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in) +static int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_start_input_stream(struct stream_in *in) +static int voice_extn_compress_voip_start_input_stream(struct stream_in *in __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_start_output_stream(struct stream_out *out) +static int voice_extn_compress_voip_start_output_stream(struct stream_out *out __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state) +static int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev __unused, bool state __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return 0; } -static int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume) +static int voice_extn_compress_voip_set_volume(struct audio_device *adev __unused, float volume __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return 0; } -static int voice_extn_compress_voip_select_devices(struct audio_device *adev, - snd_device_t *out_snd_device, - snd_device_t *in_snd_device) +static int voice_extn_compress_voip_select_devices(struct audio_device *adev __unused, + snd_device_t *out_snd_device __unused, + snd_device_t *in_snd_device __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static int voice_extn_compress_voip_set_parameters(struct audio_device *adev, - struct str_parms *parms) +static int voice_extn_compress_voip_set_parameters(struct audio_device *adev __unused, + struct str_parms *parms __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return -ENOSYS; } -static void voice_extn_compress_voip_get_parameters(const struct audio_device *adev, - struct str_parms *query, - struct str_parms *reply) +static void voice_extn_compress_voip_get_parameters(const struct audio_device *adev __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); } -static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out, - struct str_parms *query, - struct str_parms *reply) +static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); } -static void voice_extn_compress_voip_in_get_parameters(struct stream_in *in, - struct str_parms *query, - struct str_parms *reply) +static void voice_extn_compress_voip_in_get_parameters(struct stream_in *in __unused, + struct str_parms *query __unused, + struct str_parms *reply __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); } @@ -253,19 +253,19 @@ static bool voice_extn_compress_voip_pcm_prop_check() return false; } -static bool voice_extn_compress_voip_is_active(struct audio_device *adev) +static bool voice_extn_compress_voip_is_active(struct audio_device *adev __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return false; } -static bool voice_extn_compress_voip_is_format_supported(audio_format_t format) +static bool voice_extn_compress_voip_is_format_supported(audio_format_t format __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return true; } -static bool voice_extn_compress_voip_is_config_supported(struct audio_config *config) +static bool voice_extn_compress_voip_is_config_supported(struct audio_config *config __unused) { ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__); return true; -- GitLab From 69236ba7ec6c31963b0a64027bbcfcd64cd39219 Mon Sep 17 00:00:00 2001 From: Divya Narayanan Poojary Date: Thu, 18 Sep 2014 11:57:57 +0530 Subject: [PATCH 241/298] hal: fix incompatible APIs Avoid usage of deprecated API audio_stream_frame_size() Update open_input_stream() and open_output_stream() APIs to match the updated signature. Change-Id: I70f9142d53d562b2ce0a286ef2900938fc066876 --- hal/audio_hw.c | 84 +++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 3038d44f9..448f74544 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1057,7 +1057,7 @@ static bool allow_hdmi_channel_config(struct audio_device *adev) ret = false; break; } else if (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD && - popcount(usecase->stream.out->channel_mask) > 2) { + audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) { ALOGD("%s: multi-channel(%x) compress offload playback is active, " "no change in HDMI channels", __func__, usecase->stream.out->channel_mask); ret = false; @@ -1341,7 +1341,8 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) else if(out->usecase == USECASE_COMPRESS_VOIP_CALL) return voice_extn_compress_voip_out_get_buffer_size(out); - return out->config.period_size * audio_stream_frame_size(stream); + return out->config.period_size * + audio_stream_out_frame_size((const struct audio_stream_out *)stream); } static uint32_t out_get_channels(const struct audio_stream *stream) @@ -1721,7 +1722,7 @@ exit: if (out->pcm) ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); out_standby(&out->stream.common); - usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / + usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) / out_get_sample_rate(&out->stream.common)); } return bytes; @@ -1907,7 +1908,8 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) else if(audio_extn_compr_cap_usecase_supported(in->usecase)) return audio_extn_compr_cap_get_buffer_size(in->config.format); - return in->config.period_size * audio_stream_frame_size(stream); + return in->config.period_size * + audio_stream_in_frame_size((const struct audio_stream_in *)stream); } static uint32_t in_get_channels(const struct audio_stream *stream) @@ -2072,7 +2074,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, } if (in->pcm) { - if (audio_extn_ssr_get_enabled() && popcount(in->channel_mask) == 6) + if (audio_extn_ssr_get_enabled() && + audio_channel_count_from_in_mask(in->channel_mask) == 6) ret = audio_extn_ssr_read(stream, buffer, bytes); else if (audio_extn_compr_cap_usecase_supported(in->usecase)) ret = audio_extn_compr_cap_read(in, buffer, bytes); @@ -2095,7 +2098,7 @@ exit: if (ret != 0) { in_standby(&in->stream.common); ALOGV("%s: read failed - sleeping for buffer duration", __func__); - usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) / + usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) / in_get_sample_rate(&in->stream.common)); } return bytes; @@ -2177,9 +2180,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, return -ENOMEM; } - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); - if (devices == AUDIO_DEVICE_NONE) devices = AUDIO_DEVICE_OUT_SPEAKER; @@ -2223,7 +2223,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH; out->config = pcm_config_hdmi_multi; out->config.rate = config->sample_rate; - out->config.channels = popcount(out->channel_mask); + out->config.channels = audio_channel_count_from_out_mask(out->channel_mask); out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2); #ifdef COMPRESS_VOIP_ENABLED } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && @@ -2292,7 +2292,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->bit_rate = config->offload_info.bit_rate; out->compr_config.codec->ch_in = - popcount(config->channel_mask); + audio_channel_count_from_out_mask(config->channel_mask); out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; @@ -2405,6 +2405,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, /* out->muted = false; by calloc() */ /* out->written = 0; by calloc() */ + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + config->format = out->stream.common.get_format(&out->stream.common); config->channel_mask = out->stream.common.get_channels(&out->stream.common); config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); @@ -2459,23 +2462,24 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) char *str; char value[32]; int val; - int ret = 0, err; + int ret; + int status = 0; ALOGD("%s: enter: %s", __func__, kvpairs); pthread_mutex_lock(&adev->lock); parms = str_parms_create_str(kvpairs); - ret = voice_set_parameters(adev, parms); - if (ret != 0) + status = voice_set_parameters(adev, parms); + if (status != 0) goto done; - ret = platform_set_parameters(adev->platform, parms); - if (ret != 0) + status = platform_set_parameters(adev->platform, parms); + if (status != 0) goto done; - err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); - if (err >= 0) { + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); + if (ret >= 0) { /* When set to false, HAL should disable EC and NS * But it is currently not supported. */ @@ -2485,16 +2489,16 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->bluetooth_nrec = false; } - err = str_parms_get_str(parms, "screen_state", value, sizeof(value)); - if (err >= 0) { + ret = str_parms_get_str(parms, "screen_state", value, sizeof(value)); + if (ret >= 0) { if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) adev->screen_off = false; else adev->screen_off = true; } - err = str_parms_get_int(parms, "rotation", &val); - if (err >= 0) { + ret = str_parms_get_int(parms, "rotation", &val); + if (ret >= 0) { bool reverse_speakers = false; switch(val) { // FIXME: note that the code below assumes that the speakers are in the correct placement @@ -2509,17 +2513,20 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) break; default: ALOGE("%s: unexpected rotation of %d", __func__, val); + status = -EINVAL; } - if (adev->speaker_lr_swap != reverse_speakers) { - adev->speaker_lr_swap = reverse_speakers; - // only update the selected device if there is active pcm playback - struct audio_usecase *usecase; - struct listnode *node; - list_for_each(node, &adev->usecase_list) { - usecase = node_to_item(node, struct audio_usecase, list); - if (usecase->type == PCM_PLAYBACK) { - select_devices(adev, usecase->id); - break; + if (status == 0) { + if (adev->speaker_lr_swap != reverse_speakers) { + adev->speaker_lr_swap = reverse_speakers; + // only update the selected device if there is active pcm playback + struct audio_usecase *usecase; + struct listnode *node; + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_PLAYBACK) { + select_devices(adev, usecase->id); + break; + } } } } @@ -2530,8 +2537,8 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) done: str_parms_destroy(parms); pthread_mutex_unlock(&adev->lock); - ALOGV("%s: exit with code(%d)", __func__, ret); - return ret; + ALOGV("%s: exit with code(%d)", __func__, status); + return status; } static char* adev_get_parameters(const struct audio_hw_device *dev, @@ -2629,7 +2636,7 @@ static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused, const struct audio_config *config) { - int channel_count = popcount(config->channel_mask); + int channel_count = audio_channel_count_from_in_mask(config->channel_mask); return get_input_buffer_size(config->sample_rate, config->format, channel_count); } @@ -2646,7 +2653,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, struct audio_device *adev = (struct audio_device *)dev; struct stream_in *in; int ret = 0, buffer_size, frame_size; - int channel_count = popcount(config->channel_mask); + int channel_count = audio_channel_count_from_in_mask(config->channel_mask); *stream_in = NULL; @@ -2724,7 +2731,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, audio_extn_compr_cap_init(in); } else { in->config.channels = channel_count; - frame_size = audio_stream_frame_size((struct audio_stream *)in); + frame_size = audio_stream_in_frame_size(&in->stream); buffer_size = get_input_buffer_size(config->sample_rate, config->format, channel_count); @@ -2756,7 +2763,8 @@ static void adev_close_input_stream(struct audio_hw_device *dev __unused, } else in_standby(&stream->common); - if (audio_extn_ssr_get_enabled() && (popcount(in->channel_mask) == 6)) { + if (audio_extn_ssr_get_enabled() && + (audio_channel_count_from_in_mask(in->channel_mask) == 6)) { audio_extn_ssr_deinit(); } free(stream); -- GitLab From fcf8ffccce5792e0f965f4669baffe590c567b33 Mon Sep 17 00:00:00 2001 From: Satya Krishna Pindiproli Date: Tue, 9 Sep 2014 15:32:25 +0530 Subject: [PATCH 242/298] hal: fix low volume issue during device switch in a hfp call When an active hfp call is switched from the hands-free client to the audio gateway and then back to the hands-free client, voice is not heard at the client. After the switch from the gateway to the client, the volume applied is very low and hence is not audible. Fix the issue by setting the volume properly. CRs-Fixed: 720804 Change-Id: I4dfdff7d0b8e5763dc0a19d55531252994db90c3 --- hal/audio_extn/hfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index add4a7c44..8402a6239 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -89,6 +89,7 @@ static int32_t hfp_set_volume(struct audio_device *adev, float value) ALOGV("%s: entry", __func__); ALOGD("%s: (%f)\n", __func__, value); + hfpmod.hfp_volume = value; if (value < 0.0) { ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value); value = 0.0; @@ -97,7 +98,6 @@ static int32_t hfp_set_volume(struct audio_device *adev, float value) ALOGW("%s: Volume brought with in range (%f)\n", __func__, value); } vol = lrint((value * 0x2000) + 0.5); - hfpmod.hfp_volume = value; if (!hfpmod.is_hfp_running) { ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__); -- GitLab From 4a3b252faca03b7d78d605ada3645c50bee38457 Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Tue, 2 Sep 2014 15:25:51 +0530 Subject: [PATCH 243/298] audio: remove build varient check in audio daemon - Frameworks not receiving SSR notifications on release build varients - audio daemon not compiling for release & engg build varients - Remove build varient check on audiod makefile Change-Id: I242d5c02e58e4ca5a51b81a997a65deca69d1d81 --- audiod/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/audiod/Android.mk b/audiod/Android.mk index 8f25125ed..c382c9d2c 100644 --- a/audiod/Android.mk +++ b/audiod/Android.mk @@ -19,6 +19,5 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE:= audiod -LOCAL_MODULE_TAGS:= debug include $(BUILD_EXECUTABLE) -- GitLab From 6f461b9613b2bf792a7e6b71a14d3e4f1a276536 Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Fri, 30 May 2014 11:20:27 +0530 Subject: [PATCH 244/298] Audio: Fix for FM off/on delay post SSR - 8-10sec delay observed when FM is turned off/on from UI post SSR with touch tones enabled. If any new input request comes before FM is closed post SSR, pcm driver assumes AFE is still active and starts pumping data to AFE which is already closed due to SSR causing the delay - Fix is to close FM session during SSR. CRs-Fixed: 673031 Change-Id: I4a55c6ca66d94e633e768b1d40584d5a5782e13e --- hal/audio_extn/fm.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c index 8a420bdc2..668f67ad4 100644 --- a/hal/audio_extn/fm.c +++ b/hal/audio_extn/fm.c @@ -51,6 +51,8 @@ struct fm_module { struct pcm *fm_pcm_tx; bool is_fm_running; float fm_volume; + bool restart_fm; + int scard_state; }; static struct fm_module fmmod = { @@ -58,6 +60,8 @@ static struct fm_module fmmod = { .fm_pcm_tx = NULL, .fm_volume = 0, .is_fm_running = 0, + .restart_fm = 0, + .scard_state = SND_CARD_STATE_ONLINE, }; static int32_t fm_set_volume(struct audio_device *adev, float value) @@ -213,7 +217,23 @@ void audio_extn_fm_set_parameters(struct audio_device *adev, float vol =0.0; ALOGV("%s: enter", __func__); + ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value)); + if (ret >= 0) { + char *snd_card_status = value+2; + if (strstr(snd_card_status, "OFFLINE")) { + fmmod.scard_state = SND_CARD_STATE_OFFLINE; + } + else if (strstr(snd_card_status, "ONLINE")) { + fmmod.scard_state = SND_CARD_STATE_ONLINE; + } + } if(fmmod.is_fm_running) { + if (fmmod.scard_state == SND_CARD_STATE_OFFLINE) { + ALOGD("sound card is OFFLINE, stop FM"); + fm_stop(adev); + fmmod.restart_fm = 1; + } + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); if (ret >= 0) { @@ -222,6 +242,11 @@ void audio_extn_fm_set_parameters(struct audio_device *adev, select_devices(adev, USECASE_AUDIO_PLAYBACK_FM); } } + if (fmmod.restart_fm && (fmmod.scard_state == SND_CARD_STATE_ONLINE)) { + ALOGD("sound card is ONLINE, restart FM"); + fmmod.restart_fm = 0; + fm_start(adev); + } ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HANDLE_FM, value, sizeof(value)); -- GitLab From 2d19ab439c8a22a49a5bed296a953ef6f27c0527 Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Sun, 11 May 2014 19:56:25 +0530 Subject: [PATCH 245/298] hal: SSR support for pcm playback,pcm record usecases - Added SSR event handling support in HAL - Added support to drop incoming pcm data for pcm playback usecase during SSR - Added support to send dummy input(mute/zero buffer) for record usecase during SSR Change-Id: I158b62fa443bb523091128fe1308c9a9b1415502 --- hal/audio_hw.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++--- hal/audio_hw.h | 18 ++++++++ 2 files changed, 121 insertions(+), 6 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1584624bd..628f7fdbb 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -819,6 +819,15 @@ int start_input_stream(struct stream_in *in) ALOGD("%s: enter: stream(%p)usecase(%d: %s)", __func__, &in->stream, in->usecase, use_case_table[in->usecase]); + pthread_mutex_lock(&adev->snd_card_status.lock); + if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) { + ALOGE("%s: sound card is not active/SSR returning error", __func__); + ret = -ENETRESET; + pthread_mutex_unlock(&adev->snd_card_status.lock); + goto error_config; + } + pthread_mutex_unlock(&adev->snd_card_status.lock); + /* Check if source matches incall recording usecase criteria */ ret = voice_check_and_set_incall_rec_usecase(adev, in); if (ret) @@ -875,6 +884,8 @@ int start_input_stream(struct stream_in *in) } break; } + in->pcm_error_type = PCM_ERROR_NONE; + ALOGV("%s: exit", __func__); return ret; @@ -1164,6 +1175,16 @@ int start_output_stream(struct stream_out *out) ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)", __func__, &out->stream, out->usecase, use_case_table[out->usecase], out->devices); + + pthread_mutex_lock(&adev->snd_card_status.lock); + if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) { + ALOGE("%s: sound card is not active/SSR returning error", __func__); + ret = -ENETRESET; + pthread_mutex_unlock(&adev->snd_card_status.lock); + goto error_config; + } + pthread_mutex_unlock(&adev->snd_card_status.lock); + out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); if (out->pcm_device_id < 0) { ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", @@ -1228,6 +1249,7 @@ int start_output_stream(struct stream_out *out) } break; } + out->pcm_error_type = PCM_ERROR_NONE; } else { out->pcm = NULL; out->compr = compress_open(adev->snd_card, @@ -1663,9 +1685,28 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; + int scard_state = SND_CARD_STATE_ONLINE; ssize_t ret = 0; pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->snd_card_status.lock); + scard_state = adev->snd_card_status.state; + pthread_mutex_unlock(&adev->snd_card_status.lock); + + if (out->pcm) { + if (SND_CARD_STATE_OFFLINE == scard_state) { + ALOGD(" %s: sound card is not active/SSR state", __func__); + ret= -ENETRESET; + goto exit; + } else if (PCM_ERROR_ENETRESET == out->pcm_error_type) { + ALOGD(" %s restarting pcm session on post SSR", __func__); + out->standby = false; + pthread_mutex_unlock(&out->lock); + out_standby(&out->stream.common); + pthread_mutex_lock(&out->lock); + } + } + if (out->standby) { out->standby = false; pthread_mutex_lock(&adev->lock); @@ -1716,14 +1757,24 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, } exit: + + if (-ENETRESET == ret) { + pthread_mutex_lock(&adev->snd_card_status.lock); + adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; + out->pcm_error_type = PCM_ERROR_ENETRESET; + out->standby = true; /*standby will be called on post SSR */ + pthread_mutex_unlock(&adev->snd_card_status.lock); + } + pthread_mutex_unlock(&out->lock); if (ret != 0) { if (out->pcm) ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); out_standby(&out->stream.common); - usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) / - out_get_sample_rate(&out->stream.common)); + usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / + out_get_sample_rate(&out->stream.common)); + } return bytes; } @@ -2058,8 +2109,27 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int i, ret = -1; + int scard_state = SND_CARD_STATE_ONLINE; pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&adev->snd_card_status.lock); + scard_state = adev->snd_card_status.state; + pthread_mutex_unlock(&adev->snd_card_status.lock); + + if (in->pcm) { + if(SND_CARD_STATE_OFFLINE == scard_state) { + ALOGD(" %s: sound card is not active/SSR state", __func__); + ret= -ENETRESET; + goto exit; + } else if (PCM_ERROR_ENETRESET == in->pcm_error_type) { + ALOGD(" %s restarting pcm session on post SSR", __func__); + in->standby = false; + pthread_mutex_unlock(&in->lock); + in_standby(&in->stream.common); + pthread_mutex_lock(&in->lock); + } + } + if (in->standby) { pthread_mutex_lock(&adev->lock); if (in->usecase == USECASE_COMPRESS_VOIP_CALL) @@ -2093,13 +2163,22 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, memset(buffer, 0, bytes); exit: + + if (-ENETRESET == ret) { + pthread_mutex_lock(&adev->snd_card_status.lock); + adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; + in->pcm_error_type = PCM_ERROR_ENETRESET; + memset(buffer, 0, bytes); + in->standby = true; /*standby will be called on post SSR */ + pthread_mutex_unlock(&adev->snd_card_status.lock); + } pthread_mutex_unlock(&in->lock); if (ret != 0) { in_standby(&in->stream.common); ALOGV("%s: read failed - sleeping for buffer duration", __func__); - usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) / - in_get_sample_rate(&in->stream.common)); + usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) / + in_get_sample_rate(&in->stream.common)); } return bytes; } @@ -2466,10 +2545,23 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) int status = 0; ALOGD("%s: enter: %s", __func__, kvpairs); - - pthread_mutex_lock(&adev->lock); parms = str_parms_create_str(kvpairs); + ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value)); + if (ret >= 0) { + char *snd_card_status = value+2; + pthread_mutex_lock(&adev->snd_card_status.lock); + if (strstr(snd_card_status, "OFFLINE")) { + ALOGD("Received sound card OFFLINE status"); + adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; + } else if (strstr(snd_card_status, "ONLINE")) { + ALOGD("Received sound card ONLINE status"); + adev->snd_card_status.state = SND_CARD_STATE_ONLINE; + } + pthread_mutex_unlock(&adev->snd_card_status.lock); + } + + pthread_mutex_lock(&adev->lock); status = voice_set_parameters(adev, parms); if (status != 0) goto done; @@ -2860,6 +2952,9 @@ static int adev_open(const hw_module_t *module, const char *name, list_init(&adev->usecase_list); adev->cur_wfd_channels = 2; + pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL); + adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; + /* Loads platform specific libraries dynamically */ adev->platform = platform_init(adev); if (!adev->platform) { @@ -2871,6 +2966,8 @@ static int adev_open(const hw_module_t *module, const char *name, return -EINVAL; } + adev->snd_card_status.state = SND_CARD_STATE_ONLINE; + if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) { adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW); if (adev->visualizer_lib == NULL) { diff --git a/hal/audio_hw.h b/hal/audio_hw.h index fb4aaab2e..1b05ccd04 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -49,6 +49,9 @@ #define MAX_SUPPORTED_CHANNEL_MASKS 2 #define DEFAULT_HDMI_OUT_CHANNELS 2 +#define SND_CARD_STATE_OFFLINE 0 +#define SND_CARD_STATE_ONLINE 1 + typedef int snd_device_t; /* These are the supported use cases by the hardware. @@ -129,6 +132,12 @@ enum { OFFLOAD_STATE_PAUSED, }; +enum { + PCM_ERROR_NONE, + PCM_ERROR_EIO, + PCM_ERROR_ENETRESET, //Send from pcm driver during SSR +}; + struct offload_cmd { struct listnode node; int cmd; @@ -169,6 +178,7 @@ struct stream_out { void *offload_cookie; struct compr_gapless_mdata gapless_mdata; int send_new_metadata; + int pcm_error_type; struct audio_device *dev; }; @@ -187,6 +197,7 @@ struct stream_in { bool enable_aec; bool enable_ns; audio_format_t format; + int pcm_error_type; struct audio_device *dev; }; @@ -214,6 +225,11 @@ struct audio_usecase { union stream_ptr stream; }; +struct sound_card_status { + pthread_mutex_t lock; + int state; +}; + struct audio_device { struct audio_hw_device device; pthread_mutex_t lock; /* see note below on mutex acquisition order */ @@ -244,6 +260,8 @@ struct audio_device { void *offload_effects_lib; int (*offload_effects_start_output)(audio_io_handle_t, int); int (*offload_effects_stop_output)(audio_io_handle_t, int); + + struct sound_card_status snd_card_status; }; int select_devices(struct audio_device *adev, -- GitLab From 4fe3e516295e240f451fb4b4e1b334a2cad4e17b Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Mon, 26 May 2014 18:03:42 +0530 Subject: [PATCH 246/298] Audio: Revert hal changes to block pcm_close during SSR pcm driver supports pcm_close during SSR, so reverted HAL code to block pcm session close during SSR. CRs-Fixed: 663477 Change-Id: I752e3f4f55288f91294e090b974ba1367c27122d --- hal/audio_hw.c | 24 ++++-------------------- hal/audio_hw.h | 8 -------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 628f7fdbb..550d7ae6c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -884,7 +884,6 @@ int start_input_stream(struct stream_in *in) } break; } - in->pcm_error_type = PCM_ERROR_NONE; ALOGV("%s: exit", __func__); return ret; @@ -1249,7 +1248,6 @@ int start_output_stream(struct stream_out *out) } break; } - out->pcm_error_type = PCM_ERROR_NONE; } else { out->pcm = NULL; out->compr = compress_open(adev->snd_card, @@ -1698,12 +1696,6 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, ALOGD(" %s: sound card is not active/SSR state", __func__); ret= -ENETRESET; goto exit; - } else if (PCM_ERROR_ENETRESET == out->pcm_error_type) { - ALOGD(" %s restarting pcm session on post SSR", __func__); - out->standby = false; - pthread_mutex_unlock(&out->lock); - out_standby(&out->stream.common); - pthread_mutex_lock(&out->lock); } } @@ -1757,12 +1749,11 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, } exit: - + /* ToDo: There may be a corner case when SSR happens back to back during + start/stop. Need to post different error to handle that. */ if (-ENETRESET == ret) { pthread_mutex_lock(&adev->snd_card_status.lock); adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; - out->pcm_error_type = PCM_ERROR_ENETRESET; - out->standby = true; /*standby will be called on post SSR */ pthread_mutex_unlock(&adev->snd_card_status.lock); } @@ -2121,12 +2112,6 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, ALOGD(" %s: sound card is not active/SSR state", __func__); ret= -ENETRESET; goto exit; - } else if (PCM_ERROR_ENETRESET == in->pcm_error_type) { - ALOGD(" %s restarting pcm session on post SSR", __func__); - in->standby = false; - pthread_mutex_unlock(&in->lock); - in_standby(&in->stream.common); - pthread_mutex_lock(&in->lock); } } @@ -2163,13 +2148,12 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, memset(buffer, 0, bytes); exit: - + /* ToDo: There may be a corner case when SSR happens back to back during + start/stop. Need to post different error to handle that. */ if (-ENETRESET == ret) { pthread_mutex_lock(&adev->snd_card_status.lock); adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; - in->pcm_error_type = PCM_ERROR_ENETRESET; memset(buffer, 0, bytes); - in->standby = true; /*standby will be called on post SSR */ pthread_mutex_unlock(&adev->snd_card_status.lock); } pthread_mutex_unlock(&in->lock); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 1b05ccd04..3d3b2298d 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -132,12 +132,6 @@ enum { OFFLOAD_STATE_PAUSED, }; -enum { - PCM_ERROR_NONE, - PCM_ERROR_EIO, - PCM_ERROR_ENETRESET, //Send from pcm driver during SSR -}; - struct offload_cmd { struct listnode node; int cmd; @@ -178,7 +172,6 @@ struct stream_out { void *offload_cookie; struct compr_gapless_mdata gapless_mdata; int send_new_metadata; - int pcm_error_type; struct audio_device *dev; }; @@ -197,7 +190,6 @@ struct stream_in { bool enable_aec; bool enable_ns; audio_format_t format; - int pcm_error_type; struct audio_device *dev; }; -- GitLab From cef332d7fe2b06d85e30fd73a6a2196f70bea8a3 Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Wed, 4 Jun 2014 18:17:56 +0530 Subject: [PATCH 247/298] hal: SSR support for compress offload - add support for time stamp error propagation to frameworks on compress driver error - close active compress session on SSR. Change-Id: I9cbd3a6c271097b81c9b79e71573fda8d78c7dbf --- hal/audio_hw.c | 140 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 38 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 550d7ae6c..8542c7007 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -275,6 +275,32 @@ static int enable_audio_route_for_voice_usecases(struct audio_device *adev, return 0; } +static int get_snd_card_state(struct audio_device *adev) +{ + int snd_scard_state; + + if (!adev) + return SND_CARD_STATE_OFFLINE; + + pthread_mutex_lock(&adev->snd_card_status.lock); + snd_scard_state = adev->snd_card_status.state; + pthread_mutex_unlock(&adev->snd_card_status.lock); + + return snd_scard_state; +} + +static int set_snd_card_state(struct audio_device *adev, int snd_scard_state) +{ + if (!adev) + return -ENOSYS; + + pthread_mutex_lock(&adev->snd_card_status.lock); + adev->snd_card_status.state = snd_scard_state; + pthread_mutex_unlock(&adev->snd_card_status.lock); + + return 0; +} + int enable_audio_route(struct audio_device *adev, struct audio_usecase *usecase) { @@ -814,19 +840,17 @@ int start_input_stream(struct stream_in *in) int ret = 0; struct audio_usecase *uc_info; struct audio_device *adev = in->dev; + int snd_card_status = get_snd_card_state(adev); in->usecase = platform_update_usecase_from_source(in->source,in->usecase); ALOGD("%s: enter: stream(%p)usecase(%d: %s)", __func__, &in->stream, in->usecase, use_case_table[in->usecase]); - pthread_mutex_lock(&adev->snd_card_status.lock); - if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) { - ALOGE("%s: sound card is not active/SSR returning error", __func__); + if (SND_CARD_STATE_OFFLINE == snd_card_status) { + ALOGE("%s: sound card is not active/SSR returning error ", __func__); ret = -ENETRESET; - pthread_mutex_unlock(&adev->snd_card_status.lock); goto error_config; } - pthread_mutex_unlock(&adev->snd_card_status.lock); /* Check if source matches incall recording usecase criteria */ ret = voice_check_and_set_incall_rec_usecase(adev, in); @@ -1170,19 +1194,17 @@ int start_output_stream(struct stream_out *out) char prop_value[PROPERTY_VALUE_MAX] = {0}; struct audio_usecase *uc_info; struct audio_device *adev = out->dev; + int snd_card_status = get_snd_card_state(adev); ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)", __func__, &out->stream, out->usecase, use_case_table[out->usecase], out->devices); - pthread_mutex_lock(&adev->snd_card_status.lock); - if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) { + if (SND_CARD_STATE_OFFLINE == snd_card_status) { ALOGE("%s: sound card is not active/SSR returning error", __func__); ret = -ENETRESET; - pthread_mutex_unlock(&adev->snd_card_status.lock); goto error_config; } - pthread_mutex_unlock(&adev->snd_card_status.lock); out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK); if (out->pcm_device_id < 0) { @@ -1683,19 +1705,21 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; - int scard_state = SND_CARD_STATE_ONLINE; + int snd_scard_state = get_snd_card_state(adev); ssize_t ret = 0; pthread_mutex_lock(&out->lock); - pthread_mutex_lock(&adev->snd_card_status.lock); - scard_state = adev->snd_card_status.state; - pthread_mutex_unlock(&adev->snd_card_status.lock); - if (out->pcm) { - if (SND_CARD_STATE_OFFLINE == scard_state) { + if (SND_CARD_STATE_OFFLINE == snd_scard_state) { + if (out->pcm) { ALOGD(" %s: sound card is not active/SSR state", __func__); ret= -ENETRESET; goto exit; + } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + //during SSR for compress usecase we should return error to flinger + ALOGD(" copl %s: sound card is not active/SSR state", __func__); + pthread_mutex_unlock(&out->lock); + return -ENETRESET; } } @@ -1726,8 +1750,14 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); if (ret >= 0 && ret < (ssize_t)bytes) { send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); - } - if (!out->playback_started) { + } else if (-ENETRESET == ret) { + ALOGE("copl %s: received sound card offline state on compress write", __func__); + set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); + pthread_mutex_unlock(&out->lock); + out_standby(&out->stream.common); + return ret; + } + if (!out->playback_started && ret >= 0) { compress_start(out->compr); out->playback_started = 1; out->offload_state = OFFLOAD_STATE_PLAYING; @@ -1752,9 +1782,7 @@ exit: /* ToDo: There may be a corner case when SSR happens back to back during start/stop. Need to post different error to handle that. */ if (-ENETRESET == ret) { - pthread_mutex_lock(&adev->snd_card_status.lock); - adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; - pthread_mutex_unlock(&adev->snd_card_status.lock); + set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); } pthread_mutex_unlock(&out->lock); @@ -1776,15 +1804,25 @@ static int out_get_render_position(const struct audio_stream_out *stream, struct stream_out *out = (struct stream_out *)stream; *dsp_frames = 0; if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { + ssize_t ret = -EINVAL; pthread_mutex_lock(&out->lock); if (out->compr != NULL) { - compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, + ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, &out->sample_rate); ALOGVV("%s rendered frames %d sample_rate %d", __func__, *dsp_frames, out->sample_rate); } pthread_mutex_unlock(&out->lock); - return 0; + if (-ENETRESET == ret) { + ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver"); + set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); + return -EINVAL; + } else if(ret < 0) { + ALOGE(" ERROR: Unable to get time stamp from compress driver"); + return -EINVAL; + } else { + return 0; + } } else return -EINVAL; } @@ -1873,7 +1911,12 @@ static int out_pause(struct audio_stream_out* stream) if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { pthread_mutex_lock(&out->lock); if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) { - status = compress_pause(out->compr); + struct audio_device *adev = out->dev; + int snd_scard_state = get_snd_card_state(adev); + + if (SND_CARD_STATE_ONLINE == snd_scard_state) + status = compress_pause(out->compr); + out->offload_state = OFFLOAD_STATE_PAUSED; } pthread_mutex_unlock(&out->lock); @@ -1890,7 +1933,12 @@ static int out_resume(struct audio_stream_out* stream) status = 0; pthread_mutex_lock(&out->lock); if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) { - status = compress_resume(out->compr); + struct audio_device *adev = out->dev; + int snd_scard_state = get_snd_card_state(adev); + + if (SND_CARD_STATE_ONLINE == snd_scard_state) + status = compress_resume(out->compr); + out->offload_state = OFFLOAD_STATE_PLAYING; } pthread_mutex_unlock(&out->lock); @@ -2100,15 +2148,12 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int i, ret = -1; - int scard_state = SND_CARD_STATE_ONLINE; + int snd_scard_state = get_snd_card_state(adev); pthread_mutex_lock(&in->lock); - pthread_mutex_lock(&adev->snd_card_status.lock); - scard_state = adev->snd_card_status.state; - pthread_mutex_unlock(&adev->snd_card_status.lock); if (in->pcm) { - if(SND_CARD_STATE_OFFLINE == scard_state) { + if(SND_CARD_STATE_OFFLINE == snd_scard_state) { ALOGD(" %s: sound card is not active/SSR state", __func__); ret= -ENETRESET; goto exit; @@ -2151,10 +2196,8 @@ exit: /* ToDo: There may be a corner case when SSR happens back to back during start/stop. Need to post different error to handle that. */ if (-ENETRESET == ret) { - pthread_mutex_lock(&adev->snd_card_status.lock); - adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; + set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); memset(buffer, 0, bytes); - pthread_mutex_unlock(&adev->snd_card_status.lock); } pthread_mutex_unlock(&in->lock); @@ -2232,6 +2275,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev, int i, ret = 0; *stream_out = NULL; + + if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && + (SND_CARD_STATE_OFFLINE == get_snd_card_state(adev))) { + ALOGE(" sound card is not active rejecting compress output open request"); + return -EINVAL; + } + out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\ @@ -2534,15 +2584,29 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value)); if (ret >= 0) { char *snd_card_status = value+2; - pthread_mutex_lock(&adev->snd_card_status.lock); if (strstr(snd_card_status, "OFFLINE")) { + struct listnode *node; + struct audio_usecase *usecase; + ALOGD("Received sound card OFFLINE status"); - adev->snd_card_status.state = SND_CARD_STATE_OFFLINE; + set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); + + pthread_mutex_lock(&adev->lock); + //close compress session on OFFLINE status + usecase = get_usecase_from_list(adev,USECASE_AUDIO_PLAYBACK_OFFLOAD); + if (usecase && usecase->stream.out) { + ALOGD(" %s closing compress session on OFFLINE state", __func__); + + struct stream_out *out = usecase->stream.out; + + pthread_mutex_unlock(&adev->lock); + out_standby(&out->stream.common); + } else + pthread_mutex_unlock(&adev->lock); } else if (strstr(snd_card_status, "ONLINE")) { ALOGD("Received sound card ONLINE status"); - adev->snd_card_status.state = SND_CARD_STATE_ONLINE; + set_snd_card_state(adev,SND_CARD_STATE_ONLINE); } - pthread_mutex_unlock(&adev->snd_card_status.lock); } pthread_mutex_lock(&adev->lock); @@ -2626,15 +2690,15 @@ static char* adev_get_parameters(const struct audio_hw_device *dev, char *str; pthread_mutex_lock(&adev->lock); - audio_extn_get_parameters(adev, query, reply); voice_get_parameters(adev, query, reply); platform_get_parameters(adev->platform, query, reply); + pthread_mutex_unlock(&adev->lock); + str = str_parms_to_str(reply); str_parms_destroy(query); str_parms_destroy(reply); - pthread_mutex_unlock(&adev->lock); ALOGV("%s: exit: returns - %s", __func__, str); return str; } -- GitLab From c6ca63585ad52ca057a100876e73703602146aa9 Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Fri, 20 Jun 2014 02:54:48 +0530 Subject: [PATCH 248/298] hal: SSR support for compress offload - reject offload request based on sound card state. Change-Id: I38256ce6163f948a9e9c14cb895de3f71529a0e9 --- hal/audio_hw.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 8542c7007..037f1f499 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2688,13 +2688,29 @@ static char* adev_get_parameters(const struct audio_hw_device *dev, struct str_parms *reply = str_parms_create(); struct str_parms *query = str_parms_create_str(keys); char *str; + char value[256] = {0}; + int ret = 0; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SND_CARD_STATUS, value, + sizeof(value)); + if (ret >=0) { + int val = 1; + pthread_mutex_lock(&adev->snd_card_status.lock); + if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) + val = 0; + pthread_mutex_unlock(&adev->snd_card_status.lock); + str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SND_CARD_STATUS, val); + goto exit; + } pthread_mutex_lock(&adev->lock); + audio_extn_get_parameters(adev, query, reply); voice_get_parameters(adev, query, reply); platform_get_parameters(adev->platform, query, reply); pthread_mutex_unlock(&adev->lock); +exit: str = str_parms_to_str(reply); str_parms_destroy(query); str_parms_destroy(reply); -- GitLab From 369dd68fb896b57348a83803f42a2215562b1a05 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Wed, 25 Jun 2014 20:38:03 +0530 Subject: [PATCH 249/298] hal: VoIP call auto recovery if SSR happens during call Add support for VoIP call auto recovery if subsystem restart(SSR) happens during VoIP call. CRs-Fixed: 689087 Change-Id: I5617c22b79548de668b28a97c116008e7c704dee --- hal/audio_hw.c | 8 ++++++++ hal/voice_extn/compress_voip.c | 22 +++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 037f1f499..247918fac 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1790,6 +1790,10 @@ exit: if (ret != 0) { if (out->pcm) ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); + if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + voice_extn_compress_voip_close_output_stream(&out->stream.common); + out->standby = true; + } out_standby(&out->stream.common); usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / out_get_sample_rate(&out->stream.common)); @@ -2202,6 +2206,10 @@ exit: pthread_mutex_unlock(&in->lock); if (ret != 0) { + if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + voice_extn_compress_voip_close_input_stream(&in->stream.common); + in->standby = true; + } in_standby(&in->stream.common); ALOGV("%s: read failed - sleeping for buffer duration", __func__); usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) / diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 5de5a2e1d..ea6e043dd 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -561,6 +561,9 @@ int voice_extn_compress_voip_start_output_stream(struct stream_out *out) ALOGD("%s: enter", __func__); + if (!voip_data.out_stream_count) + ret = voice_extn_compress_voip_open_output_stream(out); + ret = voip_start_call(adev, &out->config); out->pcm = voip_data.pcm_rx; uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); @@ -579,6 +582,9 @@ int voice_extn_compress_voip_start_input_stream(struct stream_in *in) ALOGD("%s: enter", __func__); + if (!voip_data.in_stream_count) + ret = voice_extn_compress_voip_open_input_stream(in); + ret = voip_start_call(adev, &in->config); in->pcm = voip_data.pcm_tx; @@ -593,10 +599,11 @@ int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) int ret = 0; ALOGD("%s: enter", __func__); - - voip_data.out_stream_count--; - ret = voip_stop_call(adev); - voip_data.out_stream = NULL; + if (voip_data.out_stream_count > 0) { + voip_data.out_stream_count--; + ret = voip_stop_call(adev); + voip_data.out_stream = NULL; + } ALOGV("%s: exit: status(%d)", __func__, ret); return ret; @@ -633,12 +640,13 @@ int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) ALOGD("%s: enter", __func__); - voip_data.in_stream_count--; - status = voip_stop_call(adev); + if(voip_data.in_stream_count > 0) { + voip_data.in_stream_count--; + status = voip_stop_call(adev); + } ALOGV("%s: exit: status(%d)", __func__, status); return status; - } int voice_extn_compress_voip_open_input_stream(struct stream_in *in) -- GitLab From c9e9e2cac0e2bd96898339ad2f79984fee2ce3a4 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Wed, 9 Jul 2014 16:29:28 +0530 Subject: [PATCH 250/298] hal: Enhance VoIP call auto recovery if SSR occurs during call Enhance support for VoIP auto recovery if SSR occurs during the VoIP call. CRs-Fixed: 689087 Change-Id: Id69cb9d17fc78fd98754b19bf84539290ff54cd9 --- hal/audio_hw.c | 2 +- hal/audio_hw.h | 3 +++ hal/voice_extn/compress_voip.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 247918fac..0ad94281d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -275,7 +275,7 @@ static int enable_audio_route_for_voice_usecases(struct audio_device *adev, return 0; } -static int get_snd_card_state(struct audio_device *adev) +int get_snd_card_state(struct audio_device *adev) { int snd_scard_state; diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 3d3b2298d..370a90e29 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -147,6 +147,7 @@ struct stream_out { struct pcm *pcm; struct compress *compr; int standby; + bool voip_out_avail; int pcm_device_id; unsigned int sample_rate; audio_channel_mask_t channel_mask; @@ -182,6 +183,7 @@ struct stream_in { struct pcm_config config; struct pcm *pcm; int standby; + bool voip_in_avail; int source; int pcm_device_id; audio_devices_t device; @@ -272,6 +274,7 @@ struct audio_usecase *get_usecase_from_list(struct audio_device *adev, audio_usecase_t uc_id); int pcm_ioctl(struct pcm *pcm, int request, ...); +int get_snd_card_state(struct audio_device *adev); #define LITERAL_TO_STRING(x) #x #define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\ diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index ea6e043dd..53a831008 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -558,9 +558,16 @@ int voice_extn_compress_voip_start_output_stream(struct stream_out *out) int ret = 0; struct audio_device *adev = out->dev; struct audio_usecase *uc_info; + int snd_card_status = get_snd_card_state(adev); ALOGD("%s: enter", __func__); + if (SND_CARD_STATE_OFFLINE == snd_card_status) { + ret = -ENETRESET; + ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret); + goto error; + } + if (!voip_data.out_stream_count) ret = voice_extn_compress_voip_open_output_stream(out); @@ -570,6 +577,7 @@ int voice_extn_compress_voip_start_output_stream(struct stream_out *out) uc_info->stream.out = out; uc_info->devices = out->devices; +error: ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -579,15 +587,23 @@ int voice_extn_compress_voip_start_input_stream(struct stream_in *in) int ret = 0; struct audio_usecase *uc_info; struct audio_device *adev = in->dev; + int snd_card_status = get_snd_card_state(adev); ALOGD("%s: enter", __func__); + if (SND_CARD_STATE_OFFLINE == snd_card_status) { + ret = -ENETRESET; + ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret); + goto error; + } + if (!voip_data.in_stream_count) ret = voice_extn_compress_voip_open_input_stream(in); ret = voip_start_call(adev, &in->config); in->pcm = voip_data.pcm_tx; +error: ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -603,6 +619,7 @@ int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream) voip_data.out_stream_count--; ret = voip_stop_call(adev); voip_data.out_stream = NULL; + out->pcm = NULL; } ALOGV("%s: exit: status(%d)", __func__, ret); @@ -643,6 +660,7 @@ int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) if(voip_data.in_stream_count > 0) { voip_data.in_stream_count--; status = voip_stop_call(adev); + in->pcm = NULL; } ALOGV("%s: exit: status(%d)", __func__, status); -- GitLab From 593b7c16098247fcf52cdd50d3e5a71de0ddf5d0 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Mon, 11 Aug 2014 18:20:49 +0530 Subject: [PATCH 251/298] hal: Avoid double free while closing of VoIP driver There is a double free happening while closing of VoIP driver using passthrough apk. There is no protection of VoIP node during close of VoIP driver. Add protection to avoid double free of VoIP node Change-Id: I54c2a6aec525590e3e6782d356168f8fe8dc86b0 --- hal/audio_hw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 0ad94281d..0aed4a7eb 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1791,7 +1791,9 @@ exit: if (out->pcm) ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm)); if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + pthread_mutex_lock(&adev->lock); voice_extn_compress_voip_close_output_stream(&out->stream.common); + pthread_mutex_unlock(&adev->lock); out->standby = true; } out_standby(&out->stream.common); @@ -2207,7 +2209,9 @@ exit: if (ret != 0) { if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + pthread_mutex_lock(&adev->lock); voice_extn_compress_voip_close_input_stream(&in->stream.common); + pthread_mutex_unlock(&adev->lock); in->standby = true; } in_standby(&in->stream.common); @@ -2556,7 +2560,9 @@ static void adev_close_output_stream(struct audio_hw_device *dev __unused, ALOGD("%s: enter:stream_handle(%p)",__func__, out); if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + pthread_mutex_lock(&adev->lock); ret = voice_extn_compress_voip_close_output_stream(&stream->common); + pthread_mutex_unlock(&adev->lock); if(ret != 0) ALOGE("%s: Compress voip output cannot be closed, error:%d", __func__, ret); @@ -2917,10 +2923,14 @@ static void adev_close_input_stream(struct audio_hw_device *dev __unused, { int ret; struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + ALOGD("%s: enter:stream_handle(%p)",__func__, in); if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + pthread_mutex_lock(&adev->lock); ret = voice_extn_compress_voip_close_input_stream(&stream->common); + pthread_mutex_unlock(&adev->lock); if (ret != 0) ALOGE("%s: Compress voip input cannot be closed, error:%d", __func__, ret); -- GitLab From 834b22f54dd9bbbf4488f0818ff67fbfba32cddd Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Wed, 20 Aug 2014 12:28:34 +0530 Subject: [PATCH 252/298] audio: Update error number in HAL - Error number is not propagated from pcm/compress driver on pcm/compress error - Read error number in HAL from errno define Change-Id: I998f9a098da4061a6f3b3d9908aaad6e6d9a3a86 --- hal/audio_hw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 0aed4a7eb..ca8c8acee 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1747,6 +1747,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, } ret = compress_write(out->compr, buffer, bytes); + if (ret < 0) + ret = -errno; ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); if (ret >= 0 && ret < (ssize_t)bytes) { send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); @@ -1773,7 +1775,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes); else ret = pcm_write(out->pcm, (void *)buffer, bytes); - if (ret == 0) + if (ret < 0) + ret = -errno; + else if (ret == 0) out->written += bytes / (out->config.channels * sizeof(short)); } } @@ -1815,6 +1819,8 @@ static int out_get_render_position(const struct audio_stream_out *stream, if (out->compr != NULL) { ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, &out->sample_rate); + if (ret < 0) + ret = -errno; ALOGVV("%s rendered frames %d sample_rate %d", __func__, *dsp_frames, out->sample_rate); } @@ -2189,6 +2195,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, ret = pcm_mmap_read(in->pcm, buffer, bytes); else ret = pcm_read(in->pcm, buffer, bytes); + if (ret < 0) + ret = -errno; } /* -- GitLab From f85f6a2f92329260c3a2fa27b55477f03cf5abd0 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Tue, 5 Aug 2014 18:20:42 -0700 Subject: [PATCH 253/298] hal: fix voice call device routing issue adev->voice_device_set flag is to indicate voice call device routing update from policymanager to HAL. It is set to true in voice_start_call and reset in update_calls() which causes mismatch in flag update during back to back voice calls scenario. Update adev->voice_device_set flag in voice_stop_call instead of update_calls(). Rename voice_device_set flag to in_call for readability. Change-Id: Ie07105671f254899890bdb4c0635c7dc1f55dbff --- hal/audio_hw.c | 19 +++++++++---------- hal/voice.c | 21 ++++++++++++--------- hal/voice.h | 5 +++-- hal/voice_extn/voice_extn.c | 37 ++++++++++--------------------------- hal/voice_extn/voice_extn.h | 6 ++++-- 5 files changed, 38 insertions(+), 50 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 1584624bd..a4ecabefa 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -651,7 +651,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) * usecase. This is to avoid switching devices for voice call when * check_usecases_codec_backend() is called below. */ - if (voice_is_in_call(adev)) { + if (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL) { vc_usecase = get_usecase_from_list(adev, get_voice_usecase_id_from_list(adev)); if ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) || @@ -1507,13 +1507,6 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) val = AUDIO_DEVICE_OUT_SPEAKER; } - if ((adev->mode == AUDIO_MODE_NORMAL) && - voice_is_in_call(adev) && - output_drives_call(adev, out)) { - ret = voice_stop_call(adev); - adev->current_call_output = NULL; - } - /* * select_devices() call below switches all the usecases on the same * backend to the new device. Refer to check_usecases_codec_backend() in @@ -1541,12 +1534,18 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if ((adev->mode == AUDIO_MODE_IN_CALL) && output_drives_call(adev, out)) { adev->current_call_output = out; - if (!voice_is_in_call(adev)) + if (!adev->voice.in_call) ret = voice_start_call(adev); else voice_update_devices_for_all_voice_usecases(adev); - } + } + } + if ((adev->mode == AUDIO_MODE_NORMAL) && + adev->voice.in_call && + output_drives_call(adev, out)) { + ret = voice_stop_call(adev); + adev->current_call_output = NULL; } pthread_mutex_unlock(&adev->lock); diff --git a/hal/voice.c b/hal/voice.c index a2e3586b9..3a065da7b 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -167,26 +167,27 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id) } session->state.current = CALL_ACTIVE; - return 0; + goto done; error_start_voice: stop_call(adev, usecase_id); +done: ALOGD("%s: exit: status(%d)", __func__, ret); return ret; } -bool voice_is_in_call(struct audio_device *adev) +bool voice_is_call_state_active(struct audio_device *adev) { - bool in_call = false; + bool call_state = false; int ret = 0; - ret = voice_extn_is_in_call(adev, &in_call); + ret = voice_extn_is_call_state_active(adev, &call_state); if (ret == -ENOSYS) { - in_call = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false; + call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false; } - return in_call; + return call_state; } bool voice_is_in_call_rec_stream(struct stream_in *in) @@ -222,7 +223,7 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, int usecase_id; int rec_mode = INCALL_REC_NONE; - if (voice_is_in_call(adev)) { + if (voice_is_call_state_active(adev)) { switch (in->source) { case AUDIO_SOURCE_VOICE_UPLINK: if (audio_extn_compr_cap_enabled() && @@ -348,6 +349,7 @@ int voice_start_call(struct audio_device *adev) if (ret == -ENOSYS) { ret = start_call(adev, USECASE_VOICE_CALL); } + adev->voice.in_call = true; return ret; } @@ -356,6 +358,7 @@ int voice_stop_call(struct audio_device *adev) { int ret = 0; + adev->voice.in_call = false; ret = voice_extn_stop_call(adev); if (ret == -ENOSYS) { ret = stop_call(adev, USECASE_VOICE_CALL); @@ -409,7 +412,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) if (tty_mode != adev->voice.tty_mode) { adev->voice.tty_mode = tty_mode; adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode; - if (voice_is_in_call(adev)) + if (voice_is_call_state_active(adev)) voice_update_devices_for_all_voice_usecases(adev); } } @@ -438,7 +441,7 @@ void voice_init(struct audio_device *adev) adev->voice.tty_mode = TTY_MODE_OFF; adev->voice.volume = 1.0f; adev->voice.mic_mute = false; - adev->voice.voice_device_set = false; + adev->voice.in_call = false; for (i = 0; i < MAX_VOICE_SESSIONS; i++) { adev->voice.session[i].pcm_rx = NULL; adev->voice.session[i].pcm_tx = NULL; diff --git a/hal/voice.h b/hal/voice.h index 0098f944a..5d1ae4074 100644 --- a/hal/voice.h +++ b/hal/voice.h @@ -60,7 +60,8 @@ struct voice { int tty_mode; bool mic_mute; float volume; - bool voice_device_set; + bool is_in_call; + bool in_call; }; enum { @@ -76,8 +77,8 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms); void voice_get_parameters(struct audio_device *adev, struct str_parms *query, struct str_parms *reply); void voice_init(struct audio_device *adev); -bool voice_is_in_call(struct audio_device *adev); bool voice_is_in_call_rec_stream(struct stream_in *in); +bool voice_is_call_state_active(struct audio_device *adev); int voice_set_mic_mute(struct audio_device *dev, bool state); bool voice_get_mic_mute(struct audio_device *dev); int voice_set_volume(struct audio_device *adev, float volume); diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c index cd7270c89..b26a82410 100644 --- a/hal/voice_extn/voice_extn.c +++ b/hal/voice_extn/voice_extn.c @@ -72,7 +72,7 @@ struct pcm_config pcm_config_incall_music = { extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id); extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id); -int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); +int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active); static bool is_valid_call_state(int call_state) { @@ -152,7 +152,6 @@ static int update_calls(struct audio_device *adev) struct voice_session *session = NULL; int fd = 0; int ret = 0; - bool is_in_call = false; ALOGD("%s: enter:", __func__); @@ -214,10 +213,6 @@ static int update_calls(struct audio_device *adev) ALOGE("%s: voice_end_call() failed for usecase: %d\n", __func__, usecase_id); } else { - voice_extn_is_in_call(adev, &is_in_call); - if (!is_in_call) { - adev->voice.voice_device_set = false; - } session->state.current = session->state.new; } break; @@ -293,8 +288,7 @@ static int update_call_states(struct audio_device *adev, { struct voice_session *session = NULL; int i = 0; - bool is_in_call; - int no_of_calls_active = 0; + bool is_call_active; for (i = 0; i < MAX_VOICE_SESSIONS; i++) { if (vsid == adev->voice.session[i].vsid) { @@ -303,27 +297,16 @@ static int update_call_states(struct audio_device *adev, } } - for (i = 0; i < MAX_VOICE_SESSIONS; i++) { - if (CALL_INACTIVE != adev->voice.session[i].state.current) - no_of_calls_active++; - } - - /* When there is only one call active, wait for audio policy manager to set - * the mode to AUDIO_MODE_NORMAL and trigger routing to end the last call. - */ - if (no_of_calls_active == 1 && call_state == CALL_INACTIVE) - return 0; - if (session) { session->state.new = call_state; - voice_extn_is_in_call(adev, &is_in_call); - ALOGD("%s is_in_call:%d voice_device_set:%d, mode:%d\n", - __func__, is_in_call, adev->voice.voice_device_set, adev->mode); + voice_extn_is_call_state_active(adev, &is_call_active); + ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n", + __func__, is_call_active, adev->voice.in_call, adev->mode); /* Dont start voice call before device routing for voice usescases has * occured, otherwise voice calls will be started unintendedly on * speaker. */ - if (is_in_call || adev->voice.voice_device_set) { + if (is_call_active || adev->voice.in_call) { /* Device routing is not triggered for voice calls on the subsequent * subs, Hence update the call states if voice call is already * active on other sub. @@ -345,16 +328,16 @@ int voice_extn_get_active_session_id(struct audio_device *adev, return 0; } -int voice_extn_is_in_call(struct audio_device *adev, bool *in_call) +int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active) { struct voice_session *session = NULL; int i = 0; - *in_call = false; + *is_call_active = false; for (i = 0; i < MAX_VOICE_SESSIONS; i++) { session = &adev->voice.session[i]; if(session->state.current != CALL_INACTIVE){ - *in_call = true; + *is_call_active = true; break; } } @@ -426,7 +409,6 @@ int voice_extn_start_call(struct audio_device *adev) * udpated. */ ALOGV("%s: enter:", __func__); - adev->voice.voice_device_set = true; return update_calls(adev); } @@ -473,6 +455,7 @@ int voice_extn_set_parameters(struct audio_device *adev, err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value); if (err >= 0) { call_state = value; + str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE); } else { ALOGE("%s: call_state key not found", __func__); ret = -EINVAL; diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h index 9bac8782e..c5bc602ff 100644 --- a/hal/voice_extn/voice_extn.h +++ b/hal/voice_extn/voice_extn.h @@ -32,8 +32,9 @@ int voice_extn_set_parameters(struct audio_device *adev, void voice_extn_get_parameters(const struct audio_device *adev, struct str_parms *query, struct str_parms *reply); -int voice_extn_is_in_call(struct audio_device *adev, bool *in_call); int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec); +int voice_extn_is_call_state_active(struct audio_device *adev, + bool *is_call_active); int voice_extn_get_active_session_id(struct audio_device *adev, uint32_t *session_id); void voice_extn_in_get_parameters(struct stream_in *in, @@ -76,7 +77,8 @@ static void voice_extn_get_parameters(const struct audio_device *adev __unused, { } -static int voice_extn_is_in_call(struct audio_device *adev __unused, bool *in_call __unused) +static int voice_extn_is_call_state_active(struct audio_device *adev, + bool *is_call_active) { return -ENOSYS; } -- GitLab From eb012d6644c8e85714a5d179e7310d0bd69c6461 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Thu, 23 Oct 2014 10:53:06 +0530 Subject: [PATCH 254/298] hal: codec calibration data using hwdep nodes Push the codec driver calibration using hwdep nodes. Change-Id: I08875c543be5b69c6cf0d0bbc248806ae2f871c2 --- hal/msm8974/platform.c | 102 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index a23f87e51..d3443ff46 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -23,7 +23,9 @@ #include #include +#include #include +#include #include #include #include @@ -33,6 +35,9 @@ #include "voice_extn.h" #include "sound/compress_params.h" #include "platform_parser.h" +#include "sound/msmcal-hwdep.h" + +#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100) #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" @@ -81,6 +86,13 @@ #define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate" #define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable" #define AUDIO_PARAMETER_KEY_VOLUME_BOOST "volume_boost" +#define MAX_CAL_NAME 20 + +char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = { + [WCD9XXX_ANC_CAL] = "anc_cal", + [WCD9XXX_MBHC_CAL] = "mbhc_cal", + [WCD9XXX_MAD_CAL] = "mad_cal", +}; enum { VOICE_FEATURE_SET_DEFAULT, @@ -99,6 +111,8 @@ typedef int (*acdb_init_t)(); typedef void (*acdb_send_audio_cal_t)(int, int); typedef void (*acdb_send_voice_cal_t)(int, int); typedef int (*acdb_reload_vocvoltable_t)(int); +typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data); +acdb_loader_get_calibration_t acdb_loader_get_calibration; struct platform_data { struct audio_device *adev; @@ -123,6 +137,7 @@ struct platform_data { struct csd_data *csd; }; + static const int pcm_device_table[AUDIO_USECASE_MAX][2] = { [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE}, @@ -326,6 +341,92 @@ static int acdb_device_table[SND_DEVICE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) +static int hw_util_open(int card_no) +{ + int fd = -1; + char dev_name[256]; + + snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u", + card_no, WCD9XXX_CODEC_HWDEP_NODE); + ALOGE("%s Opening device %s\n", __func__, dev_name); + fd = open(dev_name, O_WRONLY); + if (fd < 0) { + ALOGE("%s: cannot open device '%s'\n", __func__, dev_name); + return fd; + } + ALOGE("%s success", __func__); + return fd; +} + +struct param_data { + int use_case; + int acdb_id; + int get_size; + int buff_size; + int data_size; + void *buff; +}; + +static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd) +{ + int ret = 0, type; + + for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) { + struct wcdcal_ioctl_buffer codec_buffer; + struct param_data calib; + + if (!strcmp(cal_name_info[type], "mad_cal")) + calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID; + calib.get_size = 1; + ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data), + &calib); + if (ret < 0) { + ALOGE("%s get_calibration failed\n", __func__); + return ret; + } + calib.get_size = 0; + calib.buff = malloc(calib.buff_size); + ret = acdb_loader_get_calibration(cal_name_info[type], + sizeof(struct param_data), &calib); + if (ret < 0) { + ALOGE("%s get_calibration failed\n", __func__); + free(calib.buff); + return ret; + } + codec_buffer.buffer = calib.buff; + codec_buffer.size = calib.data_size; + codec_buffer.cal_type = type; + if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0) + ALOGE("Failed to call ioctl for %s err=%d", + cal_name_info[type], errno); + ALOGE(" %s cal sent for %s", __func__, cal_name_info[type]); + free(calib.buff); + } + return ret; +} + +static void audio_hwdep_send_cal(struct platform_data *plat_data) +{ + int fd; + + fd = hw_util_open(plat_data->adev->snd_card); + if (fd == -1) { + ALOGE("%s error open\n", __func__); + return; + } + acdb_loader_get_calibration = (acdb_loader_get_calibration_t) + dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration"); + + if (acdb_loader_get_calibration == NULL) { + ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__, + dlerror()); + return; + } + if (send_codec_cal(acdb_loader_get_calibration, fd) < 0) + ALOGE("%s: Could not send anc cal", __FUNCTION__); +} + + static void set_echo_reference(struct audio_device *adev, bool enable) { @@ -618,6 +719,7 @@ void *platform_init(struct audio_device *adev) /* Read one time ssr property */ audio_extn_ssr_update_enabled(); audio_extn_spkr_prot_init(adev); + audio_hwdep_send_cal(my_data); return my_data; } -- GitLab From 8ce8ac9e6262651a7463640118e63cf97ab7b673 Mon Sep 17 00:00:00 2001 From: Tanya Finkel Date: Mon, 3 Nov 2014 10:09:51 +0200 Subject: [PATCH 255/298] hal: Add support for several DB8074 specific audio devices Fix DB8074 VoIP issue and the recording use case. Change-Id: I99aaf21474d210ce33881ab32b95821352608139 --- hal/msm8974/hw_info.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index f32ee44d3..f004aa04c 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -88,7 +88,10 @@ static const snd_device_t taiko_DB_variant_devices[] = { SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES, SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET, SND_DEVICE_IN_SPEAKER_MIC, + SND_DEVICE_OUT_VOICE_SPEAKER, + SND_DEVICE_IN_VOICE_SPEAKER_MIC, SND_DEVICE_IN_HEADSET_MIC, + SND_DEVICE_IN_HANDSET_MIC, SND_DEVICE_IN_QUAD_MIC, }; -- GitLab From fe9fc8336c16fff5a541b095950dd347ad58f35d Mon Sep 17 00:00:00 2001 From: wjiang Date: Sat, 19 Jul 2014 21:46:46 +0800 Subject: [PATCH 256/298] post_proc: Fix improper datatype of EQ preset band level value unsigned int causes negative band level turn out to be extreme large value, which results in EQ works abnormally due to unexpected parameter sent. Change-Id: I81120c604f4e9f23b25d5a45a7b0294fea63d207 CRs-Fixed: 696825 --- post_proc/equalizer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c index c635251ae..7ddee5e76 100644 --- a/post_proc/equalizer.c +++ b/post_proc/equalizer.c @@ -52,7 +52,7 @@ static const char *equalizer_preset_names[] = { "Jazz", "Pop", "Rock" - }; +}; static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = { {30000, 120000}, @@ -61,7 +61,7 @@ static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = { {1800001, 7000000}, {7000001, 20000000}}; -static const uint16_t equalizer_band_presets_level[] = { +static const int16_t equalizer_band_presets_level[] = { 3, 0, 0, 0, 3, /* Normal Preset */ 5, 3, -2, 4, 4, /* Classical Preset */ 6, 0, 2, 4, 1, /* Dance Preset */ -- GitLab From 6c23f38001bc184940b145b73991ff30a316fac2 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Thu, 14 Aug 2014 00:00:51 -0700 Subject: [PATCH 257/298] hal: NULL pointer check before using audio_usecase - Add check for NULL pointer before using audio_usecase Change-Id: Iaedd7b1dfbcf727957f6b19a54199d29afa25703 --- hal/audio_hw.c | 10 +++++----- hal/voice_extn/compress_voip.c | 10 ++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 5008cd436..3845207ab 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -680,23 +680,23 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id) if (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL) { vc_usecase = get_usecase_from_list(adev, get_voice_usecase_id_from_list(adev)); - if ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) || - (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL)) { + if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) || + (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) { in_snd_device = vc_usecase->in_snd_device; out_snd_device = vc_usecase->out_snd_device; } } else if (voice_extn_compress_voip_is_active(adev)) { voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); - if ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) && + if ((voip_usecase) && ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) && (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) && - (voip_usecase->stream.out != adev->primary_output)) { + (voip_usecase->stream.out != adev->primary_output))) { in_snd_device = voip_usecase->in_snd_device; out_snd_device = voip_usecase->out_snd_device; } } else if (audio_extn_hfp_is_active(adev)) { hfp_ucid = audio_extn_hfp_get_usecase(); hfp_usecase = get_usecase_from_list(adev, hfp_ucid); - if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) { + if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) { in_snd_device = hfp_usecase->in_snd_device; out_snd_device = hfp_usecase->out_snd_device; } diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 53a831008..df41a52fd 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -574,8 +574,14 @@ int voice_extn_compress_voip_start_output_stream(struct stream_out *out) ret = voip_start_call(adev, &out->config); out->pcm = voip_data.pcm_rx; uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL); - uc_info->stream.out = out; - uc_info->devices = out->devices; + if (uc_info) { + uc_info->stream.out = out; + uc_info->devices = out->devices; + } else { + ret = -EINVAL; + ALOGE("%s: exit(%d): failed to get use case info", __func__, ret); + goto error; + } error: ALOGV("%s: exit: status(%d)", __func__, ret); -- GitLab From 3ec42ef6b63854c8563ca9870b6c58dd7de4d5c6 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Fri, 21 Nov 2014 20:57:48 +0530 Subject: [PATCH 258/298] audio: Reject incall record request when call is not active - If application selects AUDIO_SOURCE_VOICE_CALL when voice call is not active, audio HAL is selecting afe-proxy use case which is wrong. afe-proxy usecase/device expected to be selected during USB Voice call scenario only - Fix is to fail opening the input stream with AUDIO_DEVICE_IN_TELEPHONY_RX or AUDIO_DEVICE_IN_VOICE_CALL if the call is not active Change-Id: Iae2d25d192b3b5011dd45816778ffc03d3049449 --- hal/audio_hw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 3845207ab..575f2bfba 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2873,6 +2873,10 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->format = config->format; if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) { + if (!adev->voice.in_call) { + ret = -EINVAL; + goto err_open; + } if (config->sample_rate == 0) config->sample_rate = AFE_PROXY_SAMPLING_RATE; if (config->sample_rate != 48000 && config->sample_rate != 16000 && -- GitLab From ce5f8e870530f874d01de7c68494e1c865d16187 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Thu, 27 Nov 2014 14:47:42 +0530 Subject: [PATCH 259/298] Correction of dolby format name from EAC3 to E_AC3 Change-Id: I0222fd5b3d78261215c3fa8f4abff990a130d0de --- hal/audio_extn/dolby.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c index 2184947c6..49cf4a085 100644 --- a/hal/audio_extn/dolby.c +++ b/hal/audio_extn/dolby.c @@ -243,7 +243,7 @@ void send_ddp_endp_params(struct audio_device *adev, (usecase->devices & ddp_dev) && (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && ((usecase->stream.out->format == AUDIO_FORMAT_AC3) || - (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) { + (usecase->stream.out->format == AUDIO_FORMAT_E_AC3))) { send_ddp_endp_params_stream(usecase->stream.out, ddp_dev, dev_ch_cap, false /* set cache */); } @@ -260,7 +260,7 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev) (usecase->devices & AUDIO_DEVICE_OUT_ALL) && (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && ((usecase->stream.out->format == AUDIO_FORMAT_AC3) || - (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) { + (usecase->stream.out->format == AUDIO_FORMAT_E_AC3))) { /* * Use wfd /hdmi sink channel cap for dolby params if device is wfd * or hdmi. Otherwise use stereo configuration @@ -367,7 +367,7 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev, audio_extn_dolby_set_dmid(adev); #endif break; - case AUDIO_FORMAT_EAC3: + case AUDIO_FORMAT_E_AC3: id = SND_AUDIOCODEC_EAC3; send_ddp_endp_params_stream(out, out->devices, channel_cap, true /* set_cache */); @@ -385,7 +385,7 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev, bool audio_extn_is_dolby_format(audio_format_t format) { if (format == AUDIO_FORMAT_AC3 || - format == AUDIO_FORMAT_EAC3) + format == AUDIO_FORMAT_E_AC3) return true; else return false; -- GitLab From c0ca209d9ff7167ec6cb361b60f77e9488711272 Mon Sep 17 00:00:00 2001 From: Shreyas Nagasandra Chandrasekhar Date: Thu, 27 Nov 2014 19:31:52 +0530 Subject: [PATCH 260/298] audio: Avoid mic mute on proxy during call In voice call on USB headset , mute is applied on both RX and TX . Fix is to avoid muting on out PROXY to ensure the RX data written to USB hal without mute. CRs-Fixed: 763152 Change-Id: Icb84d8c68ba15b35884806b54c3a1daeb11b2bc2 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 575f2bfba..e2b55de39 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2798,7 +2798,8 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) pthread_mutex_lock(&adev->lock); ALOGD("%s state %d\n", __func__, state); - ret = voice_set_mic_mute((struct audio_device *)dev, state); + if(!adev->voice_tx_output) + ret = voice_set_mic_mute((struct audio_device *)dev, state); pthread_mutex_unlock(&adev->lock); return ret; -- GitLab From 41f1fa0d15b82f2597f6d40441b86d3a3b777a98 Mon Sep 17 00:00:00 2001 From: Sharad Sangle Date: Wed, 20 Aug 2014 14:19:30 +0530 Subject: [PATCH 261/298] mm-audio: aenc: make frame_count variable 64 bit - After 71 minutes AAC encoding stops working - The root cause is while calculating the time stamp of the frame a variable frame_count is 32 bit and it overflows which leads incorrect timestamp calculation which leads to stopping of AAC encoding - To solve this make frame_count 64 bit variable Change-Id: Iddb7c6c8fab53314d58bdf8651d5ede0c6ca8b80 CRs-Fixed: 707449 --- mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h index 98afa718a..daeb6a1e6 100644 --- a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h +++ b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h @@ -457,7 +457,7 @@ private: unsigned int m_flags; //encapsulate the waiting states. OMX_U64 nTimestamp; OMX_U64 ts; - uint32_t m_frame_count; + uint64_t m_frame_count; unsigned int frameduration; unsigned int pcm_input; //tunnel or non-tunnel unsigned int m_inp_act_buf_count; // Num of Input Buffers -- GitLab From 9781c6c3120172aa1195b1dc2c5428f41898422c Mon Sep 17 00:00:00 2001 From: Shreyas Nagasandra Chandrasekhar Date: Mon, 1 Dec 2014 05:49:35 -0800 Subject: [PATCH 262/298] Revert " audio: Avoid mic mute on proxy during call" This reverts commit c0ca209d9ff7167ec6cb361b60f77e9488711272 Change-Id: I8e05f5ca9ecc7df3df064f39ad691e10462d57d8 --- hal/audio_hw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index e2b55de39..575f2bfba 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2798,8 +2798,7 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) pthread_mutex_lock(&adev->lock); ALOGD("%s state %d\n", __func__, state); - if(!adev->voice_tx_output) - ret = voice_set_mic_mute((struct audio_device *)dev, state); + ret = voice_set_mic_mute((struct audio_device *)dev, state); pthread_mutex_unlock(&adev->lock); return ret; -- GitLab From 6c183fdb09bdbd43ddd2bd53c3a351b00bc48884 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Thu, 4 Dec 2014 10:48:28 +0530 Subject: [PATCH 263/298] audio: Avoid mute during AFE PROXY Usecase Silence data is getting written from in_read when voice call is muted with USB Headset connected. This resulting in muting Rx path too along with Tx path in this scenario. USB Voice call scenario, PROXY_IN device is responsible for reading RX data. So not supposed to be muted. Fix is to avoid muting if the current use case is AFE_PROXY CRs-Fixed: 763152 Change-Id: I1fbd5545f343cbaea865e941214be05791dec14e --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 575f2bfba..86505601c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2202,7 +2202,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, * Instead of writing zeroes here, we could trust the hardware * to always provide zeroes when muted. */ - if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in)) + if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in) && + in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY) memset(buffer, 0, bytes); exit: -- GitLab From 3c0036d05286a0df4d4aa763e33cdcade1f13fe3 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Wed, 17 Dec 2014 16:45:10 +0530 Subject: [PATCH 264/298] audio: Reject incall record request when mode is not IN_CALL - If application selects AUDIO_SOURCE_VOICE_CALL when voice call is not active, audio HAL is selecting afe-proxy use case which is wrong. afe-proxy usecase/device expected to be selected during USB Voice call scenario only - Fix is to fail opening the input stream with AUDIO_DEVICE_IN_TELEPHONY_RX or AUDIO_DEVICE_IN_VOICE_CALL if current mode is not IN_CALL CRs-Fixed: 772386 Change-Id: I8ee3e72daec86e26d05b01a117d7a01f7f6b69a8 --- hal/audio_hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 86505601c..7e757f069 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2874,9 +2874,9 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->format = config->format; if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) { - if (!adev->voice.in_call) { - ret = -EINVAL; - goto err_open; + if (adev->mode != AUDIO_MODE_IN_CALL) { + ret = -EINVAL; + goto err_open; } if (config->sample_rate == 0) config->sample_rate = AFE_PROXY_SAMPLING_RATE; -- GitLab From ec696be48ea3de6e0be522c70ad4888cf5e77178 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Tue, 23 Dec 2014 14:22:07 +0530 Subject: [PATCH 265/298] audio: Fixed input device check - in_device is set to AUDIO_DEVICE_IN_BACK_MIC which includes AUDIO_DEVICE_BIT_IN mask. Any comparison of in_device with input devices always results in true as all the input devices include AUDIO_DEVICE_BIT_IN - Removed AUDIO_DEVICE_BIT_IN from in_device to avoid wrong comparisons CRs-Fixed: 724951 Change-Id: Ib816ad70c6793b29f79f4e36d42677739a0021c5 --- hal/msm8974/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index d3443ff46..692c510d5 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1354,7 +1354,7 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION || (mode == AUDIO_MODE_IN_COMMUNICATION)) { if (out_device & AUDIO_DEVICE_OUT_SPEAKER) - in_device = AUDIO_DEVICE_IN_BACK_MIC; + in_device = (AUDIO_DEVICE_IN_BACK_MIC & ~AUDIO_DEVICE_BIT_IN); if (adev->active_input) { if (adev->active_input->enable_aec && adev->active_input->enable_ns) { -- GitLab From ec7a7d806e1639a0478c12f5fd38b076729eb34f Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Fri, 30 Jan 2015 12:41:09 +0530 Subject: [PATCH 266/298] audio: Modified atoi to atoll to convert large Numeric values Change-Id: I0e9a8efe28c46f9f885648ddcc1bc8b2b36fd0b7 --- hal/audio_extn/dolby.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c index 49cf4a085..0b26a7fcf 100644 --- a/hal/audio_extn/dolby.c +++ b/hal/audio_extn/dolby.c @@ -449,7 +449,7 @@ void audio_extn_dolby_set_dmid(struct audio_device *adev) return; property_get("dmid",c_dmid,"0"); - i_dmid = atoi(c_dmid); + i_dmid = atoll(c_dmid); ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { -- GitLab From b8997fa327a8a76b8fd3c6b3e4d3870933e5f852 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Fri, 13 Feb 2015 11:34:42 +0530 Subject: [PATCH 267/298] hal: Update pcm_open flag for VOIP - By default CLOCK_REALTIME is used. - Change the clock type to CLOCK_MONOTONIC to synchronize the framework and VOIP driver clock and timestamps. Change-Id: I8ab64e948cea5d027bf28c4e101ff517fda3558c --- hal/voice_extn/compress_voip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index df41a52fd..3bab1275e 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -328,6 +328,7 @@ static int voip_start_call(struct audio_device *adev, int i, ret = 0; struct audio_usecase *uc_info; int pcm_dev_rx_id, pcm_dev_tx_id; + unsigned int flags = PCM_OUT | PCM_MONOTONIC; ALOGD("%s: enter", __func__); @@ -362,7 +363,7 @@ static int voip_start_call(struct audio_device *adev, __func__, adev->snd_card, pcm_dev_rx_id); voip_data.pcm_rx = pcm_open(adev->snd_card, pcm_dev_rx_id, - PCM_OUT, voip_config); + flags, voip_config); if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) { ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx)); pcm_close(voip_data.pcm_rx); -- GitLab From 04c680d7ce10df300e041cb461e1b84c5ce19e3d Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Wed, 19 Nov 2014 16:18:55 -0800 Subject: [PATCH 268/298] hal: use 0 as default return value for out_get_render_position - Initialize default return value of out_get_render_position to 0(NO_ERROR). - Default value(NO_ERROR) will be used if timestamp query happens before compress driver is opened. Return 0(NO_ERROR) in this case to avoid playback failures. Change-Id: I0f8b2e0f19cfe736a19934ddef18016599ec582c CRs-Fixed: 756508 --- hal/audio_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 7e757f069..528cbb910 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1813,7 +1813,7 @@ static int out_get_render_position(const struct audio_stream_out *stream, struct stream_out *out = (struct stream_out *)stream; *dsp_frames = 0; if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { - ssize_t ret = -EINVAL; + ssize_t ret = 0; pthread_mutex_lock(&out->lock); if (out->compr != NULL) { ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, -- GitLab From 5501ffa88da0e23659e5da71d08b5c58d363ccd6 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Mon, 30 Mar 2015 19:16:14 +0530 Subject: [PATCH 269/298] hal: Fix ANR if In-Call recording is started at end of voice call Sometimes ANR is observed, if In-call recording is started at the end of voice call. Incorrect use case "afe-proxy-record" is being picked up in this case as voice call is not active by the time audio HAL starts the input stream, thus resulting in pcm device open failures. Fix this by rejecting start input request if voice call is not active by the time input is started. CRs-Fixed: 810997 Change-Id: I8a9d0789cf37f5523de5d1da5e9fda59198eb901 --- hal/voice.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hal/voice.c b/hal/voice.c index 3a065da7b..a14784de0 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -260,6 +260,18 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev, session_id, rec_mode); ALOGV("%s: Update usecase to %d",__func__, in->usecase); } else { + /* + * Reject the recording instances, where the recording is started + * with In-call voice recording source types but voice call is not + * active by the time input is started + */ + if ((in->source == AUDIO_SOURCE_VOICE_UPLINK) || + (in->source == AUDIO_SOURCE_VOICE_DOWNLINK) || + (in->source == AUDIO_SOURCE_VOICE_CALL)) { + ret = -EINVAL; + ALOGE("%s: As voice call is not active, Incall rec usecase can't be \ + selected for requested source:%d",__func__, in->source); + } ALOGV("%s: voice call not active", __func__); } -- GitLab From 4401479a79782415db77fb000861f6b476276dad Mon Sep 17 00:00:00 2001 From: Avinash Vaish Date: Fri, 27 Mar 2015 14:46:04 +0530 Subject: [PATCH 270/298] hal: Prevent de-routing in case the usecase doesn't share codec backend During device selection for a usecase, other active usecases that share the same codec backend are supposed to be switched to the new routing device. Erroneously, during selection of the device for a capture usecase, other active usecases are being de-routed irrespective of their backends leading to unwarrented behavior e.g. voice call breakdown when a camcorder usecase begins Add a check to avoid disabling of usecases in above mentioned scenarios if these do not share the same codec backend. CRs-Fixed: 813744 Change-Id: Ic7a5b54155e70a55fd0b0b2d5ad7e380de564123 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 528cbb910..799452b9c 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -546,7 +546,8 @@ static void check_and_route_capture_usecases(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (usecase->type != PCM_PLAYBACK && usecase != uc_info && - usecase->in_snd_device != snd_device) { + usecase->in_snd_device != snd_device && + (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) { ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", __func__, use_case_table[usecase->id], platform_get_snd_device_name(usecase->in_snd_device)); -- GitLab From 7e6ba2e626c75373cdd608ea8f83e28eabf2f0c9 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Tue, 31 Mar 2015 21:53:21 -0700 Subject: [PATCH 271/298] hal: update input source type during open input stream Currently input stream source type is updated in in_set_parameters(). Some of the effects like AEC are applied based on input source type. If effects API is called before in_set_parameters() then that effect does not apply. Fix this issue by updating the source type in adev_open_input_stream() instead of in_set_parameters(). Change-Id: Iff0670264e156840c40f1f15cfc93fd5b2506e0d --- hal/audio_hw.c | 15 +++++++++++---- hal/voice_extn/compress_voip.c | 5 ++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 528cbb910..1ef002b0e 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2826,7 +2826,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, struct audio_stream_in **stream_in, audio_input_flags_t flags __unused, const char *address __unused, - audio_source_t source __unused) + audio_source_t source) { struct audio_device *adev = (struct audio_device *)dev; struct stream_in *in; @@ -2840,8 +2840,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\ - stream_handle(%p)",__func__, config->sample_rate, config->channel_mask, - devices, &in->stream); + stream_handle(%p) io_handle(%d) source(%d)",__func__, config->sample_rate, config->channel_mask, + devices, &in->stream, handle, source); pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); @@ -2862,7 +2862,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->stream.get_input_frames_lost = in_get_input_frames_lost; in->device = devices; - in->source = AUDIO_SOURCE_DEFAULT; + in->source = source; in->dev = adev; in->standby = 1; in->channel_mask = config->channel_mask; @@ -2918,6 +2918,13 @@ static int adev_open_input_stream(struct audio_hw_device *dev, config->format, channel_count); in->config.period_size = buffer_size / frame_size; + if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) && + (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) && + (voice_extn_compress_voip_is_format_supported(in->format)) && + (in->config.rate == 8000 || in->config.rate == 16000) && + (audio_channel_count_from_in_mask(in->channel_mask) == 1)) { + voice_extn_compress_voip_open_input_stream(in); + } } *stream_in = &in->stream; diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 3bab1275e..83809919a 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -690,6 +690,10 @@ int voice_extn_compress_voip_open_input_stream(struct stream_in *in) voip_data.sample_rate = in->config.rate; } + ret = voip_set_mode(in->dev, in->format); + if (ret < 0) + goto done; + in->usecase = USECASE_COMPRESS_VOIP_CALL; if (in->config.rate == 16000) in->config = pcm_config_voip_wb; @@ -697,7 +701,6 @@ int voice_extn_compress_voip_open_input_stream(struct stream_in *in) in->config = pcm_config_voip_nb; voip_data.in_stream_count++; - ret = voip_set_mode(in->dev, in->format); done: ALOGV("%s: exit, ret=%d", __func__, ret); -- GitLab From 5ef96fa8d2a1314aeffc73f54a34d385c4ac3610 Mon Sep 17 00:00:00 2001 From: Neema Shetty Date: Fri, 5 Jun 2015 18:15:19 -0700 Subject: [PATCH 272/298] hal: Add WCD9330 based soundcard for wearables Sound card for WCD9330 and its corresponding mixer controls path is added on wearables platform. CRs-fixed: 853822 Change-Id: If06ad3aaf8ca317d4540d880e4cd213f65e076ab --- hal/msm8974/hw_info.c | 5 +++-- hal/msm8974/platform.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c index f004aa04c..ec03605d7 100644 --- a/hal/msm8974/hw_info.c +++ b/hal/msm8974/hw_info.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2015 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -216,7 +216,8 @@ static void update_hardware_info_8610(struct hardware_info *hw_info, const char static void update_hardware_info_8226(struct hardware_info *hw_info, const char *snd_card_name) { - if (!strcmp(snd_card_name, "msm8226-tapan-snd-card")) { + if ((!strcmp(snd_card_name, "msm8226-tapan-snd-card")) || + (!strcmp(snd_card_name, "msm8226-tomtom-snd-card"))) { strlcpy(hw_info->type, "", sizeof(hw_info->type)); strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name)); hw_info->snd_devices = NULL; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 692c510d5..c0593c9a3 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -41,6 +41,7 @@ #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml" +#define MIXER_XML_PATH_WCD9330 "/system/etc/mixer_paths_wcd9330.xml" #define LIB_ACDB_LOADER "libacdbloader.so" #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" @@ -590,13 +591,19 @@ void *platform_init(struct audio_device *adev) } snd_card_name = mixer_get_name(adev->mixer); - ALOGV("%s: snd_card_name: %s", __func__, snd_card_name); + ALOGD("%s: snd_card_name: %s", __func__, snd_card_name); my_data->hw_info = hw_info_init(snd_card_name); if (!my_data->hw_info) { ALOGE("%s: Failed to init hardware info", __func__); } else { - if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH, + if (!strncmp(snd_card_name, "msm8226-tomtom-snd-card", + sizeof("msm8226-tomtom-snd-card"))) { + ALOGE("%s: Call MIXER_XML_PATH_WCD9330", __func__); + + adev->audio_route = audio_route_init(snd_card_num, + MIXER_XML_PATH_WCD9330); + } else if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH, MIXER_XML_PATH_AUXPCM) == -ENOSYS) adev->audio_route = audio_route_init(snd_card_num, MIXER_XML_PATH); -- GitLab From 50e5bded707e8fd6952291251e35c53032045285 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Fri, 10 Jul 2015 13:48:32 +0530 Subject: [PATCH 273/298] audiod: Removed stlport dependency Change-Id: I5c3aaa164ea7d337256b31f6823b32be71ad883f --- audiod/Android.mk | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/audiod/Android.mk b/audiod/Android.mk index c382c9d2c..aeff39079 100644 --- a/audiod/Android.mk +++ b/audiod/Android.mk @@ -1,7 +1,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -include external/stlport/libstlport.mk LOCAL_SRC_FILES:= \ audiod_main.cpp \ @@ -13,8 +12,8 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libbinder \ - libmedia \ - libstlport + libmedia + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr -- GitLab From 716bd19571ecaab1c277d567b69d745be3938fc5 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Fri, 10 Jul 2015 16:34:41 +0530 Subject: [PATCH 274/298] audio: Compilation fix for kernel include -In Android.mk Kernel include directory is protected under feature flags. Calibration header requires kernel include directory Change-Id: If24c99723ba6e3d8b0da30a5e44cf49dad042c2a --- hal/Android.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/Android.mk b/hal/Android.mk index 22c01c154..6cb7c476f 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -137,7 +137,8 @@ LOCAL_C_INCLUDES += \ $(call include-path-for, audio-effects) \ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \ $(LOCAL_PATH)/audio_extn \ - $(LOCAL_PATH)/voice_extn + $(LOCAL_PATH)/voice_extn \ + $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include ifneq ($(filter msm8974,$(AUDIO_PLATFORM)),) LOCAL_C_INCLUDES += external/expat/lib -- GitLab From ca67a02c51e37fb14e19e885d662362c7434636c Mon Sep 17 00:00:00 2001 From: Sharad Sangle Date: Thu, 28 May 2015 16:15:16 +0530 Subject: [PATCH 275/298] policy-hal: add custom audio policy - this change contains all the fixes went in audio policy made by QTI as below audio_policyhal: SSR support for compress offload Change-Id: Idc8f6690d7c06883dbfcf55b073d4456a8c27e5c audio: Fix playback of AAC clips in offload mode instead of deep buffer Change-Id: Ib946830bc2f6b9cec33c8f0943910e3aeeb6fa6e audio: primary desc check for sonification_respectful Change-Id: I5d7aef3b29791823c277452e71e0cd43f91b2ddd audio_policy: Fix for mute count mismatch for sonification strategy Change-Id: Id4f328e2f9fc6820cecfbd73df11c871f8587aad audio: execute setVoiceVolume for USB device during inCall usecase Change-Id: Ia4917807103d1cf406a03e1d6d3dada470401737 audio_policy: handle in call sonification for attached outputs of duplicating output Change-Id: I91968b33c4d93b13aae421654b2740c46269d55e audio: Fix for Sound from handset leaks to speaker Change-Id: Id2fd20de7a279f74e38a9aefe91e17b36cc9da6f audio: Fix media server crash at the start of voice call Change-Id: Ibe2d19acbed2ca44ab193ae0b613fae899f02ebb audio_policy: handle incall sound notifications on non primary outputs Change-Id: I2eec3872a2dcd10750ac20f69791a5bb51b37d8b Audiopolicymanager: handle incall sonification without checking output refCount Change-Id: I0eab939b32fe47388e2515ab56154d540e9df55c audio: use FLAG_FAST for non-music stream on WFD Change-Id: Id2f5965c8f5623646b2adb2aa892a9929f3bc5bb audiopolicy: optimize voice call start latency Chnage-Id: I77cb2ddb5a9154ffd2ac1620351992686e580f8a Change-Id: I8a5991f09063f8e00b9a1308c3307c239f3ce487 --- policy_hal/Android.mk | 53 +- policy_hal/AudioPolicyManager.cpp | 1738 ++++++++++++++--------------- policy_hal/AudioPolicyManager.h | 153 ++- 3 files changed, 935 insertions(+), 1009 deletions(-) diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index b787130ef..874b3dd57 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -1,48 +1,35 @@ -ifeq ($(strip $(BOARD_USES_EXTN_AUDIO_POLICY_MANAGER)),true) - +ifneq ($(USE_LEGACY_AUDIO_POLICY), 1) +ifeq ($(USE_CUSTOM_AUDIO_POLICY), 1) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := AudioPolicyManager.cpp +LOCAL_C_INCLUDES := $(TOPDIR)frameworks/av/services \ + $(TOPDIR)frameworks/av/services/audioflinger \ + $(call include-path-for, audio-effects) \ + $(call include-path-for, audio-utils) \ + $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ + $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \ + $(TOPDIR)frameworks/av/services/audiopolicy \ + $(TOPDIR)frameworks/av/services/audiopolicy/common/managerdefinitions/include \ + $(call include-path-for, avextension) + + LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - liblog + liblog \ + libsoundtrigger \ + libaudiopolicymanagerdefault \ + libserviceutility LOCAL_STATIC_LIBRARIES := \ - libmedia_helper - -LOCAL_WHOLE_STATIC_LIBRARIES := \ - libaudiopolicy_legacy + libmedia_helper \ -LOCAL_MODULE := audio_policy.$(TARGET_BOARD_PLATFORM) -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_MODULE_TAGS := optional - -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM)),true) -LOCAL_CFLAGS += -DAUDIO_EXTN_FM_ENABLED -endif -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) -LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED -endif -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_INCALL_MUSIC)),true) -LOCAL_CFLAGS += -DAUDIO_EXTN_INCALL_MUSIC_ENABLED -endif -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_SPK)),true) -LOCAL_CFLAGS += -DAUDIO_EXTN_HDMI_SPK_ENABLED -endif - - -ifeq ($(strip $(TARGET_BOARD_PLATFORM)),msm8916) -LOCAL_CFLAGS += -DVOICE_CONCURRENCY -LOCAL_CFLAGS += -DWFD_CONCURRENCY -endif - -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTIPLE_TUNNEL)), true) -LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED -endif +LOCAL_MODULE := libaudiopolicymanager include $(BUILD_SHARED_LIBRARY) endif +endif diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 13dd21cea..03dec5752 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2009 The Android Open Source Project @@ -17,7 +17,7 @@ * limitations under the License. */ -#define LOG_TAG "AudioPolicyManager" +#define LOG_TAG "AudioPolicyManagerCustom" //#define LOG_NDEBUG 0 //#define VERY_VERBOSE_LOGGING @@ -27,55 +27,66 @@ #define ALOGVV(a...) do { } while(0) #endif +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + // A device mask for all audio output devices that are considered "remote" when evaluating // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX +// A device mask for all audio input and output devices where matching inputs/outputs on device +// type alone is not enough: the address must match too +#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \ + AUDIO_DEVICE_OUT_REMOTE_SUBMIX) +// Following delay should be used if the calculated routing delay from all active +// input streams is higher than this value +#define MAX_VOICE_CALL_START_DELAY_MS 100 + +#include +#include +#include #include -#include "AudioPolicyManager.h" -#include #include -#include -#include -#include +#include +#include +#include +#include "AudioPolicyManager.h" +#include -namespace android_audio_legacy { +namespace android { // ---------------------------------------------------------------------------- // AudioPolicyInterface implementation // ---------------------------------------------------------------------------- +extern "C" AudioPolicyInterface* createAudioPolicyManager( + AudioPolicyClientInterface *clientInterface) +{ + return new AudioPolicyManagerCustom(clientInterface); +} -status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, - AudioSystem::device_connection_state state, - const char *device_address) +extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) { - SortedVector outputs; + delete interface; +} - ALOGD("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); +status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t device, + audio_policy_dev_state_t state, + const char *device_address, + const char *device_name) +{ + ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s", + device, state, device_address, device_name); // connect/disconnect only 1 device at a time if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; - if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { - ALOGE("setDeviceConnectionState() invalid address: %s", device_address); - return BAD_VALUE; - } + sp devDesc = + mHwModules.getDeviceDescriptor(device, device_address, device_name); // handle output devices if (audio_is_output_device(device)) { + SortedVector outputs; - if (!mHasA2dp && audio_is_a2dp_device(device)) { - ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device); - return BAD_VALUE; - } - if (!mHasUsb && audio_is_usb_device(device)) { - ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device); - return BAD_VALUE; - } - if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) { - ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device); - return BAD_VALUE; - } + ssize_t index = mAvailableOutputDevices.indexOf(devDesc); // save a copy of the opened output descriptors before any output is opened or closed // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies() @@ -83,72 +94,68 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, switch (state) { // handle output device connection - case AudioSystem::DEVICE_STATE_AVAILABLE: - if (mAvailableOutputDevices & device) { + case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { + if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %x", device); return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() connecting device %x", device); - if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) { - return INVALID_OPERATION; - } - ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", - outputs.size()); // register new device as available - mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device); - - if (!outputs.isEmpty()) { - String8 paramStr; - if (mHasA2dp && audio_is_a2dp_device(device)) { - // handle A2DP device connection - AudioParameter param; - param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address)); - paramStr = param.toString(); - mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); - mA2dpSuspended = false; - } else if (audio_is_bluetooth_sco_device(device)) { - // handle SCO device connection - mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); - } else if (mHasUsb && audio_is_usb_device(device)) { - // handle USB device connection - mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN); - paramStr = mUsbCardAndDevice; - } - // not currently handling multiple simultaneous submixes: ignoring remote submix - // case and address - if (!paramStr.isEmpty()) { - for (size_t i = 0; i < outputs.size(); i++) { - mpClientInterface->setParameters(outputs[i], paramStr); - } + index = mAvailableOutputDevices.add(devDesc); + if (index >= 0) { + sp module = mHwModules.getModuleForDevice(device); + if (module == 0) { + ALOGD("setDeviceConnectionState() could not find HW module for device %08x", + device); + mAvailableOutputDevices.remove(devDesc); + return INVALID_OPERATION; } + mAvailableOutputDevices[index]->attach(module); + } else { + return NO_MEMORY; + } + + if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR) { + mAvailableOutputDevices.remove(devDesc); + return INVALID_OPERATION; } - break; + // Propagate device availability to Engine + mEngine->setDeviceConnectionState(devDesc, state); + + // outputs should never be empty here + ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():" + "checkOutputsForDevice() returned no outputs but status OK"); + ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs", + outputs.size()); + + // Send connect to HALs + AudioParameter param = AudioParameter(devDesc->mAddress); + param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device); + mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); + + } break; // handle output device disconnection - case AudioSystem::DEVICE_STATE_UNAVAILABLE: { - if (!(mAvailableOutputDevices & device)) { + case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { + if (index < 0) { ALOGW("setDeviceConnectionState() device not connected: %x", device); return INVALID_OPERATION; } - ALOGV("setDeviceConnectionState() disconnecting device %x", device); + ALOGV("setDeviceConnectionState() disconnecting output device %x", device); + + // Send Disconnect to HALs + AudioParameter param = AudioParameter(devDesc->mAddress); + param.addInt(String8(AUDIO_PARAMETER_DEVICE_DISCONNECT), device); + mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); + // remove device from available output devices - mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device); - - checkOutputsForDevice(device, state, outputs); - if (mHasA2dp && audio_is_a2dp_device(device)) { - // handle A2DP device disconnection - mA2dpDeviceAddress = ""; - mA2dpSuspended = false; - } else if (audio_is_bluetooth_sco_device(device)) { - // handle SCO device disconnection - mScoDeviceAddress = ""; - } else if (mHasUsb && audio_is_usb_device(device)) { - // handle USB device disconnection - mUsbCardAndDevice = ""; - } - // not currently handling multiple simultaneous submixes: ignoring remote submix - // case and address + mAvailableOutputDevices.remove(devDesc); + + checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress); + + // Propagate device availability to Engine + mEngine->setDeviceConnectionState(devDesc, state); } break; default: @@ -156,222 +163,387 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, return BAD_VALUE; } + // checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP + // output is suspended before any tracks are moved to it checkA2dpSuspend(); checkOutputForAllStrategies(); // outputs must be closed after checkOutputForAllStrategies() is executed if (!outputs.isEmpty()) { for (size_t i = 0; i < outputs.size(); i++) { - AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]); + sp desc = mOutputs.valueFor(outputs[i]); // close unused outputs after device disconnection or direct outputs that have been // opened by checkOutputsForDevice() to query dynamic parameters - if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) || + if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) || (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) && (desc->mDirectOpenCount == 0))) { closeOutput(outputs[i]); } } + // check again after closing A2DP output to reset mA2dpSuspended if needed + checkA2dpSuspend(); } updateDevicesAndOutputs(); - audio_devices_t newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); -#ifdef AUDIO_EXTN_FM_ENABLED - if(device == AUDIO_DEVICE_OUT_FM) { - if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { - mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::MUSIC, 1); - newDevice = (audio_devices_t)(getNewDevice(mPrimaryOutput, false) | AUDIO_DEVICE_OUT_FM); - } else { - mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::MUSIC, -1); - } - - AudioParameter param = AudioParameter(); - param.addInt(String8("handle_fm"), (int)newDevice); - ALOGV("setDeviceConnectionState() setParameters handle_fm"); - mpClientInterface->setParameters(mPrimaryOutput, param.toString()); + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + updateCallRouting(newDevice); } -#endif for (size_t i = 0; i < mOutputs.size(); i++) { - // do not force device change on duplicated output because if device is 0, it will - // also force a device 0 for the two outputs it is duplicated to which may override - // a valid device selection on those outputs. - audio_devices_t cachedDevice = getNewDevice(mOutputs.keyAt(i), true /*fromCache*/); - AudioOutputDescriptor *desc = mOutputs.valueFor(mOutputs.keyAt(i)); - if (cachedDevice == AUDIO_DEVICE_OUT_SPEAKER && - device == AUDIO_DEVICE_OUT_PROXY && - (desc->mFlags & AUDIO_OUTPUT_FLAG_FAST)) { - ALOGI("Avoid routing touch tone to spkr as proxy is being disconnected"); - break; + sp desc = mOutputs.valueAt(i); + if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) { + audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/); + // do not force device change on duplicated output because if device is 0, it will + // also force a device 0 for the two outputs it is duplicated to which may override + // a valid device selection on those outputs. + bool force = !desc->isDuplicated() + && (!device_distinguishes_on_address(device) + // always force when disconnecting (a non-duplicated device) + || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); + setOutputDevice(desc, newDevice, force, 0); } - setOutputDevice(mOutputs.keyAt(i), - cachedDevice, - !mOutputs.valueAt(i)->isDuplicated(), - 0); } - if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) { - device = AUDIO_DEVICE_IN_WIRED_HEADSET; - } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO || - device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET || - device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { - device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; - } else if(device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET){ - device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; - } else { - return NO_ERROR; - } - } + mpClientInterface->onAudioPortListUpdate(); + return NO_ERROR; + } // end if is output device + // handle input devices if (audio_is_input_device(device)) { + SortedVector inputs; + ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { // handle input device connection - case AudioSystem::DEVICE_STATE_AVAILABLE: { - if (mAvailableInputDevices & device) { + case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { + if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } - mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN); + sp module = mHwModules.getModuleForDevice(device); + if (module == NULL) { + ALOGW("setDeviceConnectionState(): could not find HW module for device %08x", + device); + return INVALID_OPERATION; + } + if (checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress) != NO_ERROR) { + return INVALID_OPERATION; } - break; + + index = mAvailableInputDevices.add(devDesc); + if (index >= 0) { + mAvailableInputDevices[index]->attach(module); + } else { + return NO_MEMORY; + } + + // Set connect to HALs + AudioParameter param = AudioParameter(devDesc->mAddress); + param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device); + mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); + + // Propagate device availability to Engine + mEngine->setDeviceConnectionState(devDesc, state); + } break; // handle input device disconnection - case AudioSystem::DEVICE_STATE_UNAVAILABLE: { - if (!(mAvailableInputDevices & device)) { + case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { + if (index < 0) { ALOGW("setDeviceConnectionState() device not connected: %d", device); return INVALID_OPERATION; } - mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device); - } break; + + ALOGV("setDeviceConnectionState() disconnecting input device %x", device); + + // Set Disconnect to HALs + AudioParameter param = AudioParameter(devDesc->mAddress); + param.addInt(String8(AUDIO_PARAMETER_DEVICE_DISCONNECT), device); + mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); + + checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress); + mAvailableInputDevices.remove(devDesc); + + // Propagate device availability to Engine + mEngine->setDeviceConnectionState(devDesc, state); + } break; default: ALOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } - audio_io_handle_t activeInput = getActiveInput(); - if (activeInput != 0) { - AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); - audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { - ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", - inputDesc->mDevice, newDevice, activeInput); - inputDesc->mDevice = newDevice; - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); - mpClientInterface->setParameters(activeInput, param.toString()); - } + closeAllInputs(); + + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + updateCallRouting(newDevice); } + mpClientInterface->onAudioPortListUpdate(); return NO_ERROR; - } + } // end if is input device ALOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE; } +// This function checks for the parameters which can be offloaded. +// This can be enhanced depending on the capability of the DSP and policy +// of the system. +bool AudioPolicyManagerCustom::isOffloadSupported(const audio_offload_info_t& offloadInfo) +{ + ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d," + " BitRate=%u, duration=%" PRId64 " us, has_video=%d", + offloadInfo.sample_rate, offloadInfo.channel_mask, + offloadInfo.format, + offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, + offloadInfo.has_video); -void AudioPolicyManager::setPhoneState(int state) + // Check if offload has been disabled + char propValue[PROPERTY_VALUE_MAX]; + if (property_get("audio.offload.disable", propValue, "0")) { + if (atoi(propValue) != 0) { + ALOGV("offload disabled by audio.offload.disable=%s", propValue ); + return false; + } + } + + // Check if stream type is music, then only allow offload as of now. + if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC) + { + ALOGV("isOffloadSupported: stream_type != MUSIC, returning false"); + return false; + } + //check if it's multi-channel AAC (includes sub formats) and FLAC format + if ((popcount(offloadInfo.channel_mask) > 2) && + (((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_FLAC)|| + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_VORBIS))) { + ALOGD("offload disabled for multi-channel AAC,FLAC and VORBIS format"); + return false; + } + + //TODO: enable audio offloading with video when ready + const bool allowOffloadWithVideo = + property_get_bool("audio.offload.video", false /* default_value */); + if (offloadInfo.has_video && !allowOffloadWithVideo) { + ALOGV("isOffloadSupported: has_video == true, returning false"); + return false; + } + + //If duration is less than minimum value defined in property, return false + if (property_get("audio.offload.min.duration.secs", propValue, NULL)) { + if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) { + ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue); + return false; + } + } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) { + ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS); + //duration checks only valid for MP3/AAC/ formats, + //do not check duration for other audio formats, e.g. dolby AAC/AC3 and amrwb+ formats + if ((offloadInfo.format == AUDIO_FORMAT_MP3) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_FLAC) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_VORBIS) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_WMA) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_WMA_PRO) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_ALAC) || + ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_APE)) + return false; + + } + + // Do not allow offloading if one non offloadable effect is enabled. This prevents from + // creating an offloaded track and tearing it down immediately after start when audioflinger + // detects there is an active non offloadable effect. + // FIXME: We should check the audio session here but we do not have it in this context. + // This may prevent offloading in rare situations where effects are left active by apps + // in the background. + if (mEffects.isNonOffloadableEffectEnabled()) { + return false; + } + // Check for soundcard status + String8 valueStr = mpClientInterface->getParameters((audio_io_handle_t)0, + String8("SND_CARD_STATUS")); + AudioParameter result = AudioParameter(valueStr); + int isonline = 0; + if ((result.getInt(String8("SND_CARD_STATUS"), isonline) == NO_ERROR) + && !isonline) { + ALOGD("copl: soundcard is offline rejecting offload request"); + return false; + } + // See if there is a profile to support this. + // AUDIO_DEVICE_NONE + sp profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */, + offloadInfo.sample_rate, + offloadInfo.format, + offloadInfo.channel_mask, + AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + ALOGV("isOffloadSupported() profile %sfound", profile != 0 ? "" : "NOT "); + return (profile != 0); +} +audio_devices_t AudioPolicyManagerCustom::getNewOutputDevice(const sp& outputDesc, + bool fromCache) { - ALOGV("setPhoneState() state %d", state); - audio_devices_t newDevice = AUDIO_DEVICE_NONE; - if (state < 0 || state >= AudioSystem::NUM_MODES) { - ALOGW("setPhoneState() invalid state %d", state); - return; + audio_devices_t device = AUDIO_DEVICE_NONE; + + ssize_t index = mAudioPatches.indexOfKey(outputDesc->mPatchHandle); + if (index >= 0) { + sp patchDesc = mAudioPatches.valueAt(index); + if (patchDesc->mUid != mUidCached) { + ALOGV("getNewOutputDevice() device %08x forced by patch %d", + outputDesc->device(), outputDesc->mPatchHandle); + return outputDesc->device(); + } } - if (state == mPhoneState ) { - ALOGW("setPhoneState() setting same state %d", state); - return; + // check the following by order of priority to request a routing change if necessary: + // 1: the strategy enforced audible is active and enforced on the output: + // use device for strategy enforced audible + // 2: we are in call or the strategy phone is active on the output: + // use device for strategy phone + // 3: the strategy for enforced audible is active but not enforced on the output: + // use the device for strategy enforced audible + // 4: the strategy sonification is active on the output: + // use device for strategy sonification + // 5: the strategy "respectful" sonification is active on the output: + // use device for strategy "respectful" sonification + // 6: the strategy accessibility is active on the output: + // use device for strategy accessibility + // 7: the strategy media is active on the output: + // use device for strategy media + // 8: the strategy DTMF is active on the output: + // use device for strategy DTMF + // 9: the strategy for beacon, a.k.a. "transmitted through speaker" is active on the output: + // use device for strategy t-t-s + if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE) && + mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) { + device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); + } else if (isInCall() || + isStrategyActive(outputDesc, STRATEGY_PHONE)|| + isStrategyActive(mPrimaryOutput, STRATEGY_PHONE)) { + device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) { + device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)|| + (isStrategyActive(mPrimaryOutput,STRATEGY_SONIFICATION) + && (!isStrategyActive(mPrimaryOutput,STRATEGY_MEDIA)))) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)|| + (isStrategyActive(mPrimaryOutput,STRATEGY_SONIFICATION_RESPECTFUL) + && (!isStrategyActive(mPrimaryOutput, STRATEGY_MEDIA)))) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) { + device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_MEDIA)) { + device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_DTMF)) { + device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) { + device = getDeviceForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache); + } else if (isStrategyActive(outputDesc, STRATEGY_REROUTING)) { + device = getDeviceForStrategy(STRATEGY_REROUTING, fromCache); } + ALOGV("getNewOutputDevice() selected device %x", device); + return device; +} +void AudioPolicyManagerCustom::setPhoneState(audio_mode_t state) +{ + ALOGV("setPhoneState() state %d", state); + // store previous phone state for management of sonification strategy below + int oldState = mEngine->getPhoneState(); + + if (mEngine->setPhoneState(state) != NO_ERROR) { + ALOGW("setPhoneState() invalid or same state %d", state); + return; + } + /// Opens: can these line be executed after the switch of volume curves??? // if leaving call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() if (isInCall()) { ALOGV("setPhoneState() in call state management: new state is %d", state); - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - handleIncallSonification(stream, false, true); - } - } + for (size_t j = 0; j < mOutputs.size(); j++) { + audio_io_handle_t curOutput = mOutputs.keyAt(j); + for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } - // store previous phone state for management of sonification strategy below - int oldState = mPhoneState; - mPhoneState = state; - bool force = false; - - // are we entering or starting a call - if (!isStateInCall(oldState) && isStateInCall(state)) { - ALOGV(" Entering call in setPhoneState()"); - // force routing command to audio hardware when starting a call - // even if no device change is needed - force = true; - for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { - mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] = - sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]; - } - } else if (isStateInCall(oldState) && !isStateInCall(state)) { - ALOGV(" Exiting call in setPhoneState()"); - // force routing command to audio hardware when exiting a call - // even if no device change is needed - force = true; - for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { - mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] = - sVolumeProfiles[AUDIO_STREAM_DTMF][j]; + handleIncallSonification((audio_stream_type_t)stream, false, true, curOutput); + } } - } else if (isStateInCall(state) && (state != oldState)) { - ALOGV(" Switching between telephony and VoIP in setPhoneState()"); - // force routing command to audio hardware when switching between telephony and VoIP - // even if no device change is needed - force = true; + + // force reevaluating accessibility routing when call starts + mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } + /** + * Switching to or from incall state or switching between telephony and VoIP lead to force + * routing command. + */ + bool force = ((is_state_in_call(oldState) != is_state_in_call(state)) + || (is_state_in_call(state) && (state != oldState))); + // check for device and output changes triggered by new phone state - newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); - - // force routing command to audio hardware when ending call - // even if no device change is needed - if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) { - newDevice = hwOutputDesc->device(); - } + sp hwOutputDesc = mPrimaryOutput; int delayMs = 0; if (isStateInCall(state)) { nsecs_t sysTime = systemTime(); for (size_t i = 0; i < mOutputs.size(); i++) { - AudioOutputDescriptor *desc = mOutputs.valueAt(i); + sp desc = mOutputs.valueAt(i); // mute media and sonification strategies and delay device switch by the largest // latency of any output where either strategy is active. // This avoid sending the ring tone or music tail into the earpiece or headset. - if ((desc->isStrategyActive(STRATEGY_MEDIA, - SONIFICATION_HEADSET_MUSIC_DELAY, - sysTime) || - desc->isStrategyActive(STRATEGY_SONIFICATION, - SONIFICATION_HEADSET_MUSIC_DELAY, - sysTime)) && - (delayMs < (int)desc->mLatency*2)) { - delayMs = desc->mLatency*2; + if ((isStrategyActive(desc, STRATEGY_MEDIA, + SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime) || + isStrategyActive(desc, STRATEGY_SONIFICATION, + SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime)) && + (delayMs < (int)desc->latency()*2)) { + delayMs = desc->latency()*2; } - setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); - setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, + setStrategyMute(STRATEGY_MEDIA, true, desc); + setStrategyMute(STRATEGY_MEDIA, false, desc, MUTE_TIME_MS, getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); - setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i)); - setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS, + setStrategyMute(STRATEGY_SONIFICATION, true, desc); + setStrategyMute(STRATEGY_SONIFICATION, false, desc, MUTE_TIME_MS, getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/)); } + ALOGV("Setting the delay from %dms to %dms", delayMs, + MIN(delayMs, MAX_VOICE_CALL_START_DELAY_MS)); + delayMs = MIN(delayMs, MAX_VOICE_CALL_START_DELAY_MS); } - // change routing is necessary - setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); + if (hasPrimaryOutput()) { + // Note that despite the fact that getNewOutputDevice() is called on the primary output, + // the device returned is not necessarily reachable via this output + audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + // force routing command to audio hardware when ending call + // even if no device change is needed + if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) { + rxDevice = mPrimaryOutput->device(); + } - //update device for all non-primary outputs - for (size_t i = 0; i < mOutputs.size(); i++) { - audio_io_handle_t output = mOutputs.keyAt(i); - if (output != mPrimaryOutput) { - newDevice = getNewDevice(output, false /*fromCache*/); - setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + if (state == AUDIO_MODE_IN_CALL) { + updateCallRouting(rxDevice, delayMs); + } else if (oldState == AUDIO_MODE_IN_CALL) { + if (mCallRxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0); + mCallRxPatch.clear(); + } + if (mCallTxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0); + mCallTxPatch.clear(); + } + setOutputDevice(mPrimaryOutput, rxDevice, force, 0); + } else { + setOutputDevice(mPrimaryOutput, rxDevice, force, 0); } } @@ -379,626 +551,274 @@ void AudioPolicyManager::setPhoneState(int state) // pertaining to sonification strategy see handleIncallSonification() if (isStateInCall(state)) { ALOGV("setPhoneState() in call state management: new state is %d", state); - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - handleIncallSonification(stream, true, true); + for (size_t j = 0; j < mOutputs.size(); j++) { + audio_io_handle_t curOutput = mOutputs.keyAt(j); + for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } + handleIncallSonification((audio_stream_type_t)stream, true, true, curOutput); + } } } // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE - if (state == AudioSystem::MODE_RINGTONE && - isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) { + if (state == AUDIO_MODE_RINGTONE && + isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) { mLimitRingtoneVolume = true; } else { mLimitRingtoneVolume = false; } } - -void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) +status_t AudioPolicyManagerCustom::stopSource(sp outputDesc, + audio_stream_type_t stream, + bool forceDeviceUpdate) { - ALOGD("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); - - bool forceVolumeReeval = false; - switch(usage) { - case AudioSystem::FOR_COMMUNICATION: - if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO && - config != AudioSystem::FORCE_NONE) { - ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); - return; - } - forceVolumeReeval = true; - mForceUse[usage] = config; - break; - case AudioSystem::FOR_MEDIA: - if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP && -#ifdef AUDIO_EXTN_FM_ENABLED - config != AudioSystem::FORCE_SPEAKER && -#endif - config != AudioSystem::FORCE_WIRED_ACCESSORY && - config != AudioSystem::FORCE_ANALOG_DOCK && - config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE && - config != AudioSystem::FORCE_NO_BT_A2DP) { - ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config); - return; - } - mForceUse[usage] = config; - break; - case AudioSystem::FOR_RECORD: - if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY && - config != AudioSystem::FORCE_NONE) { - ALOGW("setForceUse() invalid config %d for FOR_RECORD", config); - return; - } - mForceUse[usage] = config; - break; - case AudioSystem::FOR_DOCK: - if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK && - config != AudioSystem::FORCE_BT_DESK_DOCK && - config != AudioSystem::FORCE_WIRED_ACCESSORY && - config != AudioSystem::FORCE_ANALOG_DOCK && - config != AudioSystem::FORCE_DIGITAL_DOCK) { - ALOGW("setForceUse() invalid config %d for FOR_DOCK", config); - } - forceVolumeReeval = true; - mForceUse[usage] = config; - break; - case AudioSystem::FOR_SYSTEM: - if (config != AudioSystem::FORCE_NONE && - config != AudioSystem::FORCE_SYSTEM_ENFORCED) { - ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config); - } - forceVolumeReeval = true; - mForceUse[usage] = config; - break; - default: - ALOGW("setForceUse() invalid usage %d", usage); - break; - } + // always handle stream stop, check which stream type is stopping + handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); - // check for device and output changes triggered by new force usage - checkA2dpSuspend(); - checkOutputForAllStrategies(); - updateDevicesAndOutputs(); - for (int i = 0; i < mOutputs.size(); i++) { - audio_io_handle_t output = mOutputs.keyAt(i); - audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/); - setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); - if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { - applyStreamVolumes(output, newDevice, 0, true); - } - } - - audio_io_handle_t activeInput = getActiveInput(); - if (activeInput != 0) { - AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); - audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { - ALOGV("setForceUse() changing device from %x to %x for input %d", - inputDesc->mDevice, newDevice, activeInput); - inputDesc->mDevice = newDevice; - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); - mpClientInterface->setParameters(activeInput, param.toString()); + // handle special case for sonification while in call + if (isInCall()) { + if (outputDesc->isDuplicated()) { + handleIncallSonification(stream, false, false, outputDesc->mIoHandle); + handleIncallSonification(stream, false, false, outputDesc->mIoHandle); } + handleIncallSonification(stream, false, false, outputDesc->mIoHandle); } -} - -audio_io_handle_t AudioPolicyManager::getInput(int inputSource, - uint32_t samplingRate, - uint32_t format, - uint32_t channelMask, - AudioSystem::audio_in_acoustics acoustics) -{ - audio_io_handle_t input = 0; - audio_devices_t device = getDeviceForInputSource(inputSource); - - ALOGD("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x", - inputSource, samplingRate, format, channelMask, acoustics); - - if (device == AUDIO_DEVICE_NONE) { - ALOGW("getInput() could not find device for inputSource %d", inputSource); - return 0; - } - - - IOProfile *profile = getInputProfile(device, - samplingRate, - format, - channelMask); - if (profile == NULL) { - ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d," - "channelMask %04x", - device, samplingRate, format, channelMask); - return 0; - } - - if (profile->mModule->mHandle == 0) { - ALOGE("getInput(): HW module %s not opened", profile->mModule->mName); - return 0; - } - - AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile); - - inputDesc->mInputSource = inputSource; - inputDesc->mDevice = device; - inputDesc->mSamplingRate = samplingRate; - inputDesc->mFormat = (audio_format_t)format; - inputDesc->mChannelMask = (audio_channel_mask_t)channelMask; - inputDesc->mRefCount = 0; - input = mpClientInterface->openInput(profile->mModule->mHandle, - &inputDesc->mDevice, - &inputDesc->mSamplingRate, - &inputDesc->mFormat, - &inputDesc->mChannelMask); - - // only accept input with the exact requested set of parameters - if (input == 0 || - (samplingRate != inputDesc->mSamplingRate) || - (format != inputDesc->mFormat) || - (channelMask != inputDesc->mChannelMask)) { - ALOGV("getInput() failed opening input: samplingRate %d, format %d, channelMask %d", - samplingRate, format, channelMask); - if (input != 0) { - mpClientInterface->closeInput(input); + if (outputDesc->mRefCount[stream] > 0) { + // decrement usage count of this stream on the output + outputDesc->changeRefCount(stream, -1); + + // store time at which the stream was stopped - see isStreamActive() + if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) { + outputDesc->mStopTime[stream] = systemTime(); + audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/); + // delay the device switch by twice the latency because stopOutput() is executed when + // the track stop() command is received and at that time the audio track buffer can + // still contain data that needs to be drained. The latency only covers the audio HAL + // and kernel buffers. Also the latency does not always include additional delay in the + // audio path (audio DSP, CODEC ...) + setOutputDevice(outputDesc, newDevice, false, outputDesc->latency()*2); + + // force restoring the device selection on other active outputs if it differs from the + // one being selected for this output + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t curOutput = mOutputs.keyAt(i); + sp desc = mOutputs.valueAt(i); + if (desc != outputDesc && + desc->isActive() && + outputDesc->sharesHwModuleWith(desc) && + (newDevice != desc->device())) { + setOutputDevice(desc, + getNewOutputDevice(desc, false /*fromCache*/), + true, + outputDesc->latency()*2); + } + } + // update the outputs if stopping one with a stream that can affect notification routing + handleNotificationRoutingForStream(stream); } - delete inputDesc; - return 0; - } - mInputs.add(input, inputDesc); - ALOGD("getInput() returns input %d", input); - - return input; -} - -AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(AudioSystem::stream_type stream) -{ - // stream to strategy mapping - switch (stream) { - case AudioSystem::VOICE_CALL: - case AudioSystem::BLUETOOTH_SCO: - return STRATEGY_PHONE; - case AudioSystem::RING: - case AudioSystem::ALARM: - return STRATEGY_SONIFICATION; - case AudioSystem::NOTIFICATION: - return STRATEGY_SONIFICATION_RESPECTFUL; - case AudioSystem::DTMF: - return STRATEGY_DTMF; - default: - ALOGE("unknown stream type"); - case AudioSystem::SYSTEM: - // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs - // while key clicks are played produces a poor result - case AudioSystem::TTS: - case AudioSystem::MUSIC: -#ifdef AUDIO_EXTN_INCALL_MUSIC_ENABLED - case AudioSystem::INCALL_MUSIC: -#endif - return STRATEGY_MEDIA; - case AudioSystem::ENFORCED_AUDIBLE: - return STRATEGY_ENFORCED_AUDIBLE; + return NO_ERROR; + } else { + ALOGW("stopOutput() refcount is already 0"); + return INVALID_OPERATION; } } - -audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, - bool fromCache) +status_t AudioPolicyManagerCustom::startSource(sp outputDesc, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t *delayMs) { - uint32_t device = AUDIO_DEVICE_NONE; - - if (fromCache) { - ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x", - strategy, mDeviceForStrategy[strategy]); - return mDeviceForStrategy[strategy]; - } - - switch (strategy) { - - case STRATEGY_SONIFICATION_RESPECTFUL: - if (isInCall()) { - device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); - } else if (isStreamActiveRemotely(AudioSystem::MUSIC, - SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { - // while media is playing on a remote device, use the the sonification behavior. - // Note that we test this usecase before testing if media is playing because - // the isStreamActive() method only informs about the activity of a stream, not - // if it's for local playback. Note also that we use the same delay between both tests - device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); - } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { - // while media is playing (or has recently played), use the same device - device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); + // cannot start playback of STREAM_TTS if any other output is being used + uint32_t beaconMuteLatency = 0; + + *delayMs = 0; + if (stream == AUDIO_STREAM_TTS) { + ALOGV("\t found BEACON stream"); + if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { + return INVALID_OPERATION; } else { - // when media is not playing anymore, fall back on the sonification behavior - device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + beaconMuteLatency = handleEventForBeacon(STARTING_BEACON); } + } else { + // some playback other than beacon starts + beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT); + } - break; - - case STRATEGY_DTMF: - if (!isInCall()) { - // when off call, DTMF strategy follows the same rules as MEDIA strategy - device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); - break; - } - // when in call, DTMF and PHONE strategies follow the same rules - // FALL THROUGH - - case STRATEGY_PHONE: - // for phone strategy, we first consider the forced use and then the available devices by order - // of priority - switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { - case AudioSystem::FORCE_BT_SCO: - if (!isInCall() || strategy != STRATEGY_DTMF) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; - if (device) break; - } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO; - if (device) break; - // if SCO device is requested but no SCO device is available, fall back to default case - // FALL THROUGH - - default: // FORCE_NONE - // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP - if (mHasA2dp && !isInCall() && - (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && - (getA2dpOutput() != 0) && !mA2dpSuspended) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; - if (device) break; - } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; - if (device) break; - if (mPhoneState != AudioSystem::MODE_IN_CALL) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; - if (device) break; - } - - // Allow voice call on USB ANLG DOCK headset - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; - if (device) break; + // increment usage count for this stream on the requested output: + // NOTE that the usage count is the same for duplicated output and hardware output which is + // necessary for a correct control of hardware output routing by startOutput() and stopOutput() + outputDesc->changeRefCount(stream, 1); - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE; - if (device) break; - device = mDefaultOutputDevice; - if (device == AUDIO_DEVICE_NONE) { - ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE"); - } - break; - - case AudioSystem::FORCE_SPEAKER: - // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to - // A2DP speaker when forcing to speaker output - if (mHasA2dp && !isInCall() && - (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && - (getA2dpOutput() != 0) && !mA2dpSuspended) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; - if (device) break; - } - if (mPhoneState != AudioSystem::MODE_IN_CALL) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; - if (device) break; - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; - if (device) break; - } - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; - if (device) break; - device = mDefaultOutputDevice; - if (device == AUDIO_DEVICE_NONE) { - ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER"); - } - break; + if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) { + // starting an output being rerouted? + if (device == AUDIO_DEVICE_NONE) { + device = getNewOutputDevice(outputDesc, false /*fromCache*/); } - // FIXME: Why do need to replace with speaker? If voice call is active - // We should use device from STRATEGY_PHONE -#ifdef AUDIO_EXTN_FM_ENABLED - if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) { - if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) { - device = AUDIO_DEVICE_OUT_SPEAKER; + routing_strategy strategy = getStrategy(stream); + bool shouldWait = (strategy == STRATEGY_SONIFICATION) || + (strategy == STRATEGY_SONIFICATION_RESPECTFUL) || + (beaconMuteLatency > 0); + uint32_t waitMs = beaconMuteLatency; + bool force = false; + for (size_t i = 0; i < mOutputs.size(); i++) { + sp desc = mOutputs.valueAt(i); + if (desc != outputDesc) { + // force a device change if any other output is managed by the same hw + // module and has a current device selection that differs from selected device. + // In this case, the audio HAL must receive the new device selection so that it can + // change the device currently selected by the other active output. + if (outputDesc->sharesHwModuleWith(desc) && + desc->device() != device) { + force = true; + } + // wait for audio on other active outputs to be presented when starting + // a notification so that audio focus effect can propagate, or that a mute/unmute + // event occurred for beacon + uint32_t latency = desc->latency(); + if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) { + waitMs = latency; + } } } -#endif - break; - - case STRATEGY_SONIFICATION: + uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force); - // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by - // handleIncallSonification(). + // handle special case for sonification while in call if (isInCall()) { - device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); - break; + handleIncallSonification(stream, true, false, outputDesc->mIoHandle); } - // FALL THROUGH - - case STRATEGY_ENFORCED_AUDIBLE: - // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION - // except: - // - when in call where it doesn't default to STRATEGY_PHONE behavior - // - in countries where not enforced in which case it follows STRATEGY_MEDIA - - if ((strategy == STRATEGY_SONIFICATION) || - (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) { - device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; - if (device == AUDIO_DEVICE_NONE) { - ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION"); - } - } - // The second device used for sonification is the same as the device used by media strategy - // FALL THROUGH - case STRATEGY_MEDIA: { - uint32_t device2 = AUDIO_DEVICE_NONE; + // apply volume rules for current stream and device if necessary + checkAndSetVolume(stream, + mStreams.valueFor(stream).getVolumeIndex(device), + outputDesc, + device); - if (isInCall() && (device == AUDIO_DEVICE_NONE)) { - // when in call, get the device for Phone strategy - device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); - break; - } -#ifdef AUDIO_EXTN_FM_ENABLED - if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) { - device = AUDIO_DEVICE_OUT_SPEAKER; - break; - } -#endif + // update the outputs if starting an output with a stream that can affect notification + // routing + handleNotificationRoutingForStream(stream); - if (strategy != STRATEGY_SONIFICATION) { - // no sonification on remote submix (e.g. WFD) - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; - } - if ((device2 == AUDIO_DEVICE_NONE) && - mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && - (getA2dpOutput() != 0) && !mA2dpSuspended) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; - } - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; - } - } - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; - } - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + // force reevaluating accessibility routing when ringtone or alarm starts + if (strategy == STRATEGY_SONIFICATION) { + mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; - } - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; - } - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; - } - if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) - && (device2 == AUDIO_DEVICE_NONE)) { - // no sonification on aux digital (e.g. HDMI) - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; - } - if ((device2 == AUDIO_DEVICE_NONE) && - (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK) - && (strategy != STRATEGY_SONIFICATION)) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + } + else { + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, true, false, outputDesc->mIoHandle); + } } -#ifdef AUDIO_EXTN_FM_ENABLED - if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) - && (device2 == AUDIO_DEVICE_NONE)) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX; + return NO_ERROR; +} +void AudioPolicyManagerCustom::handleIncallSonification(audio_stream_type_t stream, + bool starting, bool stateChange, + audio_io_handle_t output) +{ + if(!hasPrimaryOutput()) { + return; + } + // no action needed for AUDIO_STREAM_PATCH stream type, it's for internal flinger tracks + if (stream == AUDIO_STREAM_PATCH) { + return; + } + // if the stream pertains to sonification strategy and we are in call we must + // mute the stream if it is low visibility. If it is high visibility, we must play a tone + // in the device used for phone strategy and play the tone if the selected device does not + // interfere with the device used for phone strategy + // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as + // many times as there are active tracks on the output + const routing_strategy stream_strategy = getStrategy(stream); + if ((stream_strategy == STRATEGY_SONIFICATION) || + ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) { + sp outputDesc = mOutputs.valueFor(output); + ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", + stream, starting, outputDesc->mDevice, stateChange); + if (outputDesc->mRefCount[stream]) { + int muteCount = 1; + if (stateChange) { + muteCount = outputDesc->mRefCount[stream]; } -#endif -#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED - if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) - && (device2 == AUDIO_DEVICE_NONE)) { - // no sonification on WFD sink - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY; + if (audio_is_low_visibility(stream)) { + ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount); + for (int i = 0; i < muteCount; i++) { + setStreamMute(stream, starting, outputDesc); + } + } else { + ALOGV("handleIncallSonification() high visibility"); + if (outputDesc->device() & + getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) { + ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount); + for (int i = 0; i < muteCount; i++) { + setStreamMute(stream, starting, outputDesc); + } + } + if (starting) { + mpClientInterface->startTone(AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION, + AUDIO_STREAM_VOICE_CALL); + } else { + mpClientInterface->stopTone(); + } } -#endif - if (device2 == AUDIO_DEVICE_NONE) { - device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; } - - // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or - // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise - device |= device2; - if (device) break; - device = mDefaultOutputDevice; - if (device == AUDIO_DEVICE_NONE) { - ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); - } - } break; - - default: - ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy); - break; } - - ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device); - return device; } - -audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource) -{ - uint32_t device = AUDIO_DEVICE_NONE; - - switch (inputSource) { - case AUDIO_SOURCE_VOICE_UPLINK: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { - device = AUDIO_DEVICE_IN_VOICE_CALL; - break; - } - // FALL THROUGH - - case AUDIO_SOURCE_DEFAULT: - case AUDIO_SOURCE_MIC: - case AUDIO_SOURCE_VOICE_RECOGNITION: - case AUDIO_SOURCE_HOTWORD: - case AUDIO_SOURCE_VOICE_COMMUNICATION: - if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && - mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { - device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) { - device = AUDIO_DEVICE_IN_WIRED_HEADSET; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) { - device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { - device = AUDIO_DEVICE_IN_BUILTIN_MIC; - } - break; - case AUDIO_SOURCE_CAMCORDER: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) { - device = AUDIO_DEVICE_IN_BACK_MIC; - } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { - device = AUDIO_DEVICE_IN_BUILTIN_MIC; - } - break; - case AUDIO_SOURCE_VOICE_DOWNLINK: - case AUDIO_SOURCE_VOICE_CALL: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { - device = AUDIO_DEVICE_IN_VOICE_CALL; - } - break; - case AUDIO_SOURCE_REMOTE_SUBMIX: - if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { - device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; - } - break; -#ifdef AUDIO_EXTN_FM_ENABLED - case AUDIO_SOURCE_FM_RX: - device = AUDIO_DEVICE_IN_FM_RX; - break; - case AUDIO_SOURCE_FM_RX_A2DP: - device = AUDIO_DEVICE_IN_FM_RX_A2DP; +void AudioPolicyManagerCustom::handleNotificationRoutingForStream(audio_stream_type_t stream) { + switch(stream) { + case AUDIO_STREAM_MUSIC: + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + updateDevicesAndOutputs(); break; -#endif default: - ALOGW("getDeviceForInputSource() invalid input source %d", inputSource); break; } - ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device); - return device; } - -AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device) +status_t AudioPolicyManagerCustom::checkAndSetVolume(audio_stream_type_t stream, + int index, + const sp& outputDesc, + audio_devices_t device, + int delayMs, bool force) { - switch(getDeviceForVolume(device)) { - case AUDIO_DEVICE_OUT_EARPIECE: - return DEVICE_CATEGORY_EARPIECE; - case AUDIO_DEVICE_OUT_WIRED_HEADSET: - case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: - case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: - case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: - case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: - case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: -#ifdef AUDIO_EXTN_FM_ENABLED - case AUDIO_DEVICE_OUT_FM: -#endif - return DEVICE_CATEGORY_HEADSET; - case AUDIO_DEVICE_OUT_SPEAKER: - case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: - case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: - case AUDIO_DEVICE_OUT_AUX_DIGITAL: - case AUDIO_DEVICE_OUT_USB_ACCESSORY: - case AUDIO_DEVICE_OUT_USB_DEVICE: - case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: -#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED - case AUDIO_DEVICE_OUT_PROXY: -#endif - default: - return DEVICE_CATEGORY_SPEAKER; - } -} - -bool AudioPolicyManager::isDirectOutput(audio_io_handle_t output) { - for (size_t i = 0; i < mOutputs.size(); i++) { - audio_io_handle_t curOutput = mOutputs.keyAt(i); - AudioOutputDescriptor *desc = mOutputs.valueAt(i); - if ((curOutput == output) && (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { - return true; - } - } - return false; -} - -status_t AudioPolicyManager::checkAndSetVolume(int stream, - int index, - audio_io_handle_t output, - audio_devices_t device, - int delayMs, - bool force) -{ - ALOGV("checkAndSetVolume: index %d output %d device %x", index, output, device); // do not change actual stream volume if the stream is muted - if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { + if (outputDesc->mMuteCount[stream] != 0) { ALOGVV("checkAndSetVolume() stream %d muted count %d", - stream, mOutputs.valueFor(output)->mMuteCount[stream]); + stream, outputDesc->mMuteCount[stream]); return NO_ERROR; } - + audio_policy_forced_cfg_t forceUseForComm = + mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION); // do not change in call volume if bluetooth is connected and vice versa - if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || - (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { + if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) || + (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) { ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", - stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); + stream, forceUseForComm); return INVALID_OPERATION; } - float volume = computeVolume(stream, index, output, device); - // We actually change the volume if: - // - the float value returned by computeVolume() changed - // - the force flag is set - if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || - force) { - mOutputs.valueFor(output)->mCurVolume[stream] = volume; - ALOGV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); - // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is - // enabled - if (stream == AudioSystem::BLUETOOTH_SCO) { - mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs); -#ifdef AUDIO_EXTN_FM_ENABLED - } else if (stream == AudioSystem::MUSIC && - output == mPrimaryOutput) { - float fmVolume = -1.0; - fmVolume = computeVolume(stream, index, output, device); - if (fmVolume >= 0) { - AudioParameter param = AudioParameter(); - param.addFloat(String8("fm_volume"), fmVolume); - ALOGV("checkAndSetVolume setParameters fm_volume, volume=:%f delay=:%d",fmVolume,delayMs*2); - //Double delayMs to avoid sound burst while device switch. - mpClientInterface->setParameters(mPrimaryOutput, param.toString(), delayMs*2); - } -#endif - } - mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); + if (device == AUDIO_DEVICE_NONE) { + device = outputDesc->device(); } - if (stream == AudioSystem::VOICE_CALL || - stream == AudioSystem::BLUETOOTH_SCO) { - float voiceVolume; + float volumeDb = computeVolume(stream, index, device); + if (outputDesc->isFixedVolume(device)) { + volumeDb = 0.0f; + } + + outputDesc->setVolume(volumeDb, stream, device, delayMs, force); - if (stream == AudioSystem::VOICE_CALL) - voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; - else - // Force voice volume to max for bluetooth SCO as volume is managed by the headset + if (stream == AUDIO_STREAM_VOICE_CALL || + stream == AUDIO_STREAM_BLUETOOTH_SCO) { + float voiceVolume; + // Force voice volume to max for bluetooth SCO as volume is managed by the headset + if (stream == AUDIO_STREAM_VOICE_CALL) { + voiceVolume = (float)index/(float)mStreams.valueFor(stream).getVolumeIndexMax(); + } else { voiceVolume = 1.0; + } - if (voiceVolume != mLastVoiceVolume && ((output == mPrimaryOutput) || - isDirectOutput(output))) { + if (voiceVolume != mLastVoiceVolume && ((outputDesc == mPrimaryOutput) || + isDirectOutput(outputDesc->mIoHandle) || device & AUDIO_DEVICE_OUT_ALL_USB)) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } @@ -1006,170 +826,254 @@ status_t AudioPolicyManager::checkAndSetVolume(int stream, return NO_ERROR; } - - -float AudioPolicyManager::computeVolume(int stream, - int index, - audio_io_handle_t output, - audio_devices_t device) +bool AudioPolicyManagerCustom::isDirectOutput(audio_io_handle_t output) { + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t curOutput = mOutputs.keyAt(i); + sp desc = mOutputs.valueAt(i); + if ((curOutput == output) && (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { + return true; + } + } + return false; +} +audio_io_handle_t AudioPolicyManagerCustom::getOutputForDevice( + audio_devices_t device, + audio_session_t session __unused, + audio_stream_type_t stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { - float volume = 1.0; - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); - - if (device == AUDIO_DEVICE_NONE) { - device = outputDesc->device(); + audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; + uint32_t latency = 0; + status_t status; + +#ifdef AUDIO_POLICY_TEST + if (mCurOutput != 0) { + ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d", + mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput); + + if (mTestOutputs[mCurOutput] == 0) { + ALOGV("getOutput() opening test output"); + sp outputDesc = new SwAudioOutputDescriptor(NULL, + mpClientInterface); + outputDesc->mDevice = mTestDevice; + outputDesc->mLatency = mTestLatencyMs; + outputDesc->mFlags = + (audio_output_flags_t)(mDirectOutput ? AUDIO_OUTPUT_FLAG_DIRECT : 0); + outputDesc->mRefCount[stream] = 0; + audio_config_t config = AUDIO_CONFIG_INITIALIZER; + config.sample_rate = mTestSamplingRate; + config.channel_mask = mTestChannels; + config.format = mTestFormat; + if (offloadInfo != NULL) { + config.offload_info = *offloadInfo; + } + status = mpClientInterface->openOutput(0, + &mTestOutputs[mCurOutput], + &config, + &outputDesc->mDevice, + String8(""), + &outputDesc->mLatency, + outputDesc->mFlags); + if (status == NO_ERROR) { + outputDesc->mSamplingRate = config.sample_rate; + outputDesc->mFormat = config.format; + outputDesc->mChannelMask = config.channel_mask; + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"),mCurOutput); + mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString()); + addOutput(mTestOutputs[mCurOutput], outputDesc); + } + } + return mTestOutputs[mCurOutput]; } - - // if volume is not 0 (not muted), force media volume to max on digital output - if (stream == AudioSystem::MUSIC && - index != mStreams[stream].mIndexMin && - (device == AUDIO_DEVICE_OUT_AUX_DIGITAL || - device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET || - device == AUDIO_DEVICE_OUT_USB_ACCESSORY || -#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED - device == AUDIO_DEVICE_OUT_PROXY || -#endif - device == AUDIO_DEVICE_OUT_USB_DEVICE )) { - return 1.0; +#endif //AUDIO_POLICY_TEST + if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) && + (stream != AUDIO_STREAM_MUSIC)) { + // compress should not be used for non-music streams + ALOGE("Offloading only allowed with music stream"); + return 0; } -#ifdef AUDIO_EXTN_INCALL_MUSIC_ENABLED - if (stream == AudioSystem::INCALL_MUSIC) { - return 1.0; + /* + * WFD audio routes back to target speaker when starting a ringtone playback. + * This is because primary output is reused for ringtone, so output device is + * updated based on SONIFICATION strategy for both ringtone and music playback. + * The same issue is not seen on remoted_submix HAL based WFD audio because + * primary output is not reused and a new output is created for ringtone playback. + * Issue is fixed by updating output flag to AUDIO_OUTPUT_FLAG_FAST when there is + * a non-music stream playback on WFD, so primary output is not reused for ringtone. + */ + audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types(); + if ((availableOutputDeviceTypes & AUDIO_DEVICE_OUT_PROXY) + && (stream != AUDIO_STREAM_MUSIC)) { + ALOGD("WFD audio: use OUTPUT_FLAG_FAST for non music stream. flags:%x", flags ); + //For voip paths + if(flags & AUDIO_OUTPUT_FLAG_DIRECT) + flags = AUDIO_OUTPUT_FLAG_DIRECT; + else //route every thing else to ULL path + flags = AUDIO_OUTPUT_FLAG_FAST; + } + // open a direct output if required by specified parameters + //force direct flag if offload flag is set: offloading implies a direct output stream + // and all common behaviors are driven by checking only the direct flag + // this should normally be set appropriately in the policy configuration file + if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { + flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT); + } + if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) { + flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT); + } + // only allow deep buffering for music stream type + if (stream != AUDIO_STREAM_MUSIC) { + flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); + } + if (stream == AUDIO_STREAM_TTS) { + flags = AUDIO_OUTPUT_FLAG_TTS; } -#endif - return AudioPolicyManagerBase::computeVolume(stream, index, output, device); -} -// This function checks for the parameters which can be offloaded. -// This can be enhanced depending on the capability of the DSP and policy -// of the system. -bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo) -{ - ALOGV(" isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d," - " BitRate=%u, duration=%lld us, has_video=%d", - offloadInfo.sample_rate, offloadInfo.channel_mask, - offloadInfo.format, - offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, - offloadInfo.has_video); + sp profile; -#ifdef VOICE_CONCURRENCY - if(isInCall()) - { - ALOGD("\n blocking compress offload on call mode\n"); - return false; + // skip direct output selection if the request can obviously be attached to a mixed output + // and not explicitly requested + if (((flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && + audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE && + audio_channel_count_from_out_mask(channelMask) <= 2) { + goto non_direct_output; } -#endif - // Check if stream type is music, then only allow offload as of now. - if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC) - { - ALOGV("isOffloadSupported: stream_type != MUSIC, returning false"); - return false; + + // Do not allow offloading if one non offloadable effect is enabled. This prevents from + // creating an offloaded track and tearing it down immediately after start when audioflinger + // detects there is an active non offloadable effect. + // FIXME: We should check the audio session here but we do not have it in this context. + // This may prevent offloading in rare situations where effects are left active by apps + // in the background. + + if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || + !mEffects.isNonOffloadableEffectEnabled()) { + profile = getProfileForDirectOutput(device, + samplingRate, + format, + channelMask, + (audio_output_flags_t)flags); } - char propValue[PROPERTY_VALUE_MAX]; - bool pcmOffload = false; - if (audio_is_offload_pcm(offloadInfo.format)) { - if(property_get("audio.offload.pcm.enable", propValue, NULL)) { - bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4); - if (prop_enabled) { - ALOGW("PCM offload property is enabled"); - pcmOffload = true; + if (profile != 0) { + sp outputDesc = NULL; + + for (size_t i = 0; i < mOutputs.size(); i++) { + sp desc = mOutputs.valueAt(i); + if (!desc->isDuplicated() && (profile == desc->mProfile)) { + outputDesc = desc; + // reuse direct output if currently open and configured with same parameters + if ((samplingRate == outputDesc->mSamplingRate) && + (format == outputDesc->mFormat) && + (channelMask == outputDesc->mChannelMask)) { + outputDesc->mDirectOpenCount++; + ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i)); + return mOutputs.keyAt(i); + } } } - if (!pcmOffload) { - ALOGV("PCM offload disabled by property audio.offload.pcm.enable"); - return false; + // close direct output if currently open and configured with different parameters + if (outputDesc != NULL) { + closeOutput(outputDesc->mIoHandle); } - } - if (!pcmOffload) { - // Check if offload has been disabled - if (property_get("audio.offload.disable", propValue, "0")) { - if (atoi(propValue) != 0) { - ALOGV("offload disabled by audio.offload.disable=%s", propValue ); - return false; - } + // if the selected profile is offloaded and no offload info was specified, + // create a default one + audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER; + if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) { + flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + defaultOffloadInfo.sample_rate = samplingRate; + defaultOffloadInfo.channel_mask = channelMask; + defaultOffloadInfo.format = format; + defaultOffloadInfo.stream_type = stream; + defaultOffloadInfo.bit_rate = 0; + defaultOffloadInfo.duration_us = -1; + defaultOffloadInfo.has_video = true; // conservative + defaultOffloadInfo.is_streaming = true; // likely + offloadInfo = &defaultOffloadInfo; } - //check if it's multi-channel AAC format - if (AudioSystem::popCount(offloadInfo.channel_mask) > 2 - && offloadInfo.format == AUDIO_FORMAT_AAC) { - ALOGV("offload disabled for multi-channel AAC format"); - return false; + outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface); + outputDesc->mDevice = device; + outputDesc->mLatency = 0; + outputDesc->mFlags = (audio_output_flags_t)(outputDesc->mFlags | flags); + audio_config_t config = AUDIO_CONFIG_INITIALIZER; + config.sample_rate = samplingRate; + config.channel_mask = channelMask; + config.format = format; + if (offloadInfo != NULL) { + config.offload_info = *offloadInfo; } - - if (offloadInfo.has_video) - { - if(property_get("av.offload.enable", propValue, NULL)) { - bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4); - if (!prop_enabled) { - ALOGW("offload disabled by av.offload.enable = %s ", propValue ); - return false; - } - } else { - return false; + status = mpClientInterface->openOutput(profile->getModuleHandle(), + &output, + &config, + &outputDesc->mDevice, + String8(""), + &outputDesc->mLatency, + outputDesc->mFlags); + + // only accept an output with the requested parameters + if (status != NO_ERROR || + (samplingRate != 0 && samplingRate != config.sample_rate) || + (format != AUDIO_FORMAT_DEFAULT && format != config.format) || + (channelMask != 0 && channelMask != config.channel_mask)) { + ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d," + "format %d %d, channelMask %04x %04x", output, samplingRate, + outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask, + outputDesc->mChannelMask); + if (output != AUDIO_IO_HANDLE_NONE) { + mpClientInterface->closeOutput(output); } - - if(offloadInfo.is_streaming) { - if (property_get("av.streaming.offload.enable", propValue, NULL)) { - bool prop_enabled = atoi(propValue) || !strncmp("true", propValue, 4); - if (!prop_enabled) { - ALOGW("offload disabled by av.streaming.offload.enable = %s ", propValue ); - return false; - } - } else { - //Do not offload AV streamnig if the property is not defined - return false; - } + // fall back to mixer output if possible when the direct output could not be open + if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) { + goto non_direct_output; } - ALOGV("isOffloadSupported: has_video == true, property\ - set to enable offload"); + return AUDIO_IO_HANDLE_NONE; } - } - - //If duration is less than minimum value defined in property, return false - if (property_get("audio.offload.min.duration.secs", propValue, NULL)) { - if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) { - ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue); - return false; + outputDesc->mSamplingRate = config.sample_rate; + outputDesc->mChannelMask = config.channel_mask; + outputDesc->mFormat = config.format; + outputDesc->mRefCount[stream] = 0; + outputDesc->mStopTime[stream] = 0; + outputDesc->mDirectOpenCount = 1; + + audio_io_handle_t srcOutput = getOutputForEffect(); + addOutput(output, outputDesc); + audio_io_handle_t dstOutput = getOutputForEffect(); + if (dstOutput == output) { + mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput); } - } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) { - ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS); - //duration checks only valid for MP3/AAC formats, - //do not check duration for other audio formats, e.g. dolby AAC/AC3 and amrwb+ formats - if (offloadInfo.format == AUDIO_FORMAT_MP3 || offloadInfo.format == AUDIO_FORMAT_AAC || pcmOffload) - return false; + mPreviousOutputs = mOutputs; + ALOGV("getOutput() returns new direct output %d", output); + mpClientInterface->onAudioPortListUpdate(); + return output; } - // Do not allow offloading if one non offloadable effect is enabled. This prevents from - // creating an offloaded track and tearing it down immediately after start when audioflinger - // detects there is an active non offloadable effect. - // FIXME: We should check the audio session here but we do not have it in this context. - // This may prevent offloading in rare situations where effects are left active by apps - // in the background. - if (isNonOffloadableEffectEnabled()) { - return false; +non_direct_output: + // ignoring channel mask due to downmix capability in mixer + + // open a non direct output + + // for non direct outputs, only PCM is supported + if (audio_is_linear_pcm(format)) { + // get which output is suitable for the specified stream. The actual + // routing change will happen when startOutput() will be called + SortedVector outputs = getOutputsForDevice(device, mOutputs); + + // at this stage we should ignore the DIRECT flag as no direct output could be found earlier + flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT); + output = selectOutput(outputs, flags, format); } + ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d," + "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags); - // See if there is a profile to support this. - // AUDIO_DEVICE_NONE - IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */, - offloadInfo.sample_rate, - offloadInfo.format, - offloadInfo.channel_mask, - AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); - ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT "); - return (profile != NULL); -} + ALOGV(" getOutputForDevice() returns output %d", output); -extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) -{ - return new AudioPolicyManager(clientInterface); + return output; } - -extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) -{ - delete interface; } - -}; // namespace android diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 3b809777a..b8c9b6e5a 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2009 The Android Open Source Project @@ -18,82 +18,117 @@ */ -#include -#include -#include -#include -#include -#include +#include +#include +#include -namespace android_audio_legacy { +namespace android { +#ifndef FLAC_OFFLOAD_ENABLED +#define AUDIO_FORMAT_FLAC 0x1D000000UL +#endif +#ifndef WMA_OFFLOAD_ENABLED +#define AUDIO_FORMAT_WMA 0x13000000UL +#define AUDIO_FORMAT_WMA_PRO 0x14000000UL +#endif + +#ifndef ALAC_OFFLOAD_ENABLED +#define AUDIO_FORMAT_ALAC 0x1F000000UL +#endif + +#ifndef APE_OFFLOAD_ENABLED +#define AUDIO_FORMAT_APE 0x20000000UL +#endif + +#ifndef AFE_PROXY_ENABLED +#define AUDIO_DEVICE_OUT_PROXY 0x40000 +#endif // ---------------------------------------------------------------------------- -class AudioPolicyManager: public AudioPolicyManagerBase +class AudioPolicyManagerCustom: public AudioPolicyManager { public: - AudioPolicyManager(AudioPolicyClientInterface *clientInterface) - : AudioPolicyManagerBase(clientInterface) {} - - virtual ~AudioPolicyManager() {} - - virtual status_t setDeviceConnectionState(audio_devices_t device, - AudioSystem::device_connection_state state, - const char *device_address); - virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); - virtual audio_io_handle_t getInput(int inputSource, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::audio_in_acoustics acoustics); + AudioPolicyManagerCustom(AudioPolicyClientInterface *clientInterface) + : AudioPolicyManager(clientInterface) { + mHdmiAudioDisabled = false; + mHdmiAudioEvent = false;} + + virtual ~AudioPolicyManagerCustom() {} + + status_t setDeviceConnectionStateInt(audio_devices_t device, + audio_policy_dev_state_t state, + const char *device_address, + const char *device_name); + virtual void setPhoneState(audio_mode_t state); + + virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); - virtual void setPhoneState(int state); + + // true if given state represents a device in a telephony or VoIP call protected: - // return the strategy corresponding to a given stream type - static routing_strategy getStrategy(AudioSystem::stream_type stream); - - // return appropriate device for streams handled by the specified strategy according to current - // phone state, connected devices... - // if fromCache is true, the device is returned from mDeviceForStrategy[], - // otherwise it is determine by current state - // (device connected,phone state, force use, a2dp output...) - // This allows to: - // 1 speed up process when the state is stable (when starting or stopping an output) - // 2 access to either current device selection (fromCache == true) or - // "future" device selection (fromCache == false) when called from a context - // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND - // before updateDevicesAndOutputs() is called. - virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, - bool fromCache = true); - // select input device corresponding to requested audio source - virtual audio_devices_t getDeviceForInputSource(int inputSource); - - // compute the actual volume for a given stream according to the requested index and a particular - // device - virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device); - - // check that volume change is permitted, compute and send new volume to audio hardware - status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); - - // returns the category the device belongs to with regard to volume curve management - static device_category getDeviceCategory(audio_devices_t device); - - // returns true if give output is direct output - bool isDirectOutput(audio_io_handle_t output); - static const char* HDMI_SPKR_STR; + status_t checkAndSetVolume(audio_stream_type_t stream, + int index, + const sp& outputDesc, + audio_devices_t device, + int delayMs = 0, bool force = false); + + // selects the most appropriate device on output for current state + // must be called every time a condition that affects the device choice for a given output is + // changed: connected device, phone state, force use, output start, output stop.. + // see getDeviceForStrategy() for the use of fromCache parameter + audio_devices_t getNewOutputDevice(const sp& outputDesc, + bool fromCache); + // returns true if given output is direct output + bool isDirectOutput(audio_io_handle_t output); - //parameter indicates of HDMI speakers disabled from the Qualcomm settings + // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force + // the re-evaluation of the output device. + status_t startSource(sp outputDesc, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t *delayMs); + status_t stopSource(sp outputDesc, + audio_stream_type_t stream, + bool forceDeviceUpdate); + // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON 313 + // returns 0 if no mute/unmute event happened, the largest latency of the device where 314 + // the mute/unmute happened 315 + uint32_t handleEventForBeacon(int){return 0;} + uint32_t setBeaconMute(bool){return 0;} + + // handle special cases for sonification strategy while in call: mute streams or replace by + // a special tone in the device used for communication + void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange, audio_io_handle_t output); + //parameter indicates of HDMI speakers disabled bool mHdmiAudioDisabled; - //parameter indicates if HDMI plug in/out detected bool mHdmiAudioEvent; - private: + static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, + int indexInUi); + // updates device caching and output for streams that can influence the + // routing of notifications + void handleNotificationRoutingForStream(audio_stream_type_t stream); + static bool isVirtualInputDevice(audio_devices_t device); + static bool deviceDistinguishesOnAddress(audio_devices_t device); + uint32_t nextUniqueId(); + // internal method to return the output handle for the given device and format + audio_io_handle_t getOutputForDevice( + audio_devices_t device, + audio_session_t session, + audio_stream_type_t stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo); // Used for voip + voice concurrency usecase int mPrevPhoneState; + int mvoice_call_state; }; + }; -- GitLab From 240ac6578aef5b06abfdc6dad80a06573ecfd546 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Fri, 31 Jul 2015 16:12:29 +0530 Subject: [PATCH 276/298] hal: add FM_TUNER capture support Add FM_TUNER as supported capture source and device. Remove unused FM devices Change-Id: I575125ca485d41b04e31d60f37619037329b0895 --- hal/audio_hw.c | 11 ++++++++++- hal/msm8974/platform.c | 13 +++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 569a8ac55..254bbfdf2 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -843,7 +843,10 @@ int start_input_stream(struct stream_in *in) struct audio_device *adev = in->dev; int snd_card_status = get_snd_card_state(adev); - in->usecase = platform_update_usecase_from_source(in->source,in->usecase); + int usecase = platform_update_usecase_from_source(in->source,in->usecase); + if (get_usecase_from_list(adev, usecase) == NULL) + in->usecase = usecase; + ALOGD("%s: enter: stream(%p)usecase(%d: %s)", __func__, &in->stream, in->usecase, use_case_table[in->usecase]); @@ -860,6 +863,12 @@ int start_input_stream(struct stream_in *in) else ALOGV("%s: usecase(%d)", __func__, in->usecase); + if (get_usecase_from_list(adev, in->usecase) != NULL) { + ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)", + __func__, &in->stream, in->usecase, use_case_table[in->usecase]); + goto error_config; + } + in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); if (in->pcm_device_id < 0) { ALOGE("%s: Could not find PCM device id for the usecase(%d)", diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c0593c9a3..3362aee73 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -1428,11 +1428,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d set_echo_reference(adev, true); } } -#ifdef FM_ENABLED - } else if (source == AUDIO_SOURCE_FM_RX || - source == AUDIO_SOURCE_FM_RX_A2DP) { + } else if (source == AUDIO_SOURCE_FM_TUNER) { snd_device = SND_DEVICE_IN_CAPTURE_FM; -#endif } else if (source == AUDIO_SOURCE_DEFAULT) { goto exit; } @@ -1467,10 +1464,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET || in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) { snd_device = SND_DEVICE_IN_USB_HEADSET_MIC; -#ifdef FM_ENABLED - } else if (in_device & AUDIO_DEVICE_IN_FM_RX) { + } else if (in_device & AUDIO_DEVICE_IN_FM_TUNER) { snd_device = SND_DEVICE_IN_CAPTURE_FM; -#endif } else { ALOGE("%s: Unknown input device(s) %#x", __func__, in_device); ALOGW("%s: Using default handset-mic", __func__); @@ -1823,10 +1818,8 @@ int64_t platform_render_latency(audio_usecase_t usecase) int platform_update_usecase_from_source(int source, int usecase) { ALOGV("%s: input source :%d", __func__, source); -#ifdef FM_ENABLED - if(source == AUDIO_SOURCE_FM_RX_A2DP) + if(source == AUDIO_SOURCE_FM_TUNER) usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL; -#endif return usecase; } -- GitLab From 7f718d5fe7c46d3b2f2400bc5806be31205dd100 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Thu, 13 Aug 2015 18:41:11 +0530 Subject: [PATCH 277/298] post_proc: added header file for compilation issue Change-Id: I2a6ae37a3be409ba7a2f356d304db6c73377b060 --- post_proc/effect_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c index 2acf18e32..8b8f11956 100644 --- a/post_proc/effect_api.c +++ b/post_proc/effect_api.c @@ -42,6 +42,7 @@ #include #include "effect_api.h" +#include #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) -- GitLab From 58a28313c4c55f68181c413021e0cf930dad451f Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Fri, 14 Aug 2015 14:40:44 +0530 Subject: [PATCH 278/298] policy-hal: extend getDeviceForStrategy for WFD use-cases. Need to extend getDeviceForStrategy function in custom audio policy so that WFD use-case selects proxy for needed strategies. Change-Id: Ib5ca3d70eaeeecfa78529b939674d766388b133e --- policy_hal/AudioPolicyManager.cpp | 27 +++++++++++++++++++++++++++ policy_hal/AudioPolicyManager.h | 4 +++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 03dec5752..073920e22 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -1076,4 +1076,31 @@ non_direct_output: return output; } + +audio_devices_t AudioPolicyManagerCustom::getDeviceForStrategy(routing_strategy strategy, bool fromCache) +{ + audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types(); + audio_devices_t device = AUDIO_DEVICE_NONE; + switch (strategy) { + case STRATEGY_SONIFICATION: + case STRATEGY_ENFORCED_AUDIBLE: + case STRATEGY_ACCESSIBILITY: + case STRATEGY_REROUTING: + case STRATEGY_MEDIA: + if (strategy != STRATEGY_SONIFICATION){ + // no sonification on WFD sink + device |= availableOutputDeviceTypes & AUDIO_DEVICE_OUT_PROXY; + if (device != AUDIO_DEVICE_NONE) { + ALOGV("Found proxy for strategy %d", strategy); + return device; + } + } + break; + default: + ALOGV("getDeviceForStrategy() unknown strategy: %d", strategy); + break; + } + device = AudioPolicyManager::getDeviceForStrategy(strategy, fromCache); + return device; +} } diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index b8c9b6e5a..494ad04a4 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -42,7 +42,7 @@ namespace android { #endif #ifndef AFE_PROXY_ENABLED -#define AUDIO_DEVICE_OUT_PROXY 0x40000 +#define AUDIO_DEVICE_OUT_PROXY 0x1000000 #endif // ---------------------------------------------------------------------------- @@ -67,6 +67,8 @@ public: virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); // true if given state represents a device in a telephony or VoIP call + + virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache); protected: status_t checkAndSetVolume(audio_stream_type_t stream, -- GitLab From ae5f8900388ceace55c2c3e0b901a666af97ff60 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Wed, 19 Aug 2015 20:47:12 +0530 Subject: [PATCH 279/298] policy-hal: squash multiple changes/fixes to custom policy This commit is a squash of below changes. Only relevant changes have been ported and the other required changes are in base policy manager. audiopolicy: support extended feature in audiopolicymanager Change-Id: I1925339b591cd29f11a71c287a2e53c0627e9e62 audiopolicy: additional change for extended feature Change-Id: I9bad6a294ddd7aee72f6f6a314666b892b730c8e audiopolicy: Do not route audio to HDMI if HDMI not connected Change-Id: I1c76ba3c3a1438463461ea7c41799633bd977283 audiopolicy: Fix for device selection during concurrent audio playback Change-Id: Ibf3c1bfd05b68d70c6cb9e8b9b95e989f27c2e75 Change-Id: I00470a057cdeefff7bba3bffd333fb556f3d97e6 --- policy_hal/Android.mk | 12 ++++ policy_hal/AudioPolicyManager.cpp | 92 ++++++++++++++++++++----------- policy_hal/AudioPolicyManager.h | 5 +- 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index 874b3dd57..58f73d342 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -27,6 +27,18 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := \ libmedia_helper \ +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FORMATS)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_FORMATS_ENABLED +endif + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_SPK)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_HDMI_SPK_ENABLED +endif + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) +LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED +endif + LOCAL_MODULE := libaudiopolicymanager include $(BUILD_SHARED_LIBRARY) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 073920e22..1b3d48be4 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -96,6 +96,15 @@ status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t d // handle output device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { if (index >= 0) { +#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED + if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { + if (!strncmp(device_address, "hdmi_spkr", 9)) { + mHdmiAudioDisabled = false; + } else { + mHdmiAudioEvent = true; + } + } +#endif ALOGW("setDeviceConnectionState() device already connected: %x", device); return INVALID_OPERATION; } @@ -103,6 +112,20 @@ status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t d // register new device as available index = mAvailableOutputDevices.add(devDesc); +#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED + if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { + if (!strncmp(device_address, "hdmi_spkr", 9)) { + mHdmiAudioDisabled = false; + } else { + mHdmiAudioEvent = true; + } + if (mHdmiAudioDisabled || !mHdmiAudioEvent) { + mAvailableOutputDevices.remove(devDesc); + ALOGW("HDMI sink not connected, do not route audio to HDMI out"); + return INVALID_OPERATION; + } + } +#endif if (index >= 0) { sp module = mHwModules.getModuleForDevice(device); if (module == 0) { @@ -138,6 +161,15 @@ status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t d // handle output device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { if (index < 0) { +#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED + if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { + if (!strncmp(device_address, "hdmi_spkr", 9)) { + mHdmiAudioDisabled = true; + } else { + mHdmiAudioEvent = false; + } + } +#endif ALOGW("setDeviceConnectionState() device not connected: %x", device); return INVALID_OPERATION; } @@ -151,7 +183,15 @@ status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t d // remove device from available output devices mAvailableOutputDevices.remove(devDesc); - +#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED + if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { + if (!strncmp(device_address, "hdmi_spkr", 9)) { + mHdmiAudioDisabled = true; + } else { + mHdmiAudioEvent = false; + } + } +#endif checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress); // Propagate device availability to Engine @@ -451,6 +491,7 @@ void AudioPolicyManagerCustom::setPhoneState(audio_mode_t state) { ALOGV("setPhoneState() state %d", state); // store previous phone state for management of sonification strategy below + audio_devices_t newDevice = AUDIO_DEVICE_NONE; int oldState = mEngine->getPhoneState(); if (mEngine->setPhoneState(state) != NO_ERROR) { @@ -546,7 +587,14 @@ void AudioPolicyManagerCustom::setPhoneState(audio_mode_t state) setOutputDevice(mPrimaryOutput, rxDevice, force, 0); } } - + //update device for all non-primary outputs + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t output = mOutputs.keyAt(i); + if (output != mPrimaryOutput->mIoHandle) { + newDevice = getNewOutputDevice(mOutputs.valueFor(output), false /*fromCache*/); + setOutputDevice(mOutputs.valueFor(output), newDevice, (newDevice != AUDIO_DEVICE_NONE)); + } + } // if entering in call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() if (isStateInCall(state)) { @@ -578,10 +626,10 @@ status_t AudioPolicyManagerCustom::stopSource(sp output handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); // handle special case for sonification while in call - if (isInCall()) { + if (isInCall() && (outputDesc->mRefCount[stream] == 1)) { if (outputDesc->isDuplicated()) { - handleIncallSonification(stream, false, false, outputDesc->mIoHandle); - handleIncallSonification(stream, false, false, outputDesc->mIoHandle); + handleIncallSonification(stream, false, false, outputDesc->mOutput1->mIoHandle); + handleIncallSonification(stream, false, false, outputDesc->mOutput2->mIoHandle); } handleIncallSonification(stream, false, false, outputDesc->mIoHandle); } @@ -610,8 +658,10 @@ status_t AudioPolicyManagerCustom::stopSource(sp output desc->isActive() && outputDesc->sharesHwModuleWith(desc) && (newDevice != desc->device())) { - setOutputDevice(desc, - getNewOutputDevice(desc, false /*fromCache*/), + audio_devices_t dev = getNewOutputDevice(mOutputs.valueFor(curOutput), false + /*fromCache*/); + setOutputDevice(desc, + dev, true, outputDesc->latency()*2); } @@ -897,6 +947,7 @@ audio_io_handle_t AudioPolicyManagerCustom::getOutputForDevice( ALOGE("Offloading only allowed with music stream"); return 0; } +#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED /* * WFD audio routes back to target speaker when starting a ringtone playback. * This is because primary output is reused for ringtone, so output device is @@ -916,6 +967,7 @@ audio_io_handle_t AudioPolicyManagerCustom::getOutputForDevice( else //route every thing else to ULL path flags = AUDIO_OUTPUT_FLAG_FAST; } +#endif // open a direct output if required by specified parameters //force direct flag if offload flag is set: offloading implies a direct output stream // and all common behaviors are driven by checking only the direct flag @@ -1077,30 +1129,4 @@ non_direct_output: return output; } -audio_devices_t AudioPolicyManagerCustom::getDeviceForStrategy(routing_strategy strategy, bool fromCache) -{ - audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types(); - audio_devices_t device = AUDIO_DEVICE_NONE; - switch (strategy) { - case STRATEGY_SONIFICATION: - case STRATEGY_ENFORCED_AUDIBLE: - case STRATEGY_ACCESSIBILITY: - case STRATEGY_REROUTING: - case STRATEGY_MEDIA: - if (strategy != STRATEGY_SONIFICATION){ - // no sonification on WFD sink - device |= availableOutputDeviceTypes & AUDIO_DEVICE_OUT_PROXY; - if (device != AUDIO_DEVICE_NONE) { - ALOGV("Found proxy for strategy %d", strategy); - return device; - } - } - break; - default: - ALOGV("getDeviceForStrategy() unknown strategy: %d", strategy); - break; - } - device = AudioPolicyManager::getDeviceForStrategy(strategy, fromCache); - return device; -} } diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 494ad04a4..1dd37e8df 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -40,8 +40,7 @@ namespace android { #ifndef APE_OFFLOAD_ENABLED #define AUDIO_FORMAT_APE 0x20000000UL #endif - -#ifndef AFE_PROXY_ENABLED +#ifndef AUDIO_EXTN_AFE_PROXY_ENABLED #define AUDIO_DEVICE_OUT_PROXY 0x1000000 #endif // ---------------------------------------------------------------------------- @@ -63,12 +62,10 @@ public: const char *device_name); virtual void setPhoneState(audio_mode_t state); - virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); // true if given state represents a device in a telephony or VoIP call - virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache); protected: status_t checkAndSetVolume(audio_stream_type_t stream, -- GitLab From 7992b8edef43e2ba9e00a0b11939671463b3913e Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Mon, 21 Jul 2014 14:51:44 -0700 Subject: [PATCH 280/298] hal: fix to set tty mode properly If set parameters API called with key "tty_mode" and MULTI_VOICE_SESSION_ENABLED flag is not enabled then tty mode is not executed because voice_extn_set_parameters returns error(-ENOSYS). Fix by ignore -ENOSYS return code for voice_extn_set_parameters and voice_extn_compress_voip_set_parameters. Change-Id: Id2308b2218fdf74e420ecbe25eeadd49756494f1 --- hal/voice.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hal/voice.c b/hal/voice.c index a14784de0..7dab77372 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -397,12 +397,20 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs); ret = voice_extn_set_parameters(adev, parms); - if (ret != 0) - goto done; + if (ret != 0) { + if (ret == -ENOSYS) + ret = 0; + else + goto done; + } ret = voice_extn_compress_voip_set_parameters(adev, parms); - if (ret != 0) - goto done; + if (ret != 0) { + if (ret == -ENOSYS) + ret = 0; + else + goto done; + } err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); if (err >= 0) { @@ -437,7 +445,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms) platform_start_incall_music_usecase(adev->platform); else platform_stop_incall_music_usecase(adev->platform); - } + } done: ALOGV("%s: exit with code(%d)", __func__, ret); -- GitLab From 5b022de95e2dc883ad1a794fdbbdd2c460769946 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Tue, 15 Sep 2015 18:25:20 +0530 Subject: [PATCH 281/298] policy_hal: Function prototype correction for custom policy - Ringtone is not heard when BT is connected because mute count for stream type ring is always greater then zero. The reason is when BT is connected duplicate output is created. Base policy does not handle mute count for duplicate output in stopSource properly. Custom policy stopSource handles this scenario but it is not called as signature does not match with base class stopSource - Fix is to correct function signature for custom policy to make sure stopSource is called. Change-Id: I8c0a99dbaae860a261ce2f15b6056d3d9c545568 --- policy_hal/Android.mk | 1 + policy_hal/AudioPolicyManager.cpp | 6 ++++-- policy_hal/AudioPolicyManager.h | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index 58f73d342..ee3b56de7 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -39,6 +39,7 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED endif +LOCAL_CFLAGS += -Wno-error -fpermissive LOCAL_MODULE := libaudiopolicymanager include $(BUILD_SHARED_LIBRARY) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 1b3d48be4..41247b97c 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -618,11 +618,12 @@ void AudioPolicyManagerCustom::setPhoneState(audio_mode_t state) mLimitRingtoneVolume = false; } } -status_t AudioPolicyManagerCustom::stopSource(sp outputDesc, +status_t AudioPolicyManagerCustom::stopSource(sp outputDesc1, audio_stream_type_t stream, bool forceDeviceUpdate) { // always handle stream stop, check which stream type is stopping + sp outputDesc = (sp) outputDesc1; handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); // handle special case for sonification while in call @@ -675,13 +676,14 @@ status_t AudioPolicyManagerCustom::stopSource(sp output return INVALID_OPERATION; } } -status_t AudioPolicyManagerCustom::startSource(sp outputDesc, +status_t AudioPolicyManagerCustom::startSource(sp outputDesc1, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs) { // cannot start playback of STREAM_TTS if any other output is being used uint32_t beaconMuteLatency = 0; + sp outputDesc = (sp) outputDesc1; *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 1dd37e8df..f818a19b9 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -85,11 +85,11 @@ protected: // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force // the re-evaluation of the output device. - status_t startSource(sp outputDesc, + status_t startSource(sp outputDesc, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs); - status_t stopSource(sp outputDesc, + status_t stopSource(sp outputDesc, audio_stream_type_t stream, bool forceDeviceUpdate); // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON 313 -- GitLab From 38877807dab6549d21eb6a35d758f543ff188aa7 Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Mon, 5 Oct 2015 15:24:04 -0700 Subject: [PATCH 282/298] audio: remove 5.1 channel mask if SSR is not supported - remove 5.1 input channel mask if it cannot be supported on a chipset variant. Change-Id: Ifd5254da910e392a270067c36c31c5cfaa75f9fc --- policy_hal/AudioPolicyManager.cpp | 47 +++++++++++++++++++++++++++++++ policy_hal/AudioPolicyManager.h | 5 +--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 41247b97c..6fc611379 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -1131,4 +1131,51 @@ non_direct_output: return output; } +AudioPolicyManagerCustom::AudioPolicyManagerCustom(AudioPolicyClientInterface *clientInterface) + : AudioPolicyManager(clientInterface), + mHdmiAudioDisabled(false), + mHdmiAudioEvent(false), + mPrevPhoneState(0) +{ + char ssr_enabled[PROPERTY_VALUE_MAX] = {0}; + bool prop_ssr_enabled = false; + + if (property_get("ro.qc.sdk.audio.ssr", ssr_enabled, NULL)) { + prop_ssr_enabled = atoi(ssr_enabled) || !strncmp("true", ssr_enabled, 4); + } + + for (size_t i = 0; i < mHwModules.size(); i++) { + ALOGV("Hw module %d", i); + for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) { + const sp inProfile = mHwModules[i]->mInputProfiles[j]; + ALOGV("Input profile ", j); + for (size_t k = 0; k < inProfile->mChannelMasks.size(); k++) { + audio_channel_mask_t channelMask = + inProfile->mChannelMasks.itemAt(k); + ALOGV("Channel Mask %x size %d", channelMask, + inProfile->mChannelMasks.size()); + if (AUDIO_CHANNEL_IN_5POINT1 == channelMask) { + if (!prop_ssr_enabled) { + ALOGI("removing AUDIO_CHANNEL_IN_5POINT1 from" + " input profile as SSR(surround sound record)" + " is not supported on this chipset variant"); + inProfile->mChannelMasks.removeItemsAt(k, 1); + ALOGV("Channel Mask size now %d", + inProfile->mChannelMasks.size()); + } + } + } + } + } + +#ifdef RECORD_PLAY_CONCURRENCY + mIsInputRequestOnProgress = false; +#endif + + +#ifdef VOICE_CONCURRENCY + mFallBackflag = getFallBackPath(); +#endif +} + } diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index f818a19b9..0f44e9b04 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -49,10 +49,7 @@ class AudioPolicyManagerCustom: public AudioPolicyManager { public: - AudioPolicyManagerCustom(AudioPolicyClientInterface *clientInterface) - : AudioPolicyManager(clientInterface) { - mHdmiAudioDisabled = false; - mHdmiAudioEvent = false;} + AudioPolicyManagerCustom(AudioPolicyClientInterface *clientInterface); virtual ~AudioPolicyManagerCustom() {} -- GitLab From 4244103024b55847176104c1d75b80c6c48a6a0c Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Wed, 16 Sep 2015 19:44:33 +0530 Subject: [PATCH 283/298] policy-hal: fix glitch in playback while applying setForceUse - Headset and Speaker shares same backend on our platform, because of which routing of a stream from one device to another affects other streams on these devices as well - Reduce the impact of resultant glitch by processing routing request on LL output at the end, since LL output is used mostly for non-music playback and is less sensitive to the impact of routing from any other output's context. Change-Id: I9fa3a7b49529ace5c28e82b788ffbfd612d59791 --- policy_hal/AudioPolicyManager.cpp | 47 +++++++++++++++++++++++++++++++ policy_hal/AudioPolicyManager.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 6fc611379..04723e858 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -618,6 +618,53 @@ void AudioPolicyManagerCustom::setPhoneState(audio_mode_t state) mLimitRingtoneVolume = false; } } + +void AudioPolicyManagerCustom::setForceUse(audio_policy_force_use_t usage, + audio_policy_forced_cfg_t config) +{ + ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mEngine->getPhoneState()); + + if (mEngine->setForceUse(usage, config) != NO_ERROR) { + ALOGW("setForceUse() could not set force cfg %d for usage %d", config, usage); + return; + } + bool forceVolumeReeval = (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) || + (usage == AUDIO_POLICY_FORCE_FOR_DOCK) || + (usage == AUDIO_POLICY_FORCE_FOR_SYSTEM); + + // check for device and output changes triggered by new force usage + checkA2dpSuspend(); + checkOutputForAllStrategies(); + updateDevicesAndOutputs(); + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/); + updateCallRouting(newDevice); + } + // Use reverse loop to make sure any low latency usecases (generally tones) + // are not routed before non LL usecases (generally music). + // We can safely assume that LL output would always have lower index, + // and use this work-around to avoid routing of output with music stream + // from the context of short lived LL output. + // Note: in case output's share backend(HAL sharing is implicit) all outputs + // gets routing update while processing first output itself. + for (size_t i = mOutputs.size(); i > 0; i--) { + sp outputDesc = mOutputs.valueAt(i-1); + audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/); + if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || outputDesc != mPrimaryOutput) { + setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + } + if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { + applyStreamVolumes(outputDesc, newDevice, 0, true); + } + } + + audio_io_handle_t activeInput = mInputs.getActiveInput(); + if (activeInput != 0) { + setInputDevice(activeInput, getNewInputDevice(activeInput)); + } + +} + status_t AudioPolicyManagerCustom::stopSource(sp outputDesc1, audio_stream_type_t stream, bool forceDeviceUpdate) diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 0f44e9b04..90d2f7e31 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -58,6 +58,8 @@ public: const char *device_address, const char *device_name); virtual void setPhoneState(audio_mode_t state); + virtual void setForceUse(audio_policy_force_use_t usage, + audio_policy_forced_cfg_t config); virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); -- GitLab From 1f41cfa3b4d698a2c3f53b6af305b506c00949a0 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Tue, 8 Sep 2015 10:21:44 +0530 Subject: [PATCH 284/298] hal: add a new key to query for decoder viability - Due to resource constraints some times a decoder playback cannot be supported, for example HW decoders cannot be supported during voice calls, this key can be queried to know about this. - Bring in the this funtionality in HAL under the android prop "voice.playback.conc.disabled". Change-Id: Id6819b1b953c8ba9948c85218d98beb789f92631 CRs-Fixed: 902360 --- hal/audio_extn/audio_defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h index 335a62951..8144fa897 100644 --- a/hal/audio_extn/audio_defs.h +++ b/hal/audio_extn/audio_defs.h @@ -75,4 +75,6 @@ /* Query if Proxy can be Opend */ #define AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY "can_open_proxy" +#define AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED "is_hw_dec_session_allowed" + #endif /* AUDIO_DEFS_H */ -- GitLab From f9345b37e91d85838017f0c1a1f98edf486e5dc4 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Tue, 13 Oct 2015 18:13:04 +0530 Subject: [PATCH 285/298] policy-hal: Fix for alarm tone heard even after dismissing. -For stopping the alarm tone played during in call, handleIncallSonification must be called with second parameter i.e. starting as false from setPhoneState when the call is disconnected -isInCall method retuns false,hence handleIncallSonification is not getting called on disconnecting the call Change-Id: Ia6398eb1b0a3cb117a16f9fd4cb3637f5ce17be8 --- policy_hal/AudioPolicyManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 04723e858..033610f98 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -501,7 +501,7 @@ void AudioPolicyManagerCustom::setPhoneState(audio_mode_t state) /// Opens: can these line be executed after the switch of volume curves??? // if leaving call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() - if (isInCall()) { + if (isStateInCall(oldState)) { ALOGV("setPhoneState() in call state management: new state is %d", state); for (size_t j = 0; j < mOutputs.size(); j++) { audio_io_handle_t curOutput = mOutputs.keyAt(j); -- GitLab From eb605c95109b847170c663d139ea379aa72ab1bf Mon Sep 17 00:00:00 2001 From: Karthik Reddy Katta Date: Tue, 14 Jul 2015 16:05:18 +0530 Subject: [PATCH 286/298] policy_hal: Add voip changes to audio policy Add support for voip path where voip driver is used instead of audio playback/record path for voip application. Change-Id: Ie451ea683c90e02fdcdc5b9702649e73a55ab8c2 --- policy_hal/AudioPolicyManager.cpp | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 033610f98..9f5d7ca13 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -995,7 +995,53 @@ audio_io_handle_t AudioPolicyManagerCustom::getOutputForDevice( // compress should not be used for non-music streams ALOGE("Offloading only allowed with music stream"); return 0; + } + + if ((stream == AUDIO_STREAM_VOICE_CALL) && + (channelMask == 1) && + (samplingRate == 8000 || samplingRate == 16000)) { + // Allow Voip direct output only if: + // audio mode is MODE_IN_COMMUNCATION; AND + // voip output is not opened already; AND + // requested sample rate matches with that of voip input stream (if opened already) + int value = 0; + uint32_t mode = 0, voipOutCount = 1, voipSampleRate = 1; + String8 valueStr = mpClientInterface->getParameters((audio_io_handle_t)0, + String8("audio_mode")); + AudioParameter result = AudioParameter(valueStr); + if (result.getInt(String8("audio_mode"), value) == NO_ERROR) { + mode = value; + } + + valueStr = mpClientInterface->getParameters((audio_io_handle_t)0, + String8("voip_out_stream_count")); + result = AudioParameter(valueStr); + if (result.getInt(String8("voip_out_stream_count"), value) == NO_ERROR) { + voipOutCount = value; + } + + valueStr = mpClientInterface->getParameters((audio_io_handle_t)0, + String8("voip_sample_rate")); + result = AudioParameter(valueStr); + if (result.getInt(String8("voip_sample_rate"), value) == NO_ERROR) { + voipSampleRate = value; + } + + if ((mode == AUDIO_MODE_IN_COMMUNICATION) && (voipOutCount == 0) && + ((voipSampleRate == 0) || (voipSampleRate == samplingRate))) { + if (audio_is_linear_pcm(format)) { + char propValue[PROPERTY_VALUE_MAX] = {0}; + property_get("use.voice.path.for.pcm.voip", propValue, "0"); + bool voipPcmSysPropEnabled = !strncmp("true", propValue, sizeof("true")); + if (voipPcmSysPropEnabled && (format == AUDIO_FORMAT_PCM_16_BIT)) { + flags = (audio_output_flags_t)((flags &~AUDIO_OUTPUT_FLAG_FAST) | + AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_DIRECT); + ALOGD("Set VoIP and Direct output flags for PCM format"); + } + } + } } + #ifdef AUDIO_EXTN_AFE_PROXY_ENABLED /* * WFD audio routes back to target speaker when starting a ringtone playback. -- GitLab From fd4323f9988fd93f46a0587f7f07d4dc23a65351 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Wed, 18 Nov 2015 13:26:59 +0530 Subject: [PATCH 287/298] hal: fix compilation issues with audio FM extention. - Update FM device references to match latest definitions to fix compilation of FM extention. - Update FM feature flag for power optimization Change-Id: I17a9e240e552c4089d3e9c7a25e437fb5b5433f9 --- hal/Android.mk | 4 ++-- hal/audio_extn/audio_extn.c | 2 +- hal/audio_extn/audio_extn.h | 9 ++------- hal/audio_extn/fm.c | 4 ++-- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/hal/Android.mk b/hal/Android.mk index 6cb7c476f..35b0823f2 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -46,8 +46,8 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAFE_PROXY_ENABLED endif -ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM)),true) - LOCAL_CFLAGS += -DFM_ENABLED +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM_POWER_OPT)),true) + LOCAL_CFLAGS += -DFM_POWER_OPT LOCAL_SRC_FILES += audio_extn/fm.c endif diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index dbb29c0ee..974e19e09 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -49,7 +49,7 @@ static struct audio_extn_module aextnmod = { #define AUDIO_PARAMETER_KEY_ANC "anc_enabled" #define AUDIO_PARAMETER_KEY_WFD "wfd_channel_cap" #define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy" -#ifndef FM_ENABLED +#ifndef FM_POWER_OPT #define audio_extn_fm_set_parameters(adev, parms) (0) #else void audio_extn_fm_set_parameters(struct audio_device *adev, diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 6beaa95e2..9cbed1997 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -42,13 +42,8 @@ #define AUDIO_OUTPUT_FLAG_INCALL_MUSIC 0x8000 #endif -#ifndef FM_ENABLED -#define AUDIO_DEVICE_OUT_FM 0x80000 -#define AUDIO_DEVICE_OUT_FM_TX 0x100000 -#define AUDIO_SOURCE_FM_RX 9 -#define AUDIO_SOURCE_FM_RX_A2DP 10 -#define AUDIO_DEVICE_IN_FM_RX (AUDIO_DEVICE_BIT_IN | 0x8000) -#define AUDIO_DEVICE_IN_FM_RX_A2DP (AUDIO_DEVICE_BIT_IN | 0x10000) +#ifndef AUDIO_DEVICE_OUT_FM_TX +#define AUDIO_DEVICE_OUT_FM_TX 0x8000000 #endif diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c index 668f67ad4..d18c88b10 100644 --- a/hal/audio_extn/fm.c +++ b/hal/audio_extn/fm.c @@ -31,7 +31,7 @@ #include #include -#ifdef FM_ENABLED +#ifdef FM_POWER_OPT #define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm" #define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume" @@ -280,4 +280,4 @@ void audio_extn_fm_set_parameters(struct audio_device *adev, exit: ALOGV("%s: exit", __func__); } -#endif /* FM_ENABLED end */ +#endif /* FM_POWER_OPT end */ -- GitLab From 4a84252a1a2dc22e55658f399f074a93c095f32f Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Thu, 19 Nov 2015 17:20:25 +0530 Subject: [PATCH 288/298] Revert "policy_hal: Function prototype correction for custom policy". This reverts commit 5b022de95e2dc883ad1a794fdbbdd2c460769946 Change-Id: I90f24fbf3af0aaab309365d02893e41cc30b4087 --- policy_hal/Android.mk | 1 - policy_hal/AudioPolicyManager.cpp | 6 ++---- policy_hal/AudioPolicyManager.h | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index ee3b56de7..58f73d342 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -39,7 +39,6 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED endif -LOCAL_CFLAGS += -Wno-error -fpermissive LOCAL_MODULE := libaudiopolicymanager include $(BUILD_SHARED_LIBRARY) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 9f5d7ca13..256f004a7 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -665,12 +665,11 @@ void AudioPolicyManagerCustom::setForceUse(audio_policy_force_use_t usage, } -status_t AudioPolicyManagerCustom::stopSource(sp outputDesc1, +status_t AudioPolicyManagerCustom::stopSource(sp outputDesc, audio_stream_type_t stream, bool forceDeviceUpdate) { // always handle stream stop, check which stream type is stopping - sp outputDesc = (sp) outputDesc1; handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); // handle special case for sonification while in call @@ -723,14 +722,13 @@ status_t AudioPolicyManagerCustom::stopSource(sp outputDe return INVALID_OPERATION; } } -status_t AudioPolicyManagerCustom::startSource(sp outputDesc1, +status_t AudioPolicyManagerCustom::startSource(sp outputDesc, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs) { // cannot start playback of STREAM_TTS if any other output is being used uint32_t beaconMuteLatency = 0; - sp outputDesc = (sp) outputDesc1; *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index 90d2f7e31..fcb4f8abe 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -84,11 +84,11 @@ protected: // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force // the re-evaluation of the output device. - status_t startSource(sp outputDesc, + status_t startSource(sp outputDesc, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs); - status_t stopSource(sp outputDesc, + status_t stopSource(sp outputDesc, audio_stream_type_t stream, bool forceDeviceUpdate); // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON 313 -- GitLab From d3bfcb3af69a6dfc69256512c61a21c5ac354feb Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 20 Oct 2015 17:56:50 +0530 Subject: [PATCH 289/298] audio_policy: modify few methods to appropriately override base Few methods in AudioPolicyManagerCustom is not overriding its base implemenation due to signature mismatch. Since they act as separate method they are not getting called to override base implemenation Correct signatures to implement overriding instead of overloading. Remove custom stopOutput implementation since it is not adding any change w.r.t. base implementation Change-Id: I6fe8fd6890ee8e896b6430f3ad170850d77b17d5 --- policy_hal/AudioPolicyManager.cpp | 32 +++++++++++++++++++++++++------ policy_hal/AudioPolicyManager.h | 6 +++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 256f004a7..862b71ae5 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -665,18 +665,22 @@ void AudioPolicyManagerCustom::setForceUse(audio_policy_force_use_t usage, } -status_t AudioPolicyManagerCustom::stopSource(sp outputDesc, +status_t AudioPolicyManagerCustom::stopSource(sp outputDesc, audio_stream_type_t stream, bool forceDeviceUpdate) { + if (stream < 0 || stream >= AUDIO_STREAM_CNT) { + ALOGW("stopSource() invalid stream %d", stream); + return INVALID_OPERATION; + } // always handle stream stop, check which stream type is stopping handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); // handle special case for sonification while in call if (isInCall() && (outputDesc->mRefCount[stream] == 1)) { if (outputDesc->isDuplicated()) { - handleIncallSonification(stream, false, false, outputDesc->mOutput1->mIoHandle); - handleIncallSonification(stream, false, false, outputDesc->mOutput2->mIoHandle); + handleIncallSonification(stream, false, false, outputDesc->subOutput1()->mIoHandle); + handleIncallSonification(stream, false, false, outputDesc->subOutput2()->mIoHandle); } handleIncallSonification(stream, false, false, outputDesc->mIoHandle); } @@ -688,6 +692,7 @@ status_t AudioPolicyManagerCustom::stopSource(sp output // store time at which the stream was stopped - see isStreamActive() if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) { outputDesc->mStopTime[stream] = systemTime(); + audio_devices_t prevDevice = outputDesc->device(); audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/); // delay the device switch by twice the latency because stopOutput() is executed when // the track stop() command is received and at that time the audio track buffer can @@ -707,10 +712,16 @@ status_t AudioPolicyManagerCustom::stopSource(sp output (newDevice != desc->device())) { audio_devices_t dev = getNewOutputDevice(mOutputs.valueFor(curOutput), false /*fromCache*/); + uint32_t delayMs; + if (dev == prevDevice) { + delayMs = 0; + } else { + delayMs = outputDesc->latency()*2; + } setOutputDevice(desc, dev, true, - outputDesc->latency()*2); + delayMs); } } // update the outputs if stopping one with a stream that can affect notification routing @@ -722,7 +733,7 @@ status_t AudioPolicyManagerCustom::stopSource(sp output return INVALID_OPERATION; } } -status_t AudioPolicyManagerCustom::startSource(sp outputDesc, +status_t AudioPolicyManagerCustom::startSource(sp outputDesc, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs) @@ -730,6 +741,11 @@ status_t AudioPolicyManagerCustom::startSource(sp outpu // cannot start playback of STREAM_TTS if any other output is being used uint32_t beaconMuteLatency = 0; + if (stream < 0 || stream >= AUDIO_STREAM_CNT) { + ALOGW("startSource() invalid stream %d", stream); + return INVALID_OPERATION; + } + *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { ALOGV("\t found BEACON stream"); @@ -873,10 +889,14 @@ void AudioPolicyManagerCustom::handleNotificationRoutingForStream(audio_stream_t } status_t AudioPolicyManagerCustom::checkAndSetVolume(audio_stream_type_t stream, int index, - const sp& outputDesc, + const sp& outputDesc, audio_devices_t device, int delayMs, bool force) { + if (stream < 0 || stream >= AUDIO_STREAM_CNT) { + ALOGW("checkAndSetVolume() invalid stream %d", stream); + return INVALID_OPERATION; + } // do not change actual stream volume if the stream is muted if (outputDesc->mMuteCount[stream] != 0) { ALOGVV("checkAndSetVolume() stream %d muted count %d", diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h index fcb4f8abe..f9c872491 100644 --- a/policy_hal/AudioPolicyManager.h +++ b/policy_hal/AudioPolicyManager.h @@ -69,7 +69,7 @@ protected: status_t checkAndSetVolume(audio_stream_type_t stream, int index, - const sp& outputDesc, + const sp& outputDesc, audio_devices_t device, int delayMs = 0, bool force = false); @@ -84,11 +84,11 @@ protected: // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force // the re-evaluation of the output device. - status_t startSource(sp outputDesc, + status_t startSource(sp outputDesc, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs); - status_t stopSource(sp outputDesc, + status_t stopSource(sp outputDesc, audio_stream_type_t stream, bool forceDeviceUpdate); // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON 313 -- GitLab From 5300daaa0080c8ae59a8fe60734e4f329267acd8 Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Wed, 18 Nov 2015 13:31:47 +0530 Subject: [PATCH 290/298] policy_hal: add support for fm device loopback Use device connection event against AUDIO_DEVICE_OUT_FM to configure FM device loopback Update primary output to get routing and volume events. Change-Id: I5ddce36581568d377a08ea5afe470bdff4349ec7 --- policy_hal/Android.mk | 4 ++++ policy_hal/AudioPolicyManager.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk index 58f73d342..46dd157d3 100644 --- a/policy_hal/Android.mk +++ b/policy_hal/Android.mk @@ -39,6 +39,10 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM_POWER_OPT)),true) +LOCAL_CFLAGS += -DFM_POWER_OPT +endif + LOCAL_MODULE := libaudiopolicymanager include $(BUILD_SHARED_LIBRARY) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 862b71ae5..b6978874e 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -228,6 +228,23 @@ status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t d audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); updateCallRouting(newDevice); } + +#ifdef FM_POWER_OPT + // handle FM device connection state to trigger FM AFE loopback + if(device == AUDIO_DEVICE_OUT_FM && hasPrimaryOutput()) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { + mPrimaryOutput->changeRefCount(AUDIO_STREAM_MUSIC, 1); + newDevice = (audio_devices_t)getNewOutputDevice(mPrimaryOutput, false /*fromCache*/) | AUDIO_DEVICE_OUT_FM; + } else { + mPrimaryOutput->changeRefCount(AUDIO_STREAM_MUSIC, -1); + } + AudioParameter param = AudioParameter(); + param.addInt(String8("handle_fm"), (int)newDevice); + mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString()); + } +#endif /* FM_POWER_OPT end */ + for (size_t i = 0; i < mOutputs.size(); i++) { sp desc = mOutputs.valueAt(i); if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) { @@ -939,6 +956,13 @@ status_t AudioPolicyManagerCustom::checkAndSetVolume(audio_stream_type_t stream, mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } +#ifdef FM_POWER_OPT + } else if (stream == AUDIO_STREAM_MUSIC && hasPrimaryOutput() && + outputDesc == mPrimaryOutput) { + AudioParameter param = AudioParameter(); + param.addFloat(String8("fm_volume"), Volume::DbToAmpl(volumeDb)); + mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString(), delayMs); +#endif /* FM_POWER_OPT end */ } return NO_ERROR; -- GitLab From c2e73aa22f7bfb407e2cf73a30a17edb070b52e0 Mon Sep 17 00:00:00 2001 From: Gao Jie Date: Thu, 12 Nov 2015 08:51:22 +0800 Subject: [PATCH 291/298] Merge DAX2 changes Change-Id: If6fcfdef0b051f9015c127bdd7d28e3668e47435 (cherry picked from commit 4879ebb6d14558695044be0a22a89fc8b7ac24ec) Change-Id: I5ecf6c792bf1d5c481879a38231acfdb2a3ccc3e --- policy_hal/AudioPolicyManager.cpp | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp index 9f5d7ca13..573c103b8 100644 --- a/policy_hal/AudioPolicyManager.cpp +++ b/policy_hal/AudioPolicyManager.cpp @@ -15,6 +15,24 @@ * 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. + * + * This file was modified by Dolby Laboratories, Inc. The portions of the + * code that are surrounded by "DOLBY..." are copyrighted and + * licensed separately, as follows: + * + * (C) 2015 Dolby Laboratories, Inc. + * + * 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. */ #define LOG_TAG "AudioPolicyManagerCustom" @@ -51,6 +69,9 @@ #include #include "AudioPolicyManager.h" #include +#ifdef DOLBY_ENABLE +#include "DolbyAudioPolicy_impl.h" +#endif // DOLBY_END namespace android { @@ -224,6 +245,11 @@ status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t d } updateDevicesAndOutputs(); +#ifdef DOLBY_ENABLE + // Before closing the opened outputs, update endpoint property with device capabilities + audio_devices_t audioOutputDevice = getDeviceForStrategy(getStrategy(AUDIO_STREAM_MUSIC), true); + mDolbyAudioPolicy.setEndpointSystemProperty(audioOutputDevice, mHwModules); +#endif // DOLBY_END if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); updateCallRouting(newDevice); @@ -1193,7 +1219,23 @@ audio_io_handle_t AudioPolicyManagerCustom::getOutputForDevice( addOutput(output, outputDesc); audio_io_handle_t dstOutput = getOutputForEffect(); if (dstOutput == output) { +#ifdef DOLBY_ENABLE + status_t status = mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput); + if (status == NO_ERROR) { + for (size_t i = 0; i < mEffects.size(); i++) { + sp desc = mEffects.valueAt(i); + if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX) { + // update the mIo member of EffectDescriptor for the global effect + ALOGV("%s updating mIo", __FUNCTION__); + desc->mIo = dstOutput; + } + } + } else { + ALOGW("%s moveEffects from %d to %d failed", __FUNCTION__, srcOutput, dstOutput); + } +#else // DOLBY_END mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput); +#endif // LINE_ADDED_BY_DOLBY } mPreviousOutputs = mOutputs; ALOGV("getOutput() returns new direct output %d", output); -- GitLab From c76f2d55bf01a254849eaf858a6e5c18d1ffa524 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Thu, 17 Dec 2015 12:53:04 +0530 Subject: [PATCH 292/298] hal: msm8974: Define MIXER_CARD - Define platform specific MIXER_CARD number so that dolby and srs libraries can make use of it for setting mixer controls Change-Id: Id96525d9405d29b83c81d5586f699426dd01bf47 --- hal/msm8974/platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 2dcfd8a13..fafc64292 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -237,6 +237,7 @@ enum { #endif #define LIB_CSD_CLIENT "libcsd-client.so" +#define MIXER_CARD 0 /* CSD-CLIENT related functions */ typedef int (*init_t)(); typedef int (*deinit_t)(); -- GitLab From ac1bbf016454d950c1f4ec67903ded4b6f97a805 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Thu, 17 Dec 2015 12:53:04 +0530 Subject: [PATCH 293/298] hal: msm8974: Define MIXER_CARD - Define platform specific MIXER_CARD number so that dolby and srs libraries can make use of it for setting mixer controls Change-Id: Id96525d9405d29b83c81d5586f699426dd01bf47 --- hal/msm8974/platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 2dcfd8a13..fafc64292 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -237,6 +237,7 @@ enum { #endif #define LIB_CSD_CLIENT "libcsd-client.so" +#define MIXER_CARD 0 /* CSD-CLIENT related functions */ typedef int (*init_t)(); typedef int (*deinit_t)(); -- GitLab From 8cde13dc5bdad3a7189ecaa5d4ed9ee5276d082e Mon Sep 17 00:00:00 2001 From: Mingming Yin Date: Tue, 21 Jul 2015 15:22:22 -0700 Subject: [PATCH 294/298] hal: fix direct output flag test in open_output_stream - Multi channel HDMI PCM output should be used if AUDIO_OUTPUT_FLAG_DIRECT is set and AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD is not set. Change-Id: I9d967488717b3bf49578f7cdb56a55deda0ce379 --- hal/audio_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 254bbfdf2..d7ffbe3c6 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2336,7 +2336,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->handle = handle; /* Init use case and pcm_config */ - if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) && + if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT) && + !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && ( #ifdef AFE_PROXY_ENABLED out->devices & AUDIO_DEVICE_OUT_PROXY || -- GitLab From 98180cc89e5646a5a2065efa7618da3b39d69cac Mon Sep 17 00:00:00 2001 From: Divya Narayanan Poojary Date: Fri, 11 Mar 2016 16:55:13 +0530 Subject: [PATCH 295/298] audio: acquire lock for compress voip close input/output stream compress voip close input/output function is making call to same api "voip_call_stop()" which will close both Rx and Tx path. Now mmap->status for both pcm devices will be NULL. Meantime if any call to pcm_get_htimestamp()" will lead to crash Change-Id: Icd6953265d791b26b180744721ddb61bd33933aa CRs-fixed: 988730 --- hal/audio_hw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/audio_hw.c b/hal/audio_hw.c index d7ffbe3c6..ffeeee22d 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -2579,9 +2579,11 @@ static void adev_close_output_stream(struct audio_hw_device *dev __unused, ALOGD("%s: enter:stream_handle(%p)",__func__, out); if (out->usecase == USECASE_COMPRESS_VOIP_CALL) { + pthread_mutex_lock(&out->lock); pthread_mutex_lock(&adev->lock); ret = voice_extn_compress_voip_close_output_stream(&stream->common); pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&out->lock); if(ret != 0) ALOGE("%s: Compress voip output cannot be closed, error:%d", __func__, ret); @@ -2958,9 +2960,11 @@ static void adev_close_input_stream(struct audio_hw_device *dev __unused, ALOGD("%s: enter:stream_handle(%p)",__func__, in); if (in->usecase == USECASE_COMPRESS_VOIP_CALL) { + pthread_mutex_lock(&in->lock); pthread_mutex_lock(&adev->lock); ret = voice_extn_compress_voip_close_input_stream(&stream->common); pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&in->lock); if (ret != 0) ALOGE("%s: Compress voip input cannot be closed, error:%d", __func__, ret); -- GitLab From 9e1be9dbf2a2add4d65ee224fcef64556117c1d6 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 28 Apr 2016 13:43:44 -0700 Subject: [PATCH 296/298] DO NOT MERGE Fix AudioEffect reply overflow Bug: 28173666 Change-Id: I055af37a721b20c5da0f1ec4b02f630dcd5aee02 (cherry picked from commit 57fd9637536d40ec8c40a6bed76a71471dab0f64) --- post_proc/bundle.c | 5 +++-- voice_processing/voice_processing.c | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/post_proc/bundle.c b/post_proc/bundle.c index a0d9fcbd7..42e4c9dd4 100644 --- a/post_proc/bundle.c +++ b/post_proc/bundle.c @@ -638,8 +638,9 @@ int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || pReplyData == NULL || - *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + - sizeof(uint16_t))) { + *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint16_t)) || + // constrain memcpy below + ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) { status = -EINVAL; ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d", cmdSize, *replySize); diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c index 1d18a3d2c..0b209f2df 100644 --- a/voice_processing/voice_processing.c +++ b/voice_processing/voice_processing.c @@ -563,7 +563,9 @@ static int fx_command(effect_handle_t self, if (pCmdData == NULL || cmdSize < (int)sizeof(effect_param_t) || pReplyData == NULL || - *replySize < (int)sizeof(effect_param_t)) { + *replySize < (int)sizeof(effect_param_t) || + // constrain memcpy below + ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) { ALOGV("fx_command() EFFECT_CMD_GET_PARAM invalid args"); return -EINVAL; } -- GitLab From 894e49c8ac2a0878b3362c8a8e62078f5f988fb8 Mon Sep 17 00:00:00 2001 From: rago Date: Mon, 22 Aug 2016 17:59:38 -0700 Subject: [PATCH 297/298] Fix potential overflow in Visualizer effect Bug: 30229821 Change-Id: Iea1c4a21735e893aeded95b980044ec0861a7ea8 (cherry picked from commit 2fa52194ef64843c2908c69527384c6c2fcdbafa) (cherry picked from commit 57ac66340ad488a17fc285b6fc2635cb7375d72b) --- visualizer/offload_visualizer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c index 94c44a59b..f4cad35a1 100644 --- a/visualizer/offload_visualizer.c +++ b/visualizer/offload_visualizer.c @@ -846,6 +846,14 @@ int visualizer_command(effect_context_t * context, uint32_t cmdCode, uint32_t cm break; case VISUALIZER_CMD_MEASURE: { + if (pReplyData == NULL || replySize == NULL || + *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) { + ALOGV("%s VISUALIZER_CMD_MEASURE error *replySize %d <" + "(sizeof(int32_t) * MEASUREMENT_COUNT) %d", + __func__, *replySize, sizeof(int32_t) * MEASUREMENT_COUNT); + android_errorWriteLog(0x534e4554, "30229821"); + return -EINVAL; + } uint16_t peak_u16 = 0; float sum_rms_squared = 0.0f; uint8_t nb_valid_meas = 0; -- GitLab From c3b38101235a3b87e2371b0bf0cf23c8219a163e Mon Sep 17 00:00:00 2001 From: kunleiz Date: Thu, 4 Sep 2014 18:47:53 +0800 Subject: [PATCH 298/298] hal: Update active input stream for Voip when voip input started When voip input started, active input stream is not updated. Therefore, as active input stream is NULL no tx device switch occurs for a voip call with primary output. Fixed this by updating active input stream for voip when voip input started. Change-Id: I058bfaa0091eea4a0259224de17be32f271dbdc9 CRs-Fixed: 710923 --- hal/voice_extn/compress_voip.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c index 83809919a..baafbf38c 100644 --- a/hal/voice_extn/compress_voip.c +++ b/hal/voice_extn/compress_voip.c @@ -607,6 +607,7 @@ int voice_extn_compress_voip_start_input_stream(struct stream_in *in) if (!voip_data.in_stream_count) ret = voice_extn_compress_voip_open_input_stream(in); + adev->active_input = in; ret = voip_start_call(adev, &in->config); in->pcm = voip_data.pcm_tx; @@ -665,6 +666,7 @@ int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream) ALOGD("%s: enter", __func__); if(voip_data.in_stream_count > 0) { + adev->active_input = NULL; voip_data.in_stream_count--; status = voip_stop_call(adev); in->pcm = NULL; -- GitLab