+
+static void afh_recv_pre_select(struct sched *s, void *context)
+{
+ struct receiver_node *rn = context;
+ struct private_afh_recv_data *pard = rn->private_data;
+ struct afh_info *afhi = &pard->afhi;
+ struct lls_parse_result *lpr = rn->lpr;
+ struct timeval chunk_time;
+ int state = generic_recv_pre_select(s, rn);
+ unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
+
+ if (state <= 0)
+ return;
+ if (!j_given) {
+ sched_min_delay(s);
+ return;
+ }
+ compute_chunk_time(pard->current_chunk - pard->first_chunk,
+ &afhi->chunk_tv, &pard->stream_start, &chunk_time);
+ sched_request_barrier_or_min_delay(&chunk_time, s);
+}
+
+static int afh_recv_post_select(__a_unused struct sched *s, void *context)
+{
+ struct receiver_node *rn = context;
+ struct lls_parse_result *lpr = rn->lpr;
+ struct private_afh_recv_data *pard = rn->private_data;
+ struct btr_node *btrn = rn->btrn;
+ struct afh_info *afhi = &pard->afhi;
+ int ret;
+ char *buf;
+ const char *start;
+ size_t size;
+ struct timeval chunk_time;
+ unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
+ unsigned H_given = RECV_CMD_OPT_GIVEN(AFH, NO_HEADER, lpr);
+
+ ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
+ if (ret <= 0)
+ goto out;
+ if (pard->first_chunk > 0 && !H_given) {
+ char *header;
+ afh_get_header(afhi, pard->audio_format_num, pard->map,
+ pard->map_size, &header, &size);
+ if (size > 0) {
+ PARA_INFO_LOG("writing header (%zu bytes)\n", size);
+ buf = para_malloc(size);
+ memcpy(buf, header, size);
+ btr_add_output(buf, size, btrn);
+ afh_free_header(header, pard->audio_format_num);
+ }
+ }
+ if (!j_given) {
+ long unsigned n;
+ for (n = pard->first_chunk; n < pard->last_chunk; n++) {
+ ret = afh_get_chunk(n, afhi, pard->audio_format_num,
+ pard->map, pard->map_size, &start, &size,
+ &pard->afh_context);
+ if (ret < 0)
+ goto out;
+ PARA_INFO_LOG("adding %zu bytes\n", size);
+ btr_add_output_dont_free(start, size, btrn);
+ }
+ ret = -E_RECV_EOF;
+ goto out;
+ }
+ if (pard->current_chunk == pard->first_chunk)
+ pard->stream_start = *now;
+ else {
+ compute_chunk_time(pard->current_chunk - pard->first_chunk,
+ &afhi->chunk_tv, &pard->stream_start, &chunk_time);
+ ret = tv_diff(&chunk_time, now, NULL);
+ if (ret > 0)
+ goto out;
+ }
+ ret = afh_get_chunk(pard->current_chunk, afhi,
+ pard->audio_format_num, pard->map,
+ pard->map_size, &start, &size,
+ &pard->afh_context);
+ if (ret < 0)
+ goto out;
+ PARA_DEBUG_LOG("adding chunk %u\n", pard->current_chunk);
+ btr_add_output_dont_free(start, size, btrn);
+ if (pard->current_chunk >= pard->last_chunk) {
+ ret = -E_RECV_EOF;
+ goto out;
+ }
+ pard->current_chunk++;
+ ret = 1;
+out:
+ if (ret < 0) {
+ btr_remove_node(&rn->btrn);
+ pard->current_chunk = pard->first_chunk;
+ }
+ return ret;
+}
+
+const struct receiver lsg_recv_cmd_com_afh_user_data = {
+ .init = afh_init,
+ .open = afh_recv_open,
+ .close = afh_recv_close,
+ .pre_select = afh_recv_pre_select,
+ .post_select = afh_recv_post_select,
+ .execute = afh_execute,
+};