/* Called from thread context */ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { connection *c; pa_sink_input_assert_ref(i); c = CONNECTION(i->userdata); connection_assert_ref(c); pa_assert(chunk); if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { c->playback.underrun = true; if (c->dead && pa_sink_input_safe_to_remove(i)) pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL); return -1; } else { size_t m; chunk->length = PA_MIN(length, chunk->length); c->playback.underrun = false; pa_memblockq_drop(c->input_memblockq, chunk->length); m = pa_memblockq_pop_missing(c->input_memblockq); if (m > 0) if (pa_atomic_add(&c->playback.missing, (int) m) <= 0) pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); return 0; } }
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { memblockq_stream *u; pa_sink_input_assert_ref(i); pa_assert(chunk); u = MEMBLOCKQ_STREAM(i->userdata); memblockq_stream_assert_ref(u); if (!u->memblockq) return -1; if (pa_memblockq_peek(u->memblockq, chunk) < 0) { if (pa_sink_input_safe_to_remove(i)) { pa_memblockq_free(u->memblockq); u->memblockq = NULL; pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMBLOCKQ_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); } return -1; } /* If there's no memblock, there's going to be data in the memblockq after * a gap with length chunk->length. Drop the the gap and peek the actual * data. There should always be some data coming - hence the assert. The * gap will occur if the memblockq is rewound beyond index 0.*/ if (!chunk->memblock) { pa_memblockq_drop(u->memblockq, chunk->length); pa_assert_se(pa_memblockq_peek(u->memblockq, chunk) >= 0); } chunk->length = PA_MIN(chunk->length, nbytes); pa_memblockq_drop(u->memblockq, chunk->length); return 0; }
/* Called from IO thread context */ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { file_stream *u; pa_sink_input_assert_ref(i); pa_assert(chunk); u = FILE_STREAM(i->userdata); file_stream_assert_ref(u); if (!u->memblockq) return -1; for (;;) { pa_memchunk tchunk; size_t fs; void *p; sf_count_t n; if (pa_memblockq_peek(u->memblockq, chunk) >= 0) { chunk->length = PA_MIN(chunk->length, length); pa_memblockq_drop(u->memblockq, chunk->length); return 0; } if (!u->sndfile) break; tchunk.memblock = pa_memblock_new(i->sink->core->mempool, length); tchunk.index = 0; p = pa_memblock_acquire(tchunk.memblock); if (u->readf_function) { fs = pa_frame_size(&i->sample_spec); n = u->readf_function(u->sndfile, p, (sf_count_t) (length/fs)); } else { fs = 1; n = sf_read_raw(u->sndfile, p, (sf_count_t) length); } pa_memblock_release(tchunk.memblock); if (n <= 0) { pa_memblock_unref(tchunk.memblock); sf_close(u->sndfile); u->sndfile = NULL; break; } tchunk.length = (size_t) n * fs; pa_memblockq_push(u->memblockq, &tchunk); pa_memblock_unref(tchunk.memblock); } if (pa_sink_input_safe_to_remove(i)) { pa_memblockq_free(u->memblockq); u->memblockq = NULL; pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), FILE_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); } return -1; }