author | Jian 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) |
commit | 8c936715ae0fe847f1ac6912eafd0377ca893ac4 (patch) | |
tree | 7110b21a812eb912d9f972fd780df9b645596287 | |
parent | 66e6ff7906b80d508cfe02ab6dd39f794b3a0e1d (diff) | |
download | audio-8c936715ae0fe847f1ac6912eafd0377ca893ac4.zip audio-8c936715ae0fe847f1ac6912eafd0377ca893ac4.tar.gz audio-8c936715ae0fe847f1ac6912eafd0377ca893ac4.tar.bz2 |
PD#119007: audio: add audio hwsync and hdmi dynamic mode
Change-Id: I6fddd7d33c369da6e3f00a9c6d66a1333b5b30ba
-rw-r--r-- | Android.mk | 35 | ||||
-rw-r--r-- | audio_hw.c | 1213 | ||||
-rw-r--r-- | audio_hw.h | 31 | ||||
-rw-r--r-- | audio_hw_profile.c | 215 | ||||
-rw-r--r-- | audio_hw_profile.h | 3 | ||||
-rw-r--r-- | audio_hw_utils.c | 151 | ||||
-rw-r--r-- | audio_hw_utils.h | 10 | ||||
-rw-r--r-- | audio_hwsync.c | 122 | ||||
-rw-r--r-- | audio_hwsync.h | 58 | ||||
-rw-r--r-- | hdmi_audio_hw.c | 3760 | ||||
-rw-r--r-- | hdmi_audio_hw.h | 86 | ||||
-rwxr-xr-x | hdmi_hw.c | 831 | ||||
-rw-r--r-- | spdifenc_wrap.cpp | 80 |
13 files changed, 3037 insertions, 3558 deletions
@@ -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)) @@ -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, - ¶m->status); - if (status == 0) + EFFECT_CMD_SET_PARAM, + sizeof(effect_param_t) + psize, + param, + &size, + ¶m->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, - ¶m->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(); +} +} |