void get_spk_timestamp(struct aec_t* aec, ssize_t read_bytes, uint64_t* spk_time) {
*spk_time = 0;
uint64_t spk_time_offset = 0; float usec_per_byte = 1E6 / ((float)(aec->spk_frame_size_bytes * aec->spk_sampling_rate)); if (aec->read_write_diff_bytes < 0) { /* We're still reading a previous write packet. (We only need the first sample's timestamp, *soevenifwestraddlepacketsweonlycareaboutthefirstone) *Sowejustusetheprevioustimestamp,withanappropriateoffset
* based on the number of bytes remaining to be read from that write packet. */
spk_time_offset = (aec->last_spk_info.bytes + aec->read_write_diff_bytes) * usec_per_byte;
ALOGV("Reusing previous timestamp, calculated offset (usec) %" PRIu64, spk_time_offset);
} else { /* If read_write_diff_bytes > 0, there are no new writes, so there won't be timestamps in
* the FIFO, and the check below will fail. */ if (!fifo_available_to_read(aec->ts_fifo)) {
ALOGE("Timestamp error: no new timestamps!"); return;
} /* We just read valid data, so if we're here, we should have a valid timestamp to use. */
ssize_t ts_bytes = fifo_read(aec->ts_fifo, &aec->last_spk_info, sizeof(struct aec_info));
ALOGV("Read TS bytes: %zd, expected %zu", ts_bytes, sizeof(struct aec_info));
aec->read_write_diff_bytes -= aec->last_spk_info.bytes;
}
aec->read_write_diff_bytes += read_bytes; struct aec_info spk_info = aec->last_spk_info; while (aec->read_write_diff_bytes > 0) { /* If read_write_diff_bytes > 0, it means that there are more write packet timestamps *inFIFO(sincetherewereadmorevaliddatathesizeofthecurrenttimestamp's
* packet). Keep reading timestamps from FIFO to get to the most recent one. */ if (!fifo_available_to_read(aec->ts_fifo)) { /* There are no more timestamps, we have the most recent one. */
ALOGV("At the end of timestamp FIFO, breaking..."); break;
}
fifo_read(aec->ts_fifo, &spk_info, sizeof(struct aec_info));
ALOGV("Fast-forwarded timestamp by %zd bytes, remaining bytes: %zd," " new timestamp (usec) %" PRIu64,
spk_info.bytes, aec->read_write_diff_bytes, timespec_to_usec(spk_info.timestamp));
aec->read_write_diff_bytes -= spk_info.bytes;
}
aec->last_spk_info = spk_info;
}
/* Get timestamp*/
get_spk_timestamp(aec, read_bytes, &info->timestamp_usec);
/* Get reference - could be mono, downmixed from multichannel.
* Reference stored at spk_buf_playback_format */
get_reference_audio_in_place(aec, resampler_in_frames);
int16_t* resampler_out_buf; /* Resample to mic sampling rate (16-bit resampler) */ if (aec->spk_resampler != NULL) {
size_t in_frame_count = resampler_in_frames;
size_t out_frame_count = frames;
aec->spk_resampler->resample_from_input(aec->spk_resampler, aec->spk_buf_playback_format,
&in_frame_count, aec->spk_buf_resampler_out,
&out_frame_count);
resampler_out_buf = aec->spk_buf_resampler_out;
} else { if (sample_rate_ratio != 1) {
ALOGE("Speaker sample rate %d, mic sample rate %d but no resampler defined!",
aec->spk_sampling_rate, aec->mic_sampling_rate);
}
resampler_out_buf = aec->spk_buf_playback_format;
}
if (!aec) {
ALOGE("AEC: No valid interface found!"); return -EINVAL;
}
int ret = 0;
pthread_mutex_lock(&aec->lock); if (aec->mic_initialized) {
destroy_aec_mic_config_no_lock(aec);
}
aec->mic_sampling_rate = in->config.rate;
aec->mic_frame_size_bytes = audio_stream_in_frame_size(&in->stream);
aec->mic_num_channels = in->config.channels;
aec->mic_buf_size_bytes = in->config.period_size * aec->mic_frame_size_bytes;
aec->mic_buf = (int32_t *)malloc(aec->mic_buf_size_bytes); if (aec->mic_buf == NULL) {
ret = -ENOMEM; gotoexit;
}
memset(aec->mic_buf, 0, aec->mic_buf_size_bytes); /* Reference buffer is the same number of frames as mic,
* only with a different number of channels in the frame. */
aec->spk_buf_size_bytes = in->config.period_size * aec->spk_num_channels *
aec->mic_frame_size_bytes / aec->mic_num_channels;
aec->spk_buf = (int32_t *)malloc(aec->spk_buf_size_bytes); if (aec->spk_buf == NULL) {
ret = -ENOMEM; goto exit_1;
}
memset(aec->spk_buf, 0, aec->spk_buf_size_bytes);
/* Pre-resampler buffer */
size_t spk_frame_out_format_bytes =
aec->spk_buf_size_bytes * aec->spk_sampling_rate / aec->mic_sampling_rate;
aec->spk_buf_playback_format = (int16_t *)malloc(spk_frame_out_format_bytes); if (aec->spk_buf_playback_format == NULL) {
ret = -ENOMEM; goto exit_2;
} /* Resampler is 16-bit */
aec->spk_buf_resampler_out = (int16_t *)malloc(aec->spk_buf_size_bytes); if (aec->spk_buf_resampler_out == NULL) {
ret = -ENOMEM; goto exit_3;
}
/* Don't use resampler if it's not required */ if (in->config.rate == aec->spk_sampling_rate) {
aec->spk_resampler = NULL;
} else { int resampler_ret = create_resampler(
aec->spk_sampling_rate, in->config.rate, aec->num_reference_channels,
RESAMPLER_QUALITY_MAX - 1, /* MAX - 1 is the real max */
NULL, /* resampler_buffer_provider */
&aec->spk_resampler); if (resampler_ret) {
ALOGE("AEC: Resampler initialization failed! Error code %d", resampler_ret);
ret = resampler_ret; goto exit_4;
}
}
if (!spk_running) { /* No new playback samples, so don't run AEC.
* 'buffer' already contains input samples. */
ALOGV("Speaker not running, skipping AEC.."); gotoexit;
}
if (!aec->prev_spk_running) {
flush_aec_fifos(aec);
}
/* If there's no data in FIFO, exit */ if (fifo_available_to_read(aec->spk_fifo) <= 0) {
ALOGV("Echo reference buffer empty, zeroing reference...."); gotoexit;
}
print_queue_status_to_log(aec, false);
/* Get reference, with format and sample rate required by AEC */ struct aec_info spk_info;
spk_info.bytes = bytes; int ref_ret = get_reference_samples(aec, aec->spk_buf, &spk_info);
spk_time = spk_info.timestamp_usec;
if (ref_ret) {
ALOGE("get_reference_samples returned code %d", ref_ret);
ret = -ENOMEM; gotoexit;
}
if (!aec_status) {
ALOGE("AEC processing failed!");
ret = -EINVAL;
}
exit:
aec->prev_spk_running = spk_running;
ALOGV("Mic time: %"PRIu64", spk time: %"PRIu64, mic_time, spk_time); if (ret) { /* Best we can do is copy over the raw mic signal */
memcpy(buffer, aec->mic_buf, bytes);
flush_aec_fifos(aec);
aec_spk_mic_reset();
}
#if DEBUG_AEC /* ref data is 32-bit at this point */
size_t ref_bytes = in_frames*aec->num_reference_channels*sizeof(int32_t);
FILE *fp_in = fopen("/data/local/traces/aec_in.pcm", "a+"); if (fp_in) {
fwrite((char *)aec->mic_buf, 1, bytes, fp_in);
fclose(fp_in);
} else {
ALOGE("AEC debug: Could not open file aec_in.pcm!");
}
FILE *fp_out = fopen("/data/local/traces/aec_out.pcm", "a+"); if (fp_out) {
fwrite((char *)buffer, 1, bytes, fp_out);
fclose(fp_out);
} else {
ALOGE("AEC debug: Could not open file aec_out.pcm!");
}
FILE *fp_ref = fopen("/data/local/traces/aec_ref.pcm", "a+"); if (fp_ref) {
fwrite((char *)aec->spk_buf, 1, ref_bytes, fp_ref);
fclose(fp_ref);
} else {
ALOGE("AEC debug: Could not open file aec_ref.pcm!");
}
FILE *fp_ts = fopen("/data/local/traces/aec_timestamps.txt", "a+"); if (fp_ts) {
fprintf(fp_ts, "%"PRIu64",%"PRIu64"\n", mic_time, spk_time);
fclose(fp_ts);
} else {
ALOGE("AEC debug: Could not open file aec_timestamps.txt!");
} #endif/* #if DEBUG_AEC */
ALOGV("%s exit", __func__); return ret;
}
#endif/*#ifdef AEC_HAL*/
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-06-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.