summaryrefslogtreecommitdiff
authorLianlian Zhu <lianlian.zhu@amlogic.com>2017-12-08 12:07:09 (GMT)
committer Lianlian Zhu <lianlian.zhu@amlogic.com>2017-12-09 13:44:15 (GMT)
commit54da0156376a2d9ddf31042f0ac06d03fec73d3d (patch)
tree27de99e13735dab1b0c4597658f150d8ea65ddb6
parent1255abefa591b4aeaac3929bd4bf877e31fd81a8 (diff)
downloadaudio-54da0156376a2d9ddf31042f0ac06d03fec73d3d.zip
audio-54da0156376a2d9ddf31042f0ac06d03fec73d3d.tar.gz
audio-54da0156376a2d9ddf31042f0ac06d03fec73d3d.tar.bz2
audio: support hi_pcm_mode in hw[1/3]
PD# 154595 Change-Id: I45194c1421faa296d44c0ae7b1c26cf03bf92961
Diffstat
-rw-r--r--audio_hw.c204
-rw-r--r--audio_hw.h16
-rw-r--r--audio_hw_profile.c67
-rw-r--r--audio_hw_profile.h20
-rw-r--r--audio_hw_utils.c157
-rw-r--r--audio_hw_utils.h20
-rw-r--r--audio_hwsync.c18
-rw-r--r--audio_hwsync.h18
8 files changed, 406 insertions, 114 deletions
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 <audio_utils/resampler.h>
@@ -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 <errno.h>
#include <pthread.h>
@@ -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 <audio_utils/primitives.h>
#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 <stdint.h>
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_