+/* 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);
memset() doesn't work for unsigned samples. For unsigned samples, a stream of zeros is silence with a DC offset. When Pipewire mixes this stream with another, the result is a clipped audio stream. To hear this, start QEMU with qemu-system-x86_64 -machine pcspk-audiodev=audio0 -device ich9-intel-hda -device hda-duplex,audiodev=audio0 -audiodev pipewire,id=audio0,out.mixing-engine=off ... and start playback with the hda device.
With best regards, Volker
+ } 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); +} +