From 54da0156376a2d9ddf31042f0ac06d03fec73d3d Mon Sep 17 00:00:00 2001 From: Lianlian Zhu Date: Fri, 08 Dec 2017 12:07:09 +0000 Subject: audio: support hi_pcm_mode in hw[1/3] PD# 154595 Change-Id: I45194c1421faa296d44c0ae7b1c26cf03bf92961 --- diff --git a/audio_hw.c b/audio_hw.c index 736d423..fcb4fa9 100644 --- a/audio_hw.c +++ b/audio_hw.c @@ -515,6 +515,7 @@ static int start_output_stream_direct(struct aml_stream_out *out) if (!pcm_is_ready(out->pcm)) { ALOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm)); pcm_close(out->pcm); + out->pcm = NULL; return -EINVAL; } } else { @@ -898,6 +899,7 @@ static int out_standby(struct audio_stream *stream) static int out_standby_direct(struct audio_stream *stream) { struct aml_stream_out *out = (struct aml_stream_out *) stream; + struct aml_audio_device *adev = out->dev; int status = 0; ALOGI("%s(%p),out %p", __FUNCTION__, stream, out); @@ -909,7 +911,8 @@ static int out_standby_direct(struct audio_stream *stream) free(out->buffer); out->buffer = NULL; } - + if (adev->hi_pcm_mode) + adev->hi_pcm_mode = false; out->standby = 1; pcm_close(out->pcm); out->pcm = NULL; @@ -1248,11 +1251,16 @@ static char *out_get_parameters(const struct audio_stream *stream, const char *k struct aml_stream_out *out = (struct aml_stream_out *) stream; struct aml_audio_device *adev = out->dev; ALOGI("out_get_parameters %s,out %p\n", keys, out); + struct str_parms *parms; + audio_format_t format; + int ret = 0; + parms = str_parms_create_str(keys); + ret = str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FORMAT ,&format); if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { if (out->out_device & AUDIO_DEVICE_OUT_HDMI_ARC) { cap = (char *)get_hdmi_arc_cap(adev->hdmi_arc_ad, HDMI_ARC_MAX_FORMAT, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES); } else { - cap = (char *)get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES); + cap = (char *)get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,format); } if (cap) { para = strdup(cap); @@ -1266,7 +1274,7 @@ static char *out_get_parameters(const struct audio_stream *stream, const char *k if (out->out_device & AUDIO_DEVICE_OUT_HDMI_ARC) { cap = (char *)get_hdmi_arc_cap(adev->hdmi_arc_ad, HDMI_ARC_MAX_FORMAT, AUDIO_PARAMETER_STREAM_SUP_CHANNELS); } else { - cap = (char *)get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_CHANNELS); + cap = (char *)get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_CHANNELS,format); } if (cap) { para = strdup(cap); @@ -1280,7 +1288,7 @@ static char *out_get_parameters(const struct audio_stream *stream, const char *k if (out->out_device & AUDIO_DEVICE_OUT_HDMI_ARC) { cap = (char *)get_hdmi_arc_cap(adev->hdmi_arc_ad, HDMI_ARC_MAX_FORMAT, AUDIO_PARAMETER_STREAM_SUP_FORMATS); } else { - cap = (char *)get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_FORMATS); + cap = (char *)get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_FORMATS,format); } if (cap) { para = strdup(cap); @@ -1477,6 +1485,14 @@ static ssize_t out_write_legacy(struct audio_stream_out *stream, const void* buf */ pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); + //if hi pcm mode ,we need releae i2s device so direct stream can get it. + if (adev->hi_pcm_mode ) { + if (!out->standby) + do_output_standby(out); + ret = -1 ; + pthread_mutex_unlock(&adev->lock); + goto exit; + } //here to check whether hwsync out stream and other stream are enabled at the same time. //if that we need do the hal mixer of the two out stream. if (out->hw_sync_mode == 1) { @@ -1645,7 +1661,8 @@ if (!(adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO)) { //samesource_flag = get_sysfs_int("/sys/class/audiodsp/audio_samesource"); if (codec_type != out->last_codec_type/*samesource_flag == 0*/ && codec_type == 0) { ALOGI("to enable same source,need reset alsa,type %d,same source flag %d \n", codec_type, samesource_flag); - pcm_stop(out->pcm); + if (out->pcm) + pcm_stop(out->pcm); } out->last_codec_type = codec_type; } @@ -2244,6 +2261,14 @@ static ssize_t out_write_direct(struct audio_stream_out *stream, const void* buf */ ALOGV("out_write_direct:out %p,position %zu, out_write size %"PRIu64, out, bytes, out->frame_write_sum); + /*when hi-pcm stopped and switch to 2-ch , then switch to hi-pcm,hi-pcm-mode must be + set and wait 20ms for i2s device release*/ + if (get_codec_type(out->hal_format) == TYPE_PCM && !adev->hi_pcm_mode + && (out->config.rate > 48000 || out->config.channels >= 6) + ) { + adev->hi_pcm_mode = true; + usleep(20000); + } pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); if (out->pause_status == true) { @@ -2413,93 +2438,76 @@ static ssize_t out_write_direct(struct audio_stream_out *stream, const void* buf } goto exit; } - if (!out->standby) { - if (out->multich == 8) { - int *p32 = NULL; - short *p16 = (short *) buf; - short *p16_temp; - int i, NumSamps; - NumSamps = out_frames * frame_size / sizeof(short); - p32 = malloc(NumSamps * sizeof(int)); - if (p32 != NULL) { - //here to swap the channnl data here - //actual now:L,missing,R,RS,RRS,,LS,LRS,missing - //expect L,C,R,RS,RRS,LRS,LS,LFE (LFE comes from to center) - //actual audio data layout L,R,C,none/LFE,LRS,RRS,LS,RS - p16_temp = (short *) p32; - for (i = 0; i < NumSamps; i = i + 8) { - p16_temp[0 + i]/*L*/ = p16[0 + i]; - p16_temp[1 + i]/*R*/ = p16[1 + i]; - p16_temp[2 + i] /*LFE*/ = p16[3 + i]; - p16_temp[3 + i] /*C*/ = p16[2 + i]; - p16_temp[4 + i] /*LS*/ = p16[6 + i]; - p16_temp[5 + i] /*RS*/ = p16[7 + i]; - p16_temp[6 + i] /*LRS*/ = p16[4 + i]; - p16_temp[7 + i]/*RRS*/ = p16[5 + i]; - } - memcpy(p16, p16_temp, NumSamps * sizeof(short)); - for (i = 0; i < NumSamps; i++) { //suppose 16bit/8ch PCM - p32[i] = p16[i] << 16; - } - ret = pcm_write(out->pcm, (void *) p32, NumSamps * 4); - free(p32); - } - } else if (out->multich == 6) { - int *p32 = NULL; - short *p16 = (short *) buf; - short *p16_temp; - int i, j, NumSamps, real_samples; - real_samples = out_frames * frame_size / sizeof(short); - NumSamps = real_samples * 8 / 6; - //ALOGI("6ch to 8 ch real %d, to %d,bytes %d,frame size %d\n",real_samples,NumSamps,bytes,frame_size); - p32 = malloc(NumSamps * sizeof(int)); - if (p32 != NULL) { - p16_temp = (short *) p32; - for (i = 0; i < real_samples; i = i + 6) { - p16_temp[0 + i]/*L*/ = p16[0 + i]; - p16_temp[1 + i]/*R*/ = p16[1 + i]; - p16_temp[2 + i] /*LFE*/ = p16[3 + i]; - p16_temp[3 + i] /*C*/ = p16[2 + i]; - p16_temp[4 + i] /*LS*/ = p16[4 + i]; - p16_temp[5 + i] /*RS*/ = p16[5 + i]; - } - memcpy(p16, p16_temp, real_samples * sizeof(short)); - memset(p32, 0, NumSamps * sizeof(int)); - for (i = 0, j = 0; j < NumSamps; i = i + 6, j = j + 8) { //suppose 16bit/8ch PCM - p32[j] = p16[i] << 16; - p32[j + 1] = p16[i + 1] << 16; - p32[j + 2] = p16[i + 2] << 16; - p32[j + 3] = p16[i + 3] << 16; - p32[j + 4] = p16[i + 4] << 16; - p32[j + 5] = p16[i + 5] << 16; - } - ret = pcm_write(out->pcm, (void *) p32, NumSamps * 4); - free(p32); - } - } else { -#if 0 - codec_type = - get_sysfs_int("/sys/class/audiodsp/digital_codec"); - samesource_flag = - get_sysfs_int("/sys/class/audiodsp/audio_samesource"); - if (out->last_codec_type > 0 && codec_type != out->last_codec_type) { - samesource_flag = 1; - } - if (samesource_flag == 1 && codec_type) { - ALOGI - ("to disable same source,need reset alsa,last %d,type %d,same source flag %d ,\n", - out->last_codec_type, codec_type, samesource_flag); - out->last_codec_type = codec_type; - pcm_stop(out->pcm); - } -#endif - ALOGV("write size %zu\n", out_frames * frame_size); - ret = pcm_write(out->pcm, (void *) buf, out_frames * frame_size); - if (ret == 0) { - out->frame_write_sum += out_frames; - } - } - } + //here handle LPCM audio (hi-res audio) which goes to direct output + if (!out->standby) { + int write_size = out_frames * frame_size; + //for 5.1/7.1 LPCM direct output,we assume only use left channel volume + if (!codec_type_is_raw_data(out->codec_type) && (out->multich > 2 || out->hal_format != AUDIO_FORMAT_PCM_16_BIT)) { + //do audio format and data conversion here + int input_frames = out_frames; + write_buf = convert_audio_sample_for_output(input_frames, out->hal_format, out->multich, buf, &write_size); + //volume apply here,TODO need apply that inside convert_audio_sample_for_output function. + if (out->multich == 2) { + short *sample = (short*)write_buf; + int l, r; + int kk; + for (kk = 0; kk < input_frames; kk++) { + l = out->volume_l * sample[kk * 2]; + sample[kk * 2] = CLIP(l); + r = out->volume_r * sample[kk * 2 + 1]; + sample[kk * 2 + 1] = CLIP(r); + } + } else { + int *sample = (int*)write_buf; + int kk; + for (kk = 0; kk < write_size / 4; kk++) { + sample[kk] = out->volume_l * sample[kk]; + } + } + + if (write_buf) { + if (getprop_bool("media.hdmihal.outdump")) { + FILE *fp1 = fopen("/data/tmp/hdmi_audio_out8.pcm", "a+"); + if (fp1) { + int flen = fwrite((char *)buffer, 1, out_frames * frame_size, fp1); + LOGFUNC("flen = %d---outlen=%d ", flen, out_frames * frame_size); + fclose(fp1); + } else { + LOGFUNC("could not open file:/data/hdmi_audio_out.pcm"); + } + } + ret = pcm_write(out->pcm, write_buf, write_size); + if (ret == 0) { + out->frame_write_sum += out_frames; + }else { + ALOGI("pcm_get_error(out->pcm):%s",pcm_get_error(out->pcm)); + } + if (write_buf) { + free(write_buf); + } + } + } else { + //2 channel LPCM or raw data pass through + if (!codec_type_is_raw_data(out->codec_type) && out->config.channels == 2) { + short *sample = (short*)buf; + int l, r; + int kk; + for (kk = 0; kk < out_frames; kk++) { + l = out->volume_l * sample[kk * 2]; + sample[kk * 2] = CLIP(l); + r = out->volume_r * sample[kk * 2 + 1]; + sample[kk * 2 + 1] = CLIP(r); + } + } + ret = pcm_write(out->pcm, (void *) buf, out_frames * frame_size); + if (ret == 0) { + out->frame_write_sum += out_frames; + }else { + ALOGI("pcm_get_error(out->pcm):%s",pcm_get_error(out->pcm)); + } + } + } + exit: total_frame = out->frame_write_sum + out->frame_skip_sum; latency_frames = out_get_latency_frames(stream); @@ -3355,7 +3363,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } /* set default pcm config for direct. */ out->config = pcm_config_out_direct; - out->hal_channel_mask = config->channel_mask; + if (popcount(config->channel_mask) == 0) { + config->channel_mask =AUDIO_CHANNEL_OUT_STEREO; + } + out->hal_channel_mask = config->channel_mask; + //out->config.channels = popcount(config->channel_mask); if (config->sample_rate == 0) { config->sample_rate = 48000; } @@ -3403,6 +3415,10 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->multich = 2; //config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; } + if (digital_codec == TYPE_PCM && (out->config.rate > 48000 || out->config.channels >= 6)) { + ALOGI("open hi pcm mode !\n"); + ladev->hi_pcm_mode = true; + } } else { // TODO: add other cases here ALOGE("DO not support yet!!"); @@ -3934,7 +3950,7 @@ static int adev_open(const hw_module_t* module, const char* name, adev->mode = AUDIO_MODE_NORMAL; adev->out_device = AUDIO_DEVICE_OUT_SPEAKER; adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN; - + adev->hi_pcm_mode = false; select_devices(adev); *device = &adev->hw_device.common; diff --git a/audio_hw.h b/audio_hw.h index 4777026..efd70ec 100644 --- a/audio_hw.h +++ b/audio_hw.h @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_HW_H_ #include @@ -96,6 +111,7 @@ struct aml_audio_device { struct pcm *pcm; bool pcm_paused; unsigned hdmi_arc_ad[HDMI_ARC_MAX_FORMAT]; + bool hi_pcm_mode; }; struct aml_stream_out { diff --git a/audio_hw_profile.c b/audio_hw_profile.c index d90cdeb..81bb83f 100644 --- a/audio_hw_profile.c +++ b/audio_hw_profile.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_profile" #include #include @@ -131,7 +149,7 @@ Dobly_Digital+, 8 ch, 44.1/48 kHz, 16 bit DTS-HD, 8 ch, 44.1/48/88.2/96/176.4/192 kHz, 16 bit MAT, 8 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16 bit */ -char* get_hdmi_sink_cap(const char *keys) +char* get_hdmi_sink_cap(const char *keys,audio_format_t format) { int i = 0; char * infobuf = NULL; @@ -194,7 +212,8 @@ char* get_hdmi_sink_cap(const char *keys) if (mystrstr(infobuf, "176.4")) { size += sprintf(aud_cap + size, "|%s", "176400"); } - if (mystrstr(infobuf, "192")) { + if (mystrstr(infobuf, "192") || (mystrstr(infobuf, "Dobly_Digital+") && + format == AUDIO_FORMAT_IEC61937)) { size += sprintf(aud_cap + size, "|%s", "192000"); } } @@ -222,6 +241,8 @@ char* get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys) int dgraw = 0; int fd = -1; int size = 0; + int raw_support = 0; + int iec_added = 0; char *aud_cap = NULL; unsigned char format, ch, sr; aud_cap = (char*)malloc(1024); @@ -233,16 +254,16 @@ char* get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys) ALOGI("get_hdmi_arc_cap\n"); /* check the format cap */ if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { - size += sprintf(aud_cap, "=%s|", "AUDIO_FORMAT_PCM_16_BIT"); + size += sprintf(aud_cap, "sup_formats=%s", "AUDIO_FORMAT_PCM_16_BIT"); } /*check the channel cap */ else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { //ALOGI("check channels\n"); /* take the 2ch suppported as default */ - size += sprintf(aud_cap, "=%s|", "AUDIO_CHANNEL_OUT_STEREO"); + size += sprintf(aud_cap, "sup_channels=%s", "AUDIO_CHANNEL_OUT_STEREO"); } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { /* take the 32/44.1/48 khz suppported as default */ - size += sprintf(aud_cap, "=%s|", "32000|44100|48000"); + size += sprintf(aud_cap, "sup_sampling_rates=%s", "32000|44100|48000"); //ALOGI("check sample rate\n"); } for (i = 0; i < maxsize; i++) { @@ -255,41 +276,49 @@ char* get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys) if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { //ALOGI("check format\n"); if (format == 10) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_E_AC3"); + raw_support = 1; + size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_E_AC3"); } - if (format == 2) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_AC3"); + else if (format == 2) { + raw_support = 1; + size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_AC3"); } - if (format == 11) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTSHD"); + else if (format == 11) { + raw_support = 1; + size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTSHD"); } else if (format == 7) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS"); + raw_support = 1; + size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_DTS"); + } + else if (format == 12) { + raw_support = 1; + size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_TRUEHD"); } - if (format == 12) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_TRUEHD"); + if (raw_support == 1 && iec_added == 0) { + size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_IEC61937"); } } /*check the channel cap */ else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { //ALOGI("check channels\n"); if (/*format == 1 && */ch == 7) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1"); + size += sprintf(aud_cap + size, "|%s", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1"); } else if (/*format == 1 && */ch == 5) { - size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1"); + size += sprintf(aud_cap + size, "|%s", "AUDIO_CHANNEL_OUT_5POINT1"); } } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { ALOGI("check sample rate\n"); if (format == 1 && sr == 4) { - size += sprintf(aud_cap + size, "%s|", "88200"); + size += sprintf(aud_cap + size, "|%s", "88200"); } if (format == 1 && sr == 5) { - size += sprintf(aud_cap + size, "%s|", "96000"); + size += sprintf(aud_cap + size, "|%s", "96000"); } if (format == 1 && sr == 6) { - size += sprintf(aud_cap + size, "%s|", "176400"); + size += sprintf(aud_cap + size, "|%s", "176400"); } if (format == 1 && sr == 7) { - size += sprintf(aud_cap + size, "%s|", "192000"); + size += sprintf(aud_cap + size, "|%s", "192000"); } } diff --git a/audio_hw_profile.h b/audio_hw_profile.h index fe58eca..d0fe8b4 100644 --- a/audio_hw_profile.h +++ b/audio_hw_profile.h @@ -1,9 +1,27 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_HW_PROFILE_H_ #define _AUDIO_HW_PROFILE_H_ int get_external_card(int type); int get_aml_card(); int get_spdif_port(); -char* get_hdmi_sink_cap(const char *keys); +char* get_hdmi_sink_cap(const char *keys,audio_format_t format); char* get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys); #endif \ No newline at end of file diff --git a/audio_hw_utils.c b/audio_hw_utils.c index 17febea..6eb4bd6 100644 --- a/audio_hw_utils.c +++ b/audio_hw_utils.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_utils" #define LOG_NDEBUG 0 @@ -24,6 +42,7 @@ #include "audio_hwsync.h" #include "audio_hw.h" +#include #ifdef LOG_NDEBUG_FUNCTION #define LOGFUNC(...) ((void)0) @@ -164,3 +183,141 @@ int getprop_bool (const char *path) return 0; } +/* +convert audio formats to supported audio format +8 ch goes to 32 bit +2 ch can be 16 bit or 32 bit +@return input buffer used by alsa drivers to do the data write +*/ +void *convert_audio_sample_for_output(int input_frames, int input_format, int input_ch, void *input_buf, int *out_size) +{ + float lvol = 1.0; + int *out_buf = NULL; + short *p16 = (short*)input_buf; + int *p32 = (int*)input_buf; + int max_ch = input_ch; + int i; + //ALOGV("intput frame %d,input ch %d,buf ptr %p,vol %f\n", input_frames, input_ch, input_buf, lvol); + ALOG_ASSERT(input_buf); + if (input_ch > 2) + max_ch = 8; + //our HW need round the frames to 8 channels + out_buf = malloc(sizeof(int) * max_ch * input_frames); + if (out_buf == NULL) { + ALOGE("malloc buffer failed\n"); + return NULL; + } + switch (input_format) { + case AUDIO_FORMAT_PCM_16_BIT: + break; + case AUDIO_FORMAT_PCM_32_BIT: + break; + case AUDIO_FORMAT_PCM_8_24_BIT: + for (i = 0; i < input_frames * input_ch; i++) { + p32[i] = p32[i] << 8; + } + break; + case AUDIO_FORMAT_PCM_FLOAT: + memcpy_to_i16_from_float(out_buf, input_buf, input_frames * input_ch); + memcpy(input_buf, out_buf, sizeof(short)*input_frames * input_ch); + break; + } + //current all the data are in the input buffer + if (input_ch == 8) { + short *p16_temp; + int i, NumSamps; + int *p32_temp = out_buf; + float m_vol = lvol; + NumSamps = input_frames * input_ch; + //here to swap the channnl data here + //actual now:L,missing,R,RS,RRS,,LS,LRS,missing + //expect L,C,R,RS,RRS,LRS,LS,LFE (LFE comes from to center) + //actual audio data layout L,R,C,none/LFE,LRS,RRS,LS,RS + if (input_format == AUDIO_FORMAT_PCM_16_BIT) { + p16_temp = (short*)out_buf; + for (i = 0; i < NumSamps; i = i + 8) { + p16_temp[0 + i]/*L*/ = m_vol * p16[0 + i]; + p16_temp[1 + i]/*R*/ = m_vol * p16[1 + i]; + p16_temp[2 + i] /*LFE*/ = m_vol * p16[3 + i]; + p16_temp[3 + i] /*C*/ = m_vol * p16[2 + i]; + p16_temp[4 + i] /*LS*/ = m_vol * p16[6 + i]; + p16_temp[5 + i] /*RS*/ = m_vol * p16[7 + i]; + p16_temp[6 + i] /*LRS*/ = m_vol * p16[4 + i]; + p16_temp[7 + i]/*RRS*/ = m_vol * p16[5 + i]; + } + memcpy(p16, p16_temp, NumSamps * sizeof(short)); + for (i = 0; i < NumSamps; i++) { //suppose 16bit/8ch PCM + p32_temp[i] = p16[i] << 16; + } + } else { + p32_temp = out_buf; + for (i = 0; i < NumSamps; i = i + 8) { + p32_temp[0 + i]/*L*/ = m_vol * p32[0 + i]; + p32_temp[1 + i]/*R*/ = m_vol * p32[1 + i]; + p32_temp[2 + i] /*LFE*/ = m_vol * p32[3 + i]; + p32_temp[3 + i] /*C*/ = m_vol * p32[2 + i]; + p32_temp[4 + i] /*LS*/ = m_vol * p32[6 + i]; + p32_temp[5 + i] /*RS*/ = m_vol * p32[7 + i]; + p32_temp[6 + i] /*LRS*/ = m_vol * p32[4 + i]; + p32_temp[7 + i]/*RRS*/ = m_vol * p32[5 + i]; + } + + } + *out_size = NumSamps * sizeof(int); + + } else if (input_ch == 6) { + int j, NumSamps, real_samples; + short *p16_temp; + int *p32_temp = out_buf; + float m_vol = lvol; + NumSamps = input_frames * input_ch; + real_samples = NumSamps; + NumSamps = real_samples * 8 / 6; + //ALOGI("6ch to 8 ch real %d, to %d\n",real_samples,NumSamps); + if (input_format == AUDIO_FORMAT_PCM_16_BIT) { + p16_temp = (short*)out_buf; + for (i = 0; i < real_samples; i = i + 6) { + p16_temp[0 + i]/*L*/ = m_vol * p16[0 + i]; + p16_temp[1 + i]/*R*/ = m_vol * p16[1 + i]; + p16_temp[2 + i] /*LFE*/ = m_vol * p16[3 + i]; + p16_temp[3 + i] /*C*/ = m_vol * p16[2 + i]; + p16_temp[4 + i] /*LS*/ = m_vol * p16[4 + i]; + p16_temp[5 + i] /*RS*/ = m_vol * p16[5 + i]; + } + memcpy(p16, p16_temp, real_samples * sizeof(short)); + memset(p32_temp, 0, NumSamps * sizeof(int)); + for (i = 0, j = 0; j < NumSamps; i = i + 6, j = j + 8) { //suppose 16bit/8ch PCM + p32_temp[j + 0] = p16[i] << 16; + p32_temp[j + 1] = p16[i + 1] << 16; + p32_temp[j + 2] = p16[i + 2] << 16; + p32_temp[j + 3] = p16[i + 3] << 16; + p32_temp[j + 4] = p16[i + 4] << 16; + p32_temp[j + 5] = p16[i + 5] << 16; + } + } else { + p32_temp = out_buf; + memset(p32_temp, 0, NumSamps * sizeof(int)); + for (i = 0, j = 0; j < NumSamps; i = i + 6, j = j + 8) { //suppose 16bit/8ch PCM + p32_temp[j + 0] = m_vol * p32[i + 0]; + p32_temp[j + 1] = m_vol * p32[i + 1] ; + p32_temp[j + 2] = m_vol * p32[i + 2] ; + p32_temp[j + 3] = m_vol * p32[i + 3] ; + p32_temp[j + 4] = m_vol * p32[i + 4] ; + p32_temp[j + 5] = m_vol * p32[i + 5] ; + } + } + *out_size = NumSamps * sizeof(int); + } else { + //2ch with 24 bit/32/float audio + int *p32_temp = out_buf; + short *p16_temp = (short*)out_buf; + for (i = 0; i < input_frames; i++) { + p16_temp[2 * i + 0] = lvol * p16[2 * i + 0]; + p16_temp[2 * i + 1] = lvol * p16[2 * i + 1]; + } + *out_size = sizeof(short) * input_frames * input_ch; + } + return out_buf; + +} + diff --git a/audio_hw_utils.h b/audio_hw_utils.h index 2a2a836..55a8078 100644 --- a/audio_hw_utils.h +++ b/audio_hw_utils.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_HW_UTILS_H_ #define _AUDIO_HW_UTILS_H_ int get_sysfs_uint(const char *path, uint *value); @@ -9,4 +27,6 @@ int get_codec_type(int format); int getprop_bool (const char *path); unsigned char codec_type_is_raw_data(int type); int mystrstr(char *mystr,char *substr); +void *convert_audio_sample_for_output(int input_frames,int input_format,int input_ch,void *input_buf,int *out_size/*,float lvol*/); + #endif diff --git a/audio_hwsync.c b/audio_hwsync.c index 2fd1e89..a04fc70 100644 --- a/audio_hwsync.c +++ b/audio_hwsync.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_hwsync" #include diff --git a/audio_hwsync.h b/audio_hwsync.h index 9330c6b..c78cab0 100644 --- a/audio_hwsync.h +++ b/audio_hwsync.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2010 Amlogic Corporation. + * + * 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_HWSYNC_H_ #define _AUDIO_HWSYNC_H_ -- cgit