kopia lustrzana https://github.com/OpenRTX/OpenRTX
Fixed bug in circular buffer management inside linux output stream driver, added unit test for circular buffer mode.
TG-220md1702
rodzic
58c1c3bbd6
commit
adbd1f070d
|
@ -47,27 +47,38 @@ static enum BufMode buf_mode; // Buffer operation mode
|
|||
static stream_sample_t *buf = NULL; // Playback buffer
|
||||
static size_t buf_len = 0; // Buffer length
|
||||
static bool first_half_active = true; // Circular addressing mode flag
|
||||
static size_t offset = 0; // Playback offset
|
||||
|
||||
static void buf_circ_write_cb(pa_stream *s, size_t length, void *userdata)
|
||||
{
|
||||
(void) userdata;
|
||||
// TODO: We can play length more bytes of data
|
||||
// Start playback of the other half
|
||||
stream_sample_t *active_buf = (first_half_active) ?
|
||||
buf : buf + buf_len / 2;
|
||||
first_half_active = !first_half_active;
|
||||
size_t active_buf_len = buf_len / 2;
|
||||
size_t remaining = 0;
|
||||
|
||||
if (!s || length <= 0)
|
||||
return;
|
||||
|
||||
if (pa_stream_begin_write(s, (void **) &active_buf, &active_buf_len) < 0)
|
||||
{
|
||||
fprintf(stderr, "pa_stream_begin_write() failed: %s", pa_strerror(pa_context_errno(p->context)));
|
||||
return;
|
||||
}
|
||||
if (offset >= buf_len / 2)
|
||||
first_half_active = false;
|
||||
|
||||
pa_stream_write(s, active_buf, active_buf_len, NULL, 0, PA_SEEK_RELATIVE);
|
||||
remaining = buf_len - offset;
|
||||
|
||||
// We can play all the rest of the buffer
|
||||
if (length > remaining)
|
||||
{
|
||||
pa_stream_write(s, buf + offset, remaining, NULL, 0, PA_SEEK_RELATIVE);
|
||||
|
||||
if(first_half_active == true)
|
||||
first_half_active = false;
|
||||
else
|
||||
first_half_active = true;
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pa_stream_write(s, buf + offset, length, NULL, 0, PA_SEEK_RELATIVE);
|
||||
offset += length;
|
||||
}
|
||||
}
|
||||
|
||||
streamId outputStream_start(const enum AudioSink destination,
|
||||
|
@ -124,6 +135,12 @@ streamId outputStream_start(const enum AudioSink destination,
|
|||
{
|
||||
assert(p->stream && "Invalid PulseAudio Stream!");
|
||||
|
||||
if (pa_simple_write(p, buf, length / 2, &error) < 0) {
|
||||
fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
offset = length / 2;
|
||||
|
||||
// Register write callback
|
||||
pa_stream_set_write_callback(p->stream, buf_circ_write_cb, NULL);
|
||||
}
|
||||
|
@ -155,7 +172,10 @@ bool outputStream_sync(const streamId id, const bool bufChanged)
|
|||
return false;
|
||||
}
|
||||
|
||||
running = false;
|
||||
if (buf_mode == BUF_LINEAR)
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <interfaces/audio_stream.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define BUF_LEN 4096 * 10
|
||||
#define AMPLITUDE 20000
|
||||
|
@ -37,16 +38,21 @@
|
|||
|
||||
int16_t buffer[BUF_LEN] = { 0 };
|
||||
|
||||
int main()
|
||||
void fill_buffer_sine(int16_t *buffer, size_t len)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
// Create 440 Hz sine wave
|
||||
for(int i = 0; i < BUF_LEN; i++)
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
buffer[i] = AMPLITUDE * sin(2 * PI * i *
|
||||
((float) FREQUENCY / SAMPLE_RATE));
|
||||
}
|
||||
}
|
||||
|
||||
void play_sine_linear()
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
// Create 440 Hz sine wave
|
||||
fill_buffer_sine(buffer, BUF_LEN);
|
||||
|
||||
// Play back sine wave
|
||||
for(int i = 0; i < 10; i++)
|
||||
|
@ -64,3 +70,37 @@ int main()
|
|||
outputStream_stop(id);
|
||||
outputStream_terminate(id);
|
||||
}
|
||||
|
||||
void play_sine_circular()
|
||||
{
|
||||
int id = 0;
|
||||
stream_sample_t *buf = NULL;
|
||||
|
||||
// Fill first half of buffer with sine
|
||||
fill_buffer_sine(buffer, BUF_LEN / 2);
|
||||
|
||||
// Play back sine wave
|
||||
id = outputStream_start(SINK_SPK,
|
||||
PRIO_PROMPT,
|
||||
buffer,
|
||||
BUF_LEN,
|
||||
BUF_CIRC_DOUBLE,
|
||||
SAMPLE_RATE);
|
||||
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
buf = outputStream_getIdleBuffer(id);
|
||||
fill_buffer_sine(buf, BUF_LEN / 2);
|
||||
outputStream_sync(id, true);
|
||||
}
|
||||
|
||||
// Sync, flush, terminate
|
||||
outputStream_stop(id);
|
||||
outputStream_terminate(id);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
//play_sine_linear();
|
||||
play_sine_circular();
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue