static int join_request_frame(AVFilterLink *outlink)
{
    AVFilterContext *ctx = outlink->src;
    JoinContext *s       = ctx->priv;
    AVFilterBufferRef *buf;
    JoinBufferPriv *priv;
    int linesize   = INT_MAX;
    int perms      = ~0;
    int nb_samples = 0;
    int i, j, ret;

    /* get a frame on each input */
    for (i = 0; i < ctx->nb_inputs; i++) {
        AVFilterLink *inlink = ctx->inputs[i];

        if (!s->input_frames[i] &&
            (ret = ff_request_frame(inlink)) < 0)
            return ret;

        /* request the same number of samples on all inputs */
        if (i == 0) {
            nb_samples = s->input_frames[0]->audio->nb_samples;

            for (j = 1; !i && j < ctx->nb_inputs; j++)
                ctx->inputs[j]->request_samples = nb_samples;
        }
    }

    for (i = 0; i < s->nb_channels; i++) {
        ChannelMap *ch = &s->channels[i];
        AVFilterBufferRef *cur_buf = s->input_frames[ch->input];

        s->data[i] = cur_buf->extended_data[ch->in_channel_idx];
        linesize   = FFMIN(linesize, cur_buf->linesize[0]);
        perms     &= cur_buf->perms;
    }

    av_assert0(nb_samples > 0);
    buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms,
                                                    nb_samples, outlink->format,
                                                    outlink->channel_layout);
    if (!buf)
        return AVERROR(ENOMEM);

    buf->buf->free = join_free_buffer;
    buf->pts       = s->input_frames[0]->pts;

    if (!(priv = av_mallocz(sizeof(*priv))))
        goto fail;
    if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs)))
        goto fail;

    for (i = 0; i < ctx->nb_inputs; i++)
        priv->in_buffers[i] = s->input_frames[i];
    priv->nb_in_buffers = ctx->nb_inputs;
    buf->buf->priv      = priv;

    ff_filter_samples(outlink, buf);

    memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);

    return 0;

fail:
    avfilter_unref_buffer(buf);
    if (priv)
        av_freep(&priv->in_buffers);
    av_freep(&priv);
    return AVERROR(ENOMEM);
}