Fixed bug in circular buffer management inside linux output stream driver, added unit test for circular buffer mode.
TG-220
This commit is contained in:
parent
58c1c3bbd6
commit
adbd1f070d
|
|
@ -47,27 +47,38 @@ static enum BufMode buf_mode; // Buffer operation mode
|
||||||
static stream_sample_t *buf = NULL; // Playback buffer
|
static stream_sample_t *buf = NULL; // Playback buffer
|
||||||
static size_t buf_len = 0; // Buffer length
|
static size_t buf_len = 0; // Buffer length
|
||||||
static bool first_half_active = true; // Circular addressing mode flag
|
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)
|
static void buf_circ_write_cb(pa_stream *s, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
(void) userdata;
|
(void) userdata;
|
||||||
// TODO: We can play length more bytes of data
|
size_t remaining = 0;
|
||||||
// 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;
|
|
||||||
|
|
||||||
if (!s || length <= 0)
|
if (!s || length <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pa_stream_begin_write(s, (void **) &active_buf, &active_buf_len) < 0)
|
if (offset >= buf_len / 2)
|
||||||
{
|
first_half_active = false;
|
||||||
fprintf(stderr, "pa_stream_begin_write() failed: %s", pa_strerror(pa_context_errno(p->context)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
streamId outputStream_start(const enum AudioSink destination,
|
||||||
|
|
@ -124,6 +135,12 @@ streamId outputStream_start(const enum AudioSink destination,
|
||||||
{
|
{
|
||||||
assert(p->stream && "Invalid PulseAudio Stream!");
|
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
|
// Register write callback
|
||||||
pa_stream_set_write_callback(p->stream, buf_circ_write_cb, NULL);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = false;
|
if (buf_mode == BUF_LINEAR)
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <interfaces/audio_stream.h>
|
#include <interfaces/audio_stream.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define BUF_LEN 4096 * 10
|
#define BUF_LEN 4096 * 10
|
||||||
#define AMPLITUDE 20000
|
#define AMPLITUDE 20000
|
||||||
|
|
@ -37,16 +38,21 @@
|
||||||
|
|
||||||
int16_t buffer[BUF_LEN] = { 0 };
|
int16_t buffer[BUF_LEN] = { 0 };
|
||||||
|
|
||||||
int main()
|
void fill_buffer_sine(int16_t *buffer, size_t len)
|
||||||
{
|
{
|
||||||
int id = 0;
|
for(size_t i = 0; i < len; i++)
|
||||||
|
|
||||||
// Create 440 Hz sine wave
|
|
||||||
for(int i = 0; i < BUF_LEN; i++)
|
|
||||||
{
|
{
|
||||||
buffer[i] = AMPLITUDE * sin(2 * PI * i *
|
buffer[i] = AMPLITUDE * sin(2 * PI * i *
|
||||||
((float) FREQUENCY / SAMPLE_RATE));
|
((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
|
// Play back sine wave
|
||||||
for(int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
|
|
@ -64,3 +70,37 @@ int main()
|
||||||
outputStream_stop(id);
|
outputStream_stop(id);
|
||||||
outputStream_terminate(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();
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue