summaryrefslogtreecommitdiff
authorJian Xu <jian.xu@amlogic.com>2016-04-12 13:13:09 (GMT)
committer Jian Xu <jian.xu@amlogic.com>2016-04-23 04:59:42 (GMT)
commit8c936715ae0fe847f1ac6912eafd0377ca893ac4 (patch)
tree7110b21a812eb912d9f972fd780df9b645596287
parent66e6ff7906b80d508cfe02ab6dd39f794b3a0e1d (diff)
downloadaudio-8c936715ae0fe847f1ac6912eafd0377ca893ac4.zip
audio-8c936715ae0fe847f1ac6912eafd0377ca893ac4.tar.gz
audio-8c936715ae0fe847f1ac6912eafd0377ca893ac4.tar.bz2
PD#119007: audio: add audio hwsync and hdmi dynamic mode
Change-Id: I6fddd7d33c369da6e3f00a9c6d66a1333b5b30ba
Diffstat
-rw-r--r--Android.mk35
-rw-r--r--audio_hw.c1213
-rw-r--r--audio_hw.h31
-rw-r--r--audio_hw_profile.c215
-rw-r--r--audio_hw_profile.h3
-rw-r--r--audio_hw_utils.c151
-rw-r--r--audio_hw_utils.h10
-rw-r--r--audio_hwsync.c122
-rw-r--r--audio_hwsync.h58
-rw-r--r--hdmi_audio_hw.c3760
-rw-r--r--hdmi_audio_hw.h86
-rwxr-xr-xhdmi_hw.c831
-rw-r--r--spdifenc_wrap.cpp80
13 files changed, 3037 insertions, 3558 deletions
diff --git a/Android.mk b/Android.mk
index 3f70745..3293362 100644
--- a/Android.mk
+++ b/Android.mk
@@ -73,27 +73,26 @@ ifeq ($(strip $(BOARD_ALSA_AUDIO)),tiny)
system/media/audio_utils/include
LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libutils
- LOCAL_MODULE_TAGS := optional
-
- include $(BUILD_SHARED_LIBRARY)
+#ifdef DOLBY_UDC_PASSTHROUGH_HDMI_PACK
+LOCAL_SRC_FILES += spdifenc_wrap.cpp
+LOCAL_C_INCLUDES += \
+ $(call include-path-for, audio-utils)
+LOCAL_SHARED_LIBRARIES += \
+ libaudiospdif
+#endif # DOLBY_UDC_PASSTHROUGH_HDMI_PACK
+ifdef DOLBY_EAC3_TO_AC3_CONVERTER
+LOCAL_SHARED_LIBRARIES += \
+ libdlb_converter
+endif
+LOCAL_SRC_FILES += audio_hw_profile.c
+LOCAL_SRC_FILES += audio_hw_utils.c
+LOCAL_SRC_FILES += audio_hwsync.c
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_SHARED_LIBRARY)
#########################################################
-ifdef DOLBY_UDC
-
-include $(CLEAR_VARS)
- LOCAL_MODULE := audio.hdmi6.amlogic
- LOCAL_MODULE_RELATIVE_PATH := hw
- LOCAL_SRC_FILES := hdmi_hw.c
- LOCAL_C_INCLUDES += \
- external/tinyalsa/include \
- system/media/audio_utils/include \
- system/media/audio_effects/include
- LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libdl libutils
- LOCAL_MODULE_TAGS := optional
-
-endif
#########################################################
# Audio Policy Manager
@@ -128,4 +127,4 @@ include $(BUILD_SHARED_LIBRARY)
endif # USE_CUSTOM_AUDIO_POLICY
endif # BOARD_ALSA_AUDIO
-include $(call all-makefiles-under,$(LOCAL_PATH)) \ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio_hw.c b/audio_hw.c
index 802336a..9c7452c 100644
--- a/audio_hw.c
+++ b/audio_hw.c
@@ -13,9 +13,9 @@
* 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 LOG_NDEBUG 0
//#define LOG_NDEBUG_FUNCTION
#ifdef LOG_NDEBUG_FUNCTION
#define LOGFUNC(...) ((void)0)
@@ -49,6 +49,8 @@
#include "libTVaudio/audio/audio_effect_control.h"
+
+
/* ALSA cards for AML */
#define CARD_AMLOGIC_BOARD 0
#define CARD_AMLOGIC_USB 1
@@ -71,6 +73,8 @@ static unsigned CAPTURE_PERIOD_SIZE = DEFAULT_CAPTURE_PERIOD_SIZE;
#define RESAMPLER_BUFFER_FRAMES (PERIOD_SIZE * 6)
#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
+#define NSEC_PER_SECOND 1000000000ULL
+
static unsigned int DEFAULT_OUT_SAMPLING_RATE = 48000;
/* sampling rate when using MM low power port */
@@ -81,6 +85,13 @@ static unsigned int DEFAULT_OUT_SAMPLING_RATE = 48000;
#define VX_NB_SAMPLING_RATE 8000
#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define TSYNC_FIRSTAPTS "/sys/class/tsync/firstapts"
+#define TSYNC_PCRSCR "/sys/class/tsync/pts_pcrscr"
+#define TSYNC_EVENT "/sys/class/tsync/event"
+#define TSYNC_APTS "/sys/class/tsync/pts_audio"
+#define SYSTIME_CORRECTION_THRESHOLD (90000*10/100)
+#define APTS_DISCONTINUE_THRESHOLD_MIN (90000/2)
+#define APTS_DISCONTINUE_THRESHOLD_MAX (5*90000)
struct pcm_config pcm_config_out = {
.channels = 2,
.rate = MM_FULL_POWER_SAMPLING_RATE,
@@ -121,8 +132,16 @@ struct aml_audio_device {
struct audio_route *ar;
struct echo_reference_itfe *echo_reference;
bool low_power;
+ bool hw_sync_mode;
+ bool first_apts_flag;//flag to indicate set first apts
+ uint64_t first_apts;
+ uint64_t last_apts_from_header;
};
+#define HW_SYNC_STATE_HEADER 0
+#define HW_SYNC_STATE_BODY 1
+#define HW_SYNC_STATE_RESYNC 2
+
struct aml_stream_out {
struct audio_stream_out stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -137,12 +156,19 @@ struct aml_stream_out {
int write_threshold;
bool low_power;
uint32_t frame_count;
- int fram_write_sum;
+ int frame_write_sum;
+ uint8_t hw_sync_header[16];
+ int hw_sync_header_cnt;
+ int hw_sync_state;
+ int hw_sync_body_cnt;
+ uint8_t body_align[64];
+ uint8_t body_align_cnt;
int32_t *tmp_buffer_8ch;
int is_tv_platform;
void *audioeffect_tmp_buffer;
int has_SRS_lib;
int has_EQ_lib;
+ unsigned char pause_status;
};
#define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */
@@ -175,7 +201,7 @@ struct aml_stream_in {
};
static char cache_buffer_bytes[64];
-static uint cached_len=0;
+static uint cached_len = 0;
static bool input_standby = true;
static bool output_standby = true;
static void select_output_device(struct aml_audio_device *adev);
@@ -192,8 +218,9 @@ static int getprop_bool(const char * path)
ret = property_get(path, buf, NULL);
if (ret > 0) {
- if(strcasecmp(buf,"true")==0 || strcmp(buf,"1")==0)
+ if (strcasecmp(buf, "true") == 0 || strcmp(buf, "1") == 0) {
return 1;
+ }
}
return 0;
}
@@ -206,27 +233,88 @@ static int get_sysfs_int(const char * path)
read(fd, bcmd, sizeof(bcmd));
val = strtol(bcmd, NULL, 10);
close(fd);
- }else{
- LOGFUNC("[%s]open %s node failed! return 0\n",path, __FUNCTION__);
+ } else {
+ LOGFUNC("[%s]open %s node failed! return 0\n", path, __FUNCTION__);
}
return val;
}
+static int get_sysfs_int16(const char *path, unsigned *value)
+{
+ int fd;
+ char valstr[64];
+ unsigned val = 0;
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ memset(valstr, 0, 64);
+ read(fd, valstr, 64 - 1);
+ valstr[strlen(valstr)] = '\0';
+ close(fd);
+ } else {
+ ALOGE("unable to open file %s\n", path);
+ return -1;
+ }
+ if (sscanf(valstr, "0x%lx", &val) < 1) {
+ ALOGE("unable to get pts from: %s", valstr);
+ return -1;
+ }
+ *value = val;
+ return 0;
+}
+static int sysfs_set_sysfs_str(const char *path, const char *val)
+{
+ int fd;
+ int bytes;
+ fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
+ if (fd >= 0) {
+ bytes = write(fd, val, strlen(val));
+ close(fd);
+ return 0;
+ } else {
+ ALOGE("unable to open file %s,err: %s", path, strerror(errno));
+ }
+ return -1;
+}
-static int set_sysfs_type(const char *path, const char *type)
+static void
+set_codec_type(int type)
{
- int ret = -1;
- int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
+ char buf[16];
+ int fd = open("/sys/class/audiodsp/digital_codec", O_WRONLY);
+
if (fd >= 0) {
- char set_type[10] = {0};
- int length = snprintf(set_type, sizeof(set_type), "%s", type);
- if (length > 0)
- ret = write(fd, set_type, length);
- LOGFUNC("%s , %s\n", path, set_type);
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf), "%d", type);
+
+ write(fd, buf, sizeof(buf));
close(fd);
- }else{
- LOGFUNC("open hdmi-tx node:%s failed!\n", path);
}
- return ret;
+}
+static inline bool hwsync_header_valid(uint8_t *header)
+{
+ return (header[0] == 0x55) &&
+ (header[1] == 0x55) &&
+ (header[2] == 0x00) &&
+ (header[3] == 0x01);
+}
+
+static inline uint64_t hwsync_header_get_pts(uint8_t *header)
+{
+ return (((uint64_t)header[8]) << 56) |
+ (((uint64_t)header[9]) << 48) |
+ (((uint64_t)header[10]) << 40) |
+ (((uint64_t)header[11]) << 32) |
+ (((uint64_t)header[12]) << 24) |
+ (((uint64_t)header[13]) << 16) |
+ (((uint64_t)header[14]) << 8) |
+ ((uint64_t)header[15]);
+}
+
+static inline uint32_t hwsync_header_get_size(uint8_t *header)
+{
+ return (((uint32_t)header[4]) << 24) |
+ (((uint32_t)header[5]) << 16) |
+ (((uint32_t)header[6]) << 8) |
+ ((uint32_t)header[7]);
}
static void select_devices(struct aml_audio_device *adev)
@@ -236,7 +324,7 @@ static void select_devices(struct aml_audio_device *adev)
int headphone_on;
int speaker_on;
int hdmi_on;
- int earpiece;
+ int earpiece;
int mic_in;
int headset_mic;
@@ -245,26 +333,31 @@ static void select_devices(struct aml_audio_device *adev)
speaker_on = adev->out_device & AUDIO_DEVICE_OUT_SPEAKER;
hdmi_on = adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL;
earpiece = adev->out_device & AUDIO_DEVICE_OUT_EARPIECE;
- mic_in = adev->in_device & ( AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC);
+ mic_in = adev->in_device & (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC);
headset_mic = adev->in_device & AUDIO_DEVICE_IN_WIRED_HEADSET;
LOGFUNC("%s : hs=%d , hp=%d, sp=%d, hdmi=0x%x,earpiece=0x%x", __func__,
- headset_on, headphone_on, speaker_on,hdmi_on,earpiece);
+ headset_on, headphone_on, speaker_on, hdmi_on, earpiece);
LOGFUNC("%s : in_device(%#x), mic_in(%#x), headset_mic(%#x)", __func__,
- adev->in_device, mic_in, headset_mic);
+ adev->in_device, mic_in, headset_mic);
audio_route_reset(adev->ar);
LOGFUNC("%s : output_standby=%d,input_standby=%d", __func__,
- output_standby, input_standby);
- if (hdmi_on)
+ output_standby, input_standby);
+ if (hdmi_on) {
audio_route_apply_path(adev->ar, "hdmi");
- if (headphone_on || headset_on)
+ }
+ if (headphone_on || headset_on) {
audio_route_apply_path(adev->ar, "headphone");
- if (speaker_on ||earpiece )
+ }
+ if (speaker_on || earpiece) {
audio_route_apply_path(adev->ar, "speaker");
- if (mic_in)
+ }
+ if (mic_in) {
audio_route_apply_path(adev->ar, "main_mic");
- if (headset_mic)
+ }
+ if (headset_mic) {
audio_route_apply_path(adev->ar, "headset-mic");
+ }
audio_route_update_mixer(adev->ar);
@@ -308,10 +401,11 @@ static void select_mode(struct aml_audio_device *adev)
a call. This works because we're sure that the audio policy
manager will update the output device after the audio mode
change, even if the device selection did not change. */
- if ((adev->out_device & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER)
+ if ((adev->out_device & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER) {
adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
- else
+ } else {
adev->out_device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ }
return;
}
@@ -388,7 +482,8 @@ OUT:
return port;
}
-static int get_spdif_port(){
+static int get_spdif_port()
+{
int port = -1, err = 0;
int fd = -1;
unsigned fileSize = 512;
@@ -415,7 +510,7 @@ static int get_spdif_port(){
return -EINVAL;
}
pd = strstr(read_buf, "SPDIF");
- port = *(pd -3) - '0';
+ port = *(pd - 3) - '0';
OUT:
free(read_buf);
@@ -431,7 +526,7 @@ static int start_output_stream(struct aml_stream_out *out)
int ret;
LOGFUNC("%s(adev->out_device=%#x, adev->mode=%d)",
- __FUNCTION__, adev->out_device, adev->mode);
+ __FUNCTION__, adev->out_device, adev->mode);
adev->active_output = out;
@@ -441,22 +536,21 @@ static int start_output_stream(struct aml_stream_out *out)
}
card = get_aml_card();
- if (adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO){
+ if (adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
port = get_pcm_bt_port();
out->config = pcm_config_bt;
} else {
port = PORT_MM;
out->config = pcm_config_out;
}
- LOGFUNC("*%s, open card(%d) port(%d)", __FUNCTION__,card,port);
+ LOGFUNC("*%s, open card(%d) port(%d)", __FUNCTION__, card, port);
/* default to low power: will be corrected in out_write if necessary before first write to
* tinyalsa.
*/
- out->write_threshold = out->config.period_size*PLAYBACK_PERIOD_COUNT;
+ out->write_threshold = out->config.period_size * PLAYBACK_PERIOD_COUNT;
out->config.start_threshold = out->config.period_size * PLAYBACK_PERIOD_COUNT;
out->config.avail_min = 0;//SHORT_PERIOD_SIZE;
- out->frame_count = 0;
out->pcm = pcm_open(card, port, PCM_OUT /*| PCM_MMAP | PCM_NOIRQ*/, &(out->config));
if (!pcm_is_ready(out->pcm)) {
@@ -465,44 +559,46 @@ static int start_output_stream(struct aml_stream_out *out)
adev->active_output = NULL;
return -ENOMEM;
}
- if(out->config.rate != out_get_sample_rate(&out->stream.common)){
-
- LOGFUNC("%s(out->config.rate=%d, out->config.channels=%d)",
+ if (out->config.rate != out_get_sample_rate(&out->stream.common)) {
+
+ LOGFUNC("%s(out->config.rate=%d, out->config.channels=%d)",
__FUNCTION__, out->config.rate, out->config.channels);
ret = create_resampler(out_get_sample_rate(&out->stream.common),
- out->config.rate,
- out->config.channels,
- RESAMPLER_QUALITY_DEFAULT,
- NULL,
- &out->resampler);
- if (ret != 0)
- {
+ out->config.rate,
+ out->config.channels,
+ RESAMPLER_QUALITY_DEFAULT,
+ NULL,
+ &out->resampler);
+ if (ret != 0) {
ALOGE("cannot create resampler for output");
return -ENOMEM;
}
out->buffer_frames = (out->config.period_size * out->config.rate) /
- out_get_sample_rate(&out->stream.common) + 1;
+ out_get_sample_rate(&out->stream.common) + 1;
out->buffer = malloc(pcm_frames_to_bytes(out->pcm, out->buffer_frames));
- if (out->buffer == NULL){
+ if (out->buffer == NULL) {
ALOGE("cannot malloc memory for out->buffer");
return -ENOMEM;
}
}
LOGFUNC("channels=%d---format=%d---period_count%d---period_size%d---rate=%d---",
- out->config.channels, out->config.format, out->config.period_count,
- out->config.period_size, out->config.rate);
+ out->config.channels, out->config.format, out->config.period_count,
+ out->config.period_size, out->config.rate);
- if (adev->echo_reference != NULL)
+ if (adev->echo_reference != NULL) {
out->echo_reference = adev->echo_reference;
- if (out->resampler){
+ }
+ if (out->resampler) {
out->resampler->reset(out->resampler);
}
-
if (out->is_tv_platform == 1) {
- set_sysfs_type("/sys/class/amhdmitx/amhdmitx0/aud_output_chs", "2:1");
+ sysfs_set_sysfs_str("/sys/class/amhdmitx/amhdmitx0/aud_output_chs", "2:1");
+ }
+ set_codec_type(0);
+ if (adev->hw_sync_mode == 1) {
+ LOGFUNC("start_output_stream with hw sync enable\n");
}
-
return 0;
}
@@ -510,13 +606,15 @@ static int check_input_parameters(uint32_t sample_rate, audio_format_t format, i
{
LOGFUNC("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__, sample_rate, format, channel_count);
- if (format != AUDIO_FORMAT_PCM_16_BIT)
+ if (format != AUDIO_FORMAT_PCM_16_BIT) {
return -EINVAL;
+ }
- if ((channel_count < 1) || (channel_count > 2))
+ if ((channel_count < 1) || (channel_count > 2)) {
return -EINVAL;
+ }
- switch(sample_rate) {
+ switch (sample_rate) {
case 8000:
case 11025:
case 16000:
@@ -540,8 +638,9 @@ static size_t get_input_buffer_size(uint32_t sample_rate, audio_format_t format,
LOGFUNC("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__, sample_rate, format, channel_count);
- if (check_input_parameters(sample_rate, format, channel_count) != 0)
+ if (check_input_parameters(sample_rate, format, channel_count) != 0) {
return 0;
+ }
/* take resampling into account and return the closest majoring
multiple of 16 frames, as audioflinger expects audio buffers to
@@ -573,21 +672,22 @@ static void remove_echo_reference(struct aml_stream_out *out,
}
static void put_echo_reference(struct aml_audio_device *adev,
- struct echo_reference_itfe *reference)
+ struct echo_reference_itfe *reference)
{
if (adev->echo_reference != NULL &&
- reference == adev->echo_reference) {
- if (adev->active_output != NULL)
+ reference == adev->echo_reference) {
+ if (adev->active_output != NULL) {
remove_echo_reference(adev->active_output, reference);
+ }
release_echo_reference(reference);
adev->echo_reference = NULL;
}
}
static struct echo_reference_itfe *get_echo_reference(struct aml_audio_device *adev,
- audio_format_t format __unused,
- uint32_t channel_count,
- uint32_t sampling_rate)
+ audio_format_t format __unused,
+ uint32_t channel_count,
+ uint32_t sampling_rate)
{
put_echo_reference(adev, adev->echo_reference);
if (adev->active_output != NULL) {
@@ -602,15 +702,16 @@ static struct echo_reference_itfe *get_echo_reference(struct aml_audio_device *a
wr_channel_count,
wr_sampling_rate,
&adev->echo_reference);
- if (status == 0)
+ if (status == 0) {
add_echo_reference(adev->active_output, adev->echo_reference);
+ }
}
return adev->echo_reference;
}
static int get_playback_delay(struct aml_stream_out *out,
- size_t frames,
- struct echo_reference_buffer *buffer)
+ size_t frames,
+ struct echo_reference_buffer *buffer)
{
size_t kernel_frames;
@@ -621,16 +722,16 @@ static int get_playback_delay(struct aml_stream_out *out,
buffer->time_stamp.tv_nsec = 0;
buffer->delay_ns = 0;
ALOGV("get_playback_delay(): pcm_get_htimestamp error,"
- "setting playbackTimestamp to 0");
+ "setting playbackTimestamp to 0");
return status;
}
kernel_frames = pcm_get_buffer_size(out->pcm) - kernel_frames;
- ALOGV("~~pcm_get_buffer_size(out->pcm)=%d",pcm_get_buffer_size(out->pcm));
+ ALOGV("~~pcm_get_buffer_size(out->pcm)=%d", pcm_get_buffer_size(out->pcm));
/* adjust render time stamp with delay added by current driver buffer.
* Add the duration of current frame as we want the render time of the last
* sample being written. */
- buffer->delay_ns = (long)(((int64_t)(kernel_frames + frames)* 1000000000)/
- DEFAULT_OUT_SAMPLING_RATE);
+ buffer->delay_ns = (long)(((int64_t)(kernel_frames + frames) * 1000000000) /
+ DEFAULT_OUT_SAMPLING_RATE);
ALOGV("get_playback_delay time_stamp = [%ld].[%ld], delay_ns: [%d],"
"kernel_frames:[%d]", buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec,
@@ -691,14 +792,13 @@ static int do_output_standby(struct aml_stream_out *out)
if (!out->standby) {
pcm_close(out->pcm);
out->pcm = NULL;
- out->frame_count = 0;
adev->active_output = 0;
- if (out->buffer){
+ if (out->buffer) {
free(out->buffer);
out->buffer = NULL;
}
- if (out->resampler){
+ if (out->resampler) {
release_resampler(out->resampler);
out->resampler = NULL;
}
@@ -717,18 +817,21 @@ static int do_output_standby(struct aml_stream_out *out)
out->echo_reference->write(out->echo_reference, NULL);
out->echo_reference = NULL;
}
-
+ out->pause_status == false;
out->standby = 1;
output_standby = 1;
#if 0
LOGFUNC("%s : output_standby=%d,input_standby=%d",
- __FUNCTION__, output_standby,input_standby);
- if(output_standby && input_standby){
+ __FUNCTION__, output_standby, input_standby);
+ if (output_standby && input_standby) {
reset_mixer_state(adev->ar);
update_mixer_state(adev->ar);
}
#endif
}
+
+ //adev->hw_sync_mode = 0;
+
return 0;
}
@@ -750,7 +853,18 @@ static int out_dump(const struct audio_stream *stream __unused, int fd __unused)
LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, fd);
return 0;
}
-
+static int
+out_flush(const struct audio_stream *stream)
+{
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ pthread_mutex_lock(&out->lock);
+ out->frame_write_sum = 0;
+ out->frame_count = 0;
+ pthread_mutex_unlock(&out->lock);
+ return 0;
+}
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct aml_stream_out *out = (struct aml_stream_out *)stream;
@@ -777,15 +891,16 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
do_output_standby(out);
/* a change in output device may change the microphone selection */
if (adev->active_input &&
- adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
force_input_standby = true;
}
/* force standby if moving to/from HDMI */
if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
- (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
- ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
- (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)))
+ (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
+ ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
+ (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET))) {
do_output_standby(out);
+ }
}
adev->out_device &= ~AUDIO_DEVICE_OUT_ALL;
adev->out_device |= val;
@@ -805,7 +920,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, &sr);
if (ret >= 0) {
if (sr > 0) {
- ALOGI("audio hw sampling_rate change from %d to %d \n",DEFAULT_OUT_SAMPLING_RATE,sr);
+ ALOGI("audio hw sampling_rate change from %d to %d \n", DEFAULT_OUT_SAMPLING_RATE, sr);
DEFAULT_OUT_SAMPLING_RATE = sr;
pcm_config_out.rate = DEFAULT_OUT_SAMPLING_RATE;
out->config.rate = DEFAULT_OUT_SAMPLING_RATE;
@@ -826,7 +941,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FRAME_COUNT, &frame_size);
if (ret >= 0) {
if (frame_size > 0) {
- ALOGI("audio hw frame size change from %d to %d \n",PERIOD_SIZE,frame_size);
+ ALOGI("audio hw frame size change from %d to %d \n", PERIOD_SIZE, frame_size);
PERIOD_SIZE = frame_size;
pcm_config_out.period_size = PERIOD_SIZE;
out->config.period_size = PERIOD_SIZE;
@@ -850,16 +965,16 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
//ALOGI("audio effect EQ parameters are %s\n", value);
if (ret >= 0) {
for (i; i < 5; i++) {
- tmp[0] = value[2*i];
- tmp[1] = value[2*i + 1];
+ tmp[0] = value[2 * i];
+ tmp[1] = value[2 * i + 1];
data = atoi(tmp);
- EQ_parameters[i] = data -10;
+ EQ_parameters[i] = data - 10;
}
ALOGI("audio effect EQ parameters are %d,%d,%d,%d,%d\n", EQ_parameters[0],
- EQ_parameters[1], EQ_parameters[2], EQ_parameters[3], EQ_parameters[4]);
+ EQ_parameters[1], EQ_parameters[2], EQ_parameters[3], EQ_parameters[4]);
ret = 0;
HPEQ_setParameter(EQ_parameters[0], EQ_parameters[1],
- EQ_parameters[2], EQ_parameters[3], EQ_parameters[4]);
+ EQ_parameters[2], EQ_parameters[3], EQ_parameters[4]);
goto exit;
}
int SRS_parameters[5] = {0, 0, 0, 0, 0};
@@ -868,13 +983,13 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
//ALOGI("audio effect SRS parameters are %s\n", value);
if (ret >= 0) {
for (i; i < 5; i++) {
- tmp1[0] = value[3*i];
- tmp1[1] = value[3*i + 1];
- tmp1[2] = value[3*i + 2];
+ tmp1[0] = value[3 * i];
+ tmp1[1] = value[3 * i + 1];
+ tmp1[2] = value[3 * i + 2];
SRS_parameters[i] = atoi(tmp1);
}
ALOGI("audio effect SRS parameters are %d,%d,%d,%d,%d\n", SRS_parameters[0],
- SRS_parameters[1], SRS_parameters[2], SRS_parameters[3], SRS_parameters[4]);
+ SRS_parameters[1], SRS_parameters[2], SRS_parameters[3], SRS_parameters[4]);
ret = 0;
srs_setParameter(SRS_parameters);
goto exit;
@@ -883,9 +998,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_SRS_GAIN, value, sizeof(value));
if (ret >= 0) {
for (i; i < 2; i++) {
- tmp1[0] = value[3*i];
- tmp1[1] = value[3*i + 1];
- tmp1[2] = value[3*i + 2];
+ tmp1[0] = value[3 * i];
+ tmp1[1] = value[3 * i + 1];
+ tmp1[2] = value[3 * i + 2];
SRS_gain[i] = atoi(tmp1);
}
ALOGI("audio effect SRS input/output gain are %d,%d\n", SRS_gain[0], SRS_gain[1]);
@@ -897,8 +1012,8 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_SRS_SWITCH, value, sizeof(value));
if (ret >= 0) {
for (i; i < 3; i++) {
- tmp[0] = value[2*i];
- tmp[1] = value[2*i + 1];
+ tmp[0] = value[2 * i];
+ tmp[1] = value[2 * i + 1];
SRS_switch[i] = atoi(tmp);
}
ALOGI("audio effect SRS switch %d, %d, %d\n", SRS_switch[0], SRS_switch[1], SRS_switch[2]);
@@ -908,6 +1023,20 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
srs_truebass_enable(SRS_switch[2]);
goto exit;
}
+ ret = str_parms_get_str(parms, "hw_av_sync", value, sizeof(value));
+ if (ret >= 0) {
+ int hw_sync_id = atoi(value);
+ unsigned char sync_enable = (hw_sync_id == 12345678) ? 1 : 0;
+ ALOGI("set hw_sync_id %d,%s hw sync mode\n", hw_sync_id, sync_enable ? "enable" : "disable");
+ adev->hw_sync_mode = sync_enable;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ out->frame_count = 0;
+ out->frame_write_sum = 0;
+ pthread_mutex_unlock(&out->lock);
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
exit:
str_parms_destroy(parms);
return ret;
@@ -925,13 +1054,14 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream)
uint32_t ret;
snd_pcm_sframes_t frames = 0;
whole_latency = (out->config.period_size * out->config.period_count * 1000) / out->config.rate;
- if (!out->pcm || !pcm_is_ready(out->pcm))
+ if (!out->pcm || !pcm_is_ready(out->pcm)) {
return whole_latency;
- ret = pcm_ioctl(out->pcm,SNDRV_PCM_IOCTL_DELAY,&frames);
+ }
+ ret = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_DELAY, &frames);
if (ret < 0) {
return whole_latency;
}
- return (frames * 1000)/DEFAULT_OUT_SAMPLING_RATE/* (out->pcm->config.rate)*/;
+ return (frames * 1000) / DEFAULT_OUT_SAMPLING_RATE/* (out->pcm->config.rate)*/;
}
static int out_set_volume(struct audio_stream_out *stream __unused, float left __unused, float right __unused)
@@ -939,8 +1069,69 @@ static int out_set_volume(struct audio_stream_out *stream __unused, float left _
return -ENOSYS;
}
+static int out_pause(struct audio_stream_out *stream)
+{
+ LOGFUNC("out_pause");
+
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ int r = 0;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (out->standby) {
+ goto exit;
+ }
+ if (pcm_is_ready(out->pcm)) {
+ r = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_PAUSE, 1);
+ if (r < 0) {
+ ALOGE("cannot pause channel\n");
+ } else {
+ r = 0;
+ }
+ }
+
+ if (out->dev->hw_sync_mode) {
+ sysfs_set_sysfs_str(TSYNC_EVENT, "AUDIO_PAUSE");
+ }
+ out->pause_status = true;
+exit:
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ return r;
+}
+
+static int out_resume(struct audio_stream_out *stream)
+{
+ LOGFUNC("out_resume");
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ int r = 0;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (out->standby) {
+ goto exit;
+ }
+ if (pcm_is_ready(out->pcm)) {
+ r = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_PAUSE, 0);
+ if (r < 0) {
+ ALOGE("cannot resume channel\n");
+ } else {
+ r = 0;
+ }
+ }
+ if (out->dev->hw_sync_mode) {
+ sysfs_set_sysfs_str(TSYNC_EVENT, "AUDIO_RESUME");
+ }
+ out->pause_status = false;
+exit:
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ return r;
+}
+
+
static int audio_effect_process(struct audio_stream_out *stream,
- short* buffer, int frame_size)
+ short* buffer, int frame_size)
{
struct aml_stream_out *out = (struct aml_stream_out *)stream;
int output_size = frame_size << 2;
@@ -956,7 +1147,8 @@ static int audio_effect_process(struct audio_stream_out *stream,
static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
size_t bytes)
{
- int ret=0;
+ int ret = 0;
+ size_t oldBytes = bytes;
struct aml_stream_out *out = (struct aml_stream_out *)stream;
struct aml_audio_device *adev = out->dev;
size_t frame_size = audio_stream_out_frame_size(stream);
@@ -965,13 +1157,17 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
bool force_input_standby = false;
int16_t *in_buffer = (int16_t *)buffer;
struct aml_stream_in *in;
- char output_buffer_bytes[RESAMPLER_BUFFER_SIZE+128];
+ char output_buffer_bytes[RESAMPLER_BUFFER_SIZE + 128];
uint ouput_len;
char *data, *data_dst;
volatile char *data_src;
uint i, total_len;
int codec_type = 0;
int samesource_flag = 0;
+ if (out->pause_status == true) {
+ out_resume(out);
+ }
+ //ALOGI("out_write size %d\n",bytes);
//LOGFUNC("entring:%s(out->echo_reference=%p, in_frames=%d)", __FUNCTION__, out->echo_reference, in_frames);
/* acquiring hw device mutex systematically is useful if a low priority thread is waiting
@@ -981,30 +1177,160 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
pthread_mutex_lock(&adev->lock);
pthread_mutex_lock(&out->lock);
+ if ((out->standby) && (adev->hw_sync_mode == 1)) {
+ // todo: check timestamp header PTS discontinue for new sync point after seek
+ adev->first_apts_flag = false;
+ out->hw_sync_state = HW_SYNC_STATE_HEADER;
+ out->hw_sync_header_cnt = 0;
+ }
+
+#if 1
+ if (getprop_bool("media.audiohal.outdump")) {
+ FILE *fp1 = fopen("/data/tmp/i2s_audio_out.pcm", "a+");
+ if (fp1) {
+ int flen = fwrite((char *)buffer, 1, bytes, fp1);
+ fclose(fp1);
+ }
+ }
+#endif
+
+ if (adev->hw_sync_mode == 1) {
+ char buf[64] = {0};
+ unsigned char *header;
+
+ if (out->hw_sync_state == HW_SYNC_STATE_RESYNC) {
+ int i = 0;
+ uint8_t *p = (uint8_t *)buffer;
+ while (i < bytes) {
+ if (hwsync_header_valid(p)) {
+ ALOGI("HWSYNC resync.");
+ out->hw_sync_state = HW_SYNC_STATE_HEADER;
+ out->hw_sync_header_cnt = 0;
+ adev->first_apts_flag = false;
+ bytes -= i;
+ buffer += i;
+ in_frames = bytes / frame_size;
+ ALOGI("in_frames = %d", in_frames);
+ in_buffer = (int16_t *)buffer;
+ break;
+ } else {
+ i += 4;
+ p += 4;
+ }
+ }
+
+ if (out->hw_sync_state == HW_SYNC_STATE_RESYNC) {
+ ALOGI("Keep searching for HWSYNC header.");
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ }
+
+ header = (unsigned char *)buffer;
+#if 0
+ if (adev->first_apts_flag == false) {
+ uint64_t first_apts = 0;
+ uint32_t apts_cal;
+
+ if ((bytes >= 16) &&
+ hwsync_header_valid(header)) {
+ first_apts = hwsync_header_get_pts(header);
+ first_apts = first_apts * 90 / 1000000;
+ ALOGI("HW SYNC new first APTS %lld", first_apts);
+
+ adev->first_apts_flag = true;
+ adev->first_apts = first_apts;
+ out->frame_write_sum = 0;
+ adev->last_apts_from_header = first_apts;
+
+ sprintf(buf, "AUDIO_START:0x%lx", first_apts & 0xffffffff);
+ ALOGI("tsync -> %s", buf);
+ if (sysfs_set_sysfs_str(TSYNC_EVENT, buf) == -1) {
+ ALOGE("set AUDIO_START failed \n");
+ }
+ } else {
+ ALOGE("HW sync header not sync, 0x%x 0x%x 0x%x 0x%x",
+ header[0], header[1], header[2], header[3]);
+ }
+ } else {
+ int64_t apts;
+ uint32_t latency = out_get_latency(out) * 90;
+
+ apts = (uint64_t)out->frame_write_sum * 90000 / DEFAULT_OUT_SAMPLING_RATE;
+ apts += adev->first_apts;
+
+ if ((bytes >= 16) &&
+ hwsync_header_valid(header)) {
+ // check PTS discontinue, which may happen when audio track switching
+ // discontinue means PTS calculated based on first_apts and frame_write_sum
+ // does not match the timestamp of next audio samples
+ uint64_t apts_from_header = hwsync_header_get_pts(header);
+ uint64_t apts_current = apts_from_header * 90 / 1000000;
+ if (abs(apts_current - adev->last_apts_from_header) > 3 * 90000) {
+ ALOGI("apts discontinue cur %llx,last %llx\n", apts_current, adev->last_apts_from_header);
+ }
+ ALOGI("apts from header %llx,apts %llx,write size %d\n", apts_from_header, apts, bytes);
+ ALOGI("last apts %llx,cur %llx \n", adev->last_apts_from_header, apts_current);
+ adev->last_apts_from_header = apts_current;
+ if (apts_from_header != apts) {
+ ALOGI("HW sync PTS discontinue, 0x%llx->0x%llx(from header)",
+ apts, apts_from_header);
+ }
+ }
+
+ apts -= latency;
+ if (apts < 0) {
+ apts = 0;
+ }
+
+ unsigned long pcr = 0;
+ if (get_sysfs_int16(TSYNC_PCRSCR, &pcr) == 0) {
+ uint32_t apts_cal = apts & 0xffffffff;
+
+ //ALOGI("apts %x, pcr %x, diff %x\n", apts_cal, pcr, abs(pcr-apts_cal));
+#if 1
+ if (abs(pcr - apts_cal) < SYSTIME_CORRECTION_THRESHOLD) {
+ // do nothing
+ } else {
+ sprintf(buf, "0x%lx", apts_cal);
+ ALOGI("tsync -> reset pcrscr 0x%x -> 0x%x, diff %d ms", pcr, apts_cal, (int)(apts_cal - pcr) / 90);
+ int ret_val = sysfs_set_sysfs_str(TSYNC_APTS, buf);
+ if (ret_val == -1) {
+ ALOGE("unable to open file %s,err: %s", TSYNC_APTS, strerror(errno));
+ }
+ }
+#endif
+ }
+ }
+#endif
+ }
if (out->standby) {
ret = start_output_stream(out);
if (ret != 0) {
pthread_mutex_unlock(&adev->lock);
+ ALOGE("start_output_stream failed");
goto exit;
}
out->standby = false;
output_standby = false;
/* a change in output device may change the microphone selection */
if (adev->active_input &&
- adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
+ adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
force_input_standby = true;
+ }
}
pthread_mutex_unlock(&adev->lock);
#if 1
/* Reduce number of channels, if necessary */
if (popcount(out_get_channels(&stream->common)) >
- (int)out->config.channels) {
+ (int)out->config.channels) {
unsigned int i;
-
+
/* Discard right channel */
- for (i = 1; i < in_frames; i++)
+ for (i = 1; i < in_frames; i++) {
in_buffer[i] = in_buffer[i * 2];
-
+ }
+
/* The frame size is now half */
frame_size /= 2;
}
@@ -1028,15 +1354,15 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
out->echo_reference->write(out->echo_reference, &b);
}
-#if 1
+#if 0
if (getprop_bool("media.audiohal.outdump")) {
- FILE *fp1=fopen("/data/i2s_audio_out.pcm","a+");
+ FILE *fp1 = fopen("/data/tmp/i2s_audio_out.pcm", "a+");
if (fp1) {
- int flen=fwrite((char *)in_buffer,1,out_frames * frame_size,fp1);
- LOGFUNC("flen = %d---outlen=%d ", flen, out_frames * frame_size);
- fclose(fp1);
+ int flen = fwrite((char *)in_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/i2s_audio_out.pcm");
+ LOGFUNC("could not open file:/data/i2s_audio_out.pcm");
}
}
#endif
@@ -1044,52 +1370,254 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
codec_type = get_sysfs_int("/sys/class/audiodsp/digital_codec");
samesource_flag = get_sysfs_int("/sys/class/audiodsp/audio_samesource");
if (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);
+ 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->is_tv_platform == 1) {
int16_t *tmp_buffer = (int16_t *)out->audioeffect_tmp_buffer;
- memcpy((void *)tmp_buffer, (void *)in_buffer, out_frames*4);
+ memcpy((void *)tmp_buffer, (void *)in_buffer, out_frames * 4);
audio_effect_process(stream, tmp_buffer, out_frames);
for (i = 0; i < out_frames; i ++) {
- out->tmp_buffer_8ch[8*i] = ((int32_t)(in_buffer[2*i])) << 16;
- out->tmp_buffer_8ch[8*i + 1] = ((int32_t)(in_buffer[2*i + 1])) << 16;
- out->tmp_buffer_8ch[8*i + 2] = ((int32_t)(tmp_buffer[2*i])) << 16;
- out->tmp_buffer_8ch[8*i + 3] = ((int32_t)(tmp_buffer[2*i + 1])) << 16;
- out->tmp_buffer_8ch[8*i + 4] = 0;
- out->tmp_buffer_8ch[8*i + 5] = 0;
- out->tmp_buffer_8ch[8*i + 6] = 0;
- out->tmp_buffer_8ch[8*i + 7] = 0;
+ out->tmp_buffer_8ch[8 * i] = ((int32_t)(in_buffer[2 * i])) << 16;
+ out->tmp_buffer_8ch[8 * i + 1] = ((int32_t)(in_buffer[2 * i + 1])) << 16;
+ out->tmp_buffer_8ch[8 * i + 2] = ((int32_t)(tmp_buffer[2 * i])) << 16;
+ out->tmp_buffer_8ch[8 * i + 3] = ((int32_t)(tmp_buffer[2 * i + 1])) << 16;
+ out->tmp_buffer_8ch[8 * i + 4] = 0;
+ out->tmp_buffer_8ch[8 * i + 5] = 0;
+ out->tmp_buffer_8ch[8 * i + 6] = 0;
+ out->tmp_buffer_8ch[8 * i + 7] = 0;
}
/*if (out->frame_count < 5*1024) {
memset(out->tmp_buffer_8ch, 0, out_frames * frame_size * 8);
}*/
ret = pcm_write(out->pcm, out->tmp_buffer_8ch, out_frames * frame_size * 8);
} else {
- ret = pcm_write(out->pcm, in_buffer, out_frames * frame_size);
- }
- out->frame_count += out_frames;
- out->fram_write_sum+=out_frames;
+ if (adev->hw_sync_mode) {
+
+ int remain = out_frames * frame_size;
+ uint8_t *p = buffer;
+
+ //ALOGI(" --- out_write %d, cache cnt = %d, body = %d, hw_sync_state = %d", out_frames * frame_size, out->body_align_cnt, out->hw_sync_body_cnt, out->hw_sync_state);
+
+ while (remain > 0) {
+ if (out->hw_sync_state == HW_SYNC_STATE_HEADER) {
+ //ALOGI("Add to header buffer [%d], 0x%x", out->hw_sync_header_cnt, *p);
+ out->hw_sync_header[out->hw_sync_header_cnt++] = *p++;
+ remain--;
+ if (out->hw_sync_header_cnt == 16) {
+ uint64_t pts;
+ if (!hwsync_header_valid(&out->hw_sync_header[0])) {
+ ALOGE("hwsync header out of sync! Resync.");
+ out->hw_sync_state = HW_SYNC_STATE_RESYNC;
+ break;
+ }
+ out->hw_sync_state = HW_SYNC_STATE_BODY;
+ out->hw_sync_body_cnt = hwsync_header_get_size(&out->hw_sync_header[0]);
+ out->body_align_cnt = 0;
+ pts = hwsync_header_get_pts(&out->hw_sync_header[0]);
+ pts = pts * 90 / 1000000;
+#if 1
+ char buf[64] = {0};
+ if (adev->first_apts_flag == false) {
+ uint32_t apts_cal;
+ ALOGI("HW SYNC new first APTS %lld,body size %d", pts, out->hw_sync_body_cnt);
+ adev->first_apts_flag = true;
+ adev->first_apts = pts;
+ out->frame_write_sum = 0;
+ adev->last_apts_from_header = pts;
+ sprintf(buf, "AUDIO_START:0x%lx", pts & 0xffffffff);
+ ALOGI("tsync -> %s", buf);
+ if (sysfs_set_sysfs_str(TSYNC_EVENT, buf) == -1) {
+ ALOGE("set AUDIO_START failed \n");
+ }
+ } else {
+ int64_t apts;
+ uint32_t latency = out_get_latency(out) * 90;
+ apts = (uint64_t)out->frame_write_sum * 90000 / DEFAULT_OUT_SAMPLING_RATE;
+ apts += adev->first_apts;
+ // check PTS discontinue, which may happen when audio track switching
+ // discontinue means PTS calculated based on first_apts and frame_write_sum
+ // does not match the timestamp of next audio samples
+ apts -= latency;
+ if (apts < 0) {
+ apts = 0;
+ }
+ // here we use acutal audio frame gap,not use the differece of caculated current apts with the current frame pts,
+ //as there is a offset of audio latency from alsa.
+ // handle audio gap 0.5~5 s
+ unsigned two_frame_gap = (unsigned)abs(adev->last_apts_from_header - pts);
+ if (two_frame_gap > APTS_DISCONTINUE_THRESHOLD_MIN && two_frame_gap < APTS_DISCONTINUE_THRESHOLD_MAX) {
+ /* if (abs(pts -apts) > APTS_DISCONTINUE_THRESHOLD_MIN && abs(pts -apts) < APTS_DISCONTINUE_THRESHOLD_MAX) { */
+ ALOGI("HW sync PTS discontinue, 0x%llx->0x%llx(from header) diff %d,last apts %llx(from header)",
+ apts, pts, two_frame_gap, adev->last_apts_from_header);
+ //here handle the audio gap and insert zero to the alsa
+ int insert_size = 0;
+ int insert_size_total = 0;
+ int once_write_size = 0;
+ insert_size = two_frame_gap/*abs(pts -apts) */ / 90 * 48 * 4;
+ insert_size = insert_size & (~63);
+ insert_size_total = insert_size;
+ ALOGI("audio gap %d ms ,need insert pcm size %d\n", two_frame_gap/*abs(pts -apts) */ / 90, insert_size);
+ char *insert_buf = (char*)malloc(8192);
+ if (insert_buf == NULL) {
+ ALOGE("malloc size failed \n");
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ memset(insert_buf, 0, 8192);
+ while (insert_size > 0) {
+ once_write_size = insert_size > 8192 ? 8192 : insert_size;
+ ret = pcm_write(out->pcm, (void *) insert_buf, once_write_size);
+ if (ret != 0) {
+ ALOGE("pcm write failed\n");
+ free(insert_buf);
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ insert_size -= once_write_size;
+ }
+ free(insert_buf);
+ // insert end
+ //adev->first_apts = pts;
+ out->frame_write_sum += insert_size_total / frame_size;
+#if 0
+ sprintf(buf, "AUDIO_TSTAMP_DISCONTINUITY:0x%lx", pts);
+ if (sysfs_set_sysfs_str(TSYNC_EVENT, buf) == -1) {
+ ALOGE("unable to open file %s,err: %s", TSYNC_EVENT, strerror(errno));
+ }
+#endif
+ } else {
+ unsigned long pcr = 0;
+ if (get_sysfs_int16(TSYNC_PCRSCR, &pcr) == 0) {
+ uint32_t apts_cal = apts & 0xffffffff;
+ if (abs(pcr - apts_cal) < SYSTIME_CORRECTION_THRESHOLD) {
+ // do nothing
+ } else {
+ sprintf(buf, "0x%lx", apts_cal);
+ ALOGI("tsync -> reset pcrscr 0x%x -> 0x%x, diff %d ms,frame pts %llx,latency pts %d", pcr, apts_cal, (int)(apts_cal - pcr) / 90, pts, latency);
+ int ret_val = sysfs_set_sysfs_str(TSYNC_APTS, buf);
+ if (ret_val == -1) {
+ ALOGE("unable to open file %s,err: %s", TSYNC_APTS, strerror(errno));
+ }
+ }
+ }
+ }
+ adev->last_apts_from_header = pts;
+ }
+#endif
- exit:
- pthread_mutex_unlock(&out->lock);
- if (ret != 0) {
- usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
- out_get_sample_rate(&stream->common));
+ //ALOGI("get header body_cnt = %d, pts = %lld", out->hw_sync_body_cnt, pts);
+ }
+ continue;
+ } else if (out->hw_sync_state == HW_SYNC_STATE_BODY) {
+ int align;
+ int m = (out->hw_sync_body_cnt < remain) ? out->hw_sync_body_cnt : remain;
+
+ //ALOGI("m = %d", m);
+
+ // process m bytes, upto end of hw_sync_body_cnt or end of remaining our_write bytes.
+ // within m bytes, there is no hw_sync header and all are body bytes.
+ if (out->body_align_cnt) {
+ // clear fragment first for alignment limitation on ALSA driver, which
+ // requires each pcm_writing aligned at 16 frame boundaries
+ // assuming data are always PCM16 based, so aligned at 64 bytes unit.
+ if ((m + out->body_align_cnt) < 64) {
+ // merge only
+ memcpy(&out->body_align[out->body_align_cnt], p, m);
+ p += m;
+ remain -= m;
+ out->body_align_cnt += m;
+ out->hw_sync_body_cnt -= m;
+ if (out->hw_sync_body_cnt == 0) {
+ // end of body, research for HW SYNC header
+ out->hw_sync_state = HW_SYNC_STATE_HEADER;
+ out->hw_sync_header_cnt = 0;
+ continue;
+ }
+ //ALOGI("align cache add %d, cnt = %d", remain, out->body_align_cnt);
+ break;
+ } else {
+ // merge-submit-continue
+ memcpy(&out->body_align[out->body_align_cnt], p, 64 - out->body_align_cnt);
+ p += 64 - out->body_align_cnt;
+ remain -= 64 - out->body_align_cnt;
+ //ALOGI("pcm_write 64, out remain %d", remain);
+
+ ret = pcm_write(out->pcm, &out->body_align[0], 64);
+ out->frame_write_sum += 64 / frame_size;
+ out->frame_count += 64 / frame_size;
+
+ out->hw_sync_body_cnt -= 64 - out->body_align_cnt;
+ out->body_align_cnt = 0;
+ if (out->hw_sync_body_cnt == 0) {
+ out->hw_sync_state = HW_SYNC_STATE_HEADER;
+ out->hw_sync_header_cnt = 0;
+ }
+ continue;
+ }
+ }
+
+ // process m bytes body with an empty fragment for alignment
+ align = m & 63;
+ if ((m - align) > 0) {
+ ret = pcm_write(out->pcm, p, m - align);
+ out->frame_write_sum += (m - align) / frame_size;
+ out->frame_count += (m - align) / frame_size;
+
+ p += m - align;
+ remain -= m - align;
+ //ALOGI("pcm_write %d, remain %d", m - align, remain);
+
+ out->hw_sync_body_cnt -= (m - align);
+ if (out->hw_sync_body_cnt == 0) {
+ out->hw_sync_state = HW_SYNC_STATE_HEADER;
+ out->hw_sync_header_cnt = 0;
+ continue;
+ }
+ }
+
+ if (align) {
+ memcpy(&out->body_align[0], p, align);
+ p += align;
+ remain -= align;
+ out->body_align_cnt = align;
+ //ALOGI("align cache add %d, cnt = %d, remain = %d", align, out->body_align_cnt, remain);
+
+ out->hw_sync_body_cnt -= align;
+ if (out->hw_sync_body_cnt == 0) {
+ out->hw_sync_state = HW_SYNC_STATE_HEADER;
+ out->hw_sync_header_cnt = 0;
+ continue;
+ }
+ }
+ }
+ }
+
+ } else {
+ ret = pcm_write(out->pcm, in_buffer, out_frames * frame_size);
+ out->frame_count += out_frames;
}
+ }
- if (force_input_standby) {
- pthread_mutex_lock(&adev->lock);
- if (adev->active_input) {
- in = adev->active_input;
- pthread_mutex_lock(&in->lock);
- do_input_standby(in);
- pthread_mutex_unlock(&in->lock);
- }
- pthread_mutex_unlock(&adev->lock);
+exit:
+ pthread_mutex_unlock(&out->lock);
+ if (ret != 0) {
+ usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
+ out_get_sample_rate(&stream->common));
+ }
+
+ if (force_input_standby) {
+ pthread_mutex_lock(&adev->lock);
+ if (adev->active_input) {
+ in = adev->active_input;
+ pthread_mutex_lock(&in->lock);
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
}
- return bytes;
+ pthread_mutex_unlock(&adev->lock);
+ }
+ return oldBytes;
}
static int out_get_render_position(const struct audio_stream_out *stream,
@@ -1119,11 +1647,18 @@ static int out_get_next_write_timestamp(const struct audio_stream_out *stream __
//actually maybe it be not useful now except pass CTS_TEST:
// run cts -c android.media.cts.AudioTrackTest -m testGetTimestamp
-static int out_get_presentation_position(const struct audio_stream_out *stream,uint64_t *frames, struct timespec *timestamp)
+static int out_get_presentation_position(const struct audio_stream_out *stream, uint64_t *frames, struct timespec *timestamp)
{
- struct aml_stream_out *out=(struct aml_stream_out *)stream;
- if (frames != NULL)
- *frames=out->fram_write_sum;
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ if (frames != NULL) {
+ uint32_t latency = out_get_latency(out) * out->config.rate / 1000;
+ if (out->frame_count >= latency) {
+ *frames = out->frame_count - latency;
+ } else {
+ *frames = out->frame_count;
+ }
+ }
+
if (timestamp != NULL) {
clock_gettime(CLOCK_MONOTONIC, timestamp);
}
@@ -1131,9 +1666,9 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,u
return 0;
}
static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer* buffer);
+ struct resampler_buffer* buffer);
static void release_buffer(struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer* buffer);
+ struct resampler_buffer* buffer);
/** audio_stream_in implementation **/
@@ -1146,8 +1681,8 @@ static int start_input_stream(struct aml_stream_in *in)
unsigned int port = PORT_MM;
struct aml_audio_device *adev = in->dev;
- LOGFUNC("%s(need_echo_reference=%d, channels=%d, rate=%d, requested_rate=%d, mode= %d)",
- __FUNCTION__, in->need_echo_reference, in->config.channels, in->config.rate, in->requested_rate, adev->mode);
+ LOGFUNC("%s(need_echo_reference=%d, channels=%d, rate=%d, requested_rate=%d, mode= %d)",
+ __FUNCTION__, in->need_echo_reference, in->config.channels, in->config.rate, in->requested_rate, adev->mode);
adev->active_input = in;
if (adev->mode != AUDIO_MODE_IN_CALL) {
@@ -1157,31 +1692,29 @@ static int start_input_stream(struct aml_stream_in *in)
}
card = get_aml_card();
- ALOGV("%s(in->requested_rate=%d, in->config.rate=%d)",
- __FUNCTION__, in->requested_rate, in->config.rate);
- if (adev->in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET){
+ ALOGV("%s(in->requested_rate=%d, in->config.rate=%d)",
+ __FUNCTION__, in->requested_rate, in->config.rate);
+ if (adev->in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
port = get_pcm_bt_port();
- } else if(getprop_bool("sys.hdmiIn.Capture")){
+ } else if (getprop_bool("sys.hdmiIn.Capture")) {
port = get_spdif_port();
} else {
port = PORT_MM;
}
- LOGFUNC("*%s, open card(%d) port(%d)-------", __FUNCTION__,card,port);
+ LOGFUNC("*%s, open card(%d) port(%d)-------", __FUNCTION__, card, port);
- if(getprop_bool("media.libplayer.wfd")){
- CAPTURE_PERIOD_SIZE = DEFAULT_CAPTURE_PERIOD_SIZE/2;
+ if (getprop_bool("media.libplayer.wfd")) {
+ CAPTURE_PERIOD_SIZE = DEFAULT_CAPTURE_PERIOD_SIZE / 2;
in->config.period_size = CAPTURE_PERIOD_SIZE;
- }
- else
- {
+ } else {
CAPTURE_PERIOD_SIZE = DEFAULT_CAPTURE_PERIOD_SIZE;
in->config.period_size = CAPTURE_PERIOD_SIZE;
}
if (in->need_echo_reference && in->echo_reference == NULL) {
in->echo_reference = get_echo_reference(adev,
- AUDIO_FORMAT_PCM_16_BIT,
- in->config.channels,
- in->requested_rate);
+ AUDIO_FORMAT_PCM_16_BIT,
+ in->config.channels,
+ in->requested_rate);
LOGFUNC("%s(after get_echo_ref.... now in->echo_reference = %p)", __FUNCTION__, in->echo_reference);
}
/* this assumes routing is done previously */
@@ -1225,7 +1758,7 @@ static size_t in_get_buffer_size(const struct audio_stream *stream)
static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
{
- struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
if (in->config.channels == 1) {
return AUDIO_CHANNEL_IN_MONO;
@@ -1271,8 +1804,8 @@ static int do_input_standby(struct aml_stream_in *in)
input_standby = true;
#if 0
LOGFUNC("%s : output_standby=%d,input_standby=%d",
- __FUNCTION__, output_standby,input_standby);
- if(output_standby && input_standby){
+ __FUNCTION__, output_standby, input_standby);
+ if (output_standby && input_standby) {
reset_mixer_state(adev->ar);
update_mixer_state(adev->ar);
}
@@ -1334,8 +1867,9 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
}
}
- if (do_standby)
+ if (do_standby) {
do_input_standby(in);
+ }
pthread_mutex_unlock(&in->lock);
pthread_mutex_unlock(&adev->lock);
@@ -1343,17 +1877,17 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FRAME_COUNT, &framesize);
if (ret >= 0) {
- if(framesize > 0){
+ if (framesize > 0) {
ALOGI("Reset audio input hw frame size from %d to %d\n",
- CAPTURE_PERIOD_SIZE*CAPTURE_PERIOD_COUNT,framesize);
- CAPTURE_PERIOD_SIZE = framesize/CAPTURE_PERIOD_COUNT;
+ CAPTURE_PERIOD_SIZE * CAPTURE_PERIOD_COUNT, framesize);
+ CAPTURE_PERIOD_SIZE = framesize / CAPTURE_PERIOD_COUNT;
pcm_config_in.period_size = CAPTURE_PERIOD_SIZE;
in->config.period_size = CAPTURE_PERIOD_SIZE;
pthread_mutex_lock(&adev->lock);
pthread_mutex_lock(&in->lock);
- if(!in->standby && (in == adev->active_input)){
+ if (!in->standby && (in == adev->active_input)) {
do_input_standby(in);
start_input_stream(in);
in->standby = 0;
@@ -1381,8 +1915,8 @@ static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unu
}
static void get_capture_delay(struct aml_stream_in *in,
- size_t frames __unused,
- struct echo_reference_buffer *buffer)
+ size_t frames __unused,
+ struct echo_reference_buffer *buffer)
{
/* read frames available in kernel driver buffer */
size_t kernel_frames;
@@ -1391,7 +1925,7 @@ static void get_capture_delay(struct aml_stream_in *in,
long rsmp_delay;
long kernel_delay;
long delay_ns;
- int rsmp_mul = in->config.rate/VX_NB_SAMPLING_RATE;
+ int rsmp_mul = in->config.rate / VX_NB_SAMPLING_RATE;
if (pcm_get_htimestamp(in->pcm, &kernel_frames, &tstamp) < 0) {
buffer->time_stamp.tv_sec = 0;
buffer->time_stamp.tv_nsec = 0;
@@ -1404,7 +1938,7 @@ static void get_capture_delay(struct aml_stream_in *in,
* add number of frames being read as we want the capture time of first sample
* in current buffer */
buf_delay = (long)(((int64_t)(in->frames_in + in->proc_frames_in * rsmp_mul) * 1000000000)
- / in->config.rate);
+ / in->config.rate);
/* add delay introduced by resampler */
rsmp_delay = 0;
if (in->resampler) {
@@ -1437,7 +1971,7 @@ static int32_t update_echo_reference(struct aml_stream_in *in, size_t frames)
if (in->ref_buf_size < frames) {
in->ref_buf_size = frames;
in->ref_buf = (int16_t *)realloc(in->ref_buf,
- in->ref_buf_size * in->config.channels * sizeof(int16_t));
+ in->ref_buf_size * in->config.channels * sizeof(int16_t));
}
b.frame_count = frames - in->ref_frames_in;
@@ -1446,39 +1980,40 @@ static int32_t update_echo_reference(struct aml_stream_in *in, size_t frames)
get_capture_delay(in, frames, &b);
LOGFUNC("update_echo_reference return ::b.delay_ns=%d", b.delay_ns);
- if (in->echo_reference->read(in->echo_reference, &b) == 0)
- {
+ if (in->echo_reference->read(in->echo_reference, &b) == 0) {
in->ref_frames_in += b.frame_count;
ALOGV("update_echo_reference: in->ref_frames_in:[%d], "
"in->ref_buf_size:[%d], frames:[%d], b.frame_count:[%d]",
- in->ref_frames_in, in->ref_buf_size, frames, b.frame_count);
+ in->ref_frames_in, in->ref_buf_size, frames, b.frame_count);
}
- } else
+ } else {
ALOGW("update_echo_reference: NOT enough frames to read ref buffer");
+ }
return b.delay_ns;
}
static int set_preprocessor_param(effect_handle_t handle,
- effect_param_t *param)
+ effect_param_t *param)
{
uint32_t size = sizeof(int);
uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
- param->vsize;
+ param->vsize;
int status = (*handle)->command(handle,
- EFFECT_CMD_SET_PARAM,
- sizeof (effect_param_t) + psize,
- param,
- &size,
- &param->status);
- if (status == 0)
+ EFFECT_CMD_SET_PARAM,
+ sizeof(effect_param_t) + psize,
+ param,
+ &size,
+ &param->status);
+ if (status == 0) {
status = param->status;
+ }
return status;
}
static int set_preprocessor_echo_delay(effect_handle_t handle,
- int32_t delay_us)
+ int32_t delay_us)
{
uint32_t buf[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
effect_param_t *param = (effect_param_t *)buf;
@@ -1495,23 +2030,25 @@ static void push_echo_reference(struct aml_stream_in *in, size_t frames)
{
/* read frames from echo reference buffer and update echo delay
* in->ref_frames_in is updated with frames available in in->ref_buf */
- int32_t delay_us = update_echo_reference(in, frames)/1000;
+ int32_t delay_us = update_echo_reference(in, frames) / 1000;
int i;
audio_buffer_t buf;
- if (in->ref_frames_in < frames)
+ if (in->ref_frames_in < frames) {
frames = in->ref_frames_in;
+ }
buf.frameCount = frames;
buf.raw = in->ref_buf;
for (i = 0; i < in->num_preprocessors; i++) {
- if ((*in->preprocessors[i])->process_reverse == NULL)
+ if ((*in->preprocessors[i])->process_reverse == NULL) {
continue;
+ }
(*in->preprocessors[i])->process_reverse(in->preprocessors[i],
- &buf,
- NULL);
+ &buf,
+ NULL);
set_preprocessor_echo_delay(in->preprocessors[i], delay_us);
}
@@ -1524,15 +2061,16 @@ static void push_echo_reference(struct aml_stream_in *in, size_t frames)
}
static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer* buffer)
+ struct resampler_buffer* buffer)
{
struct aml_stream_in *in;
- if (buffer_provider == NULL || buffer == NULL)
+ if (buffer_provider == NULL || buffer == NULL) {
return -EINVAL;
+ }
in = (struct aml_stream_in *)((char *)buffer_provider -
- offsetof(struct aml_stream_in, buf_provider));
+ offsetof(struct aml_stream_in, buf_provider));
if (in->pcm == NULL) {
buffer->raw = NULL;
@@ -1543,7 +2081,7 @@ static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
if (in->frames_in == 0) {
in->read_status = pcm_read(in->pcm, (void*)in->buffer,
- in->config.period_size * audio_stream_in_frame_size(&in->stream));
+ in->config.period_size * audio_stream_in_frame_size(&in->stream));
if (in->read_status != 0) {
ALOGE("get_next_buffer() pcm_read error %d", in->read_status);
buffer->raw = NULL;
@@ -1554,24 +2092,25 @@ static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
}
buffer->frame_count = (buffer->frame_count > in->frames_in) ?
- in->frames_in : buffer->frame_count;
+ in->frames_in : buffer->frame_count;
buffer->i16 = in->buffer + (in->config.period_size - in->frames_in) *
- in->config.channels;
+ in->config.channels;
return in->read_status;
}
static void release_buffer(struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer* buffer)
+ struct resampler_buffer* buffer)
{
struct aml_stream_in *in;
- if (buffer_provider == NULL || buffer == NULL)
+ if (buffer_provider == NULL || buffer == NULL) {
return;
+ }
in = (struct aml_stream_in *)((char *)buffer_provider -
- offsetof(struct aml_stream_in, buf_provider));
+ offsetof(struct aml_stream_in, buf_provider));
in->frames_in -= buffer->frame_count;
}
@@ -1586,28 +2125,30 @@ static ssize_t read_frames(struct aml_stream_in *in, void *buffer, ssize_t frame
size_t frames_rd = frames - frames_wr;
if (in->resampler != NULL) {
in->resampler->resample_from_provider(in->resampler,
- (int16_t *)((char *)buffer +
- frames_wr * audio_stream_in_frame_size(&in->stream)),
- &frames_rd);
+ (int16_t *)((char *)buffer +
+ frames_wr * audio_stream_in_frame_size(&in->stream)),
+ &frames_rd);
} else {
struct resampler_buffer buf = {
- { raw : NULL, },
- frame_count : frames_rd,
+ { raw : NULL, },
+frame_count :
+ frames_rd,
};
get_next_buffer(&in->buf_provider, &buf);
if (buf.raw != NULL) {
memcpy((char *)buffer +
- frames_wr * audio_stream_in_frame_size(&in->stream),
- buf.raw,
- buf.frame_count * audio_stream_in_frame_size(&in->stream));
+ frames_wr * audio_stream_in_frame_size(&in->stream),
+ buf.raw,
+ buf.frame_count * audio_stream_in_frame_size(&in->stream));
frames_rd = buf.frame_count;
}
release_buffer(&in->buf_provider, &buf);
}
/* in->read_status is updated by getNextBuffer() also called by
* in->resampler->resample_from_provider() */
- if (in->read_status != 0)
+ if (in->read_status != 0) {
return in->read_status;
+ }
frames_wr += frames_rd;
}
@@ -1633,14 +2174,14 @@ static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t fr
if (in->proc_buf_size < (size_t)frames) {
in->proc_buf_size = (size_t)frames;
in->proc_buf = (int16_t *)realloc(in->proc_buf,
- in->proc_buf_size *
- in->config.channels * sizeof(int16_t));
+ in->proc_buf_size *
+ in->config.channels * sizeof(int16_t));
ALOGV("process_frames(): in->proc_buf %p size extended to %d frames",
- in->proc_buf, in->proc_buf_size);
+ in->proc_buf, in->proc_buf_size);
}
frames_rd = read_frames(in,
in->proc_buf +
- in->proc_frames_in * in->config.channels,
+ in->proc_frames_in * in->config.channels,
frames - in->proc_frames_in);
if (frames_rd < 0) {
frames_wr = frames_rd;
@@ -1649,11 +2190,12 @@ static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t fr
in->proc_frames_in += frames_rd;
}
- if (in->echo_reference != NULL)
+ if (in->echo_reference != NULL) {
push_echo_reference(in, in->proc_frames_in);
+ }
- /* in_buf.frameCount and out_buf.frameCount indicate respectively
- * the maximum number of frames to be consumed and produced by process() */
+ /* in_buf.frameCount and out_buf.frameCount indicate respectively
+ * the maximum number of frames to be consumed and produced by process() */
in_buf.frameCount = in->proc_frames_in;
in_buf.s16 = in->proc_buf;
out_buf.frameCount = frames - frames_wr;
@@ -1661,8 +2203,8 @@ static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t fr
for (i = 0; i < in->num_preprocessors; i++)
(*in->preprocessors[i])->process(in->preprocessors[i],
- &in_buf,
- &out_buf);
+ &in_buf,
+ &out_buf);
/* process() has updated the number of frames consumed and produced in
* in_buf.frameCount and out_buf.frameCount respectively
@@ -1675,8 +2217,9 @@ static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t fr
}
/* if not enough frames were passed to process(), read more and retry. */
- if (out_buf.frameCount == 0)
+ if (out_buf.frameCount == 0) {
continue;
+ }
frames_wr += out_buf.frameCount;
}
@@ -1686,43 +2229,46 @@ static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t fr
static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
size_t bytes)
{
- int ret = 0;
- struct aml_stream_in *in = (struct aml_stream_in *)stream;
- struct aml_audio_device *adev = in->dev;
- size_t frames_rq = bytes / audio_stream_in_frame_size(&in->stream);
+ int ret = 0;
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ struct aml_audio_device *adev = in->dev;
+ size_t frames_rq = bytes / audio_stream_in_frame_size(&in->stream);
- /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
- * on the input stream mutex - e.g. executing select_mode() while holding the hw device
- * mutex
- */
- pthread_mutex_lock(&adev->lock);
- pthread_mutex_lock(&in->lock);
- if (in->standby) {
- ret = start_input_stream(in);
- if (ret == 0){
- in->standby = 0;
- input_standby = false;
- }
+ /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
+ * on the input stream mutex - e.g. executing select_mode() while holding the hw device
+ * mutex
+ */
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (in->standby) {
+ ret = start_input_stream(in);
+ if (ret == 0) {
+ in->standby = 0;
+ input_standby = false;
}
- pthread_mutex_unlock(&adev->lock);
+ }
+ pthread_mutex_unlock(&adev->lock);
+
+ if (ret < 0) {
+ goto exit;
+ }
+
+ if (in->num_preprocessors != 0) {
+ ret = process_frames(in, buffer, frames_rq);
+ } else if (in->resampler != NULL) {
+ ret = read_frames(in, buffer, frames_rq);
+ } else {
+ ret = pcm_read(in->pcm, buffer, bytes);
+ }
+
+ if (ret > 0) {
+ ret = 0;
+ }
+
+ if (ret == 0 && adev->mic_mute) {
+ memset(buffer, 0, bytes);
+ }
- if (ret < 0)
- goto exit;
-
- if (in->num_preprocessors != 0)
- ret = process_frames(in, buffer, frames_rq);
- else if (in->resampler != NULL)
- ret = read_frames(in, buffer, frames_rq);
- else
- ret = pcm_read(in->pcm, buffer, bytes);
-
- if (ret > 0)
- ret = 0;
-
- if (ret == 0 && adev->mic_mute){
- memset(buffer, 0, bytes);
- }
-
#if 0
FILE *dump_fp = NULL;
@@ -1730,19 +2276,18 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
if (dump_fp != NULL) {
fwrite(buffer, bytes, 1, dump_fp);
fclose(dump_fp);
- }
- else {
+ } else {
ALOGW("[Error] Can't write to /data/dump_in.pcm");
}
#endif
- exit:
- if (ret < 0)
- usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
- in_get_sample_rate(&stream->common));
+exit:
+ if (ret < 0)
+ usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
+ in_get_sample_rate(&stream->common));
- pthread_mutex_unlock(&in->lock);
- return bytes;
+ pthread_mutex_unlock(&in->lock);
+ return bytes;
}
@@ -1766,8 +2311,9 @@ static int in_add_audio_effect(const struct audio_stream *stream,
}
status = (*effect)->get_descriptor(effect, &desc);
- if (status != 0)
+ if (status != 0) {
goto exit;
+ }
in->preprocessors[in->num_preprocessors++] = effect;
@@ -1811,14 +2357,16 @@ static int in_remove_audio_effect(const struct audio_stream *stream,
}
}
- if (status != 0)
+ if (status != 0) {
goto exit;
+ }
in->num_preprocessors--;
status = (*effect)->get_descriptor(effect, &desc);
- if (status != 0)
+ if (status != 0) {
goto exit;
+ }
if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
in->need_echo_reference = false;
do_input_standby(in);
@@ -1843,12 +2391,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
int channel_count = popcount(config->channel_mask);
int ret;
- LOGFUNC("**enter %s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d)", __FUNCTION__, devices,
- config->format, config->channel_mask, config->sample_rate);
+ LOGFUNC("**enter %s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d, flags=0x%x)", __FUNCTION__, devices,
+ config->format, config->channel_mask, config->sample_rate, flags);
out = (struct aml_stream_out *)calloc(1, sizeof(struct aml_stream_out));
- if (!out)
+ if (!out) {
return -ENOMEM;
+ }
out->stream.common.get_sample_rate = out_get_sample_rate;
out->stream.common.set_sample_rate = out_set_sample_rate;
@@ -1867,28 +2416,39 @@ 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->stream.get_presentation_position = out_get_presentation_position;
+ out->stream.pause = out_pause;
+ out->stream.resume = out_resume;
+ out->stream.flush = out_flush;
out->config = pcm_config_out;
out->is_tv_platform = 0;
out->dev = ladev;
out->standby = true;
output_standby = true;
out->frame_count = 0;
- out->fram_write_sum=0;
- /* FIXME: when we support multiple output devices, we will want to
- * do the following:
- * adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
- * adev->devices |= out->device;
- * select_output_device(adev);
- * This is because out_set_parameters() with a route is not
- * guaranteed to be called after an output stream is opened.
- */
+ out->frame_write_sum = 0;
+ ladev->hw_sync_mode = false;
+ ladev->first_apts_flag = false;
+
+ if (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
+ ladev->hw_sync_mode = true;
+ ALOGI("Output stream open with AUDIO_OUTPUT_FLAG_HW_AV_SYNC");
+ }
+
+ /* FIXME: when we support multiple output devices, we will want to
+ * do the following:
+ * adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
+ * adev->devices |= out->device;
+ * select_output_device(adev);
+ * This is because out_set_parameters() with a route is not
+ * guaranteed to be called after an output stream is opened.
+ */
config->format = out_get_format(&out->stream.common);
config->channel_mask = out_get_channels(&out->stream.common);
config->sample_rate = out_get_sample_rate(&out->stream.common);
LOGFUNC("**leave %s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d)", __FUNCTION__, devices,
- config->format, config->channel_mask, config->sample_rate);
+ config->format, config->channel_mask, config->sample_rate);
*stream_out = &out->stream;
@@ -1906,17 +2466,18 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
ALOGE("cannot malloc memory for audioeffect_tmp_buffer");
return -ENOMEM;
}
- //EQ lib load and init EQ
+ //EQ lib load and init EQ
ret = load_EQ_lib();
if (ret < 0) {
ALOGE("%s, Load EQ lib fail!\n", __FUNCTION__);
out->has_EQ_lib = 0;
} else {
ret = HPEQ_init();
- if (ret < 0)
+ if (ret < 0) {
out->has_EQ_lib = 0;
- else
+ } else {
out->has_EQ_lib = 1;
+ }
HPEQ_enable(1);
}
//load srs lib and init it.
@@ -1926,10 +2487,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
out->has_SRS_lib = 0;
} else {
ret = srs_init(48000);
- if (ret < 0)
+ if (ret < 0) {
out->has_SRS_lib = 0;
- else
+ } else {
out->has_SRS_lib = 1;
+ }
}
}
return 0;
@@ -1963,16 +2525,15 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
char *str;
char value[32];
int ret;
-
parms = str_parms_create_str(kvpairs);
ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
if (ret >= 0) {
- if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) {
adev->low_power = false;
- else
+ } else {
adev->low_power = true;
+ }
}
-
str_parms_destroy(parms);
return ret;
}
@@ -1980,6 +2541,13 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
static char * adev_get_parameters(const struct audio_hw_device *dev __unused,
const char *keys __unused)
{
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+ if (!strcmp(keys, AUDIO_PARAMETER_HW_AV_SYNC)) {
+ ALOGI("get hwsync id\n");
+ adev->hw_sync_mode = 0;
+ adev->first_apts_flag = false;
+ return strdup("hw_av_sync=12345678");
+ }
return strdup("");
}
@@ -2048,18 +2616,19 @@ 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,
- const struct audio_config *config)
+ const struct audio_config *config)
{
size_t size;
int channel_count = popcount(config->channel_mask);
LOGFUNC("%s(%p, %d, %d, %d)", __FUNCTION__, dev, config->sample_rate,
- config->format, channel_count);
- if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
+ config->format, channel_count);
+ if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) {
return 0;
+ }
return get_input_buffer_size(config->sample_rate,
- config->format, channel_count);
+ config->format, channel_count);
}
@@ -2075,13 +2644,15 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
int ret;
int channel_count = popcount(config->channel_mask);
LOGFUNC("%s(%#x, %d, 0x%04x, %d)", __FUNCTION__,
- devices, config->format, config->channel_mask, config->sample_rate);
- if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
+ devices, config->format, config->channel_mask, config->sample_rate);
+ if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) {
return -EINVAL;
+ }
in = (struct aml_stream_in *)calloc(1, sizeof(struct aml_stream_in));
- if (!in)
+ if (!in) {
return -ENOMEM;
+ }
in->stream.common.get_sample_rate = in_get_sample_rate;
in->stream.common.set_sample_rate = in_set_sample_rate;
@@ -2102,22 +2673,17 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
in->requested_rate = config->sample_rate;
in->device = devices & ~AUDIO_DEVICE_BIT_IN;
- if (in->device & AUDIO_DEVICE_IN_ALL_SCO){
+ if (in->device & AUDIO_DEVICE_IN_ALL_SCO) {
memcpy(&in->config, &pcm_config_bt, sizeof(pcm_config_bt));
} else {
memcpy(&in->config, &pcm_config_in, sizeof(pcm_config_in));
}
- if(in->config.channels == 1)
- {
+ if (in->config.channels == 1) {
config->channel_mask = AUDIO_CHANNEL_IN_MONO;
- }
- else if(in->config.channels == 2)
- {
+ } else if (in->config.channels == 2) {
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
- }
- else
- {
+ } else {
ALOGE("Bad value of channel count : %d", in->config.channels);
}
in->buffer = malloc(in->config.period_size *
@@ -2128,8 +2694,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
}
if (in->requested_rate != in->config.rate) {
- LOGFUNC("%s(in->requested_rate=%d, in->config.rate=%d)",
- __FUNCTION__, in->requested_rate, in->config.rate);
+ LOGFUNC("%s(in->requested_rate=%d, in->config.rate=%d)",
+ __FUNCTION__, in->requested_rate, in->config.rate);
in->buf_provider.get_next_buffer = get_next_buffer;
in->buf_provider.release_buffer = release_buffer;
ret = create_resampler(in->config.rate,
@@ -2153,8 +2719,9 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
return 0;
err_open:
- if (in->resampler)
+ if (in->resampler) {
release_resampler(in->resampler);
+ }
free(in);
*stream_in = NULL;
@@ -2162,7 +2729,7 @@ err_open:
}
static void adev_close_input_stream(struct audio_hw_device *dev,
- struct audio_stream_in *stream)
+ struct audio_stream_in *stream)
{
struct aml_stream_in *in = (struct aml_stream_in *)stream;
@@ -2173,10 +2740,12 @@ static void adev_close_input_stream(struct audio_hw_device *dev,
free(in->buffer);
release_resampler(in->resampler);
}
- if (in->proc_buf)
+ if (in->proc_buf) {
free(in->proc_buf);
- if (in->ref_buf)
+ }
+ if (in->ref_buf) {
free(in->ref_buf);
+ }
free(stream);
@@ -2203,12 +2772,14 @@ static int adev_open(const hw_module_t* module, const char* name,
struct aml_audio_device *adev;
int card = CARD_AMLOGIC_DEFAULT;
int ret;
- if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) {
return -EINVAL;
+ }
adev = calloc(1, sizeof(struct aml_audio_device));
- if (!adev)
+ if (!adev) {
return -ENOMEM;
+ }
adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
@@ -2233,11 +2804,11 @@ static int adev_open(const hw_module_t* module, const char* name,
adev->hw_device.close_input_stream = adev_close_input_stream;
adev->hw_device.dump = adev_dump;
card = get_aml_card();
- if ((card < 0)||(card > 7)){
+ if ((card < 0) || (card > 7)) {
ALOGE("error to get audio card");
- return -EINVAL;
+ return -EINVAL;
}
-
+
adev->card = card;
adev->ar = audio_route_init(adev->card, MIXER_XML_PATH);
diff --git a/audio_hw.h b/audio_hw.h
new file mode 100644
index 0000000..b7e1342
--- a/dev/null
+++ b/audio_hw.h
@@ -0,0 +1,31 @@
+#ifndef _AUDIO_HW_H_
+#define _AUDIO_HW_H_
+#define _AUDIO_HW_H_
+/* ALSA cards for AML */
+#define CARD_AMLOGIC_BOARD 0
+#define CARD_AMLOGIC_DEFAULT CARD_AMLOGIC_BOARD
+/* ALSA ports for AML */
+#define PORT_MM 1
+/* number of frames per period */
+#define DEFAULT_PERIOD_SIZE 1024 //(1024 * 2)
+static unsigned PERIOD_SIZE = DEFAULT_PERIOD_SIZE;
+/* number of periods for low power playback */
+#define PLAYBACK_PERIOD_COUNT 4
+/* number of periods for capture */
+#define CAPTURE_PERIOD_COUNT 4
+
+/* minimum sleep time in out_write() when write threshold is not reached */
+#define MIN_WRITE_SLEEP_US 5000
+
+#define RESAMPLER_BUFFER_FRAMES (PERIOD_SIZE * 6)
+#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
+
+static unsigned int DEFAULT_OUT_SAMPLING_RATE = 48000;
+
+/* sampling rate when using MM low power port */
+#define MM_LOW_POWER_SAMPLING_RATE 44100
+/* sampling rate when using MM full power port */
+#define MM_FULL_POWER_SAMPLING_RATE 48000
+/* sampling rate when using VX port for narrow band */
+#define VX_NB_SAMPLING_RATE 8000
+#endif
diff --git a/audio_hw_profile.c b/audio_hw_profile.c
new file mode 100644
index 0000000..dccc081
--- a/dev/null
+++ b/audio_hw_profile.c
@@ -0,0 +1,215 @@
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+/*
+ type : 0 -> playback, 1 -> capture
+*/
+#define MAX_CARD_NUM 2
+int get_external_card(int type)
+{
+ int card_num = 1; // start num, 0 is defualt sound card.
+ struct stat card_stat;
+ char fpath[256];
+ int ret;
+ while (card_num <= MAX_CARD_NUM) {
+ snprintf(fpath, sizeof(fpath), "/proc/asound/card%d", card_num);
+ ret = stat(fpath, &card_stat);
+ if (ret < 0) {
+ ret = -1;
+ } else {
+ snprintf(fpath, sizeof(fpath), "/dev/snd/pcmC%uD0%c", card_num,
+ type ? 'c' : 'p');
+ ret = stat(fpath, &card_stat);
+ if (ret == 0) {
+ return card_num;
+ }
+ }
+ card_num++;
+ }
+ return ret;
+}
+
+int
+get_aml_card()
+{
+ int card = -1, err = 0;
+ int fd = -1;
+ unsigned fileSize = 512;
+ char *read_buf = NULL, *pd = NULL;
+ static const char *const SOUND_CARDS_PATH = "/proc/asound/cards";
+ fd = open(SOUND_CARDS_PATH, O_RDONLY);
+ if (fd < 0) {
+ ALOGE("ERROR: failed to open config file %s error: %d\n",
+ SOUND_CARDS_PATH, errno);
+ close(fd);
+ return -EINVAL;
+ }
+
+ read_buf = (char *) malloc(fileSize);
+ if (!read_buf) {
+ ALOGE("Failed to malloc read_buf");
+ close(fd);
+ return -ENOMEM;
+ }
+ memset(read_buf, 0x0, fileSize);
+ err = read(fd, read_buf, fileSize);
+ if (fd < 0) {
+ ALOGE("ERROR: failed to read config file %s error: %d\n",
+ SOUND_CARDS_PATH, errno);
+ close(fd);
+ return -EINVAL;
+ }
+ pd = strstr(read_buf, "AML");
+ card = *(pd - 3) - '0';
+OUT:
+ free(read_buf);
+ close(fd);
+ return card;
+}
+
+int
+get_spdif_port()
+{
+ int port = -1, err = 0;
+ int fd = -1;
+ unsigned fileSize = 512;
+ char *read_buf = NULL, *pd = NULL;
+ static const char *const SOUND_PCM_PATH = "/proc/asound/pcm";
+ fd = open(SOUND_PCM_PATH, O_RDONLY);
+ if (fd < 0) {
+ ALOGE("ERROR: failed to open config file %s error: %d\n",
+ SOUND_PCM_PATH, errno);
+ close(fd);
+ return -EINVAL;
+ }
+ read_buf = (char *) malloc(fileSize);
+ if (!read_buf) {
+ ALOGE("Failed to malloc read_buf");
+ close(fd);
+ return -ENOMEM;
+ }
+ memset(read_buf, 0x0, fileSize);
+ err = read(fd, read_buf, fileSize);
+ if (fd < 0) {
+ ALOGE("ERROR: failed to read config file %s error: %d\n",
+ SOUND_PCM_PATH, errno);
+ close(fd);
+ return -EINVAL;
+ }
+ pd = strstr(read_buf, "SPDIF");
+ port = *(pd - 3) - '0';
+OUT:
+ free(read_buf);
+ close(fd);
+ return port;
+}
+
+
+/*
+CodingType MaxChannels SamplingFreq SampleSize
+PCM, 2 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16/20/24 bit
+PCM, 8 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16/20/24 bit
+AC-3, 8 ch, 32/44.1/48 kHz, bit
+DTS, 8 ch, 44.1/48 kHz, bit
+OneBitAudio, 2 ch, 44.1 kHz, bit
+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)
+{
+ int i = 0;
+ char * infobuf = NULL;
+ int channel = 0;
+ int dgraw = 0;
+ int fd = -1;
+ int size = 0;
+ char *aud_cap = NULL;
+ infobuf = (char *)malloc(1024 * sizeof(char));
+ if (infobuf == NULL) {
+ ALOGE("malloc buffer failed\n");
+ goto fail;
+ }
+ aud_cap = (char*)malloc(1024);
+ if (aud_cap == NULL) {
+ ALOGE("malloc buffer failed\n");
+ goto fail;
+ }
+ memset(aud_cap, 0, 1024);
+ memset(infobuf, 0, 1024);
+ fd = open("/sys/class/amhdmitx/amhdmitx0/aud_cap", O_RDONLY);
+ if (fd >= 0) {
+ int nread = read(fd, infobuf, 1024);
+ /* check the format cap */
+ if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+ size += sprintf(aud_cap, "=");
+ if (mystrstr(infobuf, "Dobly_Digital+")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_E_AC3");
+ }
+ if (mystrstr(infobuf, "AC-3")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_AC3");
+ }
+ if (mystrstr(infobuf, "DTS-HD")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTSHD");
+ } else if (mystrstr(infobuf, "DTS")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS");
+ }
+ if (mystrstr(infobuf, "MAT")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_TRUEHD");
+ }
+ }
+ /*check the channel cap */
+ else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+ /* take the 2ch suppported as default */
+ size += sprintf(aud_cap, "=%s|", "AUDIO_CHANNEL_OUT_STEREO");
+ if (mystrstr(infobuf, "PCM, 8 ch")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1");
+ } else if (mystrstr(infobuf, "PCM, 6 ch")) {
+ size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1");
+ }
+ } 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");
+ if (mystrstr(infobuf, "88.2")) {
+ size += sprintf(aud_cap + size, "%s|", "88200");
+ }
+ if (mystrstr(infobuf, "96")) {
+ size += sprintf(aud_cap + size, "%s|", "96000");
+ }
+ if (mystrstr(infobuf, "176.4")) {
+ size += sprintf(aud_cap + size, "%s|", "176400");
+ }
+ if (mystrstr(infobuf, "192")) {
+ size += sprintf(aud_cap + size, "%s|", "192000");
+ }
+ }
+ }
+ if (infobuf) {
+ free(infobuf);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+ return aud_cap;
+fail:
+ if (aud_cap) {
+ free(aud_cap);
+ }
+ if (infobuf) {
+ free(infobuf);
+ }
+ return NULL;
+}
+
+
diff --git a/audio_hw_profile.h b/audio_hw_profile.h
new file mode 100644
index 0000000..1af6436
--- a/dev/null
+++ b/audio_hw_profile.h
@@ -0,0 +1,3 @@
+#ifndef _AUDIO_HW_PROFILE_H_
+#define _AUDIO_HW_PROFILE_H_
+#endif \ No newline at end of file
diff --git a/audio_hw_utils.c b/audio_hw_utils.c
new file mode 100644
index 0000000..64d0a55
--- a/dev/null
+++ b/audio_hw_utils.c
@@ -0,0 +1,151 @@
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <utils/Timers.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <linux/ioctl.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+#include <sound/asound.h>
+#include <tinyalsa/asoundlib.h>
+
+#include "audio_hw_utils.h"
+
+#include "audio_hwsync.h"
+#include "hdmi_audio_hw.h"
+
+#define LOG_TAG "audio_hw_utils"
+#define LOG_NDEBUG 0
+#ifdef LOG_NDEBUG_FUNCTION
+#define LOGFUNC(...) ((void)0)
+#else
+#define LOGFUNC(...) (ALOGD(__VA_ARGS__))
+#endif
+int get_sysfs_int16(const char *path,unsigned *value)
+{
+ int fd;
+ char valstr[64];
+ unsigned val = 0;
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ memset(valstr, 0, 64);
+ read(fd, valstr, 64 - 1);
+ valstr[strlen(valstr)] = '\0';
+ close(fd);
+ } else {
+ ALOGE("unable to open file %s\n", path);
+ return -1;
+ }
+ if (sscanf(valstr, "0x%lx", &val) < 1) {
+ ALOGE("unable to get pts from: %s", valstr);
+ return -1;
+ }
+ *value = val;
+ return 0;
+}
+
+int sysfs_set_sysfs_str(const char *path, const char *val)
+{
+ int fd;
+ int bytes;
+ fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
+ if (fd >= 0) {
+ bytes = write(fd, val, strlen(val));
+ close(fd);
+ return 0;
+ } else {
+ ALOGE("unable to open file %s,err: %s", path, strerror(errno));
+ }
+ return -1;
+}
+
+int get_sysfs_int (const char *path)
+{
+ int val = 0;
+ int fd = open (path, O_RDONLY);
+ if (fd >= 0)
+ {
+ char bcmd[16];
+ read (fd, bcmd, sizeof (bcmd));
+ val = strtol (bcmd, NULL, 10);
+ close (fd);
+ }
+ else
+ {
+ LOGFUNC ("[%s]open %s node failed! return 0\n", path, __FUNCTION__);
+ }
+ return val;
+}
+int mystrstr(char *mystr,char *substr) {
+ int i=0;
+ int j=0;
+ int score = 0;
+ int substrlen = strlen(substr);
+ int ok = 0;
+ for (i =0;i < 1024 - substrlen;i++) {
+ for (j = 0;j < substrlen;j++) {
+ score += (substr[j] == mystr[i+j])?1:0;
+ }
+ if (score == substrlen) {
+ ok = 1;
+ break;
+ }
+ score = 0;
+ }
+ return ok;
+}
+void set_codec_type(int type)
+{
+ char buf[16];
+ int fd = open ("/sys/class/audiodsp/digital_codec", O_WRONLY);
+
+ if (fd >= 0) {
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf), "%d", type);
+
+ write(fd, buf, sizeof(buf));
+ close(fd);
+ }
+}
+
+int get_codec_type(int format)
+{
+ switch (format) {
+ case AUDIO_FORMAT_AC3:
+ return TYPE_AC3;
+ case AUDIO_FORMAT_E_AC3:
+ return TYPE_EAC3;
+ case AUDIO_FORMAT_DTS:
+ return TYPE_DTS;
+ case AUDIO_FORMAT_DTS_HD:
+ return TYPE_DTS_HD;
+ case AUDIO_FORMAT_TRUEHD:
+ return TYPE_TRUE_HD;
+ case AUDIO_FORMAT_PCM:
+ return 0;
+ default:
+ return 0;
+ }
+}
+int getprop_bool (const char *path)
+{
+ char buf[PROPERTY_VALUE_MAX];
+ int ret = -1;
+
+ ret = property_get (path, buf, NULL);
+ if (ret > 0)
+ {
+ if (strcasecmp (buf, "true") == 0 || strcmp (buf, "1") == 0)
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/audio_hw_utils.h b/audio_hw_utils.h
new file mode 100644
index 0000000..9145092
--- a/dev/null
+++ b/audio_hw_utils.h
@@ -0,0 +1,10 @@
+#ifndef _AUDIO_HW_UTILS_H_
+#define _AUDIO_HW_UTILS_H_
+int get_sysfs_int16(const char *path,unsigned *value);
+int sysfs_set_sysfs_str(const char *path, const char *val);
+int get_sysfs_int (const char *path);
+int mystrstr(char *mystr,char *substr) ;
+void set_codec_type(int type);
+int get_codec_type(int format);
+int getprop_bool (const char *path);
+#endif
diff --git a/audio_hwsync.c b/audio_hwsync.c
new file mode 100644
index 0000000..0832dcb
--- a/dev/null
+++ b/audio_hwsync.c
@@ -0,0 +1,122 @@
+#define LOG_TAG "audio_hwsync"
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <utils/Timers.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <linux/ioctl.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+#include <sound/asound.h>
+#include <tinyalsa/asoundlib.h>
+
+#include "audio_hwsync.h"
+#include "audio_hw_utils.h"
+#include "audio_hw.h"
+#include "hdmi_audio_hw.h"
+static uint32_t aml_hwsync_out_get_latency(const struct audio_stream_out *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ uint32_t whole_latency;
+ uint32_t ret;
+ snd_pcm_sframes_t frames = 0;
+ whole_latency = (out->config.period_size * out->config.period_count * 1000) / out->config.rate;
+ if (!out->pcm || !pcm_is_ready(out->pcm)) {
+ return whole_latency;
+ }
+ ret = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_DELAY, &frames);
+ if (ret < 0) {
+ return whole_latency;
+ }
+ if (out->format == AUDIO_FORMAT_E_AC3) {
+ frames /= 4;
+ }
+ return (uint32_t)((frames * 1000) / out->config.rate);
+}
+
+void aml_audio_hwsync_clear_status(struct aml_stream_out *out)
+{
+ struct aml_audio_device *adev = out->dev;
+ audio_hwsync_t *p_hwsync = &adev->hwsync;
+ p_hwsync->first_apts_flag = 0;
+ p_hwsync->hw_sync_state = HW_SYNC_STATE_HEADER;
+ p_hwsync->hw_sync_header_cnt = 0;
+ return;
+}
+//return bytes cost from input,
+int aml_audio_hwsync_find_frame(struct aml_stream_out *out, const void *in_buffer, size_t in_bytes, uint64_t *cur_pts, int *outsize)
+{
+ int remain = in_bytes;
+ uint8_t *p = in_buffer;
+ struct aml_audio_device *adev = out->dev;
+ audio_hwsync_t *p_hwsync = &adev->hwsync;
+ int time_diff = 0;
+ //ALOGI(" --- out_write %d, cache cnt = %d, body = %d, hw_sync_state = %d", out_frames * frame_size, out->body_align_cnt, out->hw_sync_body_cnt, out->hw_sync_state);
+ while (remain > 0) {
+ //if (p_hwsync->hw_sync_state == HW_SYNC_STATE_RESYNC) {
+ //}
+ if (p_hwsync->hw_sync_state == HW_SYNC_STATE_HEADER) {
+ //ALOGI("Add to header buffer [%d], 0x%x", out->hw_sync_header_cnt, *p);
+ p_hwsync->hw_sync_header[p_hwsync->hw_sync_header_cnt++] = *p++;
+ remain--;
+ if (p_hwsync->hw_sync_header_cnt == 16) {
+ uint64_t pts;
+ if (!hwsync_header_valid(&p_hwsync->hw_sync_header[0])) {
+ ALOGE("!!!!!!hwsync header out of sync! Resync.should not happen????");
+ p_hwsync->hw_sync_state = HW_SYNC_STATE_HEADER;
+ memcpy(p_hwsync->hw_sync_header, p_hwsync->hw_sync_header + 1, 15);
+ p_hwsync->hw_sync_header_cnt--;
+ continue;
+ }
+ p_hwsync->hw_sync_state = HW_SYNC_STATE_BODY;
+ p_hwsync->hw_sync_body_cnt = hwsync_header_get_size(&p_hwsync->hw_sync_header[0]);
+ p_hwsync->hw_sync_frame_size = p_hwsync->hw_sync_body_cnt;
+ p_hwsync->body_align_cnt = 0;
+ pts = hwsync_header_get_pts(&p_hwsync->hw_sync_header[0]);
+ //memcpy(write_buf+write_pos,&p_hwsync->hw_sync_header[0],16);
+ //write_pos += 16;
+ pts = pts * 90 / 1000000;
+ time_diff = (abs(pts - p_hwsync->last_apts_from_header)) / 90;
+ ALOGV("pts %llx,frame len %d\n", pts, p_hwsync->hw_sync_body_cnt);
+ ALOGV("last pts %llx,diff %d ms\n", p_hwsync->last_apts_from_header, time_diff);
+
+ if (time_diff > 32) {
+ ALOGI("pts time gap %d ms,last %llx,cur %llx\n", time_diff,
+ p_hwsync->last_apts_from_header, pts);
+ }
+ p_hwsync->last_apts_from_header = pts;
+ *cur_pts = pts;
+ //ALOGI("get header body_cnt = %d, pts = %lld", out->hw_sync_body_cnt, pts);
+ }
+ continue;
+ } else if (p_hwsync->hw_sync_state == HW_SYNC_STATE_BODY) {
+ int m = (p_hwsync->hw_sync_body_cnt < remain) ? p_hwsync->hw_sync_body_cnt : remain;
+ //ALOGI("m = %d", m);
+ // process m bytes body with an empty fragment for alignment
+ if (m > 0) {
+ //ret = pcm_write(out->pcm, p, m - align);
+ memcpy(p_hwsync->hw_sync_body_buf + p_hwsync->hw_sync_frame_size - p_hwsync->hw_sync_body_cnt, p, m);
+ p += m;
+ remain -= m;
+ //ALOGI("pcm_write %d, remain %d", m - align, remain);
+ p_hwsync->hw_sync_body_cnt -= m;
+ if (p_hwsync->hw_sync_body_cnt == 0) {
+ p_hwsync->hw_sync_state = HW_SYNC_STATE_HEADER;
+ p_hwsync->hw_sync_header_cnt = 0;
+ *outsize = p_hwsync->hw_sync_frame_size;
+ ALOGV("we found the frame total body,yeah\n");
+ break;//continue;
+ }
+ }
+ }
+ }
+ return in_bytes - remain;
+}
diff --git a/audio_hwsync.h b/audio_hwsync.h
new file mode 100644
index 0000000..0cdddab
--- a/dev/null
+++ b/audio_hwsync.h
@@ -0,0 +1,58 @@
+#ifndef _AUDIO_HWSYNC_H_
+#define _AUDIO_HWSYNC_H_
+
+
+#define TSYNC_FIRSTAPTS "/sys/class/tsync/firstapts"
+#define TSYNC_PCRSCR "/sys/class/tsync/pts_pcrscr"
+#define TSYNC_EVENT "/sys/class/tsync/event"
+#define TSYNC_APTS "/sys/class/tsync/pts_audio"
+#define SYSTIME_CORRECTION_THRESHOLD (90000*10/100)
+#define NSEC_PER_SECOND 1000000000ULL
+#define HW_SYNC_STATE_HEADER 0
+#define HW_SYNC_STATE_BODY 1
+#define HW_SYNC_STATE_RESYNC 2
+#define APTS_DISCONTINUE_THRESHOLD (90000)
+#define APTS_DISCONTINUE_THRESHOLD_MIN (90000/2)
+#define APTS_DISCONTINUE_THRESHOLD_MAX (5*90000)
+
+typedef struct audio_hwsync {
+ uint8_t hw_sync_header[16];
+ int hw_sync_header_cnt;
+ int hw_sync_state;
+ int hw_sync_body_cnt;
+ int hw_sync_frame_size;
+ uint8_t hw_sync_body_buf[4096];
+ uint8_t body_align[64];
+ uint8_t body_align_cnt;
+ bool first_apts_flag;//flag to indicate set first apts
+ uint64_t first_apts;
+ uint64_t last_apts_from_header;
+} audio_hwsync_t;
+static inline bool hwsync_header_valid(uint8_t *header)
+{
+ return (header[0] == 0x55) &&
+ (header[1] == 0x55) &&
+ (header[2] == 0x00) &&
+ (header[3] == 0x01);
+}
+
+static inline uint64_t hwsync_header_get_pts(uint8_t *header)
+{
+ return (((uint64_t)header[8]) << 56) |
+ (((uint64_t)header[9]) << 48) |
+ (((uint64_t)header[10]) << 40) |
+ (((uint64_t)header[11]) << 32) |
+ (((uint64_t)header[12]) << 24) |
+ (((uint64_t)header[13]) << 16) |
+ (((uint64_t)header[14]) << 8) |
+ ((uint64_t)header[15]);
+}
+
+static inline uint32_t hwsync_header_get_size(uint8_t *header)
+{
+ return (((uint32_t)header[4]) << 24) |
+ (((uint32_t)header[5]) << 16) |
+ (((uint32_t)header[6]) << 8) |
+ ((uint32_t)header[7]);
+}
+#endif
diff --git a/hdmi_audio_hw.c b/hdmi_audio_hw.c
index a97707f..378fbc7 100644
--- a/hdmi_audio_hw.c
+++ b/hdmi_audio_hw.c
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -15,14 +15,19 @@
*/
#define LOG_TAG "audio_hw_hdmi"
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
//#define LOG_NDEBUG_FUNCTION
#ifdef LOG_NDEBUG_FUNCTION
#define LOGFUNC(...) ((void)0)
#else
#define LOGFUNC(...) (ALOGD(__VA_ARGS__))
#endif
-
+//#define DEBUG_HWSYNC_PASSTHROUGH
+#ifndef DEBUG_HWSYNC_PASSTHROUGH
+#define DEBUG(...) ((void)0)
+#else
+#define DEBUG(...) (ALOGD(__VA_ARGS__))
+#endif
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
@@ -30,2671 +35,1650 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
-#include <math.h>
-
+#include <time.h>
+#include <utils/Timers.h>
#include <cutils/log.h>
#include <cutils/str_parms.h>
#include <cutils/properties.h>
-
+#include <linux/ioctl.h>
#include <hardware/hardware.h>
#include <system/audio.h>
#include <hardware/audio.h>
-
+#include <sound/asound.h>
#include <tinyalsa/asoundlib.h>
+
#include <audio_utils/resampler.h>
#include <audio_utils/echo_reference.h>
#include <hardware/audio_effect.h>
#include <audio_effects/effect_aec.h>
-/* ALSA cards for AML */
-#define CARD_AMLOGIC_BOARD 0
-#define CARD_AMLOGIC_USB 1
-#define CARD_AMLOGIC_DEFAULT CARD_AMLOGIC_BOARD
-/* ALSA ports for AML */
-#define PORT_MM 1
-/* number of frames per period */
-#define DEFAULT_PERIOD_SIZE 1024 //(1024 * 2)
-static unsigned PERIOD_SIZE = DEFAULT_PERIOD_SIZE;
-/* number of periods for low power playback */
-#define PLAYBACK_PERIOD_COUNT 4
-/* number of periods for capture */
-#define CAPTURE_PERIOD_COUNT 4
-
-/* minimum sleep time in out_write() when write threshold is not reached */
-#define MIN_WRITE_SLEEP_US 5000
-
-#define RESAMPLER_BUFFER_FRAMES (PERIOD_SIZE * 6)
-#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
-
-static unsigned int DEFAULT_OUT_SAMPLING_RATE = 48000;
-
-/* sampling rate when using MM low power port */
-#define MM_LOW_POWER_SAMPLING_RATE 44100
-/* sampling rate when using MM full power port */
-#define MM_FULL_POWER_SAMPLING_RATE 48000
-/* sampling rate when using VX port for narrow band */
-#define VX_NB_SAMPLING_RATE 8000
-
-static unsigned int first_write_status;
-
-
+#include "audio_hw.h"
+#include "audio_hwsync.h"
+#include "hdmi_audio_hw.h"
+#include "audio_hw_profile.h"
+#include "audio_hw_utils.h"
+extern int aml_audio_hwsync_find_frame(struct aml_stream_out *out, const void *in_buffer, size_t in_bytes, uint64_t *cur_pts, int *outsize);
+extern int spdifenc_write(const void *buffer, size_t numBytes);
+extern uint64_t spdifenc_get_total();
struct pcm_config pcm_config_out = {
- .channels = 2,
- .rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = DEFAULT_PERIOD_SIZE,
- .period_count = PLAYBACK_PERIOD_COUNT,
- .format = PCM_FORMAT_S16_LE,
+ .channels = 2,
+ .rate = MM_FULL_POWER_SAMPLING_RATE,
+ .period_size = DEFAULT_PERIOD_SIZE,
+ .period_count = PLAYBACK_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
};
struct pcm_config pcm_config_in = {
- .channels = 2,
- .rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = DEFAULT_PERIOD_SIZE,
- .period_count = PLAYBACK_PERIOD_COUNT,
- .format = PCM_FORMAT_S16_LE,
-};
-
-struct aml_audio_device
-{
- struct audio_hw_device hw_device;
-
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
- int mode;
- audio_devices_t in_device;
- audio_devices_t out_device;
- int in_call;
- //int cur_devices;
- struct pcm *pcm_modem_dl;
- struct pcm *pcm_modem_ul;
- struct aml_stream_in *active_input;
- struct aml_stream_out *active_output;
-
- bool mic_mute;
- struct echo_reference_itfe *echo_reference;
- bool bluetooth_nrec;
- bool low_power;
- /* RIL */
- //struct ril_handle ril;
-};
-
-struct aml_stream_out
-{
- struct audio_stream_out stream;
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
- struct pcm_config config;
- struct pcm *pcm;
- struct resampler_itfe *resampler;
- char *buffer;
- int standby;
- struct echo_reference_itfe *echo_reference;
- struct aml_audio_device *dev;
- int write_threshold;
- bool low_power;
- unsigned multich;
+ .channels = 2,
+ .rate = MM_FULL_POWER_SAMPLING_RATE,
+ .period_size = DEFAULT_PERIOD_SIZE,
+ .period_count = PLAYBACK_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
};
-#define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */
-struct aml_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 device;
- struct resampler_itfe *resampler;
- struct resampler_itfe *up_resampler; //shuai
- struct resampler_buffer_provider buf_provider;
- char *up_resampler_buffer;
- struct resampler_buffer_provider up_buf_provider;
- int16_t *buffer;
- size_t frames_in;
- unsigned int requested_rate;
- int standby;
- int source;
- struct echo_reference_itfe *echo_reference;
- bool need_echo_reference;
- effect_handle_t preprocessors[MAX_PREPROCESSORS];
- int num_preprocessors;
- int16_t *proc_buf;
- size_t proc_buf_size;
- size_t proc_frames_in;
- int16_t *ref_buf;
- size_t ref_buf_size;
- size_t ref_frames_in;
- int read_status;
- int voip_mode;
- //hdmi in volume parameters
- int volume_index;
- float last_volume;
- int indexMIn;
- int indexMax;
-
- struct aml_audio_device *dev;
-};
-
-static char cache_buffer_bytes[64];
-static uint cached_len = 0;
-static void select_output_device (struct aml_audio_device *adev);
-static void select_input_device (struct aml_audio_device *adev);
-static int adev_set_voice_volume (struct audio_hw_device *dev, float volume);
-static int do_input_standby (struct aml_stream_in *in);
-static int do_output_standby (struct aml_stream_out *out);
-
-// add compute hdmi in volume function, volume index between 0 and 15 ,this reference AudioPolicyManagerBase
+static void select_output_device(struct aml_audio_device *adev);
+static void select_input_device(struct aml_audio_device *adev);
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume);
+static int do_input_standby(struct aml_stream_in *in);
+static int do_output_standby(struct aml_stream_out *out);
-enum
-{ VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4 };
-
-struct VolumeCurvePoint
+static void select_output_device(struct aml_audio_device *adev)
{
- int mIndex;
- float mDBAttenuation;
-};
-
-struct VolumeCurvePoint sSpeakerMediaVolumeCurve[VOLCNT] = {
- {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
-};
-
-// stream descriptor used for volume control
-struct StreamDescriptor
-{
- int mIndexMin; // min volume index
- int mIndexMax; // max volume index
- int mIndexCur[15]; // current volume index
- struct VolumeCurvePoint *mVolumeCurve;
-};
-
-
-float
-volIndexToAmpl (struct audio_stream_in *stream, int indexInUi)
-{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- struct VolumeCurvePoint *curve = NULL;
- struct StreamDescriptor *streamDesc = NULL;
-
- streamDesc = malloc (sizeof (struct StreamDescriptor));
- streamDesc->mVolumeCurve = sSpeakerMediaVolumeCurve;
-
- curve = streamDesc->mVolumeCurve;
- streamDesc->mIndexMin = in->indexMIn;
- streamDesc->mIndexMax = in->indexMax;
- // the volume index in the UI is relative to the min and max volume indices for this stream type
- int nbSteps = 1 + curve[VOLMAX].mIndex - curve[VOLMIN].mIndex;
-
- ALOGD ("volIndexToAmpl,nbSteps=%d", nbSteps);
- int volIdx = (nbSteps * (indexInUi - streamDesc->mIndexMin)) /
- (streamDesc->mIndexMax - streamDesc->mIndexMin);
-
- // find what part of the curve this index volume belongs to, or if it's out of bounds
- int segment = 0;
- if (volIdx < curve[VOLMIN].mIndex)
- { // out of bounds
- return 0.0f;
- }
- else if (volIdx < curve[VOLKNEE1].mIndex)
- {
- segment = 0;
- }
- else if (volIdx < curve[VOLKNEE2].mIndex)
- {
- segment = 1;
- }
- else if (volIdx <= curve[VOLMAX].mIndex)
- {
- segment = 2;
- }
- else
- { // out of bounds
- return 1.0f;
- }
-
- // linear interpolation in the attenuation table in dB
- float decibels = curve[segment].mDBAttenuation +
- ((float) (volIdx - curve[segment].mIndex)) *
- ((curve[segment + 1].mDBAttenuation -
- curve[segment].mDBAttenuation) /
- ((float) (curve[segment + 1].mIndex - curve[segment].mIndex)));
-
- float amplification = exp (decibels * 0.115129f); // exp( dB * ln(10) / 20 )
-
- ALOGD ("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
- curve[segment].mIndex, volIdx,curve[segment + 1].mIndex,
- curve[segment].mDBAttenuation,
- decibels, curve[segment + 1].mDBAttenuation, amplification);
-
- return amplification;
-}
-
-float
-computeVolume (struct audio_stream_in *stream)
-{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- float volume = 1.0f;
- char prop[PROPERTY_VALUE_MAX];
-
- property_get ("mbx.hdmiin.vol", prop, "15");
-
- int indexUI = atoi (prop);
- if (indexUI > in->indexMax)
- indexUI = in->indexMax;
- else if (indexUI < in->indexMIn)
- indexUI = in->indexMIn;
-
- if (in->volume_index != indexUI)
- {
- in->volume_index = indexUI;
-
- volume = volIndexToAmpl (stream, indexUI);
- in->last_volume = volume;
- }
- else
- {
- volume = in->last_volume;
- }
- return volume;
+ LOGFUNC("%s(mode=%d, out_device=%#x)", __FUNCTION__, adev->mode,
+ adev->out_device);
}
-static int
-getprop_bool (const char *path)
+static void select_input_device(struct aml_audio_device *adev)
{
- char buf[PROPERTY_VALUE_MAX];
- int ret = -1;
-
- ret = property_get (path, buf, NULL);
- if (ret > 0)
- {
- if (strcasecmp (buf, "true") == 0 || strcmp (buf, "1") == 0)
- return 1;
- }
- return 0;
-}
-
-static int
-get_codec_type (const char *path)
-{
- int val = 0;
- int fd = open ("/sys/class/audiodsp/digital_codec", O_RDONLY);
- if (fd >= 0)
- {
- char bcmd[16];
- read (fd, bcmd, sizeof (bcmd));
- val = strtol (bcmd, NULL, 10);
- close (fd);
- }
- else
- {
- LOGFUNC ("[%s]open digital_codec node failed! return 0\n",
- __FUNCTION__);
- }
- return val;
+ int mic_in = adev->in_device & AUDIO_DEVICE_IN_BUILTIN_MIC;
+ int headset_mic = adev->in_device & AUDIO_DEVICE_IN_WIRED_HEADSET;
+ LOGFUNC("~~~~ %s : in_device(%#x), mic_in(%#x), headset_mic(%#x)",
+ __func__, adev->in_device, mic_in, headset_mic);
+ return;
}
static void
-select_output_device (struct aml_audio_device *adev)
+force_all_standby(struct aml_audio_device *adev)
{
- LOGFUNC ("%s(mode=%d, out_device=%#x)", __FUNCTION__, adev->mode,
- adev->out_device);
-}
+ struct aml_stream_in *in;
+ struct aml_stream_out *out;
-static void
-select_input_device (struct aml_audio_device *adev)
-{
- int mic_in = adev->in_device & AUDIO_DEVICE_IN_BUILTIN_MIC;
- int headset_mic = adev->in_device & AUDIO_DEVICE_IN_WIRED_HEADSET;
- LOGFUNC ("~~~~ %s : in_device(%#x), mic_in(%#x), headset_mic(%#x)",
- __func__, adev->in_device, mic_in, headset_mic);
- return;
-}
-
-static void
-force_all_standby (struct aml_audio_device *adev)
-{
- struct aml_stream_in *in;
- struct aml_stream_out *out;
+ LOGFUNC("%s(%p)", __FUNCTION__, adev);
- LOGFUNC ("%s(%p)", __FUNCTION__, adev);
+ if (adev->active_output) {
+ out = adev->active_output;
+ pthread_mutex_lock(&out->lock);
+ do_output_standby(out);
+ pthread_mutex_unlock(&out->lock);
+ }
- if (adev->active_output)
- {
- out = adev->active_output;
- pthread_mutex_lock (&out->lock);
- do_output_standby (out);
- pthread_mutex_unlock (&out->lock);
- }
-
- if (adev->active_input)
- {
- in = adev->active_input;
- pthread_mutex_lock (&in->lock);
- do_input_standby (in);
- pthread_mutex_unlock (&in->lock);
- }
+ if (adev->active_input) {
+ in = adev->active_input;
+ pthread_mutex_lock(&in->lock);
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ }
}
static void
-select_mode (struct aml_audio_device *adev)
-{
- LOGFUNC ("%s(out_device=%#x)", __FUNCTION__, adev->out_device);
- LOGFUNC ("%s(in_device=%#x)", __FUNCTION__, adev->in_device);
- return;
- force_all_standby (adev);
- /* force earpiece route for in call state if speaker is the
- only currently selected route. This prevents having to tear
- down the modem PCMs to change route from speaker to earpiece
- after the ringtone is played, but doesn't cause a route
- change if a headset or bt device is already connected. If
- speaker is not the only thing active, just remove it from
- the route. We'll assume it'll never be used initally during
- a call. This works because we're sure that the audio policy
- manager will update the output device after the audio mode
- change, even if the device selection did not change. */
- if ((adev->out_device & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER)
- adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
- else
- adev->out_device &= ~AUDIO_DEVICE_OUT_SPEAKER;
-
- select_output_device (adev);
- select_input_device (adev);
- return;
+select_mode(struct aml_audio_device *adev)
+{
+ LOGFUNC("%s(out_device=%#x)", __FUNCTION__, adev->out_device);
+ LOGFUNC("%s(in_device=%#x)", __FUNCTION__, adev->in_device);
+ return;
+ force_all_standby(adev);
+ /* force earpiece route for in call state if speaker is the
+ only currently selected route. This prevents having to tear
+ down the modem PCMs to change route from speaker to earpiece
+ after the ringtone is played, but doesn't cause a route
+ change if a headset or bt device is already connected. If
+ speaker is not the only thing active, just remove it from
+ the route. We'll assume it'll never be used initally during
+ a call. This works because we're sure that the audio policy
+ manager will update the output device after the audio mode
+ change, even if the device selection did not change. */
+ if ((adev->out_device & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER) {
+ adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
+ } else {
+ adev->out_device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ }
+ select_output_device(adev);
+ select_input_device(adev);
+ return;
}
-/*
- type : 0 -> playback, 1 -> capture
-*/
-#define MAX_CARD_NUM 2
-int
-get_external_card (int type)
-{
- int card_num = 1; // start num, 0 is defualt sound card.
-
- struct stat card_stat;
- char fpath[256];
- int ret;
-
-
- while (card_num <= MAX_CARD_NUM)
- {
- snprintf (fpath, sizeof (fpath), "/proc/asound/card%d", card_num);
-
- ret = stat (fpath, &card_stat);
- if (ret < 0)
- {
- ret = -1;
- }
- else
- {
- snprintf (fpath, sizeof (fpath), "/dev/snd/pcmC%uD0%c", card_num,
- type ? 'c' : 'p');
- ret = stat (fpath, &card_stat);
- if (ret == 0)
- {
- return card_num;
- }
- }
-
- card_num++;
- }
-
- return ret;
-}
-
-static int
-check_output_stream (struct aml_stream_out *out)
-{
- int ret = 0;
- unsigned int card = CARD_AMLOGIC_DEFAULT;
- unsigned int port = PORT_MM;
- int ext_card;
- ext_card = get_external_card (0);
- if (ext_card < 0)
- {
- card = CARD_AMLOGIC_DEFAULT;
- }
- else
- {
- card = ext_card;
- }
-
- out->config.start_threshold = PERIOD_SIZE * 2;
- out->config.avail_min = 0; //SHORT_PERIOD_SIZE;
- return 0;
-}
-
-static int
-get_aml_card ()
-{
- int card = -1, err = 0;
- int fd = -1;
- unsigned fileSize = 512;
- char *read_buf = NULL, *pd = NULL;
- static const char *const SOUND_CARDS_PATH = "/proc/asound/cards";
- fd = open (SOUND_CARDS_PATH, O_RDONLY);
- if (fd < 0)
- {
- ALOGE ("ERROR: failed to open config file %s error: %d\n",
- SOUND_CARDS_PATH, errno);
- close (fd);
- return -EINVAL;
- }
-
- read_buf = (char *) malloc (fileSize);
- if (!read_buf)
- {
- ALOGE ("Failed to malloc read_buf");
- close (fd);
- return -ENOMEM;
- }
- memset (read_buf, 0x0, fileSize);
- err = read (fd, read_buf, fileSize);
- if (fd < 0)
- {
- ALOGE ("ERROR: failed to read config file %s error: %d\n",
- SOUND_CARDS_PATH, errno);
- close (fd);
- return -EINVAL;
- }
- pd = strstr (read_buf, "AML");
- card = *(pd - 3) - '0';
-
-OUT:
- free (read_buf);
- close (fd);
- return card;
-}
static int
-get_spdif_port ()
-{
- int port = -1, err = 0;
- int fd = -1;
- unsigned fileSize = 512;
- char *read_buf = NULL, *pd = NULL;
- static const char *const SOUND_PCM_PATH = "/proc/asound/pcm";
- fd = open (SOUND_PCM_PATH, O_RDONLY);
- if (fd < 0)
- {
- ALOGE ("ERROR: failed to open config file %s error: %d\n",
- SOUND_PCM_PATH, errno);
- close (fd);
- return -EINVAL;
- }
-
- read_buf = (char *) malloc (fileSize);
- if (!read_buf)
- {
- ALOGE ("Failed to malloc read_buf");
- close (fd);
- return -ENOMEM;
- }
- memset (read_buf, 0x0, fileSize);
- err = read (fd, read_buf, fileSize);
- if (fd < 0)
- {
- ALOGE ("ERROR: failed to read config file %s error: %d\n",
- SOUND_PCM_PATH, errno);
- close (fd);
- return -EINVAL;
- }
- pd = strstr (read_buf, "SPDIF");
- port = *(pd - 3) - '0';
-
-OUT:
- free (read_buf);
- close (fd);
- return port;
+check_output_stream(struct aml_stream_out *out)
+{
+ int ret = 0;
+ unsigned int card = CARD_AMLOGIC_DEFAULT;
+ unsigned int port = PORT_MM;
+ int ext_card;
+ ext_card = get_external_card(0);
+ if (ext_card < 0) {
+ card = CARD_AMLOGIC_DEFAULT;
+ } else {
+ card = ext_card;
+ }
+ out->config.start_threshold = PERIOD_SIZE * 2;
+ out->config.avail_min = 0; //SHORT_PERIOD_SIZE;
+ return 0;
}
/* must be called with hw device and output stream mutexes locked */
-static int
-start_output_stream (struct aml_stream_out *out)
-{
- struct aml_audio_device *adev = out->dev;
- int card = CARD_AMLOGIC_DEFAULT;
- int port = PORT_MM;
- int ret = 0;
-
- adev->active_output = out;
-
- if (adev->mode != AUDIO_MODE_IN_CALL)
- {
- /* FIXME: only works if only one output can be active at a time */
- select_output_device (adev);
- }
- LOGFUNC ("%s(adev->out_device=%#x, adev->mode=%d)", __FUNCTION__,
- adev->out_device, adev->mode);
-
- card = get_aml_card ();
- if (card < 0)
- {
- ALOGE ("hdmi get aml card id failed \n");
- card = CARD_AMLOGIC_DEFAULT;
- }
- port = get_spdif_port ();
- if (port < 0)
- {
- ALOGE ("hdmi get aml card port failed \n");
- card = PORT_MM;
- }
- ALOGI ("hdmi sound card id %d,device id %d \n", card, port);
- if (out->config.channels == 8)
- {
- port = 0;
- out->config.format = PCM_FORMAT_S32_LE;
- adev->out_device = AUDIO_DEVICE_OUT_SPEAKER;
- ALOGI ("[%s %d]8CH format output: set port/0 adev->out_device/%d\n",
- __FUNCTION__, __LINE__, AUDIO_DEVICE_OUT_SPEAKER);
- }
- LOGFUNC ("------------open on board audio-------");
- if (getprop_bool ("media.libplayer.wfd"))
- {
- out->config.period_size = PERIOD_SIZE;
- }
- /* default to low power: will be corrected in out_write if necessary before first write to
- * tinyalsa.
- */
- int codec_type = get_codec_type ("/sys/class/audiodsp/digital_codec");
- if (codec_type == 4 || codec_type == 5)
- {
- out->config.period_size = PERIOD_SIZE * 2;
- out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 2;
- out->config.start_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 2;
- }
- else if (codec_type == 7 || codec_type == 8)
- {
- out->config.period_size = PERIOD_SIZE * 4 * 2;
- out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 4 * 2;
- out->config.start_threshold =
- PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 4 * 2;
- }
- else
- {
- out->config.period_size = PERIOD_SIZE;
- out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE;
- out->config.start_threshold = PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
- }
- out->config.avail_min = 0; //SHORT_PERIOD_SIZE
-
- if (out->config.rate != DEFAULT_OUT_SAMPLING_RATE)
- {
-
- ret = create_resampler (DEFAULT_OUT_SAMPLING_RATE,
- out->config.rate,
- 2,
- RESAMPLER_QUALITY_DEFAULT,
- NULL, &out->resampler);
- if (ret != 0)
- {
- ALOGE ("cannot create resampler for output");
- return ENOMEM;
- }
- out->buffer = malloc (RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
- if (out->buffer == NULL)
- return ENOMEM;
- }
-
- ALOGI
- ("channels=%d---format=%d---period_count%d---period_size%d---rate=%d---",
- out->config.channels, out->config.format, out->config.period_count,
- out->config.period_size, out->config.rate);
- out->pcm =
- pcm_open (card, port, PCM_OUT /*| PCM_MMAP | PCM_NOIRQ */ ,
- &(out->config));
- if (!pcm_is_ready (out->pcm))
- {
- ALOGE ("cannot open pcm_out driver: %s", pcm_get_error (out->pcm));
- pcm_close (out->pcm);
- adev->active_output = NULL;
- return -ENOMEM;
- }
- if (adev->echo_reference != NULL)
- out->echo_reference = adev->echo_reference;
- if (out->resampler)
- {
- out->resampler->reset (out->resampler);
- }
-
- return 0;
+static int start_output_stream(struct aml_stream_out *out)
+{
+ struct aml_audio_device *adev = out->dev;
+ int card = CARD_AMLOGIC_DEFAULT;
+ int port = PORT_MM;
+ int ret = 0;
+ int codec_type = get_codec_type(out->format);
+ adev->active_output = out;
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ /* FIXME: only works if only one output can be active at a time */
+ select_output_device(adev);
+ }
+ LOGFUNC("%s(adev->out_device=%#x, adev->mode=%d)", __FUNCTION__,
+ adev->out_device, adev->mode);
+ card = get_aml_card();
+ if (card < 0) {
+ ALOGE("hdmi get aml card id failed \n");
+ card = CARD_AMLOGIC_DEFAULT;
+ }
+ port = get_spdif_port();
+ if (port < 0) {
+ ALOGE("hdmi get aml card port failed \n");
+ card = PORT_MM;
+ }
+ ALOGI("hdmi sound card id %d,device id %d \n", card, port);
+ if (out->config.channels == 6) {
+ ALOGI("round 6ch to 8 ch output \n");
+ out->config.channels = 8;
+ }
+ /*
+ 8 channel audio only support 32 byte mode,so need convert them to
+ PCM_FORMAT_S32_LE
+ */
+ if (out->config.channels == 8) {
+ port = 0;
+ out->config.format = PCM_FORMAT_S32_LE;
+ adev->out_device = AUDIO_DEVICE_OUT_SPEAKER;
+ ALOGI("[%s %d]8CH format output: set port/0 adev->out_device/%d\n",
+ __FUNCTION__, __LINE__, AUDIO_DEVICE_OUT_SPEAKER);
+ }
+ LOGFUNC("------------open on board audio-------");
+ if (getprop_bool("media.libplayer.wfd")) {
+ out->config.period_size = PERIOD_SIZE;
+ }
+ switch (out->format) {
+ case AUDIO_FORMAT_E_AC3:
+ out->config.period_size = PERIOD_SIZE * 2;
+ out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 2;
+ out->config.start_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 2;
+ break;
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_TRUEHD:
+ out->config.period_size = PERIOD_SIZE * 4 * 2;
+ out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 4 * 2;
+ out->config.start_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE * 4 * 2;
+ break;
+ case AUDIO_FORMAT_PCM:
+ default:
+ out->config.period_size = PERIOD_SIZE;
+ out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE;
+ out->config.start_threshold = PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
+ }
+ out->config.avail_min = 0;
+ set_codec_type(codec_type);
+ ALOGI("channels=%d---format=%d---period_count%d---period_size%d---rate=%d---",
+ out->config.channels, out->config.format, out->config.period_count,
+ out->config.period_size, out->config.rate);
+ out->pcm = pcm_open(card, port, PCM_OUT /*| PCM_MMAP | PCM_NOIRQ */ ,
+ &(out->config));
+ if (!pcm_is_ready(out->pcm)) {
+ ALOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm));
+ pcm_close(out->pcm);
+ adev->active_output = NULL;
+ return -ENOMEM;
+ }
+#if 1
+ if (codec_type != TYPE_PCM && !(out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)) {
+ spdifenc_init(out->pcm);
+ out->spdif_enc_init_frame_write_sum = out->frame_write_sum;
+ }
+#endif
+ //out->frame_write_sum=0;
+ out->codec_type = codec_type;
+ out->bytes_write_total = 0;
+ if (adev->hw_sync_mode == 1) {
+ LOGFUNC("start_output_stream with hw sync enable\n");
+ }
+ return 0;
}
static int
-check_input_parameters (uint32_t sample_rate, int format, int channel_count)
+check_input_parameters(uint32_t sample_rate, int format, int channel_count)
{
- LOGFUNC ("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__,
- sample_rate, format, channel_count);
+ LOGFUNC("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__,
+ sample_rate, format, channel_count);
- if (format != AUDIO_FORMAT_PCM_16_BIT)
- return -EINVAL;
+ if (format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
- if ((channel_count < 1) || (channel_count > 2))
- return -EINVAL;
+ if ((channel_count < 1) || (channel_count > 2)) {
+ return -EINVAL;
+ }
- switch (sample_rate)
- {
- case 8000:
- case 11025:
- case 16000:
- case 22050:
- case 24000:
- case 32000:
- case 44100:
- case 48000:
- break;
- default:
- return -EINVAL;
- }
+ switch (sample_rate) {
+ case 8000:
+ case 11025:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ break;
+ default:
+ return -EINVAL;
+ }
- return 0;
+ return 0;
}
static size_t
-get_input_buffer_size (uint32_t sample_rate, int format, int channel_count)
+get_input_buffer_size(uint32_t sample_rate, int format, int channel_count)
{
- size_t size;
- size_t device_rate;
-
- LOGFUNC ("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__,
- sample_rate, format, channel_count);
+ size_t size;
+ size_t device_rate;
- if (check_input_parameters (sample_rate, format, channel_count) != 0)
- return 0;
+ LOGFUNC("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__,
+ sample_rate, format, channel_count);
- /* take resampling into account and return the closest majoring
- multiple of 16 frames, as audioflinger expects audio buffers to
- be a multiple of 16 frames */
- size = (pcm_config_in.period_size * sample_rate) / pcm_config_in.rate;
- size = ((size + 15) / 16) * 16;
+ if (check_input_parameters(sample_rate, format, channel_count) != 0) {
+ return 0;
+ }
- return size * channel_count * sizeof (short);
-}
+ /* take resampling into account and return the closest majoring
+ multiple of 16 frames, as audioflinger expects audio buffers to
+ be a multiple of 16 frames */
+ size = (pcm_config_in.period_size * sample_rate) / pcm_config_in.rate;
+ size = ((size + 15) / 16) * 16;
-static void
-add_echo_reference (struct aml_stream_out *out,
- struct echo_reference_itfe *reference)
-{
- pthread_mutex_lock (&out->lock);
- out->echo_reference = reference;
- pthread_mutex_unlock (&out->lock);
+ return size * channel_count * sizeof(short);
}
-static void
-remove_echo_reference (struct aml_stream_out *out,
- struct echo_reference_itfe *reference)
-{
- pthread_mutex_lock (&out->lock);
- if (out->echo_reference == reference)
- {
- /* stop writing to echo reference */
- reference->write (reference, NULL);
- out->echo_reference = NULL;
- }
- pthread_mutex_unlock (&out->lock);
-}
-
-static void
-put_echo_reference (struct aml_audio_device *adev,
- struct echo_reference_itfe *reference)
-{
- if (adev->echo_reference != NULL && reference == adev->echo_reference)
- {
- if (adev->active_output != NULL)
- remove_echo_reference (adev->active_output, reference);
- release_echo_reference (reference);
- adev->echo_reference = NULL;
- }
-}
-
-static struct echo_reference_itfe *
-get_echo_reference (struct aml_audio_device *adev,
- audio_format_t format,
- uint32_t channel_count, uint32_t sampling_rate)
-{
- put_echo_reference (adev, adev->echo_reference);
- if (adev->active_output != NULL)
- {
- struct audio_stream *stream = &adev->active_output->stream.common;
- uint32_t wr_channel_count = popcount (stream->get_channels (stream));
- uint32_t wr_sampling_rate = stream->get_sample_rate (stream);
-
- int status = create_echo_reference (AUDIO_FORMAT_PCM_16_BIT,
- channel_count,
- sampling_rate,
- AUDIO_FORMAT_PCM_16_BIT,
- wr_channel_count,
- wr_sampling_rate,
- &adev->echo_reference);
- if (status == 0)
- add_echo_reference (adev->active_output, adev->echo_reference);
- }
- return adev->echo_reference;
-}
-static int
-get_playback_delay (struct aml_stream_out *out,
- size_t frames, struct echo_reference_buffer *buffer)
-{
-
- size_t kernel_frames;
- int status;
- status = pcm_get_htimestamp (out->pcm, &kernel_frames, &buffer->time_stamp);
- if (status < 0)
- {
- buffer->time_stamp.tv_sec = 0;
- buffer->time_stamp.tv_nsec = 0;
- buffer->delay_ns = 0;
- ALOGV ("get_playback_delay(): pcm_get_htimestamp error,"
- "setting playbackTimestamp to 0");
- return status;
- }
- kernel_frames = pcm_get_buffer_size (out->pcm) - kernel_frames;
- ALOGV ("~~pcm_get_buffer_size(out->pcm)=%d",
- pcm_get_buffer_size (out->pcm));
- /* adjust render time stamp with delay added by current driver buffer.
- * Add the duration of current frame as we want the render time of the last
- * sample being written. */
- buffer->delay_ns =
- (long) (((int64_t) (kernel_frames + frames) * 1000000000) /
- DEFAULT_OUT_SAMPLING_RATE);
-
- ALOGV ("get_playback_delay time_stamp = [%ld].[%ld], delay_ns: [%d],"
- "kernel_frames:[%d]",
- buffer->time_stamp.tv_sec, buffer->time_stamp.tv_nsec,
- buffer->delay_ns, kernel_frames);
- return 0;
-}
static uint32_t
-out_get_sample_rate (const struct audio_stream *stream)
+out_get_sample_rate(const struct audio_stream *stream)
{
- return DEFAULT_OUT_SAMPLING_RATE;
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ if (out->config.rate > 0) {
+ return out->config.rate;
+ } else {
+ return DEFAULT_OUT_SAMPLING_RATE;
+ }
}
static int
-out_set_sample_rate (struct audio_stream *stream, uint32_t rate)
+out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
{
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, stream, rate);
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, rate);
- return 0;
+ return 0;
}
static size_t
-out_get_buffer_size (const struct audio_stream *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
-
- LOGFUNC ("%s(out->config.rate=%d)", __FUNCTION__, out->config.rate);
-
- /* take resampling into account and return the closest majoring
- * multiple of 16 frames, as audioflinger expects audio buffers to
- * be a multiple of 16 frames
- */
- size_t size;
- int codec_type = get_codec_type ("/sys/class/audiodsp/digital_codec");
- if (codec_type == 4 || codec_type == 5) //dd+
- size =
- (PERIOD_SIZE * 2 * PLAYBACK_PERIOD_COUNT *
- (int64_t) DEFAULT_OUT_SAMPLING_RATE) / out->config.rate;
- else if (codec_type == 7)
- size =
- (PERIOD_SIZE * 4 * PLAYBACK_PERIOD_COUNT *
- (int64_t) DEFAULT_OUT_SAMPLING_RATE) / out->config.rate;
- else if (codec_type > 0 && codec_type < 4) //dd/dts
- size =
- (PERIOD_SIZE * 4 * (int64_t) DEFAULT_OUT_SAMPLING_RATE) /
- out->config.rate;
- else //pcm
- size =
- (PERIOD_SIZE * (int64_t) DEFAULT_OUT_SAMPLING_RATE) / out->config.rate;
-
- size = ((size + 15) / 16) * 16;
- return size * audio_stream_out_frame_size (&out->stream);
+out_get_buffer_size(const struct audio_stream *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+
+ LOGFUNC("%s(out->config.rate=%d)", __FUNCTION__, out->config.rate);
+
+ /* take resampling into account and return the closest majoring
+ * multiple of 16 frames, as audioflinger expects audio buffers to
+ * be a multiple of 16 frames
+ */
+ size_t size;
+ switch (out->format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_DTS:
+ if (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) {
+ size = 4 * PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
+ } else {
+ size = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE / 2;
+ }
+ break;
+ case AUDIO_FORMAT_E_AC3:
+ if (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) {
+ size = 16 * PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
+ } else {
+ size = PERIOD_SIZE; //2*PLAYBACK_PERIOD_COUNT*PERIOD_SIZE;
+ }
+ break;
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_TRUEHD:
+ if (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) {
+ size = 16 * PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
+ } else {
+ size = 4 * PLAYBACK_PERIOD_COUNT * PERIOD_SIZE;
+ }
+ break;
+ case AUDIO_FORMAT_PCM:
+ default:
+ size = PERIOD_SIZE;
+ }
+ size = ((size + 15) / 16) * 16;
+ size = size * audio_stream_out_frame_size(&out->stream);
+ DEBUG("format %x,buffer size %d\n", out->format, size);
+ return size;
}
static audio_channel_mask_t
-out_get_channels (const struct audio_stream *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- if (out->multich > 2)
- {
- if (out->multich == 6)
- return AUDIO_CHANNEL_OUT_5POINT1;
- else if (out->multich == 8)
- return AUDIO_CHANNEL_OUT_7POINT1;
- }
- if (out->config.channels == 1)
- {
- return AUDIO_CHANNEL_OUT_MONO;
- }
- else
- {
- return AUDIO_CHANNEL_OUT_STEREO;
- }
+out_get_channels(const struct audio_stream *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ if (out->multich > 2) {
+ if (out->multich == 6) {
+ return AUDIO_CHANNEL_OUT_5POINT1;
+ } else if (out->multich == 8) {
+ return AUDIO_CHANNEL_OUT_7POINT1;
+ }
+ }
+ if (out->config.channels == 1) {
+ return AUDIO_CHANNEL_OUT_MONO;
+ } else {
+ return AUDIO_CHANNEL_OUT_STEREO;
+ }
}
static audio_format_t
-out_get_format (const struct audio_stream *stream)
+out_get_format(const struct audio_stream *stream)
{
- return AUDIO_FORMAT_PCM_16_BIT;
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+
+ return out->format;
}
static int
-out_set_format (struct audio_stream *stream, int format)
+out_set_format(struct audio_stream *stream, int format)
{
- LOGFUNC ("%s(%p)", __FUNCTION__, stream);
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
- return 0;
+ return 0;
}
/* must be called with hw device and output stream mutexes locked */
static int
-do_output_standby (struct aml_stream_out *out)
+do_output_standby(struct aml_stream_out *out)
{
- struct aml_audio_device *adev = out->dev;
- if (!out->standby)
- {
- pcm_close (out->pcm);
- out->pcm = NULL;
-
- adev->active_output = 0;
-
- /* if in call, don't turn off the output stage. This will
- be done when the call is ended */
- if (adev->mode != AUDIO_MODE_IN_CALL)
- {
- /* FIXME: only works if only one output can be active at a time */
+ struct aml_audio_device *adev = out->dev;
+ if (!out->standby) {
+ pcm_close(out->pcm);
+ out->pcm = NULL;
- //reset_mixer_state(adev->ar);
- }
+ adev->active_output = 0;
- /* stop writing to echo reference */
- if (out->echo_reference != NULL)
- {
- out->echo_reference->write (out->echo_reference, NULL);
- out->echo_reference = NULL;
- }
+ /* if in call, don't turn off the output stage. This will
+ be done when the call is ended */
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ /* FIXME: only works if only one output can be active at a time */
- out->standby = 1;
- first_write_status = 0;
- }
+ //reset_mixer_state(adev->ar);
+ }
+ out->standby = 1;
+ out->pause_status == false;
+ }
- return 0;
+ return 0;
}
static int
-out_standby (struct audio_stream *stream)
+out_standby(struct audio_stream *stream)
{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- int status;
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ int status;
- LOGFUNC ("%s(%p)", __FUNCTION__, stream);
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
- pthread_mutex_lock (&out->dev->lock);
- pthread_mutex_lock (&out->lock);
- status = do_output_standby (out);
- pthread_mutex_unlock (&out->lock);
- pthread_mutex_unlock (&out->dev->lock);
- return status;
+ pthread_mutex_lock(&out->dev->lock);
+ pthread_mutex_lock(&out->lock);
+ status = do_output_standby(out);
+ pthread_mutex_unlock(&out->lock);
+ pthread_mutex_unlock(&out->dev->lock);
+ return status;
}
static int
-out_dump (const struct audio_stream *stream, int fd)
+out_dump(const struct audio_stream *stream, int fd)
{
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, stream, fd);
- return 0;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, fd);
+ return 0;
+}
+static int
+out_flush(const struct audio_stream *stream)
+{
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ pthread_mutex_lock(&out->lock);
+ out->spdif_enc_init_frame_write_sum = 0;
+ out->frame_write_sum = 0;
+ pthread_mutex_unlock(&out->lock);
+ return 0;
}
static int
-out_set_parameters (struct audio_stream *stream, const char *kvpairs)
-{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- struct aml_audio_device *adev = out->dev;
- struct aml_stream_in *in;
- struct str_parms *parms;
- char *str;
- char value[32];
- int ret, val = 0;
- bool force_input_standby = false;
-
- LOGFUNC ("%s(kvpairs(%s), out_device=%#x)", __FUNCTION__, kvpairs,
- adev->out_device);
- 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 (&adev->lock);
- pthread_mutex_lock (&out->lock);
- if (((adev->out_device & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0))
- {
- if (out == adev->active_output)
- {
- do_output_standby (out);
- /* a change in output device may change the microphone selection */
- if (adev->active_input &&
- adev->active_input->source ==
- AUDIO_SOURCE_VOICE_COMMUNICATION)
- {
- force_input_standby = true;
- }
- /* force standby if moving to/from HDMI */
- if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
- (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
- ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
- (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)))
- do_output_standby (out);
- }
- adev->out_device &= ~AUDIO_DEVICE_OUT_ALL;
- adev->out_device |= val;
- select_output_device (adev);
- }
- pthread_mutex_unlock (&out->lock);
- if (force_input_standby)
- {
- in = adev->active_input;
- pthread_mutex_lock (&in->lock);
- do_input_standby (in);
- pthread_mutex_unlock (&in->lock);
- }
- pthread_mutex_unlock (&adev->lock);
- goto exit;
- }
- int sr = 0;
- ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, &sr);
- if (ret >= 0)
- {
- if (sr > 0)
- {
- ALOGI ("audio hw sampling_rate change from %d to %d \n",
- DEFAULT_OUT_SAMPLING_RATE, sr);
- DEFAULT_OUT_SAMPLING_RATE = sr;
- pcm_config_out.rate = DEFAULT_OUT_SAMPLING_RATE;
- out->config.rate = DEFAULT_OUT_SAMPLING_RATE;
- pthread_mutex_lock (&adev->lock);
- pthread_mutex_lock (&out->lock);
- if (!out->standby && (out == adev->active_output))
- {
- //do_output_standby (out);
- //start_output_stream (out);
- //out->standby = 0;
- }
- pthread_mutex_unlock (&adev->lock);
- pthread_mutex_unlock (&out->lock);
-
- }
- goto exit;
- }
- int frame_size = 0;
- ret =
- str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_FRAME_COUNT,
- &frame_size);
- if (ret >= 0)
- {
- if (frame_size > 0)
- {
- ALOGI ("audio hw frame size change from %d to %d \n", PERIOD_SIZE,
- frame_size);
- PERIOD_SIZE = frame_size;
- pcm_config_out.period_size = PERIOD_SIZE;
- out->config.period_size = PERIOD_SIZE;
- pthread_mutex_lock (&adev->lock);
- pthread_mutex_lock (&out->lock);
- if (!out->standby && (out == adev->active_output))
- {
- //do_output_standby (out);
- //start_output_stream (out);
- //out->standby = 0;
- }
- pthread_mutex_unlock (&adev->lock);
- pthread_mutex_unlock (&out->lock);
-
- }
- }
+out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ struct aml_stream_in *in;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int ret, val = 0;
+ bool force_input_standby = false;
+
+ LOGFUNC("%s(kvpairs(%s), out_device=%#x)", __FUNCTION__, kvpairs,
+ adev->out_device);
+ 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(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (((adev->out_device & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0)) {
+ if (out == adev->active_output) {
+ do_output_standby(out);
+ /* a change in output device may change the microphone selection */
+ if (adev->active_input &&
+ adev->active_input->source ==
+ AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ force_input_standby = true;
+ }
+ /* force standby if moving to/from HDMI */
+ if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
+ (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
+ ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
+ (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET))) {
+ do_output_standby(out);
+ }
+ }
+ adev->out_device &= ~AUDIO_DEVICE_OUT_ALL;
+ adev->out_device |= val;
+ select_output_device(adev);
+ }
+ pthread_mutex_unlock(&out->lock);
+ if (force_input_standby) {
+ in = adev->active_input;
+ pthread_mutex_lock(&in->lock);
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ }
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ int sr = 0;
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, &sr);
+ if (ret >= 0) {
+ if (sr > 0) {
+ ALOGI("audio hw sampling_rate change from %d to %d \n",
+ DEFAULT_OUT_SAMPLING_RATE, sr);
+ DEFAULT_OUT_SAMPLING_RATE = sr;
+ pcm_config_out.rate = DEFAULT_OUT_SAMPLING_RATE;
+ out->config.rate = DEFAULT_OUT_SAMPLING_RATE;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (!out->standby && (out == adev->active_output)) {
+ //do_output_standby (out);
+ //start_output_stream (out);
+ //out->standby = 0;
+ }
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+
+ }
+ goto exit;
+ }
+ int frame_size = 0;
+ ret =
+ str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FRAME_COUNT,
+ &frame_size);
+ if (ret >= 0) {
+ if (frame_size > 0) {
+ ALOGI("audio hw frame size change from %d to %d \n", PERIOD_SIZE,
+ frame_size);
+ PERIOD_SIZE = frame_size;
+ pcm_config_out.period_size = PERIOD_SIZE;
+ out->config.period_size = PERIOD_SIZE;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (!out->standby && (out == adev->active_output)) {
+ //do_output_standby (out);
+ //start_output_stream (out);
+ //out->standby = 0;
+ }
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+
+ }
+ goto exit;
+ }
+
+ ret = str_parms_get_str(parms, "hw_av_sync", value, sizeof(value));
+ if (ret >= 0) {
+ int hw_sync_id = atoi(value);
+ unsigned char sync_enable = (hw_sync_id == 12345678) ? 1 : 0;
+ ALOGI("set hw_sync_id %d,%s hw sync mode\n", hw_sync_id, sync_enable ? "enable" : "disable");
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ adev->hw_sync_mode = sync_enable;
+ out->frame_write_sum = 0;
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ goto exit;
+ }
+
exit:
- str_parms_destroy (parms);
- return ret;
+ str_parms_destroy(parms);
+ return ret;
}
-
static char *
-out_get_parameters (const struct audio_stream *stream, const char *keys)
-{
- return strdup ("");
-}
+out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ ALOGI("out_get_parameters %s\n", keys);
+ char *cap = NULL;
+ char *para = NULL;
+ if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+ cap = get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES);
+ if (cap) {
+ para = strdup(cap);
+ free(cap);
+ }
+ ALOGI("%s\n", cap);
+ return para;
+ } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+ cap = get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+ if (cap) {
+ para = strdup(cap);
+ free(cap);
+ }
+ ALOGI("%s\n", cap);
+ return para;
+ } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+ cap = get_hdmi_sink_cap(AUDIO_PARAMETER_STREAM_SUP_FORMATS);
+ if (cap) {
+ para = strdup(cap);
+ free(cap);
+ }
+ ALOGI("%s\n", cap);
+ return para;
+ }
+ return strdup("");
+}
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ uint32_t whole_latency;
+ uint32_t ret;
+ snd_pcm_sframes_t frames = 0;
+ whole_latency = (out->config.period_size * out->config.period_count * 1000) / out->config.rate;
+ if (!out->pcm || !pcm_is_ready(out->pcm)) {
+ return whole_latency;
+ }
+ ret = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_DELAY, &frames);
+ if (ret < 0) {
+ return whole_latency;
+ }
+ if (out->format == AUDIO_FORMAT_E_AC3) {
+ frames /= 4;
+ }
+ return (frames * 1000) / out->config.rate;
-#if 0
-static uint32_t
-out_get_latency (const struct audio_stream_out *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- uint32_t whole_latency;
- uint32_t ret;
- whole_latency =
- (out->config.period_size * out->config.period_count * 1000) /
- out->config.rate;
- if (!out->pcm || !pcm_is_ready (out->pcm))
- return whole_latency;
- ret = pcm_get_latency (out->pcm);
- if (ret == -1)
- {
- return whole_latency;
- }
- return ret;
}
-#else
-static uint32_t
-out_get_latency (const struct audio_stream_out *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- return (out->config.period_size * out->config.period_count * 1000) /
- out->config.rate;
-}
-#endif
static int
-out_set_volume (struct audio_stream_out *stream, float left, float right)
-{
- return -ENOSYS;
+out_set_volume(struct audio_stream_out *stream, float left, float right)
+{
+ return -ENOSYS;
+}
+
+static int out_pause(struct audio_stream_out *stream)
+{
+ LOGFUNC("out_pause");
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ int r = 0;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (out->standby) {
+ goto exit;
+ }
+ if (pcm_is_ready(out->pcm)) {
+ r = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_PAUSE, 1);
+ if (r < 0) {
+ ALOGE("cannot pause channel\n");
+ } else {
+ r = 0;
+ }
+ }
+ if (out->dev->hw_sync_mode) {
+ sysfs_set_sysfs_str(TSYNC_EVENT, "AUDIO_PAUSE");
+ }
+ out->pause_status = true;
+exit:
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ return r;
+}
+
+static int out_resume(struct audio_stream_out *stream)
+{
+ LOGFUNC("out_resume");
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ int r = 0;
+ if (out->standby) {
+ goto exit;
+ }
+ if (pcm_is_ready(out->pcm)) {
+ r = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_PAUSE, 0);
+ if (r < 0) {
+ ALOGE("cannot resume channel\n");
+ } else {
+ r = 0;
+ }
+ }
+ if (out->dev->hw_sync_mode) {
+ sysfs_set_sysfs_str(TSYNC_EVENT, "AUDIO_RESUME");
+ }
+ out->pause_status = false;
+exit:
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ return r;
}
-static int
-get_sysfs_int (const char *path)
-{
- int val = 0;
- int fd = open (path, O_RDONLY);
- if (fd >= 0)
- {
- char bcmd[16];
- read (fd, bcmd, sizeof (bcmd));
- val = strtol (bcmd, NULL, 10);
- close (fd);
- }
- else
- {
- LOGFUNC ("[%s]open %s node failed! return 0\n", path, __FUNCTION__);
- }
- return val;
-}
-
-static int last_codec_type = -1;
static ssize_t
-out_write (struct audio_stream_out *stream, const void *buffer, size_t bytes)
-{
-
- int ret = 0;
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- struct aml_audio_device *adev = out->dev;
- size_t frame_size = audio_stream_out_frame_size (stream);
- size_t in_frames = bytes / frame_size;
- size_t out_frames = RESAMPLER_BUFFER_SIZE / frame_size;
- bool force_input_standby = false;
- struct aml_stream_in *in;
- bool low_power;
- int kernel_frames;
- void *buf;
- char output_buffer_bytes[RESAMPLER_BUFFER_SIZE + 128];
- uint ouput_len;
- char *data, *data_dst;
- volatile char *data_src;
- short *dataprint;
- uint i, total_len;
- char prop[PROPERTY_VALUE_MAX];
- int codec_type = 0;
- int samesource_flag = 0;
- /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
- * on the output stream mutex - e.g. executing select_mode() while holding the hw device
- * mutex
- */
-
-
- pthread_mutex_lock (&adev->lock);
- pthread_mutex_lock (&out->lock);
- if (out->standby)
- {
- ret = start_output_stream (out);
- if (ret != 0)
- {
- pthread_mutex_unlock (&adev->lock);
- goto exit;
- }
- out->standby = 0;
- first_write_status = 0;
- /* a change in output device may change the microphone selection */
- if (adev->active_input &&
- adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
- force_input_standby = true;
- }
- pthread_mutex_unlock (&adev->lock);
-
- /* only use resampler if required */
- if (out->config.rate != DEFAULT_OUT_SAMPLING_RATE)
- {
- if (!out->resampler)
- {
-
- ret = create_resampler (DEFAULT_OUT_SAMPLING_RATE,
- out->config.rate,
- 2,
- RESAMPLER_QUALITY_DEFAULT,
- NULL, &out->resampler);
- if (ret != 0)
- goto exit;
- out->buffer = malloc (RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
- if (!out->buffer)
- {
- ret = -ENOMEM;
- goto exit;
- }
- }
- out->resampler->resample_from_input (out->resampler,
- (int16_t *) buffer,
- &in_frames,
- (int16_t *) out->buffer,
- &out_frames);
- buf = out->buffer;
- }
- else
- {
- out_frames = in_frames;
- buf = (void *) buffer;
- }
- if (out->echo_reference != NULL)
- {
- struct echo_reference_buffer b;
- b.raw = (void *) buffer;
- b.frame_count = in_frames;
- get_playback_delay (out, out_frames, &b);
- out->echo_reference->write (out->echo_reference, &b);
- }
-
-#if 1
- if (getprop_bool("media.audiohal.outdump")) {
- FILE *fp1=fopen("/data/hdmi_audio_out.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");
- }
- }
+out_write(struct audio_stream_out *stream, const void *buffer, size_t bytes)
+{
+ int ret = 0;
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ size_t frame_size = audio_stream_out_frame_size(stream);
+ size_t in_frames = bytes / frame_size;
+ bool force_input_standby = false;
+ size_t out_frames = 0;
+ void *buf;
+ uint i, total_len;
+ char prop[PROPERTY_VALUE_MAX];
+ int codec_type = out->codec_type;
+ int samesource_flag = 0;
+ audio_hwsync_t *p_hwsync = &adev->hwsync;
+ /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
+ * on the output stream mutex - e.g. executing select_mode() while holding the hw device
+ * mutex
+ */
+ out->bytes_write_total += bytes;
+ DEBUG("out %p,dev %p out_write total size %lld\n", out, adev, out->bytes_write_total);
+ if (out->pause_status == true) {
+ out_resume(out);
+ }
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if ((out->standby) && adev->hw_sync_mode) {
+ /*
+ there are two types of raw data come to hdmi audio hal
+ 1) compressed audio data without IEC61937 wrapped
+ 2) compressed audio data with IEC61937 wrapped (typically from amlogic amadec source)
+ we use the AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO to distiguwish the two cases.
+ */
+ if ((codec_type == TYPE_AC3 || codec_type == TYPE_EAC3) && (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)) {
+ spdifenc_init(out->pcm);
+ out->spdif_enc_init_frame_write_sum = out->frame_write_sum;
+ }
+ // todo: check timestamp header PTS discontinue for new sync point after seek
+ aml_audio_hwsync_clear_status(out);
+ out->spdif_enc_init_frame_write_sum = out->frame_write_sum;
+ }
+ if (out->standby) {
+ ret = start_output_stream(out);
+ if (ret != 0) {
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ out->standby = 0;
+ /* a change in output device may change the microphone selection */
+ if (adev->active_input &&
+ adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ force_input_standby = true;
+ }
+ }
+ void *write_buf = NULL;
+ int hwsync_cost_bytes = 0;
+ if (adev->hw_sync_mode == 1) {
+ uint64_t cur_pts = 0xffffffff;
+ int outsize = 0;
+ char tempbuf[128];
+ DEBUG("before aml_audio_hwsync_find_frame bytes %d\n", bytes);
+ hwsync_cost_bytes = aml_audio_hwsync_find_frame(out, buffer, bytes, &cur_pts, &outsize);
+ DEBUG("after aml_audio_hwsync_find_frame bytes remain %d,cost %d,outsize %d,pts %llx\n",
+ bytes - hwsync_cost_bytes, hwsync_cost_bytes, outsize, cur_pts);
+ if (cur_pts != 0xffffffff) {
+ if (p_hwsync->first_apts_flag == false) {
+ p_hwsync->first_apts_flag = true;
+ p_hwsync->first_apts = cur_pts;
+ sprintf(tempbuf, "AUDIO_START:0x%lx", cur_pts & 0xffffffff);
+ ALOGI("tsync -> %s", tempbuf);
+ if (sysfs_set_sysfs_str(TSYNC_EVENT, tempbuf) == -1) {
+ ALOGE("set AUDIO_START failed \n");
+ }
+ } else {
+ unsigned long apts;
+ unsigned long latency = out_get_latency(out) * 90;
+ // check PTS discontinue, which may happen when audio track switching
+ // discontinue means PTS calculated based on first_apts and frame_write_sum
+ // does not match the timestamp of next audio samples
+ if (cur_pts > latency) {
+ apts = (unsigned long)cur_pts - latency;
+ } else {
+ apts = 0;
+ }
+ if (0) { //abs(cur_pts -apts) > APTS_DISCONTINUE_THRESHOLD) {
+ ALOGI("HW sync PTS discontinue, 0x%llx->0x%llx(from header) diff %llx,last apts %llx(from header)",
+ apts, cur_pts, abs(cur_pts - apts), p_hwsync->last_apts_from_header);
+ p_hwsync->first_apts = cur_pts;
+ sprintf(tempbuf, "AUDIO_TSTAMP_DISCONTINUITY:0x%lx", cur_pts);
+ if (sysfs_set_sysfs_str(TSYNC_EVENT, tempbuf) == -1) {
+ ALOGE("unable to open file %s,err: %s", TSYNC_EVENT, strerror(errno));
+ }
+ } else {
+ unsigned long pcr = 0;
+ if (get_sysfs_int16(TSYNC_PCRSCR, &pcr) == 0) {
+ uint32_t apts_cal = apts & 0xffffffff;
+ if (abs(pcr - apts) < SYSTIME_CORRECTION_THRESHOLD) {
+ // do nothing
+ }
+ // limit the gap handle to 0.5~5 s.
+ else if ((apts - pcr) > APTS_DISCONTINUE_THRESHOLD_MIN && (apts - pcr) < APTS_DISCONTINUE_THRESHOLD_MAX) {
+ int insert_size = 0;
+ int once_write_size = 0;
+ if (out->codec_type == TYPE_EAC3) {
+ insert_size = abs(apts - pcr) / 90 * 48 * 4 * 4;
+ } else {
+ insert_size = abs(apts - pcr) / 90 * 48 * 4;
+ }
+ insert_size = insert_size & (~63);
+ ALOGI("audio gap %d ms ,need insert data %d\n", abs(apts - pcr) / 90, insert_size);
+ char *insert_buf = (char*)malloc(8192);
+ if (insert_buf == NULL) {
+ ALOGE("malloc size failed \n");
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ memset(insert_buf, 0, 8192);
+ while (insert_size > 0) {
+ once_write_size = insert_size > 8192 ? 8192 : insert_size;
+ ret = pcm_write(out->pcm, (void *) insert_buf, once_write_size);
+ if (ret != 0) {
+ ALOGE("pcm write failed\n");
+ free(insert_buf);
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ insert_size -= once_write_size;
+ }
+ free(insert_buf);
+ } else {
+ sprintf(tempbuf, "0x%lx", apts);
+ ALOGI("tsync -> reset pcrscr 0x%x -> 0x%x, diff %d ms", pcr, apts, abs(apts - pcr) / 90);
+ int ret_val = sysfs_set_sysfs_str(TSYNC_APTS, tempbuf);
+ if (ret_val == -1) {
+ ALOGE("unable to open file %s,err: %s", TSYNC_APTS, strerror(errno));
+ }
+ }
+ }
+ }
+ }
+ }
+ if (outsize > 0) {
+ in_frames = outsize / frame_size;
+ write_buf = p_hwsync->hw_sync_body_buf;
+ } else {
+ bytes = hwsync_cost_bytes;
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ } else {
+ write_buf = (void *) buffer;
+ }
+ pthread_mutex_unlock(&adev->lock);
+ out_frames = in_frames;
+ buf = (void *) write_buf;
+ if (getprop_bool("media.hdmihal.outdump")) {
+ FILE *fp1 = fopen("/data/tmp/hdmi_audio_out.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");
+ }
+ }
+ if (out->codec_type != TYPE_PCM && !(out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)) {
+ //here to do IEC61937 pack
+ DEBUG("IEC61937 write size %d,hw_sync_mode %d,flag %x\n", out_frames * frame_size, adev->hw_sync_mode, out->flags);
+ if (out->codec_type > 0) {
+ // compressed audio DD/DD+
+ out->write_status = 1;
+ bytes = spdifenc_write((void *) buf, out_frames * frame_size);
+ //need return actual size of this burst write
+ if (adev->hw_sync_mode == 1) {
+ bytes = hwsync_cost_bytes;
+ }
+ DEBUG("spdifenc_write return %d\n", bytes);
+ if (out->codec_type == TYPE_EAC3) {
+ out->frame_write_sum = spdifenc_get_total() / 16 + out->spdif_enc_init_frame_write_sum;
+ } else {
+ out->frame_write_sum = spdifenc_get_total() / 4 + out->spdif_enc_init_frame_write_sum;
+ }
+ out->write_status = 0;
+ DEBUG("out %p,spdifenc_get_total() / 4 %lld\n", out, spdifenc_get_total() / 16);
+ }
+ goto exit;
+ }
+ if (!out->standby) {
+ if (out->multich == 8) {
+ int *p32 = NULL;
+ short *p16 = (short *) buf;
+ int i, NumSamps;
+ NumSamps = out_frames * frame_size / sizeof(short);
+ p32 = malloc(NumSamps * sizeof(int));
+ if (p32 != NULL) {
+ 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;
+ 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) {
+ 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
-
- if (out->config.rate != DEFAULT_OUT_SAMPLING_RATE)
- {
- total_len = out_frames * frame_size + cached_len;
-
-
- LOGFUNC ("total_len(%d) = resampler_out_len(%d) + cached_len111(%d)",
- total_len, out_frames * frame_size, cached_len);
-
- data_src = (char *) cache_buffer_bytes;
- data_dst = (char *) output_buffer_bytes;
-
-
-
- /*write_back data from cached_buffer */
- if (cached_len)
- {
- memcpy ((void *) data_dst, (void *) data_src, cached_len);
- data_dst += cached_len;
- }
-
- ouput_len = total_len & (~0x3f);
- data = (char *) buf;
-
- memcpy ((void *) data_dst, (void *) data, ouput_len - cached_len);
- data += (ouput_len - cached_len);
- cached_len = total_len & 0x3f;
- data_src = (char *) cache_buffer_bytes;
-
- /*save data to cached_buffer */
- if (cached_len)
- {
- memcpy ((void *) data_src, (void *) data, cached_len);
- }
- if (!out->standby)
- ret = pcm_write (out->pcm, (void *) output_buffer_bytes, ouput_len);
- }
- else
- {
- if (!out->standby)
- {
- property_get ("sys.hdmiIn.Capture", prop, "false");
- // ALOGD("****first_write_status=%d***",first_write_status);
- if (!strcmp (prop, "true"))
- {
- if (first_write_status < 20)
- {
- first_write_status = first_write_status + 1;
- memset ((char *) buf, 0, bytes);
- }
- }
- else
- {
- first_write_status = 0;
- }
- if (out->config.channels == 8)
- {
- int *p32 = NULL;
- short *p16 = (short *) buf;
- int i, NumSamps;
- NumSamps = out_frames * frame_size / sizeof (short);
- p32 = malloc (NumSamps * sizeof (int));
- if (p32 != NULL)
- {
- 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
- {
- codec_type =
- get_sysfs_int ("/sys/class/audiodsp/digital_codec");
- samesource_flag =
- get_sysfs_int ("/sys/class/audiodsp/audio_samesource");
- if (last_codec_type > 0 && codec_type != 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",
- last_codec_type, codec_type, samesource_flag);
- last_codec_type = codec_type;
- pcm_stop (out->pcm);
- }
- ret =
- pcm_write (out->pcm, (void *) buf, out_frames * frame_size);
- }
- //ret = pcm_mmap_write(out->pcm, (void *)buf, out_frames * frame_size);
- }
- }
-
-
+ DEBUG("write size %d\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;
+ }
+ }
+ }
exit:
- pthread_mutex_unlock (&out->lock);
- if (ret != 0)
- {
- usleep (bytes * 1000000 / audio_stream_out_frame_size (stream) /
- out_get_sample_rate (&stream->common));
- }
-
- if (force_input_standby)
- {
- pthread_mutex_lock (&adev->lock);
- if (adev->active_input)
- {
- in = adev->active_input;
- pthread_mutex_lock (&in->lock);
- do_input_standby (in);
- pthread_mutex_unlock (&in->lock);
- }
- pthread_mutex_unlock (&adev->lock);
- }
-
-
- return bytes;
+ pthread_mutex_unlock(&out->lock);
+ if (ret != 0) {
+ usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
+ out_get_sample_rate(&stream->common));
+ }
+ return bytes;
}
static int
-out_get_render_position (const struct audio_stream_out *stream,
- uint32_t * dsp_frames)
+out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t * dsp_frames)
{
- LOGFUNC ("%s(%p, %p)", __FUNCTION__, stream, dsp_frames);
- return -EINVAL;
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, stream, dsp_frames);
+ return -EINVAL;
}
static int
-out_add_audio_effect (const struct audio_stream *stream,
- effect_handle_t effect)
+out_add_audio_effect(const struct audio_stream *stream,
+ effect_handle_t effect)
{
- LOGFUNC ("%s(%p, %p)", __FUNCTION__, stream, effect);
- return 0;
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, stream, effect);
+ return 0;
}
static int
-out_remove_audio_effect (const struct audio_stream *stream,
- effect_handle_t effect)
+out_remove_audio_effect(const struct audio_stream *stream,
+ effect_handle_t effect)
{
- return 0;
+ return 0;
}
static int
-out_get_next_write_timestamp (const struct audio_stream_out *stream,
- int64_t * timestamp)
+out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t * timestamp)
{
- return -EINVAL;
+ return -EINVAL;
+}
+static int out_get_presentation_position(const struct audio_stream_out *stream, uint64_t *frames, struct timespec *timestamp)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ //pthread_mutex_lock (&out->lock);
+#if 1
+ if (frames != NULL) {
+
+ if (0/*out->write_status == 1*/) {
+ *frames = out->last_frames_pos;
+ } else {
+ uint32_t latency_frames = out_get_latency(out) * out->config.rate / 1000;
+ DEBUG("out %p,adev %p latency_frames %d,out->frame_write_sum %lld\n", out, out->dev, latency_frames, out->frame_write_sum);
+ if (out->frame_write_sum >= latency_frames) {
+ *frames = out->frame_write_sum - latency_frames;
+ } else {
+ *frames = out->frame_write_sum;
+ }
+ out->last_frames_pos = *frames;
+ }
+
+ }
+ DEBUG("write_status %d,%p,*frames %lld\n", out->write_status, out, *frames);
+ if (timestamp != NULL) {
+ clock_gettime(CLOCK_MONOTONIC, timestamp);
+ }
+#else
+#define TIME_TO_MS(time) ((uint64_t)time->tv_sec * 1000 + time->tv_nsec/1000000ULL)
+
+ if (timestamp != NULL) {
+ clock_gettime(CLOCK_MONOTONIC, timestamp);
+ if (out->last_frames_pos == 0) {
+
+ ALOGI("first frame pos \n");
+ if (frames != NULL) {
+ *frames = out->last_frames_pos;
+ }
+ out->last_frames_pos = TIME_TO_MS(timestamp) * 48;
+ } else {
+ if (frames != NULL) {
+ *frames = TIME_TO_MS(timestamp) * 48 - out->last_frames_pos;
+ }
+ ALOGI("pos %lld,first %lld\n", *frames, out->last_frames_pos);
+ }
+
+ }
+#undef TIME_TO_MS
+#endif
+ //pthread_mutex_unlock (&out->lock);
+ return 0;
}
-
-static int get_next_buffer (struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer *buffer);
-static void release_buffer (struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer *buffer);
-
-
/** audio_stream_in implementation **/
/* must be called with hw device and input stream mutexes locked */
static int
-start_input_stream (struct aml_stream_in *in)
-{
- int ret = 0;
- unsigned int card = CARD_AMLOGIC_DEFAULT;
- unsigned int port = PORT_MM;
-
- struct aml_audio_device *adev = in->dev;
- LOGFUNC
- ("%s(need_echo_reference=%d, channels=%d, rate=%d, requested_rate=%d, mode= %d)",
- __FUNCTION__, in->need_echo_reference, in->config.channels,
- in->config.rate, in->requested_rate, adev->mode);
- adev->active_input = in;
-
- if (adev->mode != AUDIO_MODE_IN_CALL)
- {
- adev->in_device &= ~AUDIO_DEVICE_IN_ALL;
- adev->in_device |= in->device;
- select_input_device (adev);
- }
-
- ALOGV ("%s(in->requested_rate=%d, in->config.rate=%d)",
- __FUNCTION__, in->requested_rate, in->config.rate);
-
- if (getprop_bool ("media.libplayer.wfd"))
- {
- PERIOD_SIZE = DEFAULT_PERIOD_SIZE / 2;
- in->config.period_size = PERIOD_SIZE;
- }
- else
- {
- PERIOD_SIZE = DEFAULT_PERIOD_SIZE;
- in->config.period_size = PERIOD_SIZE;
- }
- if (in->need_echo_reference && in->echo_reference == NULL)
- {
- in->echo_reference = get_echo_reference (adev,
- AUDIO_FORMAT_PCM_16_BIT,
- in->config.channels,
- VX_NB_SAMPLING_RATE);
- //in->requested_rate);
- LOGFUNC ("%s(after get_echo_ref.... now in->echo_reference = %p)",
- __FUNCTION__, in->echo_reference);
-
- if (in->echo_reference != NULL)
- {
- in->buf_provider.get_next_buffer = get_next_buffer;
- in->buf_provider.release_buffer = release_buffer;
- ret = create_resampler (in->config.rate,
- VX_NB_SAMPLING_RATE,
- in->config.channels,
- RESAMPLER_QUALITY_DEFAULT,
- &in->buf_provider, &in->resampler);
-
- if (ret != 0)
- {
- ret = -EINVAL;
- return ret;
- }
- ret = create_resampler (VX_NB_SAMPLING_RATE, in->config.rate, in->config.channels, RESAMPLER_QUALITY_DEFAULT, NULL, //&in->up_buf_provider,
- &in->up_resampler);
-
- if (ret != 0)
- {
- ret = -EINVAL;
- return ret;
- }
- in->up_resampler_buffer = malloc (RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
- if (in->up_resampler_buffer == NULL)
- return ENOMEM;
- }
- }
- /* this assumes routing is done previously */
- in->pcm = pcm_open (card, port, PCM_IN, &in->config);
- if (!pcm_is_ready (in->pcm))
- {
- ALOGE ("cannot open pcm_in driver: %s", pcm_get_error (in->pcm));
- pcm_close (in->pcm);
- adev->active_input = NULL;
- return -ENOMEM;
- }
- ALOGD ("pcm_open in: card(%d), port(%d)", card, port);
-
- /* if no supported sample rate is available, use the resampler */
- if (in->resampler)
- {
- in->resampler->reset (in->resampler);
- in->frames_in = 0;
- }
- return 0;
+start_input_stream(struct aml_stream_in *in)
+{
+ int ret = 0;
+ unsigned int card = CARD_AMLOGIC_DEFAULT;
+ unsigned int port = PORT_MM;
+ struct aml_audio_device *adev = in->dev;
+ LOGFUNC
+ ("%s(need_echo_reference=%d, channels=%d, rate=%d, requested_rate=%d, mode= %d)",
+ __FUNCTION__, in->need_echo_reference, in->config.channels,
+ in->config.rate, in->requested_rate, adev->mode);
+ adev->active_input = in;
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ adev->in_device &= ~AUDIO_DEVICE_IN_ALL;
+ adev->in_device |= in->device;
+ select_input_device(adev);
+ }
+ PERIOD_SIZE = DEFAULT_PERIOD_SIZE;
+ in->config.period_size = PERIOD_SIZE;
+ /* this assumes routing is done previously */
+ in->pcm = pcm_open(card, port, PCM_IN, &in->config);
+ if (!pcm_is_ready(in->pcm)) {
+ ALOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ adev->active_input = NULL;
+ return -ENOMEM;
+ }
+ ALOGI("pcm_open in: card(%d), port(%d)", card, port);
+ return 0;
}
static int
-check_input_stream (struct aml_stream_in *in)
-{
- int ret = 0;
- unsigned int card = CARD_AMLOGIC_BOARD;
- unsigned int port = 0;
- int ext_card;
-
- ext_card = get_external_card (1);
- if (ext_card < 0)
- {
- card = CARD_AMLOGIC_BOARD;
- }
- else
- {
- card = ext_card;
- }
-
- /* this assumes routing is done previously */
- in->pcm = pcm_open (card, port, PCM_IN, &in->config);
- if (!pcm_is_ready (in->pcm))
- {
- ALOGE ("check_input_stream:cannot open pcm_in driver: %s",
- pcm_get_error (in->pcm));
- pcm_close (in->pcm);
- return -ENOMEM;
- }
-
- pcm_close (in->pcm);
-
- return 0;
+check_input_stream(struct aml_stream_in *in)
+{
+ int ret = 0;
+ unsigned int card = CARD_AMLOGIC_BOARD;
+ unsigned int port = 0;
+ int ext_card;
+ ext_card = get_external_card(1);
+ if (ext_card < 0) {
+ card = CARD_AMLOGIC_BOARD;
+ } else {
+ card = ext_card;
+ }
+ /* this assumes routing is done previously */
+ in->pcm = pcm_open(card, port, PCM_IN, &in->config);
+ if (!pcm_is_ready(in->pcm)) {
+ ALOGE("check_input_stream:cannot open pcm_in driver: %s",
+ pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ return -ENOMEM;
+ }
+ pcm_close(in->pcm);
+ return 0;
}
static uint32_t
-in_get_sample_rate (const struct audio_stream *stream)
+in_get_sample_rate(const struct audio_stream *stream)
{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
- LOGFUNC ("%s(%p)", __FUNCTION__, stream);
- return in->requested_rate;
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ return in->requested_rate;
}
static int
-in_set_sample_rate (struct audio_stream *stream, uint32_t rate)
+in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
{
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, stream, rate);
- return 0;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, rate);
+ return 0;
}
static size_t
-in_get_buffer_size (const struct audio_stream *stream)
+in_get_buffer_size(const struct audio_stream *stream)
{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
- LOGFUNC ("%s(%p)", __FUNCTION__, stream);
- return get_input_buffer_size (in->config.rate,
- AUDIO_FORMAT_PCM_16_BIT, in->config.channels);
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ return get_input_buffer_size(in->config.rate,
+ AUDIO_FORMAT_PCM_16_BIT, in->config.channels);
}
static audio_channel_mask_t
-in_get_channels (const struct audio_stream *stream)
+in_get_channels(const struct audio_stream *stream)
{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- if (in->config.channels == 1)
- {
- return AUDIO_CHANNEL_IN_MONO;
- }
- else
- {
- return AUDIO_CHANNEL_IN_STEREO;
- }
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ if (in->config.channels == 1) {
+ return AUDIO_CHANNEL_IN_MONO;
+ } else {
+ return AUDIO_CHANNEL_IN_STEREO;
+ }
}
static audio_format_t
-in_get_format (const struct audio_stream *stream)
+in_get_format(const struct audio_stream *stream)
{
- return AUDIO_FORMAT_PCM_16_BIT;
+ return AUDIO_FORMAT_PCM_16_BIT;
}
static int
-in_set_format (struct audio_stream *stream, audio_format_t format)
+in_set_format(struct audio_stream *stream, audio_format_t format)
{
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, stream, format);
- return 0;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, format);
+ return 0;
}
/* must be called with hw device and input stream mutexes locked */
static int
-do_input_standby (struct aml_stream_in *in)
-{
- struct aml_audio_device *adev = in->dev;
-
- LOGFUNC ("%s(%p)", __FUNCTION__, in);
- if (!in->standby)
- {
- pcm_close (in->pcm);
- in->pcm = NULL;
-
- adev->active_input = 0;
- if (adev->mode != AUDIO_MODE_IN_CALL)
- {
- adev->in_device &= ~AUDIO_DEVICE_IN_ALL;
- select_input_device (adev);
- }
-
- if (in->echo_reference != NULL)
- {
- /* stop reading from echo reference */
- in->echo_reference->read (in->echo_reference, NULL);
- put_echo_reference (adev, in->echo_reference);
- in->echo_reference = NULL;
- }
-
- in->standby = 1;
- }
- return 0;
+do_input_standby(struct aml_stream_in *in)
+{
+ struct aml_audio_device *adev = in->dev;
+ LOGFUNC("%s(%p)", __FUNCTION__, in);
+ if (!in->standby) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ adev->active_input = 0;
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ adev->in_device &= ~AUDIO_DEVICE_IN_ALL;
+ select_input_device(adev);
+ }
+ in->standby = 1;
+ }
+ return 0;
}
static int
-in_standby (struct audio_stream *stream)
+in_standby(struct audio_stream *stream)
{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- int status;
- LOGFUNC ("%s(%p)", __FUNCTION__, stream);
-
- pthread_mutex_lock (&in->dev->lock);
- pthread_mutex_lock (&in->lock);
- status = do_input_standby (in);
- pthread_mutex_unlock (&in->lock);
- pthread_mutex_unlock (&in->dev->lock);
- return status;
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ int status;
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ pthread_mutex_lock(&in->dev->lock);
+ pthread_mutex_lock(&in->lock);
+ status = do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ pthread_mutex_unlock(&in->dev->lock);
+ return status;
}
static int
-in_dump (const struct audio_stream *stream, int fd)
+in_dump(const struct audio_stream *stream, int fd)
{
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, stream, fd);
- return 0;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, fd);
+ return 0;
}
static int
-in_set_parameters (struct audio_stream *stream, const char *kvpairs)
-{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- struct aml_audio_device *adev = in->dev;
- struct str_parms *parms;
- char *str;
- char value[32];
- int ret, val = 0;
- bool do_standby = false;
-
- LOGFUNC ("%s(%p, %s)", __FUNCTION__, stream, kvpairs);
- parms = str_parms_create_str (kvpairs);
-
- ret =
- str_parms_get_str (parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value,
- sizeof (value));
-
- pthread_mutex_lock (&adev->lock);
- pthread_mutex_lock (&in->lock);
- if (ret >= 0)
- {
- val = atoi (value);
- /* no audio source uses val == 0 */
- if ((in->source != val) && (val != 0))
- {
- in->source = val;
- do_standby = true;
- }
- }
-
- ret =
- str_parms_get_str (parms, AUDIO_PARAMETER_STREAM_ROUTING, value,
- sizeof (value));
- if (ret >= 0)
- {
- val = atoi (value) & ~AUDIO_DEVICE_BIT_IN;
- if ((in->device != val) && (val != 0))
- {
- in->device = val;
- do_standby = true;
- }
- }
-
- if (do_standby)
- do_input_standby (in);
- pthread_mutex_unlock (&in->lock);
- pthread_mutex_unlock (&adev->lock);
-
- str_parms_destroy (parms);
- return ret;
+in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ struct aml_audio_device *adev = in->dev;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int ret, val = 0;
+ bool do_standby = false;
+ LOGFUNC("%s(%p, %s)", __FUNCTION__, stream, kvpairs);
+ parms = str_parms_create_str(kvpairs);
+ ret =
+ str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value,
+ sizeof(value));
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (ret >= 0) {
+ val = atoi(value);
+ /* no audio source uses val == 0 */
+ if ((in->source != val) && (val != 0)) {
+ in->source = val;
+ do_standby = true;
+ }
+ }
+ ret =
+ str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value,
+ sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value) & ~AUDIO_DEVICE_BIT_IN;
+ if ((in->device != val) && (val != 0)) {
+ in->device = val;
+ do_standby = true;
+ }
+ }
+ if (do_standby) {
+ do_input_standby(in);
+ }
+ pthread_mutex_unlock(&in->lock);
+ pthread_mutex_unlock(&adev->lock);
+ str_parms_destroy(parms);
+ return ret;
}
static char *
-in_get_parameters (const struct audio_stream *stream, const char *keys)
+in_get_parameters(const struct audio_stream *stream, const char *keys)
{
- return strdup ("");
+ return strdup("");
}
static int
-in_set_gain (struct audio_stream_in *stream, float gain)
+in_set_gain(struct audio_stream_in *stream, float gain)
{
- LOGFUNC ("%s(%p, %f)", __FUNCTION__, stream, gain);
- return 0;
-}
-
-static void
-get_capture_delay (struct aml_stream_in *in,
- size_t frames, struct echo_reference_buffer *buffer)
-{
- /* read frames available in kernel driver buffer */
- size_t kernel_frames;
- struct timespec tstamp;
- long buf_delay;
- long rsmp_delay;
- long kernel_delay;
- long delay_ns;
- int rsmp_mul = in->config.rate / VX_NB_SAMPLING_RATE;
- if (pcm_get_htimestamp (in->pcm, &kernel_frames, &tstamp) < 0)
- {
- buffer->time_stamp.tv_sec = 0;
- buffer->time_stamp.tv_nsec = 0;
- buffer->delay_ns = 0;
- ALOGW ("read get_capture_delay(): pcm_htimestamp error");
- return;
- }
-
- /* read frames available in audio HAL input buffer
- * add number of frames being read as we want the capture time of first sample
- * in current buffer */
- buf_delay =
- (long) (((int64_t) (in->frames_in + in->proc_frames_in * rsmp_mul) *
- 1000000000) / in->config.rate);
- /* add delay introduced by resampler */
- rsmp_delay = 0;
- if (in->resampler)
- {
- rsmp_delay = in->resampler->delay_ns (in->resampler);
- }
-
- kernel_delay =
- (long) (((int64_t) kernel_frames * 1000000000) / in->config.rate);
-
- delay_ns = kernel_delay + buf_delay + rsmp_delay;
-
- buffer->time_stamp = tstamp;
- buffer->delay_ns = delay_ns;
- ALOGV ("get_capture_delay time_stamp = [%ld].[%ld], delay_ns: [%d],"
- " kernel_delay:[%ld], buf_delay:[%ld], rsmp_delay:[%ld], kernel_frames:[%d], "
- "in->frames_in:[%d], in->proc_frames_in:[%d], frames:[%d]",
- buffer->time_stamp.tv_sec, buffer->time_stamp.tv_nsec,
- buffer->delay_ns, kernel_delay, buf_delay, rsmp_delay, kernel_frames,
- in->frames_in, in->proc_frames_in, frames);
-
-}
-
-static int32_t
-update_echo_reference (struct aml_stream_in *in, size_t frames)
-{
- struct echo_reference_buffer b;
- b.delay_ns = 0;
-
- ALOGV ("update_echo_reference, frames = [%d], in->ref_frames_in = [%d], "
- "b.frame_count = [%d]",
- frames, in->ref_frames_in, frames - in->ref_frames_in);
- if (in->ref_frames_in < frames)
- {
- if (in->ref_buf_size < frames)
- {
- in->ref_buf_size = frames;
- in->ref_buf = (int16_t *) realloc (in->ref_buf,
- in->ref_buf_size *
- in->config.channels *
- sizeof (int16_t));
- }
-
- b.frame_count = frames - in->ref_frames_in;
- b.raw =
- (void *) (in->ref_buf + in->ref_frames_in * in->config.channels);
-
- get_capture_delay (in, frames, &b);
- LOGFUNC ("update_echo_reference return ::b.delay_ns=%d", b.delay_ns);
-
- if (in->echo_reference->read (in->echo_reference, &b) == 0)
- {
- in->ref_frames_in += b.frame_count;
- ALOGV ("update_echo_reference: in->ref_frames_in:[%d], "
- "in->ref_buf_size:[%d], frames:[%d], b.frame_count:[%d]",
- in->ref_frames_in, in->ref_buf_size, frames, b.frame_count);
- }
- }
- else
- ALOGW ("update_echo_reference: NOT enough frames to read ref buffer");
- return b.delay_ns;
-}
-
-static int
-set_preprocessor_param (effect_handle_t handle, effect_param_t * param)
-{
- uint32_t size = sizeof (int);
- uint32_t psize = ((param->psize - 1) / sizeof (int) + 1) * sizeof (int) +
- param->vsize;
-
- int status = (*handle)->command (handle,
- EFFECT_CMD_SET_PARAM,
- sizeof (effect_param_t) + psize,
- param,
- &size,
- &param->status);
- if (status == 0)
- status = param->status;
-
- return status;
-}
-
-static int
-set_preprocessor_echo_delay (effect_handle_t handle, int32_t delay_us)
-{
- uint32_t buf[sizeof (effect_param_t) / sizeof (uint32_t) + 2];
- effect_param_t *param = (effect_param_t *) buf;
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, handle, delay_us);
-
- param->psize = sizeof (uint32_t);
- param->vsize = sizeof (uint32_t);
- *(uint32_t *) param->data = AEC_PARAM_ECHO_DELAY;
- *((int32_t *) param->data + 1) = delay_us;
-
- return set_preprocessor_param (handle, param);
-}
-
-static void
-push_echo_reference (struct aml_stream_in *in, size_t frames)
-{
- /* read frames from echo reference buffer and update echo delay
- * in->ref_frames_in is updated with frames available in in->ref_buf */
- int32_t delay_us = update_echo_reference (in, frames) / 1000;
- int i;
- audio_buffer_t buf;
-
- if (in->ref_frames_in < frames)
- frames = in->ref_frames_in;
-
- buf.frameCount = frames;
- buf.raw = in->ref_buf;
-
- for (i = 0; i < in->num_preprocessors; i++)
- {
- if ((*in->preprocessors[i])->process_reverse == NULL)
- continue;
-
- (*in->preprocessors[i])->process_reverse (in->preprocessors[i],
- &buf, NULL);
- set_preprocessor_echo_delay (in->preprocessors[i], delay_us);
- }
-
- in->ref_frames_in -= buf.frameCount;
- if (in->ref_frames_in)
- {
- memcpy (in->ref_buf,
- in->ref_buf + buf.frameCount * in->config.channels,
- in->ref_frames_in * in->config.channels * sizeof (int16_t));
- }
-}
-
-static int
-get_next_buffer (struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer *buffer)
-{
- struct aml_stream_in *in;
-
- if (buffer_provider == NULL || buffer == NULL)
- return -EINVAL;
-
- in = (struct aml_stream_in *) ((char *) buffer_provider -
- offsetof (struct aml_stream_in,
- buf_provider));
-
- if (in->pcm == NULL)
- {
- buffer->raw = NULL;
- buffer->frame_count = 0;
- in->read_status = -ENODEV;
- return -ENODEV;
- }
-
- if (in->frames_in == 0)
- {
- in->read_status = pcm_read (in->pcm,
- (void *) in->buffer,
- in->config.period_size *
- audio_stream_in_frame_size (&in->stream));
- if (in->read_status != 0)
- {
- ALOGE ("get_next_buffer() pcm_read error %d", in->read_status);
- buffer->raw = NULL;
- buffer->frame_count = 0;
- return in->read_status;
- }
- in->frames_in = in->config.period_size;
- }
-
- buffer->frame_count = (buffer->frame_count > in->frames_in) ?
- in->frames_in : buffer->frame_count;
- buffer->i16 = in->buffer + (in->config.period_size - in->frames_in) *
- in->config.channels;
-
- return in->read_status;
-
+ LOGFUNC("%s(%p, %f)", __FUNCTION__, stream, gain);
+ return 0;
}
-
-static void
-release_buffer (struct resampler_buffer_provider *buffer_provider,
- struct resampler_buffer *buffer)
-{
- struct aml_stream_in *in;
- if (buffer_provider == NULL || buffer == NULL)
- return;
-
- in = (struct aml_stream_in *) ((char *) buffer_provider -
- offsetof (struct aml_stream_in,
- buf_provider));
-
- in->frames_in -= buffer->frame_count;
-}
-
-/* read_frames() reads frames from kernel driver, down samples to capture rate
- * if necessary and output the number of frames requested to the buffer specified */
-static ssize_t
-read_frames (struct aml_stream_in *in, void *buffer, ssize_t frames)
-{
- ssize_t frames_wr = 0;
- while (frames_wr < frames)
- {
- size_t frames_rd = frames - frames_wr;
- if (in->resampler != NULL)
- {
- in->resampler->resample_from_provider (in->resampler,
- (int16_t *) ((char *) buffer
- +
- frames_wr *
- audio_stream_in_frame_size
- (&in->stream)),
- &frames_rd);
- }
- else
- {
- struct resampler_buffer buf = {
- {raw:NULL,},
- frame_count:frames_rd,
- };
- get_next_buffer (&in->buf_provider, &buf);
- if (buf.raw != NULL)
- {
- memcpy ((char *) buffer +
- frames_wr * audio_stream_in_frame_size (&in->stream),
- buf.raw,
- buf.frame_count *
- audio_stream_in_frame_size (&in->stream));
- frames_rd = buf.frame_count;
- }
- release_buffer (&in->buf_provider, &buf);
- }
- /* in->read_status is updated by getNextBuffer() also called by
- * in->resampler->resample_from_provider() */
- if (in->read_status != 0)
- return in->read_status;
-
- frames_wr += frames_rd;
- }
- return frames_wr;
-}
-
-/* process_frames() reads frames from kernel driver (via read_frames()),
- * calls the active audio pre processings and output the number of frames requested
- * to the buffer specified */
-static ssize_t
-process_frames (struct aml_stream_in *in, void *buffer, ssize_t frames)
-{
- ssize_t frames_wr = 0;
- ssize_t proc_frames;
- audio_buffer_t in_buf;
- audio_buffer_t proc_buf;
- audio_buffer_t out_buf;
- int i, resp_mul;
- resp_mul = in->requested_rate / VX_NB_SAMPLING_RATE;
-
- proc_frames = frames / resp_mul;
-
- while (frames_wr < proc_frames)
- {
- /* first reload enough frames at the end of process input buffer */
- if (in->proc_frames_in < (size_t) proc_frames)
- {
- ssize_t frames_rd;
-
- if (in->proc_buf_size < (size_t) proc_frames)
- {
- in->proc_buf_size = (size_t) proc_frames;
- in->proc_buf = (int16_t *) realloc (in->proc_buf,
- in->proc_buf_size *
- in->config.channels *
- sizeof (int16_t));
- ALOGV
- ("process_frames(): in->proc_buf %p size extended to %d frames",
- in->proc_buf, in->proc_buf_size);
- }
- frames_rd = read_frames (in,
- in->proc_buf +
- in->proc_frames_in * in->config.channels,
- proc_frames - in->proc_frames_in);
- if (frames_rd < 0)
- {
- frames_wr = frames_rd;
- break;
- }
- in->proc_frames_in += frames_rd;
- }
-
- if (in->echo_reference != NULL)
- push_echo_reference (in, in->proc_frames_in);
-
- /* in_buf.frameCount and out_buf.frameCount indicate respectively
- * the maximum number of frames to be consumed and produced by process() */
- in_buf.frameCount = in->proc_frames_in;
- in_buf.s16 = in->proc_buf;
- proc_buf.frameCount = proc_frames - frames_wr;
- proc_buf.s16 =
- (int16_t *) in->up_resampler_buffer + frames_wr * in->config.channels;
- out_buf.frameCount = (proc_frames - frames_wr) * resp_mul;
- out_buf.s16 =
- (int16_t *) buffer + resp_mul * frames_wr * in->config.channels;
- ALOGV
- ("first**in_buf.frameCount=%d***\n**proc_buf.frameCount=%d\n**out_buf.frameCount=%d***",
- in_buf.frameCount, proc_buf.frameCount, out_buf.frameCount);
-
- for (i = 0; i < in->num_preprocessors; i++)
- (*in->preprocessors[i])->process (in->preprocessors[i], &in_buf, &proc_buf); //&out_buf);
- if (in->up_resampler != NULL)
- {
- in->up_resampler->resample_from_input (in->up_resampler,
- proc_buf.s16,
- &(proc_buf.frameCount),
- out_buf.s16,
- &(out_buf.frameCount));
- }
- ALOGV
- ("after**in_buf.frameCount=%d***\n**proc_buf.frameCount=%d\n**out_buf.frameCount=%d***",
- in_buf.frameCount, proc_buf.frameCount, out_buf.frameCount);
-
- /* process() has updated the number of frames consumed and produced in
- * in_buf.frameCount and out_buf.frameCount respectively
- * move remaining frames to the beginning of in->proc_buf */
- in->proc_frames_in -= in_buf.frameCount;
- if (in->proc_frames_in)
- {
- memcpy (in->proc_buf,
- in->proc_buf + in_buf.frameCount * in->config.channels,
- in->proc_frames_in * in->config.channels *
- sizeof (int16_t));
- }
-
- /* if not enough frames were passed to process(), read more and retry. */
- if (out_buf.frameCount == 0)
- continue;
-
- frames_wr += out_buf.frameCount / resp_mul; //out_buf.frameCount * VX_NB_SAMPLING_RATE/in->requested_rate;
- ALOGV ("***last*****frames_wr=%ld***********", frames_wr);
- }
- return frames_wr;
-}
-
static ssize_t
-in_read (struct audio_stream_in *stream, void *buffer, size_t bytes)
-{
- int ret = 0;
- int i = 0;
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- struct aml_audio_device *adev = in->dev;
- size_t frames_rq = bytes / audio_stream_in_frame_size (stream);
- if (in->voip_mode)
- {
- int sleepTime;
-
- sleepTime = 1000 * bytes / (in->config.channels * in->config.rate * 2);
- usleep (sleepTime * 1000);
- return bytes;
- }
- /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
- * on the input stream mutex - e.g. executing select_mode() while holding the hw device
- * mutex
- */
- pthread_mutex_lock (&adev->lock);
- pthread_mutex_lock (&in->lock);
- if (in->standby)
- {
- ret = start_input_stream (in);
- if (ret == 0)
- in->standby = 0;
- }
- pthread_mutex_unlock (&adev->lock);
-
- if (ret < 0)
- goto exit;
- if (in->need_echo_reference && in->echo_reference == NULL)
- {
- in->echo_reference = get_echo_reference (adev,
- AUDIO_FORMAT_PCM_16_BIT,
- in->config.channels,
- VX_NB_SAMPLING_RATE);
- //in->requested_rate);
- LOGFUNC ("%s(after get_echo_ref.... now in->echo_reference = %p)",
- __FUNCTION__, in->echo_reference);
-#if 1
- if (in->echo_reference != NULL)
- {
- in->buf_provider.get_next_buffer = get_next_buffer;
- in->buf_provider.release_buffer = release_buffer;
- ret = create_resampler (in->config.rate,
- VX_NB_SAMPLING_RATE,
- in->config.channels,
- RESAMPLER_QUALITY_DEFAULT,
- &in->buf_provider, &in->resampler);
-
- if (ret != 0)
- {
- ret = -EINVAL;
- return ret;
- }
- ret = create_resampler (VX_NB_SAMPLING_RATE, in->config.rate, in->config.channels, RESAMPLER_QUALITY_DEFAULT, NULL, //&in->up_buf_provider,
- &in->up_resampler);
-
- if (ret != 0)
- {
- ret = -EINVAL;
- return ret;
- }
- in->up_resampler_buffer = malloc (RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
- if (in->up_resampler_buffer == NULL)
- return ENOMEM;
- }
-#endif
- }
-
-/////////////////////////////////////////////////////////////////////
- if (in->num_preprocessors != 0 && in->echo_reference != NULL)
- //if (in->num_preprocessors != 0)
- ret = process_frames (in, buffer, frames_rq);
- else if (in->resampler != NULL)
- ret = read_frames (in, buffer, frames_rq);
- else
- ret = pcm_read (in->pcm, buffer, bytes);
-
- float volume = computeVolume (stream);
- int16_t *hdmi_buf = (int16_t *) buffer;
- for (i = 0; i < bytes / 2; i++)
- {
- hdmi_buf[i] = (int16_t) (((float) hdmi_buf[i]) * volume);
- }
-
- if (ret > 0)
- ret = 0;
-
- if (ret == 0 && adev->mic_mute)
- {
- LOGFUNC ("%s(adev->mic_mute = %d)", __FUNCTION__, adev->mic_mute);
- memset (buffer, 0, bytes);
- }
+in_read(struct audio_stream_in *stream, void *buffer, size_t bytes)
+{
+ int ret = 0;
+ int i = 0;
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ struct aml_audio_device *adev = in->dev;
+ size_t frames_rq = bytes / audio_stream_in_frame_size(stream);
+ /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
+ * on the input stream mutex - e.g. executing select_mode() while holding the hw device
+ * mutex
+ */
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (in->standby) {
+ ret = start_input_stream(in);
+ if (ret == 0) {
+ in->standby = 0;
+ }
+ }
+ pthread_mutex_unlock(&adev->lock);
+ ret = pcm_read(in->pcm, buffer, bytes);
+ if (ret > 0) {
+ ret = 0;
+ }
+ if (ret == 0 && adev->mic_mute) {
+ LOGFUNC("%s(adev->mic_mute = %d)", __FUNCTION__, adev->mic_mute);
+ memset(buffer, 0, bytes);
+ }
exit:
- if (ret < 0)
- usleep (bytes * 1000000 / audio_stream_in_frame_size (stream) /
- in_get_sample_rate (&stream->common));
-
- pthread_mutex_unlock (&in->lock);
- return bytes;
-
+ if (ret < 0)
+ usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
+ in_get_sample_rate(&stream->common));
+ pthread_mutex_unlock(&in->lock);
+ return bytes;
}
static uint32_t
-in_get_input_frames_lost (struct audio_stream_in *stream)
+in_get_input_frames_lost(struct audio_stream_in *stream)
{
- return 0;
-}
-
-static int
-in_add_audio_effect (const struct audio_stream *stream,
- effect_handle_t effect)
-{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- int status;
- effect_descriptor_t desc;
- LOGFUNC ("*********%s", __FUNCTION__);
-
- pthread_mutex_lock (&in->dev->lock);
- pthread_mutex_lock (&in->lock);
- if (in->num_preprocessors >= MAX_PREPROCESSORS)
- {
- status = -ENOSYS;
- goto exit;
- }
-
- status = (*effect)->get_descriptor (effect, &desc);
- if (status != 0)
- goto exit;
-
- in->preprocessors[in->num_preprocessors++] = effect;
-
- if (memcmp (&desc.type, FX_IID_AEC, sizeof (effect_uuid_t)) == 0)
- {
- in->need_echo_reference = true;
- do_input_standby (in);
- }
-
-exit:
-
- pthread_mutex_unlock (&in->lock);
- pthread_mutex_unlock (&in->dev->lock);
- return status;
-}
-
-static int
-in_remove_audio_effect (const struct audio_stream *stream,
- effect_handle_t effect)
-{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
- int i;
- int status = -EINVAL;
- bool found = false;
- effect_descriptor_t desc;
-
- pthread_mutex_lock (&in->dev->lock);
- pthread_mutex_lock (&in->lock);
- if (in->num_preprocessors <= 0)
- {
- status = -ENOSYS;
- goto exit;
- }
-
- for (i = 0; i < in->num_preprocessors; i++)
- {
- if (found)
- {
- in->preprocessors[i - 1] = in->preprocessors[i];
- continue;
- }
- if (in->preprocessors[i] == effect)
- {
- in->preprocessors[i] = NULL;
- status = 0;
- found = true;
- }
- }
-
- if (status != 0)
- goto exit;
-
- in->num_preprocessors--;
-
- status = (*effect)->get_descriptor (effect, &desc);
- if (status != 0)
- goto exit;
- if (memcmp (&desc.type, FX_IID_AEC, sizeof (effect_uuid_t)) == 0)
- {
- in->need_echo_reference = false;
- do_input_standby (in);
- }
-
-exit:
-
- pthread_mutex_unlock (&in->lock);
- pthread_mutex_unlock (&in->dev->lock);
- return status;
+ return 0;
}
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 aml_audio_device *ladev = (struct aml_audio_device *) dev;
- struct aml_stream_out *out;
- int channel_count = popcount (config->channel_mask);
- int ret;
- int dc; //digital_codec
-
- LOGFUNC ("%s(devices=0x%04x,format=%d, chnum=0x%04x, SR=%d,io handle %d )",
- __FUNCTION__, devices, config->format, channel_count,
- config->sample_rate, handle);
-
- out = (struct aml_stream_out *) calloc (1, sizeof (struct aml_stream_out));
- if (!out)
- return -ENOMEM;
-
- 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.common.set_voip_mode = out_set_voip_mode;
- 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->config = pcm_config_out;
- dc = get_codec_type ("/sys/class/audiodsp/digital_codec");
- if (dc == 4 || dc == 5)
- out->config.period_size = pcm_config_out.period_size * 2;
- else if (dc == 7)
- out->config.period_size = pcm_config_out.period_size * 4 * 2;
- if (channel_count > 2)
- {
- ALOGI ("[adev_open_output_stream]: out/%p channel/%d\n", out,
- channel_count);
- out->multich = channel_count;
- out->config.channels = channel_count;
- }
- out->dev = ladev;
- out->standby = 1;
-
- /* FIXME: when we support multiple output devices, we will want to
- * do the following:
- * adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
- * adev->devices |= out->device;
- * select_output_device(adev);
- * This is because out_set_parameters() with a route is not
- * guaranteed to be called after an output stream is opened.
- */
-
- //config->format = out_get_format(&out->stream.common);
- //config->channel_mask = out_get_channels(&out->stream.common);
- //config->sample_rate = out_get_sample_rate(&out->stream.common);
- LOGFUNC ("%s(devices=0x%04x,format=0x%x, chmask=0x%04x, SR=%d)",
- __FUNCTION__, devices, config->format, config->channel_mask,
- config->sample_rate);
-
-
-
- *stream_out = &out->stream;
- return 0;
-
+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)
+{
+ int ret;
+ int digital_codec; //digital_codec
+ struct aml_audio_device *ladev = (struct aml_audio_device *) dev;
+ struct aml_stream_out *out;
+ int channel_count = popcount(config->channel_mask);
+ LOGFUNC("%s(devices=0x%04x,format=%d, chnum=0x%04x, SR=%d,io handle %d, flags = 0x%x )",
+ __FUNCTION__, devices, config->format, channel_count,
+ config->sample_rate, handle, flags);
+ out = (struct aml_stream_out *) calloc(1, sizeof(struct aml_stream_out));
+ if (!out) {
+ return -ENOMEM;
+ }
+ 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 = NULL;//out_add_audio_effect;
+ out->stream.common.remove_audio_effect = NULL;//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.pause = out_pause;
+ out->stream.resume = out_resume;
+ out->stream.get_presentation_position = out_get_presentation_position;
+ out->stream.flush = out_flush;
+ out->config = pcm_config_out;
+ digital_codec = get_codec_type(config->format);
+ if (digital_codec == TYPE_EAC3) {
+ out->config.period_size = pcm_config_out.period_size * 2;
+ } else if (digital_codec == TYPE_TRUE_HD || digital_codec == TYPE_DTS_HD) {
+ out->config.period_size = pcm_config_out.period_size * 4 * 2;
+ }
+ if (channel_count > 2) {
+ ALOGI("[adev_open_output_stream]: out/%p channel/%d\n", out,
+ channel_count);
+ out->multich = channel_count;
+ out->config.channels = channel_count;
+ }
+ if (digital_codec != TYPE_PCM) {
+ ALOGI("for raw audio output,force alsa stereo output\n");
+ out->config.channels = 2;
+ out->multich = 2;
+ }
+ out->format = config->format;
+ out->dev = ladev;
+ out->standby = 1;
+ ladev->hw_sync_mode = false;
+ ladev->hwsync.first_apts_flag = false;
+ out->frame_write_sum = 0;
+ if (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
+ ALOGI("Output stream open with AUDIO_OUTPUT_FLAG_HW_AV_SYNC");
+ }
+ if (audio_is_raw_data(config->format) || (flags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+ if (config->format == 0) {
+ config->format = AUDIO_FORMAT_AC3;
+ out->format = AUDIO_FORMAT_AC3;
+ }
+ }
+ if (config->sample_rate == 0) {
+ out->config.rate = config->sample_rate = 48000;
+ }
+ if (audio_is_raw_data(config->format)) {
+ out->config.rate = config->sample_rate;
+ }
+ LOGFUNC("%s(devices=0x%04x,format=0x%x, chmask=0x%04x, SR=%d)",
+ __FUNCTION__, devices, config->format, config->channel_mask,
+ config->sample_rate);
+ out->flags = flags;
+ *stream_out = &out->stream;
+ return 0;
err_open:
- free (out);
- *stream_out = NULL;
- return ret;
+ free(out);
+ *stream_out = NULL;
+ return ret;
}
static void
-adev_close_output_stream (struct audio_hw_device *dev,
- struct audio_stream_out *stream)
+adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out *stream)
{
- struct aml_stream_out *out = (struct aml_stream_out *) stream;
- LOGFUNC ("%s(%p, %p)", __FUNCTION__, dev, stream);
- out_standby (&stream->common);
- if (out->buffer)
- free (out->buffer);
- if (out->resampler)
- release_resampler (out->resampler);
-
- free (stream);
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, stream);
+ out_standby(&stream->common);
+ if (out->buffer) {
+ free(out->buffer);
+ }
+ free(stream);
}
static int
-adev_set_parameters (struct audio_hw_device *dev, const char *kvpairs)
+adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
{
- LOGFUNC ("%s(%p, %s)", __FUNCTION__, dev, kvpairs);
-
- struct aml_audio_device *adev = (struct aml_audio_device *) dev;
- struct str_parms *parms;
- char *str;
- char value[32];
- int ret;
-
- parms = str_parms_create_str (kvpairs);
- ret = str_parms_get_str (parms, "screen_state", value, sizeof (value));
- if (ret >= 0)
- {
- if (strcmp (value, AUDIO_PARAMETER_VALUE_ON) == 0)
- adev->low_power = false;
- else
- adev->low_power = true;
- }
-
- str_parms_destroy (parms);
- return ret;
+ LOGFUNC("%s(%p, %s)", __FUNCTION__, dev, kvpairs);
+ struct aml_audio_device *adev = (struct aml_audio_device *) dev;
+ return 0;
}
static char *
-adev_get_parameters (const struct audio_hw_device *dev, const char *keys)
+adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
{
- LOGFUNC ("%s(%p, %s)", __FUNCTION__, dev, keys);
- return strdup ("");
+ LOGFUNC("%s(%p, %s)", __FUNCTION__, dev, keys);
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+ if (!strcmp(keys, AUDIO_PARAMETER_HW_AV_EAC3_SYNC)) {
+ return strdup("true");
+ }
+ return strdup("");
}
static int
-adev_init_check (const struct audio_hw_device *dev)
+adev_init_check(const struct audio_hw_device *dev)
{
- LOGFUNC ("%s(%p)", __FUNCTION__, dev);
- return 0;
+ LOGFUNC("%s(%p)", __FUNCTION__, dev);
+ return 0;
}
static int
-adev_set_voice_volume (struct audio_hw_device *dev, float volume)
+adev_set_voice_volume(struct audio_hw_device *dev, float volume)
{
- struct aml_audio_device *adev = (struct aml_audio_device *) dev;
- LOGFUNC ("%s(%p, %f)", __FUNCTION__, dev, volume);
- return 0;
+ struct aml_audio_device *adev = (struct aml_audio_device *) dev;
+ LOGFUNC("%s(%p, %f)", __FUNCTION__, dev, volume);
+ return 0;
}
static int
-adev_set_master_volume (struct audio_hw_device *dev, float volume)
+adev_set_master_volume(struct audio_hw_device *dev, float volume)
{
- LOGFUNC ("%s(%p, %f)", __FUNCTION__, dev, volume);
- return -ENOSYS;
+ LOGFUNC("%s(%p, %f)", __FUNCTION__, dev, volume);
+ return -ENOSYS;
}
static int
-adev_get_master_volume (struct audio_hw_device *dev, float *volume)
+adev_get_master_volume(struct audio_hw_device *dev, float *volume)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int
-adev_set_master_mute (struct audio_hw_device *dev, bool muted)
+adev_set_master_mute(struct audio_hw_device *dev, bool muted)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int
-adev_get_master_mute (struct audio_hw_device *dev, bool * muted)
+adev_get_master_mute(struct audio_hw_device *dev, bool * muted)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int
-adev_set_mode (struct audio_hw_device *dev, audio_mode_t mode)
+adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
{
- struct aml_audio_device *adev = (struct aml_audio_device *) dev;
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, dev, mode);
-
- pthread_mutex_lock (&adev->lock);
- if (adev->mode != mode)
- {
- adev->mode = mode;
- select_mode (adev);
- }
- pthread_mutex_unlock (&adev->lock);
-
- return 0;
+ struct aml_audio_device *adev = (struct aml_audio_device *) dev;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, dev, mode);
+ pthread_mutex_lock(&adev->lock);
+ if (adev->mode != mode) {
+ adev->mode = mode;
+ select_mode(adev);
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return 0;
}
static int
-adev_set_mic_mute (struct audio_hw_device *dev, bool state)
+adev_set_mic_mute(struct audio_hw_device *dev, bool state)
{
- struct aml_audio_device *adev = (struct aml_audio_device *) dev;
-
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, dev, state);
- adev->mic_mute = state;
-
- return 0;
+ struct aml_audio_device *adev = (struct aml_audio_device *) dev;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, dev, state);
+ adev->mic_mute = state;
+ return 0;
}
static int
-adev_get_mic_mute (const struct audio_hw_device *dev, bool * state)
+adev_get_mic_mute(const struct audio_hw_device *dev, bool * state)
{
- struct aml_audio_device *adev = (struct aml_audio_device *) dev;
-
- LOGFUNC ("%s(%p, %p)", __FUNCTION__, dev, state);
- *state = adev->mic_mute;
+ struct aml_audio_device *adev = (struct aml_audio_device *) dev;
- return 0;
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, state);
+ *state = adev->mic_mute;
+ return 0;
}
static size_t
-adev_get_input_buffer_size (const struct audio_hw_device *dev,
- const struct audio_config *config)
+adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
{
- size_t size;
- int channel_count = popcount (config->channel_mask);
-
- LOGFUNC ("%s(%p, %d, %d, %d)", __FUNCTION__, dev, config->sample_rate,
- config->format, channel_count);
- if (check_input_parameters
- (config->sample_rate, config->format, channel_count) != 0)
- return 0;
-
- return get_input_buffer_size (config->sample_rate,
- config->format, channel_count);
+ size_t size;
+ int channel_count = popcount(config->channel_mask);
+ LOGFUNC("%s(%p, %d, %d, %d)", __FUNCTION__, dev, config->sample_rate,
+ config->format, channel_count);
+ if (check_input_parameters
+ (config->sample_rate, config->format, channel_count) != 0) {
+ return 0;
+ }
+ 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 aml_audio_device *ladev = (struct aml_audio_device *) dev;
- struct aml_stream_in *in;
- int ret;
- int channel_count = popcount (config->channel_mask);
- LOGFUNC ("**********%s(%#x, %d, 0x%04x, %d)", __FUNCTION__,
- devices, config->format, config->channel_mask,
- config->sample_rate);
- if (check_input_parameters
- (config->sample_rate, config->format, channel_count) != 0)
- return -EINVAL;
-
- in = (struct aml_stream_in *) calloc (1, sizeof (struct aml_stream_in));
- if (!in)
- return -ENOMEM;
-
- 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.common.set_voip_mode = in_set_voip_mode;
- in->stream.set_gain = in_set_gain;
- in->stream.read = in_read;
- in->stream.get_input_frames_lost = in_get_input_frames_lost;
-
- in->requested_rate = config->sample_rate;
-
- memcpy (&in->config, &pcm_config_in, sizeof (pcm_config_in));
- ret = check_input_stream (in);
- if (ret < 0)
- {
- ALOGE ("fail to open input stream, change channel count from %d to %d",
- in->config.channels, channel_count);
- in->config.channels = channel_count;
- }
-
- if (in->config.channels == 1)
- {
- config->channel_mask = AUDIO_CHANNEL_IN_MONO;
- }
- else if (in->config.channels == 2)
- {
- config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
- }
- else
- {
- ALOGE ("Bad value of channel count : %d", in->config.channels);
- }
- in->buffer = malloc (in->config.period_size *
- audio_stream_in_frame_size (&in->stream));
- if (!in->buffer)
- {
- ret = -ENOMEM;
- goto err_open;
- }
-
- if (in->requested_rate != in->config.rate)
- {
- LOGFUNC ("%s(in->requested_rate=%d, in->config.rate=%d)",
- __FUNCTION__, in->requested_rate, in->config.rate);
- in->buf_provider.get_next_buffer = get_next_buffer;
- in->buf_provider.release_buffer = release_buffer;
- ret = create_resampler (in->config.rate,
- in->requested_rate,
- in->config.channels,
- RESAMPLER_QUALITY_DEFAULT,
- &in->buf_provider, &in->resampler);
-
- if (ret != 0)
- {
- ret = -EINVAL;
- goto err_open;
- }
- }
-
- in->dev = ladev;
- in->standby = 1;
- in->device = devices & ~AUDIO_DEVICE_BIT_IN;
-
- // init hdmi in volume parameters
- in->volume_index = 0;
- in->last_volume = 0.0f;
- in->indexMIn = 0;
- in->indexMax = 15;
-
- *stream_in = &in->stream;
- return 0;
-
+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 aml_audio_device *ladev = (struct aml_audio_device *) dev;
+ struct aml_stream_in *in;
+ int ret;
+ int channel_count = popcount(config->channel_mask);
+ LOGFUNC("**********%s(%#x, %d, 0x%04x, %d)", __FUNCTION__,
+ devices, config->format, config->channel_mask,
+ config->sample_rate);
+ if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) {
+ return -EINVAL;
+ }
+ in = (struct aml_stream_in *) calloc(1, sizeof(struct aml_stream_in));
+ if (!in) {
+ return -ENOMEM;
+ }
+ 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 = NULL;//in_add_audio_effect;
+ in->stream.common.remove_audio_effect = NULL;//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->requested_rate = config->sample_rate;
+ memcpy(&in->config, &pcm_config_in, sizeof(pcm_config_in));
+ ret = check_input_stream(in);
+ if (ret < 0) {
+ ALOGE("fail to open input stream, change channel count from %d to %d",
+ in->config.channels, channel_count);
+ in->config.channels = channel_count;
+ }
+ if (in->config.channels == 1) {
+ config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+ } else if (in->config.channels == 2) {
+ config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ } else {
+ ALOGE("Bad value of channel count : %d", in->config.channels);
+ }
+ in->buffer = malloc(in->config.period_size *
+ audio_stream_in_frame_size(&in->stream));
+ if (!in->buffer) {
+ ret = -ENOMEM;
+ goto err_open;
+ }
+ in->dev = ladev;
+ in->standby = 1;
+ in->device = devices & ~AUDIO_DEVICE_BIT_IN;
+ *stream_in = &in->stream;
+ return 0;
err_open:
- if (in->resampler)
- release_resampler (in->resampler);
-
- free (in);
- *stream_in = NULL;
- return ret;
+ free(in);
+ *stream_in = NULL;
+ return ret;
}
static void
-adev_close_input_stream (struct audio_hw_device *dev,
- struct audio_stream_in *stream)
+adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream)
{
- struct aml_stream_in *in = (struct aml_stream_in *) stream;
+ struct aml_stream_in *in = (struct aml_stream_in *) stream;
- LOGFUNC ("%s(%p, %p)", __FUNCTION__, dev, stream);
- in_standby (&stream->common);
-
- if (in->resampler)
- {
- free (in->buffer);
- release_resampler (in->resampler);
- }
- if (in->up_resampler)
- {
- free (in->up_resampler_buffer);
- release_resampler (in->up_resampler);
- }
- if (in->proc_buf)
- free (in->proc_buf);
- if (in->ref_buf)
- free (in->ref_buf);
-
- free (stream);
-
- return;
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, stream);
+ in_standby(&stream->common);
+ free(stream);
+ return;
}
static int
-adev_dump (const audio_hw_device_t * device, int fd)
+adev_dump(const audio_hw_device_t * device, int fd)
{
- LOGFUNC ("%s(%p, %d)", __FUNCTION__, device, fd);
- return 0;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, device, fd);
+#if 0
+ struct aml_audio_device *adev = (struct aml_audio_device *) device;
+ struct aml_stream_out *out = (struct aml_stream_out *) stream;
+ struct aml_audio_device *adev = out->dev;
+ audio_hwsync_t *p_hwsync = &adev->hwsync;
+ dprintf(fd, "Out %p dump:\n", out);
+ dprintf(fd, "frame write sum %lld,spdif_enc_init_frame_write_sum %lld\n",
+ out->frame_write_sum, out->spdif_enc_init_frame_write_sum);
+ dprintf(fd, "HWSYNC status:\n");
+ dprintf(fd, "hwsync enable:%d\n", adev->hw_sync_mode);
+ dprintf(fd, "hw_sync_state:%d\n", p_hwsync->hw_sync_state);
+ dprintf(fd, "first_apts_flag:%d\n", p_hwsync->first_apts_flag);
+ dprintf(fd, "first_apts:%llx\n", p_hwsync->first_apts);
+ dprintf(fd, "last_apts_from_header:%llx\n", p_hwsync->last_apts_from_header);
+ dprintf(fd, "first_apts_flag:%d\n", p_hwsync->first_apts_flag);
+ dprintf(fd, "hw_sync_frame_size:%d\n", p_hwsync->hw_sync_frame_size);
+#endif
+ return 0;
}
static int
-adev_close (hw_device_t * device)
+adev_close(hw_device_t * device)
{
- struct aml_audio_device *adev = (struct aml_audio_device *) device;
+ struct aml_audio_device *adev = (struct aml_audio_device *) device;
- LOGFUNC ("%s(%p)", __FUNCTION__, device);
- /* RIL */
- //ril_close(&adev->ril);
- //audio_route_free(adev->ar);
- free (device);
- return 0;
+ LOGFUNC("%s(%p)", __FUNCTION__, device);
+ free(device);
+ return 0;
}
static int
-adev_open (const hw_module_t * module, const char *name,
- hw_device_t ** device)
-{
- struct aml_audio_device *adev;
- int ret;
- LOGFUNC ("%s(%p, %s, %p)", __FUNCTION__, module, name, device);
- if (strcmp (name, AUDIO_HARDWARE_INTERFACE) != 0)
- return -EINVAL;
-
- adev = calloc (1, sizeof (struct aml_audio_device));
- if (!adev)
- return -ENOMEM;
-
- adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
- adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
- adev->hw_device.common.module = (struct hw_module_t *) module;
- adev->hw_device.common.close = adev_close;
-
- //adev->hw_device.get_supported_devices = adev_get_supported_devices;
- adev->hw_device.init_check = adev_init_check;
- adev->hw_device.set_voice_volume = adev_set_voice_volume;
- adev->hw_device.set_master_volume = adev_set_master_volume;
- adev->hw_device.get_master_volume = adev_get_master_volume;
- adev->hw_device.set_master_mute = adev_set_master_mute;
- adev->hw_device.get_master_mute = adev_get_master_mute;
- adev->hw_device.set_mode = adev_set_mode;
- adev->hw_device.set_mic_mute = adev_set_mic_mute;
- adev->hw_device.get_mic_mute = adev_get_mic_mute;
- adev->hw_device.set_parameters = adev_set_parameters;
- adev->hw_device.get_parameters = adev_get_parameters;
- adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
- adev->hw_device.open_output_stream = adev_open_output_stream;
- adev->hw_device.close_output_stream = adev_close_output_stream;
- adev->hw_device.open_input_stream = adev_open_input_stream;
- adev->hw_device.close_input_stream = adev_close_input_stream;
- adev->hw_device.dump = adev_dump;
-
- /* Set the default route before the PCM stream is opened */
- adev->mode = AUDIO_MODE_NORMAL;
- adev->out_device = AUDIO_DEVICE_OUT_AUX_DIGITAL;
- adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
-
- select_output_device (adev);
-
- *device = &adev->hw_device.common;
- return 0;
+adev_open(const hw_module_t * module, const char *name,
+ hw_device_t ** device)
+{
+ struct aml_audio_device *adev;
+ int ret;
+ LOGFUNC("%s(%p, %s, %p)", __FUNCTION__, module, name, device);
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) {
+ return -EINVAL;
+ }
+
+ adev = calloc(1, sizeof(struct aml_audio_device));
+ if (!adev) {
+ return -ENOMEM;
+ }
+
+ adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
+ adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ adev->hw_device.common.module = (struct hw_module_t *) module;
+ adev->hw_device.common.close = adev_close;
+ //adev->hw_device.get_supported_devices = adev_get_supported_devices;
+ adev->hw_device.init_check = adev_init_check;
+ adev->hw_device.set_voice_volume = adev_set_voice_volume;
+ adev->hw_device.set_master_volume = adev_set_master_volume;
+ adev->hw_device.get_master_volume = adev_get_master_volume;
+ adev->hw_device.set_master_mute = adev_set_master_mute;
+ adev->hw_device.get_master_mute = adev_get_master_mute;
+ adev->hw_device.set_mode = adev_set_mode;
+ adev->hw_device.set_mic_mute = adev_set_mic_mute;
+ adev->hw_device.get_mic_mute = adev_get_mic_mute;
+ adev->hw_device.set_parameters = adev_set_parameters;
+ adev->hw_device.get_parameters = adev_get_parameters;
+ adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
+ adev->hw_device.open_output_stream = adev_open_output_stream;
+ adev->hw_device.close_output_stream = adev_close_output_stream;
+ adev->hw_device.open_input_stream = adev_open_input_stream;
+ adev->hw_device.close_input_stream = adev_close_input_stream;
+ adev->hw_device.dump = adev_dump;
+ /* Set the default route before the PCM stream is opened */
+ adev->mode = AUDIO_MODE_NORMAL;
+ adev->out_device = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
+ select_output_device(adev);
+ *device = &adev->hw_device.common;
+ return 0;
}
static struct hw_module_methods_t hal_module_methods = {
- .open = adev_open,
+ .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 = "aml HDMI audio HW HAL",
- .author = "amlogic, Corp.",
- .methods = &hal_module_methods,
- },
+ .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 = "aml HDMI audio HW HAL",
+ .author = "amlogic, Corp.",
+ .methods = &hal_module_methods,
+ },
};
diff --git a/hdmi_audio_hw.h b/hdmi_audio_hw.h
new file mode 100644
index 0000000..dd50423
--- a/dev/null
+++ b/hdmi_audio_hw.h
@@ -0,0 +1,86 @@
+#ifndef _HDMI_AUDIO_HW_H_
+#define _HDMI_AUDIO_HW_H_
+
+
+// add compute hdmi in volume function, volume index between 0 and 15 ,this reference AudioPolicyManagerBase
+
+enum
+{ VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4 };
+
+struct VolumeCurvePoint {
+ int mIndex;
+ float mDBAttenuation;
+};
+
+static struct VolumeCurvePoint sSpeakerMediaVolumeCurve[VOLCNT] = {
+ {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+// stream descriptor used for volume control
+struct StreamDescriptor {
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ int mIndexCur[15]; // current volume index
+ struct VolumeCurvePoint *mVolumeCurve;
+};
+enum {
+ TYPE_PCM = 0,
+ TYPE_AC3 = 2,
+ TYPE_DTS = 3,
+ TYPE_EAC3 = 4,
+ TYPE_DTS_HD = 5 ,
+ TYPE_TRUE_HD = 7,
+};
+
+struct aml_audio_device {
+ struct audio_hw_device hw_device;
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ int mode;
+ audio_devices_t in_device;
+ audio_devices_t out_device;
+ int in_call;
+ struct aml_stream_in *active_input;
+ struct aml_stream_out *active_output;
+ bool mic_mute;
+ struct echo_reference_itfe *echo_reference;
+ bool hw_sync_mode;
+ audio_hwsync_t hwsync;
+};
+
+struct aml_stream_out {
+ struct audio_stream_out stream;
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ struct pcm_config config;
+ struct pcm *pcm;
+ char *buffer;
+ int standby;
+ struct aml_audio_device *dev;
+ int write_threshold;
+ unsigned multich;
+ int codec_type;
+ int last_codec_type;
+ int format;
+ uint64_t frame_write_sum;
+ audio_output_flags_t flags;
+ uint64_t spdif_enc_init_frame_write_sum;
+ unsigned char write_status;
+ uint64_t last_frames_pos;
+ uint64_t bytes_write_total;
+ unsigned char pause_status;
+};
+
+struct aml_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 device;
+ int16_t *buffer;
+ size_t frames_in;
+ int standby;
+ int source;
+ bool need_echo_reference;
+ int requested_rate;
+ struct aml_audio_device *dev;
+};
+#endif
diff --git a/hdmi_hw.c b/hdmi_hw.c
deleted file mode 100755
index 58d5526..0000000
--- a/hdmi_hw.c
+++ b/dev/null
@@ -1,831 +0,0 @@
-/*
- * Copyright (C) 2011 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_hdmi6"
-#define LOG_NDEBUG 0
-#define LOG_NDEBUG_FUNCTION
-#ifdef LOG_NDEBUG_FUNCTION
-#define LOGFUNC(...) ((void)0)
-#else
-#define LOGFUNC(...) (ALOGD(__VA_ARGS__))
-#endif
-
-#include <errno.h>
-#include <pthread.h>
-#include <stdint.h>
-#include <sys/time.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-#include <cutils/log.h>
-#include <cutils/str_parms.h>
-#include <cutils/properties.h>
-
-#include <hardware/hardware.h>
-#include <system/audio.h>
-#include <hardware/audio.h>
-
-#include <tinyalsa/asoundlib.h>
-#include <audio_utils/resampler.h>
-
-/* ALSA cards for AML */
-#define CARD_AMLOGIC_BOARD 0
-#define CARD_AMLOGIC_DEFAULT CARD_AMLOGIC_BOARD
-/* ALSA ports for AML */
-#define PORT_MM 1
-/* number of frames per period */
-#define PERIOD_SIZE 256//1024
-/* number of periods for low power playback */
-#define PLAYBACK_PERIOD_COUNT 4
-/* number of periods for capture */
-#define CAPTURE_PERIOD_COUNT 4
-
-/* minimum sleep time in out_write() when write threshold is not reached */
-#define MIN_WRITE_SLEEP_US 5000
-
-#define RESAMPLER_BUFFER_FRAMES (PERIOD_SIZE * 8)
-#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
-
-#define DEFAULT_OUT_SAMPLING_RATE 48000
-
-/* sampling rate when using MM low power port */
-#define MM_LOW_POWER_SAMPLING_RATE 44100
-/* sampling rate when using MM full power port */
-#define MM_FULL_POWER_SAMPLING_RATE 48000
-/* sampling rate when using VX port for narrow band */
-#define VX_NB_SAMPLING_RATE 8000
-
-struct pcm_config pcm_config_out = {
- .channels = 8,
- .rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = PERIOD_SIZE,
- .period_count = PLAYBACK_PERIOD_COUNT,
- .format = PCM_FORMAT_S32_LE,
-};
-
-
-struct aml_audio_device {
- struct audio_hw_device hw_device;
-
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
-
- int mode;
- audio_devices_t out_device;
-
-
- struct aml_stream_out *active_output;
-
- bool mic_mute;
-};
-
-struct aml_stream_out {
- struct audio_stream_out stream;
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
- struct pcm_config config;
- struct pcm *pcm;
- struct resampler_itfe *resampler;
- char *buffer;
- int standby;
- struct aml_audio_device *dev;
- int write_threshold;
-};
-
-static char cache_buffer_bytes[64];
-static uint cached_len=0;
-
-static int adev_set_voice_volume(struct audio_hw_device *dev, float volume);
-static int do_output_standby(struct aml_stream_out *out);
-
-#define MAX_CARD_NUM 2
-int get_external_card(int type)
-{
- int card_num = 1; // start num, 0 is defualt sound card.
-
- struct stat card_stat;
- char fpath[256];
- int ret;
-
-
- while(card_num <= MAX_CARD_NUM)
- {
- snprintf(fpath, sizeof(fpath), "/proc/asound/card%d", card_num);
-
- ret = stat(fpath, &card_stat);
- //ALOGV("stat : %s : %d\n", fpath, ret);
-
- if(ret < 0)
- {
- ret = -1;
- }
- else
- {
- snprintf(fpath, sizeof(fpath), "/dev/snd/pcmC%uD0%c", card_num,
- type ? 'c' : 'p');
-
- ret = stat(fpath, &card_stat);
- //ALOGV("stat : %s : %d\n", fpath, ret);
-
- if(ret == 0)
- {
- return card_num;
- }
-
- }
-
- card_num++;
- }
-
- return ret;
-}
-
-static int check_output_stream(struct aml_stream_out *out)
-{
- int ret = 0;
- unsigned int card = CARD_AMLOGIC_DEFAULT;
- unsigned int port = PORT_MM;
- int ext_card;
- ALOGI("*******%s*********", __FUNCTION__);
-
- ext_card = get_external_card(0);
- if(ext_card < 0)
- {
- card = CARD_AMLOGIC_DEFAULT;
- }
- else
- {
- card = ext_card;
- }
-
- out->config.start_threshold = PERIOD_SIZE * 2;
- out->config.avail_min = 0;//SHORT_PERIOD_SIZE;
- ALOGI("%s(out->config.rate=%d)", __FUNCTION__,out->config.rate);
-
- /* this assumes routing is done previously */
- out->pcm = pcm_open(card, port, PCM_OUT, &out->config);
- if (!pcm_is_ready(out->pcm)) {
- ALOGI("check_out_stream:cannot open pcm_out driver: %s", pcm_get_error(out->pcm));
- pcm_close(out->pcm);
- return -ENOMEM;
- }
-
- pcm_close(out->pcm);
-
- return 0;
-}
-
-
-/* must be called with hw device and output stream mutexes locked */
-static int start_output_stream(struct aml_stream_out *out)
-{
- struct aml_audio_device *adev = out->dev;
- unsigned int card = CARD_AMLOGIC_DEFAULT;
- unsigned int port = PORT_MM;
- int ret;
-
- adev->active_output = out;
-
- ALOGI("%s(adev->out_device=%#x, adev->mode=%d)", __FUNCTION__, adev->out_device, adev->mode);
-
- card = CARD_AMLOGIC_BOARD;
- port = PORT_MM;
- ALOGI("------------open on board audio-------");
- out->config.rate = MM_FULL_POWER_SAMPLING_RATE;
- /* default to low power: will be corrected in out_write if necessary before first write to
- * tinyalsa.
- */
- out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE;
- out->config.start_threshold = PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
- out->config.avail_min = 0;//SHORT_PERIOD_SIZE;
-
-
- if(out->config.rate!=DEFAULT_OUT_SAMPLING_RATE){
-
- ret = create_resampler(DEFAULT_OUT_SAMPLING_RATE,
- out->config.rate,
- 2,
- RESAMPLER_QUALITY_DEFAULT,
- NULL,
- &out->resampler);
- if (ret != 0)
- {
- ALOGI("cannot create resampler for output");
- return ENOMEM;
- }
- out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
- if (out->buffer == NULL)
- return ENOMEM;
- }
-
- ALOGI("channels=%d---format=%d---period_count%d---period_size%d---rate=%d---",
- out->config.channels, out->config.format, out->config.period_count,
- out->config.period_size, out->config.rate);
- out->pcm = pcm_open(card, port, PCM_OUT, &(out->config));
-
- if (!pcm_is_ready(out->pcm)) {
- ALOGI("cannot open pcm_out driver: %s", pcm_get_error(out->pcm));
- pcm_close(out->pcm);
- adev->active_output = NULL;
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static uint32_t out_get_sample_rate(const struct audio_stream *stream)
-{
-
- ALOGI("%s(%p)", __FUNCTION__, stream);
- return DEFAULT_OUT_SAMPLING_RATE;
-}
-
-static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
-{
- ALOGI("%s(%p, %d)", __FUNCTION__, stream, rate);
-
- return 0;
-}
-
-static size_t out_get_buffer_size(const struct audio_stream *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
-
- ALOGI("%s(out->config.rate=%d)", __FUNCTION__, out->config.rate);
-
-
- size_t size = (PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) / out->config.rate;
-
- size = ((size + 15) / 16) * 16;
- return size * audio_stream_frame_size((struct audio_stream *)stream);
-}
-
-static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
-{
- ALOGI("%s(%p)", __FUNCTION__, stream);
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
-
- if (out->config.channels == 1) {
- return AUDIO_CHANNEL_OUT_MONO;
- } else if (out->config.channels == 6) {
- return AUDIO_CHANNEL_OUT_5POINT1;
- } else if (out->config.channels == 8){
- return AUDIO_CHANNEL_OUT_7POINT1;
- } else {
- return AUDIO_CHANNEL_OUT_STEREO;
- }
-}
-
-static audio_format_t out_get_format(const struct audio_stream *stream)
-{
- return AUDIO_FORMAT_PCM_16_BIT;
-}
-
-static int out_set_format(struct audio_stream *stream, int format)
-{
- ALOGI("%s(%p)", __FUNCTION__, stream);
-
- return 0;
-}
-
-/* must be called with hw device and output stream mutexes locked */
-static int do_output_standby(struct aml_stream_out *out)
-{
- struct aml_audio_device *adev = out->dev;
-
- ALOGI("%s(%p)", __FUNCTION__, out);
-
- if (!out->standby){
- pcm_close(out->pcm);
- out->pcm = NULL;
-
- adev->active_output = 0;
- out->standby = 1;
- }
- return 0;
-}
-
-static int out_standby(struct audio_stream *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
- int status;
-
- LOGFUNC("%s(%p)", __FUNCTION__, stream);
-
- pthread_mutex_lock(&out->dev->lock);
- pthread_mutex_lock(&out->lock);
- status = do_output_standby(out);
- pthread_mutex_unlock(&out->lock);
- pthread_mutex_unlock(&out->dev->lock);
- return status;
-}
-
-static int out_dump(const struct audio_stream *stream, int fd)
-{
- LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, fd);
- return 0;
-}
-
-static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
-{
- ALOGI("%s\n", __FUNCTION__);
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
- struct aml_audio_device *adev = out->dev;
- struct str_parms *parms;
- char *str;
- char value[32];
- int ret, val = 0;
-
-
- ALOGI("%s(kvpairs(%s), out_device=%#x)", __FUNCTION__, kvpairs, adev->out_device);
- 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(&adev->lock);
- pthread_mutex_lock(&out->lock);
- if (((adev->out_device & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0)) {
- if (out == adev->active_output) {
- do_output_standby(out);
-
- /* force standby if moving to/from HDMI */
- if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
- (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
- ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
- (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)))
- do_output_standby(out);
- }
- adev->out_device &= ~AUDIO_DEVICE_OUT_ALL;
- adev->out_device |= val;
- }
- pthread_mutex_unlock(&out->lock);
- pthread_mutex_unlock(&adev->lock);
- }
-
- str_parms_destroy(parms);
- return ret;
-
-}
-
-static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
-{
- ALOGI("%s(%p, %s)", __FUNCTION__, stream, keys);
- return strdup("");
-}
-
-static uint32_t out_get_latency(const struct audio_stream_out *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
- return (PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * 1000) / out->config.rate;
-}
-
-static int out_set_volume(struct audio_stream_out *stream, float left,
- float right)
-{
- return -ENOSYS;
-}
-
-static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
- size_t bytes)
-{
-
- int ret;
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
- struct aml_audio_device *adev = out->dev;
- size_t frame_size = audio_stream_frame_size(&out->stream.common);
- size_t in_frames = bytes / frame_size;
- size_t out_frames = RESAMPLER_BUFFER_SIZE / frame_size;
- int kernel_frames;
- void *buf;
- char output_buffer_bytes[RESAMPLER_BUFFER_SIZE+128];
- uint ouput_len;
- char *data, *data_dst;
- volatile char *data_src;
- short *dataprint;
- uint i, total_len;
-
- pthread_mutex_lock(&adev->lock);
- pthread_mutex_lock(&out->lock);
- if (out->standby) {
- ret = start_output_stream(out);
- if (ret != 0) {
- pthread_mutex_unlock(&adev->lock);
- goto exit;
- }
- out->standby = 0;
- }
- pthread_mutex_unlock(&adev->lock);
-
- /* only use resampler if required */
- if (out->config.rate != DEFAULT_OUT_SAMPLING_RATE) {
- if (!out->resampler) {
-
- ret = create_resampler(DEFAULT_OUT_SAMPLING_RATE,
- out->config.rate,
- 2,
- RESAMPLER_QUALITY_DEFAULT,
- NULL,
- &out->resampler);
- if (ret != 0)
- goto exit;
- out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
- if (!out->buffer) {
- ret = -ENOMEM;
- goto exit;
- }
- }
- out->resampler->resample_from_input(out->resampler,
- (int16_t *)buffer,
- &in_frames,
- (int16_t *)out->buffer,
- &out_frames);
- buf = out->buffer;
- } else {
- out_frames = in_frames;
- buf = (void *)buffer;
- }
-
-#if 1
-
- if(out->config.rate != DEFAULT_OUT_SAMPLING_RATE) {
- total_len = out_frames*frame_size + cached_len;
-
-
- ALOGI("total_len(%d) = resampler_out_len(%d) + cached_len111(%d)", total_len, out_frames*frame_size, cached_len);
-
- data_src = (char *)cache_buffer_bytes;
- data_dst = (char *)output_buffer_bytes;
-
-
-
- /*write_back data from cached_buffer*/
- if(cached_len){
- memcpy((void *)data_dst, (void *)data_src, cached_len);
- data_dst += cached_len;
- }
-
- ouput_len = total_len &(~0x3f);
- data = (char*)buf;
-
- memcpy((void *)data_dst, (void *)data, ouput_len-cached_len);
- data += (ouput_len-cached_len);
- cached_len = total_len & 0x3f;
- data_src = (char *)cache_buffer_bytes;
-
- /*save data to cached_buffer*/
- if(cached_len){
- memcpy((void *)data_src, (void *)data, cached_len);
- }
-
- ret = pcm_write(out->pcm, (void *)output_buffer_bytes, ouput_len);
-
- }else{
- /*frames not change, frame_size = frame_size * 2, 16bit -> 32bit */
-
- size_t frame_sbytes = out_frames * frame_size / 2;
- int32_t * s2i = (int32_t *) malloc(frame_sbytes * sizeof(int32_t));
- if(s2i == NULL){
- ALOGI("s2i==NULL\n");
- ret = pcm_write(out->pcm, (void *)buf, out_frames * frame_size);
- } else{
- ALOGI("s2i malloc success\n");
-
- short * p_s2i;
- p_s2i = (short *)buf;
-
- int32_t * s2i_buf;
- s2i_buf = s2i;
-
- int i;
- for(i = 0; i < frame_sbytes; i++){
- *s2i_buf++ = (*p_s2i) << 16;
- p_s2i++;
- }
-
-
- ret = pcm_write(out->pcm, (void *)s2i, frame_sbytes * sizeof(int32_t));
- free(s2i);
- }
-
- //ret = pcm_write(out->pcm, (void *)buf, out_frames * frame_size);
- //ret = pcm_mmap_write(out->pcm, (void *)buf, out_frames * frame_size);
- }
-#endif
-
- exit:
- pthread_mutex_unlock(&out->lock);
-
- if (ret != 0) {
- usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
- out_get_sample_rate(&stream->common));
- }
-
-
- return bytes;
-}
-
-static int out_get_render_position(const struct audio_stream_out *stream,
- uint32_t *dsp_frames)
-{
- ALOGI("%s(%p, %p)", __FUNCTION__, stream, dsp_frames);
- return -EINVAL;
-}
-
-static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
-{
- LOGFUNC("%s(%p, %p)", __FUNCTION__, stream, 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)
-{
- ALOGI("%d\n",__FUNCTION__);
- return -EINVAL;
-}
-
-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 aml_audio_device *ladev = (struct aml_audio_device *)dev;
- struct aml_stream_out *out;
- int channel_count = popcount(config->channel_mask);
- int ret;
-
- ALOGI("%s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d)", __FUNCTION__, devices,
- config->format, channel_count, config->sample_rate);
-
- out = (struct aml_stream_out *)calloc(1, sizeof(struct aml_stream_out));
- if (!out)
- return -ENOMEM;
-
- 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->config = pcm_config_out;
-
- ret = check_output_stream(out);
- ALOGI("check_output_stream_ret=%d\n",ret);
- if(ret < 0)
- {
- ALOGI("fail to open out stream, change channel count frome %d to %d", out->config.channels, channel_count);
- out->config.channels = channel_count;
- }
- ALOGI("out->config.channels =%d\n",out->config.channels);
- if(out->config.channels == 1)
- {
- config->channel_mask = AUDIO_CHANNEL_OUT_MONO;
- }
- else if(out->config.channels == 2)
- {
- config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
- }
- else if(out->config.channels == 6)
- {
- ALOGI("AUDIO_CHANNEL_OUT_5POINT1\n");
- config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
- }
- else if(out->config.channels == 8)
- {
- ALOGI("AUDIO_CHANNEL_OUT_7POINT1\n");
- config->channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
- }
- else
- {
- ALOGI("Bad value of channel count : %d", out->config.channels);
- }
- out->dev = ladev;
- out->standby = 1;
-
- config->format = out_get_format(&out->stream.common);
- config->channel_mask = out_get_channels(&out->stream.common);
- config->sample_rate = out_get_sample_rate(&out->stream.common);
- ALOGI("%s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d)", __FUNCTION__, devices,
- config->format, config->channel_mask, config->sample_rate);
-
- *stream_out = &out->stream;
- return 0;
-
-err_open:
- free(out);
- *stream_out = NULL;
- return ret;
-}
-
-static void adev_close_output_stream(struct audio_hw_device *dev,
- struct audio_stream_out *stream)
-{
- struct aml_stream_out *out = (struct aml_stream_out *)stream;
-
- LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, stream);
- out_standby(&stream->common);
- if (out->buffer)
- free(out->buffer);
- if (out->resampler)
- release_resampler(out->resampler);
-
- free(stream);
-}
-
-static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
-{
- ALOGI("%s(%p, %s)", __FUNCTION__, dev, kvpairs);
-
- return 0;
-}
-
-static char * adev_get_parameters(const struct audio_hw_device *dev,
- const char *keys)
-{
- ALOGI("%s(%p, %s)", __FUNCTION__, dev, keys);
- return strdup("");
-}
-
-static int adev_init_check(const struct audio_hw_device *dev)
-{
- LOGFUNC("%s(%p)", __FUNCTION__, dev);
- return 0;
-}
-
-static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
-{
- struct aml_audio_device *adev = (struct aml_audio_device *)dev;
-
-
-
- LOGFUNC("%s(%p, %f)", __FUNCTION__, dev, volume);
-
-
- return 0;
-}
-
-static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
-{
- LOGFUNC("%s(%p, %f)", __FUNCTION__, dev, 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 aml_audio_device *adev = (struct aml_audio_device *)dev;
- LOGFUNC("%s(%p, %d)", __FUNCTION__, dev, mode);
-
- return 0;
-}
-
-static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
-{
- return -ENOSYS;
-}
-
-static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
-{
- struct aml_audio_device *adev = (struct aml_audio_device *)dev;
-
- LOGFUNC("%s(%p, %d)", __FUNCTION__, dev, state);
- return -ENOSYS;
-}
-
-static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
- const struct audio_config *config)
-{
- return 0;
-}
-
-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)
-{
- return -ENOSYS;
-}
-
-static void adev_close_input_stream(struct audio_hw_device *dev,
- struct audio_stream_in *stream)
-{
-}
-
-static int adev_dump(const audio_hw_device_t *device, int fd)
-{
- ALOGI("%s(%p, %d)", __FUNCTION__, device, fd);
- return 0;
-}
-
-static int adev_close(hw_device_t *device)
-{
- struct aml_audio_device *adev = (struct aml_audio_device *)device;
-
- LOGFUNC("%s(%p)", __FUNCTION__, device);
-
- free(device);
- return 0;
-}
-
-static int adev_open(const hw_module_t* module, const char* name,
- hw_device_t** device)
-{
- struct aml_audio_device *adev;
- int ret;
- LOGFUNC("%s(%p, %s, %p)", __FUNCTION__, module, name, device);
- if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0){
- ALOGI("%s\n",__FUNCTION__);
- return -EINVAL;
- }
-
- adev = calloc(1, sizeof(struct aml_audio_device));
- if (!adev)
- return -ENOMEM;
-
- adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
- adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
- adev->hw_device.common.module = (struct hw_module_t *) module;
- adev->hw_device.common.close = adev_close;
-
-
- adev->hw_device.init_check = adev_init_check;
- adev->hw_device.set_voice_volume = adev_set_voice_volume;
- adev->hw_device.set_master_volume = adev_set_master_volume;
- //adev->hw_device.get_master_volume = adev_get_master_volume;
- //adev->hw_device.set_master_mute = adev_set_master_mute;
- //adev->hw_device.get_master_mute = adev_get_master_mute;
- adev->hw_device.set_mode = adev_set_mode;
- adev->hw_device.set_mic_mute = adev_set_mic_mute;
- adev->hw_device.get_mic_mute = adev_get_mic_mute;
- adev->hw_device.set_parameters = adev_set_parameters;
- adev->hw_device.get_parameters = adev_get_parameters;
- adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
- adev->hw_device.open_output_stream = adev_open_output_stream;
- adev->hw_device.close_output_stream = adev_close_output_stream;
- adev->hw_device.open_input_stream = adev_open_input_stream;
- adev->hw_device.close_input_stream = adev_close_input_stream;
- adev->hw_device.dump = adev_dump;
-
- *device = &adev->hw_device.common;
- 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 = "hdmi6 audio HW HAL",
- .author = "amlogic, Corp.",
- .methods = &hal_module_methods,
- },
-};
diff --git a/spdifenc_wrap.cpp b/spdifenc_wrap.cpp
new file mode 100644
index 0000000..ec4f6b6
--- a/dev/null
+++ b/spdifenc_wrap.cpp
@@ -0,0 +1,80 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioSPDIF-wrap"
+#include <stdint.h>
+#include <utils/Log.h>
+#include <audio_utils/spdif/SPDIFEncoder.h>
+#include <tinyalsa/asoundlib.h>
+#include <cutils/properties.h>
+static int
+getprop_bool(const char *path)
+{
+ char buf[PROPERTY_VALUE_MAX];
+ int ret = -1;
+ ret = property_get(path, buf, NULL);
+ if (ret > 0) {
+ if (strcasecmp(buf, "true") == 0 || strcmp(buf, "1") == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+namespace android
+{
+class MySPDIFEncoder : public SPDIFEncoder
+{
+public:
+ MySPDIFEncoder(struct pcm *mypcm)
+ : pcm_handle(mypcm), mTotalBytes(0), eac3_frame(0)
+ {};
+ virtual ssize_t writeOutput(const void* buffer, size_t bytes)
+ {
+ ALOGV("write size %d \n", bytes);
+#if 1
+ if (getprop_bool("media.spdif.outdump")) {
+ FILE *fp1 = fopen("/data/tmp/hdmi_audio_out.spdif", "a+");
+ if (fp1) {
+ int flen = fwrite((char *)buffer, 1, bytes, fp1);
+ //LOGFUNC("flen = %d---outlen=%d ", flen, out_frames * frame_size);
+ fclose(fp1);
+ } else {
+ //LOGFUNC("could not open file:/data/hdmi_audio_out.pcm");
+ }
+ }
+#endif
+ mTotalBytes += bytes;
+ return pcm_write(pcm_handle, buffer, bytes);
+ }
+ virtual uint64_t total_bytes()
+ {
+ return mTotalBytes;
+ }
+protected:
+ struct pcm *pcm_handle;
+private:
+ uint64_t mTotalBytes;
+ uint64_t eac3_frame;
+};
+static MySPDIFEncoder *myencoder = NULL;
+extern "C" int spdifenc_init(struct pcm *mypcm)
+{
+ if (myencoder) {
+ delete myencoder;
+ myencoder = NULL;
+ }
+ myencoder = new MySPDIFEncoder(mypcm);
+ if (myencoder == NULL) {
+ ALOGE("init SPDIFEncoder failed \n");
+ return -1;
+ }
+ ALOGI("init SPDIFEncoder done\n");
+ return 0;
+}
+extern "C" int spdifenc_write(const void *buffer, size_t numBytes)
+{
+ return myencoder->write(buffer, numBytes);
+}
+extern "C" uint64_t spdifenc_get_total()
+{
+ return myencoder->total_bytes();
+}
+}