+ struct resample_context *ctx = fn->private_data;
+ int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL);
+
+ if (ret != 0)
+ return sched_min_delay(s);
+ check_wav_pre_select(s, ctx->cwc);
+}
+
+static int get_btr_val(const char *what, struct btr_node *btrn)
+{
+ char *buf;
+ int32_t val;
+ int ret = btr_exec_up(btr_parent(btrn), what, &buf);
+
+ if (ret < 0) {
+ PARA_NOTICE_LOG("btr exec for \"%s\" failed\n", what);
+ return ret;
+ }
+ ret = para_atoi32(buf, &val);
+ free(buf);
+ return ret < 0? ret : val;
+}
+
+static int resample_set_params(struct filter_node *fn)
+{
+ int ret;
+ struct resample_context *ctx = fn->private_data;
+ struct resample_filter_args_info *conf = fn->conf;
+ struct btr_node *btrn = fn->btrn;
+
+ ctx->channels = conf->channels_arg;
+ if (!conf->channels_given) {
+ ret = get_btr_val("channels", btrn);
+ if (ret >= 0)
+ ctx->channels = ret;
+ }
+
+ ctx->source_sample_rate = conf->sample_rate_arg;
+ if (!conf->sample_rate_given) {
+ ret = get_btr_val("sample_rate", btrn);
+ if (ret >= 0)
+ ctx->source_sample_rate = ret;
+ }
+ /* reject all sample formats except 16 bit signed, little endian */
+ ret = get_btr_val("sample_format", btrn);
+ if (ret >= 0 && ret != SF_S16_LE) {
+ const char *sample_formats[] = {SAMPLE_FORMATS};
+ PARA_ERROR_LOG("unsupported sample format: %s\n",
+ sample_formats[ret]);
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ }
+ ctx->ratio = (float)conf->dest_sample_rate_arg / ctx->source_sample_rate;
+ return 1;
+}
+
+static int resample_init(struct filter_node *fn)
+{
+ int ret, converter;
+ struct resample_context *ctx = fn->private_data;
+ struct resample_filter_args_info *conf = fn->conf;
+ struct btr_node *btrn = fn->btrn;
+
+ ret = -E_RESAMPLE_EOF;
+ if (btr_no_parent(btrn))
+ return ret;
+ if (btr_get_input_queue_size(btrn) == 0)
+ return 0;
+ ret = resample_set_params(fn);
+ if (ret < 0)
+ return ret;
+ switch (conf->converter_arg) {
+ case converter_arg_best:
+ converter = SRC_SINC_BEST_QUALITY;
+ break;
+ case converter_arg_medium:
+ converter = SRC_SINC_MEDIUM_QUALITY;
+ break;
+ case converter_arg_fastest:
+ converter = SRC_SINC_FASTEST;
+ break;
+ case converter_arg_zero_order_hold:
+ converter = SRC_ZERO_ORDER_HOLD;
+ break;
+ case converter_arg_linear:
+ converter = SRC_LINEAR;
+ break;
+ default:
+ assert(0);
+ }
+ ctx->src_state = src_new(converter, conf->channels_arg, &ret);
+ if (!ctx->src_state) {
+ PARA_ERROR_LOG("%s\n", src_strerror(ret));
+ return -E_LIBSAMPLERATE;
+ }
+ fn->min_iqs = 2 * ctx->channels;
+ return 1;
+}
+
+/* returns number of input frames used */
+static int resample_frames(int16_t *in, size_t num_frames, bool have_more,
+ struct resample_context *ctx, int16_t **result,
+ size_t *result_frames)
+{
+ int ret, num_samples, out_samples;
+ int16_t *out;
+ SRC_DATA data;
+
+ data.src_ratio = ctx->ratio;
+ data.end_of_input = !have_more;
+
+ data.input_frames = num_frames;
+ num_samples = num_frames * ctx->channels;
+ data.output_frames = num_frames * ctx->ratio + 1;
+ out_samples = data.output_frames * ctx->channels;
+
+ data.data_in = para_malloc(num_samples * sizeof(float));
+ src_short_to_float_array(in, data.data_in, num_samples);
+ data.data_out = para_malloc(out_samples * sizeof(float));
+ ret = src_process(ctx->src_state, &data);
+ free(data.data_in);
+ if (ret != 0) {
+ PARA_ERROR_LOG("%s\n", src_strerror(ret));
+ free(data.data_out);
+ return -E_LIBSAMPLERATE;
+ }
+ out_samples = data.output_frames_gen * ctx->channels;
+ out = para_malloc(out_samples * sizeof(short));
+ src_float_to_short_array(data.data_out, out, out_samples);
+ free(data.data_out);
+ *result = out;
+ *result_frames = data.output_frames_gen;
+ return data.input_frames_used;