+/* output data processing function to read stuffs from the buffer */
+static void
+playback_on_process(void *data)
+{
+ PWVoice *v = (PWVoice *) data;
+ void *p;
+ struct pw_buffer *b;
+ struct spa_buffer *buf;
+ uint32_t n_frames, req, index, n_bytes;
+ int32_t avail;
+
+ if (!v->stream) {
+ return;
+ }
+
+ /* obtain a buffer to read from */
+ b = pw_stream_dequeue_buffer(v->stream);
+ if (b == NULL) {
+ error_report("out of buffers: %s", strerror(errno));
+ return;
+ }
+
+ buf = b->buffer;
+ p = buf->datas[0].data;
+ if (p == NULL) {
+ return;
+ }
+ req = b->requested * v->frame_size;
+ if (req == 0) {
+ req = 4096 * v->frame_size;
+ }
+ n_frames = SPA_MIN(req, buf->datas[0].maxsize);
+ n_bytes = n_frames * v->frame_size;
+
+ /* get no of available bytes to read data from buffer */
+
+ avail = spa_ringbuffer_get_read_index(&v->ring, &index);
+
+ if (!v->enabled) {
+ avail = 0;
+ }
+
+ if (avail == 0) {
+ memset(p, 0, n_bytes);
+ } else {
+ if (avail < (int32_t) n_bytes) {
+ n_bytes = avail;
+ }
+
+ spa_ringbuffer_read_data(&v->ring,
+ v->buffer, RINGBUFFER_SIZE,
+ index & RINGBUFFER_MASK, p, n_bytes);
+
+ index += n_bytes;
+ spa_ringbuffer_read_update(&v->ring, index);
+ }
+
+ buf->datas[0].chunk->offset = 0;
+ buf->datas[0].chunk->stride = v->frame_size;
+ buf->datas[0].chunk->size = n_bytes;
+
+ /* queue the buffer for playback */
+ pw_stream_queue_buffer(v->stream, b);
+}
+