hardware/libaudio
Revision | fc4aceec5137d1658bedc97e257896e81bad625f (tree) |
---|---|
Time | 2020-04-23 23:49:22 |
Author | Michael Goffioul <michael.goffioul@gmai...> |
Commiter | Chih-Wei Huang |
Support preprocessing filters in audio HAL
This adds support for some preprocessing filters like NS and AGC in the
audio HAL. This does not include AEC.
Derived from audio HAL in device/samsung/tuna and vero2-android-audio
@@ -133,6 +133,7 @@ struct stream_out { | ||
133 | 133 | struct audio_device *dev; |
134 | 134 | }; |
135 | 135 | |
136 | +#define MAX_PREPROCESSORS 3 | |
136 | 137 | struct stream_in { |
137 | 138 | struct audio_stream_in stream; |
138 | 139 |
@@ -150,6 +151,12 @@ struct stream_in { | ||
150 | 151 | int read_status; |
151 | 152 | |
152 | 153 | struct audio_device *dev; |
154 | + | |
155 | + effect_handle_t preprocessors[MAX_PREPROCESSORS]; | |
156 | + int num_preprocessors; | |
157 | + int16_t *proc_buf; | |
158 | + size_t proc_buf_size; | |
159 | + size_t proc_frames_in; | |
153 | 160 | }; |
154 | 161 | |
155 | 162 | enum { |
@@ -332,6 +339,11 @@ static void do_in_standby(struct stream_in *in) | ||
332 | 339 | free(in->buffer); |
333 | 340 | in->buffer = NULL; |
334 | 341 | } |
342 | + if (in->proc_buf) { | |
343 | + free(in->proc_buf); | |
344 | + in->proc_buf = NULL; | |
345 | + in->proc_buf_size = 0; | |
346 | + } | |
335 | 347 | in->standby = true; |
336 | 348 | } |
337 | 349 | } |
@@ -577,6 +589,78 @@ static ssize_t read_frames(struct stream_in *in, void *buffer, ssize_t frames) | ||
577 | 589 | return frames_wr; |
578 | 590 | } |
579 | 591 | |
592 | +static ssize_t process_frames(struct stream_in *in, void* buffer, ssize_t frames) | |
593 | +{ | |
594 | + ssize_t frames_wr = 0; | |
595 | + audio_buffer_t in_buf; | |
596 | + audio_buffer_t out_buf; | |
597 | + int i; | |
598 | + | |
599 | + while (frames_wr < frames) { | |
600 | + /* first reload enough frames at the end of process input buffer */ | |
601 | + if (in->proc_frames_in < (size_t)frames) { | |
602 | + ssize_t frames_rd; | |
603 | + | |
604 | + if (in->proc_buf_size < (size_t)frames) { | |
605 | + in->proc_buf_size = (size_t)frames; | |
606 | + in->proc_buf = (int16_t *)realloc(in->proc_buf, in->proc_buf_size * sizeof(int16_t)); | |
607 | + ALOGV("process_frames(): in->proc_buf %p size extended to %zu frames", | |
608 | + in->proc_buf, in->proc_buf_size); | |
609 | + } | |
610 | + frames_rd = read_frames(in, | |
611 | + in->proc_buf + in->proc_frames_in, | |
612 | + frames - in->proc_frames_in); | |
613 | + if (frames_rd < 0) { | |
614 | + frames_wr = frames_rd; | |
615 | + break; | |
616 | + } | |
617 | + | |
618 | + in->proc_frames_in += frames_rd; | |
619 | + } | |
620 | + | |
621 | + | |
622 | + /* in_buf.frameCount and out_buf.frameCount indicate respectively | |
623 | + * the maximum number of frames to be consumed and produced by process() */ | |
624 | + in_buf.frameCount = in->proc_frames_in; | |
625 | + in_buf.s16 = in->proc_buf; | |
626 | + out_buf.frameCount = frames - frames_wr; | |
627 | + out_buf.s16 = (int16_t *)buffer + frames_wr; | |
628 | + | |
629 | + /* FIXME: this works because of current pre processing library implementation that | |
630 | + * does the actual process only when the last enabled effect process is called. | |
631 | + * The generic solution is to have an output buffer for each effect and pass it as | |
632 | + * input to the next. */ | |
633 | + for (i = 0; i < in->num_preprocessors; i++) { | |
634 | + (*in->preprocessors[i])->process(in->preprocessors[i], &in_buf, &out_buf); | |
635 | + } | |
636 | + | |
637 | + /* process() has updated the number of frames consumed and produced in | |
638 | + * in_buf.frameCount and out_buf.frameCount respectively | |
639 | + * move remaining frames to the beginning of in->proc_buf_in */ | |
640 | + in->proc_frames_in -= in_buf.frameCount; | |
641 | + if (in->proc_frames_in) { | |
642 | + memmove(in->proc_buf, | |
643 | + in->proc_buf + in_buf.frameCount, | |
644 | + in->proc_frames_in * sizeof(int16_t)); | |
645 | + } | |
646 | + | |
647 | + /* if not enough frames were passed to process(), read more and retry. */ | |
648 | + if (out_buf.frameCount == 0) | |
649 | + continue; | |
650 | + | |
651 | + if ((frames_wr + (ssize_t)out_buf.frameCount) <= frames) { | |
652 | + frames_wr += out_buf.frameCount; | |
653 | + } else { | |
654 | + /* The effect does not comply to the API. In theory, we should never end up here! */ | |
655 | + ALOGE("preprocessing produced too many frames: %d + %zu > %d !", | |
656 | + (unsigned int)frames_wr, out_buf.frameCount, (unsigned int)frames); | |
657 | + frames_wr = frames; | |
658 | + } | |
659 | + } | |
660 | + | |
661 | + return frames_wr; | |
662 | +} | |
663 | + | |
580 | 664 | /* API functions */ |
581 | 665 | |
582 | 666 | static uint32_t out_get_sample_rate(const struct audio_stream *stream __unused) |
@@ -1011,25 +1095,10 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, | ||
1011 | 1095 | if (ret < 0) |
1012 | 1096 | goto exit; |
1013 | 1097 | |
1014 | - /*if (in->num_preprocessors != 0) { | |
1098 | + if (in->num_preprocessors != 0) { | |
1015 | 1099 | ret = process_frames(in, buffer, frames_rq); |
1016 | - } else */if (in->resampler != NULL) { | |
1017 | - ret = read_frames(in, buffer, frames_rq); | |
1018 | - } else if (in->pcm_config->channels == 2) { | |
1019 | - /* | |
1020 | - * If the PCM is stereo, capture twice as many frames and | |
1021 | - * discard the right channel. | |
1022 | - */ | |
1023 | - unsigned int i; | |
1024 | - int16_t *in_buffer = (int16_t *)buffer; | |
1025 | - | |
1026 | - ret = pcm_read(in->pcm, in->buffer, bytes * 2); | |
1027 | - | |
1028 | - /* Discard right channel */ | |
1029 | - for (i = 0; i < frames_rq; i++) | |
1030 | - in_buffer[i] = in->buffer[i * 2]; | |
1031 | 1100 | } else { |
1032 | - ret = pcm_read(in->pcm, buffer, bytes); | |
1101 | + ret = read_frames(in, buffer, frames_rq); | |
1033 | 1102 | } |
1034 | 1103 | |
1035 | 1104 | if (ret > 0) |
@@ -1056,16 +1125,63 @@ static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused | ||
1056 | 1125 | return 0; |
1057 | 1126 | } |
1058 | 1127 | |
1059 | -static int in_add_audio_effect(const struct audio_stream *stream __unused, | |
1060 | - effect_handle_t effect __unused) | |
1128 | +static int in_add_audio_effect(const struct audio_stream *stream, | |
1129 | + effect_handle_t effect) | |
1061 | 1130 | { |
1062 | - return 0; | |
1131 | + struct stream_in *in = (struct stream_in *)stream; | |
1132 | + int status = 0; | |
1133 | + | |
1134 | + pthread_mutex_lock(&in->dev->lock); | |
1135 | + pthread_mutex_lock(&in->lock); | |
1136 | + if (in->num_preprocessors >= MAX_PREPROCESSORS) { | |
1137 | + status = -ENOSYS; | |
1138 | + goto exit; | |
1139 | + } | |
1140 | + | |
1141 | + in->preprocessors[in->num_preprocessors++] = effect; | |
1142 | + | |
1143 | +exit: | |
1144 | + | |
1145 | + pthread_mutex_unlock(&in->lock); | |
1146 | + pthread_mutex_unlock(&in->dev->lock); | |
1147 | + return status; | |
1063 | 1148 | } |
1064 | 1149 | |
1065 | -static int in_remove_audio_effect(const struct audio_stream *stream __unused, | |
1066 | - effect_handle_t effect __unused) | |
1150 | +static int in_remove_audio_effect(const struct audio_stream *stream, | |
1151 | + effect_handle_t effect) | |
1067 | 1152 | { |
1068 | - return 0; | |
1153 | + struct stream_in *in = (struct stream_in *)stream; | |
1154 | + int status = -EINVAL; | |
1155 | + int i; | |
1156 | + | |
1157 | + pthread_mutex_lock(&in->dev->lock); | |
1158 | + pthread_mutex_lock(&in->lock); | |
1159 | + if (in->num_preprocessors <= 0) { | |
1160 | + status = -ENOSYS; | |
1161 | + goto exit; | |
1162 | + } | |
1163 | + | |
1164 | + for (i = 0; i < in->num_preprocessors; i++) { | |
1165 | + if (status == 0) { | |
1166 | + in->preprocessors[i - 1] = in->preprocessors[i]; | |
1167 | + continue; | |
1168 | + } | |
1169 | + if (in->preprocessors[i] == effect) { | |
1170 | + in->preprocessors[i] = NULL; | |
1171 | + status = 0; | |
1172 | + } | |
1173 | + } | |
1174 | + | |
1175 | + if (status != 0) | |
1176 | + goto exit; | |
1177 | + | |
1178 | + in->num_preprocessors--; | |
1179 | + | |
1180 | +exit: | |
1181 | + | |
1182 | + pthread_mutex_unlock(&in->lock); | |
1183 | + pthread_mutex_unlock(&in->dev->lock); | |
1184 | + return status; | |
1069 | 1185 | } |
1070 | 1186 | |
1071 | 1187 |