mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 23:25:34 +00:00
add and export a ring buffer implementation
This commit is contained in:
parent
dc05a82c28
commit
a69ff6025c
|
@ -51,8 +51,8 @@ set(LIBSOUNDIO_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/src/util.cpp"
|
"${CMAKE_SOURCE_DIR}/src/util.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/dummy.cpp"
|
"${CMAKE_SOURCE_DIR}/src/dummy.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/dummy_ring_buffer.cpp"
|
|
||||||
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
||||||
|
"${CMAKE_SOURCE_DIR}/src/ring_buffer.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
|
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
|
||||||
|
@ -67,8 +67,8 @@ set(TEST_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/soundio.cpp"
|
"${CMAKE_SOURCE_DIR}/src/soundio.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/dummy.cpp"
|
"${CMAKE_SOURCE_DIR}/src/dummy.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/dummy_ring_buffer.cpp"
|
|
||||||
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
||||||
|
"${CMAKE_SOURCE_DIR}/src/ring_buffer.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(SOUNDIO_HAVE_PULSEAUDIO)
|
if(SOUNDIO_HAVE_PULSEAUDIO)
|
||||||
|
@ -152,6 +152,13 @@ set_target_properties(list_devices PROPERTIES
|
||||||
include_directories(${EXAMPLE_INCLUDES})
|
include_directories(${EXAMPLE_INCLUDES})
|
||||||
target_link_libraries(list_devices libsoundio_shared)
|
target_link_libraries(list_devices libsoundio_shared)
|
||||||
|
|
||||||
|
add_executable(microphone example/microphone.c)
|
||||||
|
set_target_properties(microphone PROPERTIES
|
||||||
|
LINKER_LANGUAGE C
|
||||||
|
COMPILE_FLAGS ${EXAMPLE_CFLAGS})
|
||||||
|
include_directories(${EXAMPLE_INCLUDES})
|
||||||
|
target_link_libraries(microphone libsoundio_shared)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
97
example/microphone.c
Normal file
97
example/microphone.c
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of libsoundio, which is MIT licensed.
|
||||||
|
* See http://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <soundio.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
__attribute__ ((cold))
|
||||||
|
__attribute__ ((noreturn))
|
||||||
|
__attribute__ ((format (printf, 1, 2)))
|
||||||
|
static void panic(const char *format, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
vfprintf(stderr, format, ap);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_callback(struct SoundIoInputDevice *input_device) {
|
||||||
|
fprintf(stderr, "read_callback\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_callback(struct SoundIoOutputDevice *output_device, int requested_frame_count) {
|
||||||
|
fprintf(stderr, "write_callback\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void underrun_callback(struct SoundIoOutputDevice *output_device) {
|
||||||
|
static int count = 0;
|
||||||
|
fprintf(stderr, "underrun %d\n", count++);
|
||||||
|
soundio_output_device_fill_with_silence(output_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
struct SoundIo *soundio = soundio_create();
|
||||||
|
if (!soundio)
|
||||||
|
panic("out of memory");
|
||||||
|
|
||||||
|
int err;
|
||||||
|
if ((err = soundio_connect(soundio)))
|
||||||
|
panic("error connecting: %s", soundio_error_string(err));
|
||||||
|
|
||||||
|
int default_out_device_index = soundio_get_default_output_device_index(soundio);
|
||||||
|
if (default_out_device_index < 0)
|
||||||
|
panic("no output device found");
|
||||||
|
|
||||||
|
int default_in_device_index = soundio_get_default_output_device_index(soundio);
|
||||||
|
if (default_in_device_index < 0)
|
||||||
|
panic("no output device found");
|
||||||
|
|
||||||
|
struct SoundIoDevice *out_device = soundio_get_output_device(soundio, default_out_device_index);
|
||||||
|
if (!out_device)
|
||||||
|
panic("could not get output device: out of memory");
|
||||||
|
|
||||||
|
struct SoundIoDevice *in_device = soundio_get_input_device(soundio, default_in_device_index);
|
||||||
|
if (!in_device)
|
||||||
|
panic("could not get input device: out of memory");
|
||||||
|
|
||||||
|
fprintf(stderr, "Input device: %s: %s\n",
|
||||||
|
soundio_device_name(in_device),
|
||||||
|
soundio_device_description(in_device));
|
||||||
|
fprintf(stderr, "Output device: %s: %s\n",
|
||||||
|
soundio_device_name(out_device),
|
||||||
|
soundio_device_description(out_device));
|
||||||
|
|
||||||
|
struct SoundIoInputDevice *input_device;
|
||||||
|
soundio_input_device_create(in_device, SoundIoSampleFormatFloat, 0.1, NULL,
|
||||||
|
read_callback, &input_device);
|
||||||
|
|
||||||
|
struct SoundIoOutputDevice *output_device;
|
||||||
|
soundio_output_device_create(out_device, SoundIoSampleFormatFloat, 0.1, NULL,
|
||||||
|
write_callback, underrun_callback, &output_device);
|
||||||
|
|
||||||
|
if ((err = soundio_input_device_start(input_device)))
|
||||||
|
panic("unable to start input device: %s", soundio_error_string(err));
|
||||||
|
|
||||||
|
if ((err = soundio_output_device_start(output_device)))
|
||||||
|
panic("unable to start output device: %s", soundio_error_string(err));
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
soundio_wait_events(soundio);
|
||||||
|
|
||||||
|
soundio_output_device_destroy(output_device);
|
||||||
|
soundio_input_device_destroy(input_device);
|
||||||
|
soundio_device_unref(in_device);
|
||||||
|
soundio_device_unref(out_device);
|
||||||
|
soundio_destroy(soundio);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -3,10 +3,15 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
using std::atomic_flag;
|
using std::atomic_flag;
|
||||||
|
using std::atomic_int;
|
||||||
using std::atomic_long;
|
using std::atomic_long;
|
||||||
using std::atomic_bool;
|
using std::atomic_bool;
|
||||||
using std::atomic_uintptr_t;
|
using std::atomic_uintptr_t;
|
||||||
|
|
||||||
|
#if ATOMIC_INT_LOCK_FREE != 2
|
||||||
|
#error "require atomic_int to be lock free"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ATOMIC_LONG_LOCK_FREE != 2
|
#if ATOMIC_LONG_LOCK_FREE != 2
|
||||||
#error "require atomic_long to be lock free"
|
#error "require atomic_long to be lock free"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
#include "dummy.hpp"
|
#include "dummy.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "dummy_ring_buffer.hpp"
|
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
#include "atomics.hpp"
|
#include "atomics.hpp"
|
||||||
|
#include "ring_buffer.hpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -20,7 +20,7 @@ struct SoundIoOutputDeviceDummy {
|
||||||
atomic_flag abort_flag;
|
atomic_flag abort_flag;
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
double period;
|
double period;
|
||||||
struct SoundIoDummyRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInputDeviceDummy {
|
struct SoundIoInputDeviceDummy {
|
||||||
|
@ -49,12 +49,12 @@ static void playback_thread_run(void *arg) {
|
||||||
double total_time = now - start_time;
|
double total_time = now - start_time;
|
||||||
long total_frames = total_time / time_per_frame;
|
long total_frames = total_time / time_per_frame;
|
||||||
int frames_to_kill = total_frames - frames_consumed;
|
int frames_to_kill = total_frames - frames_consumed;
|
||||||
int fill_count = soundio_dummy_ring_buffer_fill_count(&opd->ring_buffer);
|
int fill_count = soundio_ring_buffer_fill_count(&opd->ring_buffer);
|
||||||
int frames_in_buffer = fill_count / output_device->bytes_per_frame;
|
int frames_in_buffer = fill_count / output_device->bytes_per_frame;
|
||||||
int read_count = min(frames_to_kill, frames_in_buffer);
|
int read_count = min(frames_to_kill, frames_in_buffer);
|
||||||
int frames_left = frames_to_kill - read_count;
|
int frames_left = frames_to_kill - read_count;
|
||||||
int byte_count = read_count * output_device->bytes_per_frame;
|
int byte_count = read_count * output_device->bytes_per_frame;
|
||||||
soundio_dummy_ring_buffer_advance_read_ptr(&opd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_read_ptr(&opd->ring_buffer, byte_count);
|
||||||
frames_consumed += read_count;
|
frames_consumed += read_count;
|
||||||
|
|
||||||
if (frames_left > 0) {
|
if (frames_left > 0) {
|
||||||
|
@ -128,7 +128,7 @@ static void output_device_destroy_dummy(SoundIo *soundio,
|
||||||
soundio_os_cond_destroy(opd->cond);
|
soundio_os_cond_destroy(opd->cond);
|
||||||
opd->cond = nullptr;
|
opd->cond = nullptr;
|
||||||
|
|
||||||
soundio_dummy_ring_buffer_deinit(&opd->ring_buffer);
|
soundio_ring_buffer_deinit(&opd->ring_buffer);
|
||||||
|
|
||||||
destroy(opd);
|
destroy(opd);
|
||||||
output_device->backend_data = nullptr;
|
output_device->backend_data = nullptr;
|
||||||
|
@ -150,7 +150,7 @@ static int output_device_init_dummy(SoundIo *soundio,
|
||||||
opd->buffer_size = output_device->bytes_per_frame * buffer_frame_count;
|
opd->buffer_size = output_device->bytes_per_frame * buffer_frame_count;
|
||||||
opd->period = output_device->latency * 0.5;
|
opd->period = output_device->latency * 0.5;
|
||||||
|
|
||||||
soundio_dummy_ring_buffer_init(&opd->ring_buffer, opd->buffer_size);
|
soundio_ring_buffer_init(&opd->ring_buffer, opd->buffer_size);
|
||||||
|
|
||||||
opd->cond = soundio_os_cond_create();
|
opd->cond = soundio_os_cond_create();
|
||||||
if (!opd->cond) {
|
if (!opd->cond) {
|
||||||
|
@ -167,7 +167,7 @@ static int output_device_start_dummy(SoundIo *soundio,
|
||||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||||
|
|
||||||
soundio_output_device_fill_with_silence(output_device);
|
soundio_output_device_fill_with_silence(output_device);
|
||||||
assert(soundio_dummy_ring_buffer_fill_count(&opd->ring_buffer) == opd->buffer_size);
|
assert(soundio_ring_buffer_fill_count(&opd->ring_buffer) == opd->buffer_size);
|
||||||
|
|
||||||
opd->abort_flag.test_and_set();
|
opd->abort_flag.test_and_set();
|
||||||
int err;
|
int err;
|
||||||
|
@ -182,7 +182,7 @@ static int output_device_free_count_dummy(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||||
int fill_count = soundio_dummy_ring_buffer_fill_count(&opd->ring_buffer);
|
int fill_count = soundio_ring_buffer_fill_count(&opd->ring_buffer);
|
||||||
int bytes_free_count = opd->buffer_size - fill_count;
|
int bytes_free_count = opd->buffer_size - fill_count;
|
||||||
return bytes_free_count / output_device->bytes_per_frame;
|
return bytes_free_count / output_device->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
@ -203,14 +203,14 @@ static void output_device_write_dummy(SoundIo *soundio,
|
||||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||||
assert(data == opd->ring_buffer.address);
|
assert(data == opd->ring_buffer.address);
|
||||||
int byte_count = frame_count * output_device->bytes_per_frame;
|
int byte_count = frame_count * output_device->bytes_per_frame;
|
||||||
soundio_dummy_ring_buffer_advance_write_ptr(&opd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_write_ptr(&opd->ring_buffer, byte_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_device_clear_buffer_dummy(SoundIo *soundio,
|
static void output_device_clear_buffer_dummy(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||||
soundio_dummy_ring_buffer_clear(&opd->ring_buffer);
|
soundio_ring_buffer_clear(&opd->ring_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int input_device_init_dummy(SoundIo *soundio,
|
static int input_device_init_dummy(SoundIo *soundio,
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
#include "dummy_ring_buffer.hpp"
|
|
||||||
#include "soundio.hpp"
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
int soundio_dummy_ring_buffer_create(int requested_capacity, struct SoundIoDummyRingBuffer **out) {
|
|
||||||
*out = nullptr;
|
|
||||||
SoundIoDummyRingBuffer *rb = create<SoundIoDummyRingBuffer>();
|
|
||||||
|
|
||||||
if (!rb) {
|
|
||||||
soundio_dummy_ring_buffer_destroy(rb);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
|
|
||||||
int err;
|
|
||||||
if ((err = soundio_dummy_ring_buffer_init(rb, requested_capacity))) {
|
|
||||||
soundio_dummy_ring_buffer_destroy(rb);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = rb;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundio_dummy_ring_buffer_init(struct SoundIoDummyRingBuffer *rb, int requested_capacity) {
|
|
||||||
// round size up to the nearest power of two
|
|
||||||
rb->capacity = powf(2, ceilf(log2(requested_capacity)));
|
|
||||||
|
|
||||||
rb->address = allocate_nonzero<char>(rb->capacity);
|
|
||||||
if (!rb->address) {
|
|
||||||
soundio_dummy_ring_buffer_deinit(rb);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void soundio_dummy_ring_buffer_destroy(struct SoundIoDummyRingBuffer *rb) {
|
|
||||||
if (!rb)
|
|
||||||
return;
|
|
||||||
|
|
||||||
soundio_dummy_ring_buffer_deinit(rb);
|
|
||||||
|
|
||||||
destroy(rb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void soundio_dummy_ring_buffer_deinit(struct SoundIoDummyRingBuffer *rb) {
|
|
||||||
deallocate(rb->address, rb->capacity);
|
|
||||||
rb->address = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void soundio_dummy_ring_buffer_clear(struct SoundIoDummyRingBuffer *rb) {
|
|
||||||
rb->write_offset.store(rb->read_offset.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundio_dummy_ring_buffer_free_count(struct SoundIoDummyRingBuffer *rb) {
|
|
||||||
return rb->capacity - soundio_dummy_ring_buffer_fill_count(rb);
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundio_dummy_ring_buffer_fill_count(struct SoundIoDummyRingBuffer *rb) {
|
|
||||||
int count = rb->write_offset - rb->read_offset;
|
|
||||||
assert(count >= 0);
|
|
||||||
assert(count <= rb->capacity);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void soundio_dummy_ring_buffer_advance_write_ptr(struct SoundIoDummyRingBuffer *rb, int count) {
|
|
||||||
rb->write_offset += count;
|
|
||||||
assert(soundio_dummy_ring_buffer_fill_count(rb) >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void soundio_dummy_ring_buffer_advance_read_ptr(struct SoundIoDummyRingBuffer *rb, int count) {
|
|
||||||
rb->read_offset += count;
|
|
||||||
assert(soundio_dummy_ring_buffer_fill_count(rb) >= 0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef SOUNDIO_DUMMY_RING_BUFFER_HPP
|
|
||||||
#define SOUNDIO_DUMMY_RING_BUFFER_HPP
|
|
||||||
|
|
||||||
#include "util.hpp"
|
|
||||||
#include "atomics.hpp"
|
|
||||||
|
|
||||||
struct SoundIoDummyRingBuffer {
|
|
||||||
char *address;
|
|
||||||
long capacity;
|
|
||||||
atomic_long write_offset;
|
|
||||||
atomic_long read_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
int soundio_dummy_ring_buffer_create(int requested_capacity, struct SoundIoDummyRingBuffer **out);
|
|
||||||
void soundio_dummy_ring_buffer_destroy(struct SoundIoDummyRingBuffer *rb);
|
|
||||||
int soundio_dummy_ring_buffer_init(struct SoundIoDummyRingBuffer *rb, int requested_capacity);
|
|
||||||
void soundio_dummy_ring_buffer_deinit(struct SoundIoDummyRingBuffer *rb);
|
|
||||||
|
|
||||||
// must be called by the writer
|
|
||||||
void soundio_dummy_ring_buffer_clear(struct SoundIoDummyRingBuffer *rb);
|
|
||||||
|
|
||||||
|
|
||||||
// how much is available, ready for writing
|
|
||||||
int soundio_dummy_ring_buffer_free_count(struct SoundIoDummyRingBuffer *rb);
|
|
||||||
|
|
||||||
// how much of the buffer is used, ready for reading
|
|
||||||
int soundio_dummy_ring_buffer_fill_count(struct SoundIoDummyRingBuffer *rb);
|
|
||||||
|
|
||||||
void soundio_dummy_ring_buffer_advance_write_ptr(struct SoundIoDummyRingBuffer *rb, int count);
|
|
||||||
void soundio_dummy_ring_buffer_advance_read_ptr(struct SoundIoDummyRingBuffer *rb, int count);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -720,7 +720,8 @@ static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
ord->stream_ready = true;
|
ord->stream_ready = true;
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_FAILED:
|
case PA_STREAM_FAILED:
|
||||||
soundio_panic("pulseaudio stream error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
|
soundio_panic("pulseaudio stream error: %s",
|
||||||
|
pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -730,10 +731,39 @@ static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, voi
|
||||||
input_device->read_callback(input_device);
|
input_device->read_callback(input_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int input_device_init_pa(SoundIo *soundio,
|
static void input_device_destroy_pa(SoundIo *soundio,
|
||||||
SoundIoInputDevice *input_device)
|
SoundIoInputDevice *input_device)
|
||||||
{
|
{
|
||||||
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
||||||
|
if (!ord)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
pa_stream *stream = ord->stream;
|
||||||
|
if (stream) {
|
||||||
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
||||||
|
pa_stream_set_read_callback(stream, nullptr, nullptr);
|
||||||
|
pa_stream_disconnect(stream);
|
||||||
|
pa_stream_unref(stream);
|
||||||
|
|
||||||
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
|
ord->stream = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int input_device_init_pa(SoundIo *soundio,
|
||||||
|
SoundIoInputDevice *input_device)
|
||||||
|
{
|
||||||
|
SoundIoInputDevicePulseAudio *ord = create<SoundIoInputDevicePulseAudio>();
|
||||||
|
if (!ord) {
|
||||||
|
input_device_destroy_pa(soundio, input_device);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
input_device->backend_data = ord;
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
SoundIoDevice *device = input_device->device;
|
SoundIoDevice *device = input_device->device;
|
||||||
ord->stream_ready = false;
|
ord->stream_ready = false;
|
||||||
|
@ -750,6 +780,7 @@ static int input_device_init_pa(SoundIo *soundio,
|
||||||
ord->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
ord->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
||||||
if (!input_device) {
|
if (!input_device) {
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
input_device_destroy_pa(soundio, input_device);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,26 +804,6 @@ static int input_device_init_pa(SoundIo *soundio,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_device_destroy_pa(SoundIo *soundio,
|
|
||||||
SoundIoInputDevice *input_device)
|
|
||||||
{
|
|
||||||
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
|
||||||
pa_stream *stream = ord->stream;
|
|
||||||
if (stream) {
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
|
||||||
|
|
||||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
|
||||||
pa_stream_set_read_callback(stream, nullptr, nullptr);
|
|
||||||
pa_stream_disconnect(stream);
|
|
||||||
pa_stream_unref(stream);
|
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
|
||||||
|
|
||||||
ord->stream = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int input_device_start_pa(SoundIo *soundio,
|
static int input_device_start_pa(SoundIo *soundio,
|
||||||
SoundIoInputDevice *input_device)
|
SoundIoInputDevice *input_device)
|
||||||
{
|
{
|
||||||
|
|
125
src/ring_buffer.cpp
Normal file
125
src/ring_buffer.cpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of libsoundio, which is MIT licensed.
|
||||||
|
* See http://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ring_buffer.hpp"
|
||||||
|
#include "soundio.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) {
|
||||||
|
SoundIoRingBuffer *rb = create<SoundIoRingBuffer>();
|
||||||
|
|
||||||
|
if (!rb) {
|
||||||
|
soundio_ring_buffer_destroy(rb);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (soundio_ring_buffer_init(rb, requested_capacity)) {
|
||||||
|
soundio_ring_buffer_destroy(rb);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundio_ring_buffer_destroy(struct SoundIoRingBuffer *rb) {
|
||||||
|
if (!rb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
soundio_ring_buffer_deinit(rb);
|
||||||
|
|
||||||
|
destroy(rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int soundio_ring_buffer_capacity(struct SoundIoRingBuffer *rb) {
|
||||||
|
return rb->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *rb) {
|
||||||
|
return rb->address + (rb->write_offset % rb->capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *rb, int count) {
|
||||||
|
rb->write_offset += count;
|
||||||
|
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *rb) {
|
||||||
|
return rb->address + (rb->read_offset % rb->capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *rb, int count) {
|
||||||
|
rb->read_offset += count;
|
||||||
|
assert(soundio_ring_buffer_fill_count(rb) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *rb) {
|
||||||
|
int count = rb->write_offset - rb->read_offset;
|
||||||
|
assert(count >= 0);
|
||||||
|
assert(count <= rb->capacity);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *rb) {
|
||||||
|
return rb->capacity - soundio_ring_buffer_fill_count(rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundio_ring_buffer_clear(struct SoundIoRingBuffer *rb) {
|
||||||
|
return rb->write_offset.store(rb->read_offset.load());
|
||||||
|
}
|
||||||
|
|
||||||
|
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity) {
|
||||||
|
// round size up to the nearest power of two
|
||||||
|
int pow2_size = powf(2, ceilf(log2(requested_capacity)));
|
||||||
|
// at minimum must be page size
|
||||||
|
int page_size = getpagesize();
|
||||||
|
rb->capacity = max(pow2_size, page_size);
|
||||||
|
|
||||||
|
rb->write_offset = 0;
|
||||||
|
rb->read_offset = 0;
|
||||||
|
|
||||||
|
char shm_path[] = "/dev/shm/ring-buffer-XXXXXX";
|
||||||
|
int fd = mkstemp(shm_path);
|
||||||
|
if (fd < 0)
|
||||||
|
return SoundIoErrorSystemResources;
|
||||||
|
|
||||||
|
if (unlink(shm_path))
|
||||||
|
return SoundIoErrorSystemResources;
|
||||||
|
|
||||||
|
if (ftruncate(fd, rb->capacity))
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
rb->address = (char*)mmap(NULL, rb->capacity * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (rb->address == MAP_FAILED)
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
char *other_address = (char*)mmap(rb->address, rb->capacity,
|
||||||
|
PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
|
||||||
|
if (other_address != rb->address)
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
other_address = (char*)mmap(rb->address + rb->capacity, rb->capacity,
|
||||||
|
PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
|
||||||
|
if (other_address != rb->address + rb->capacity)
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
|
||||||
|
if (close(fd))
|
||||||
|
return SoundIoErrorSystemResources;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundio_ring_buffer_deinit(struct SoundIoRingBuffer *rb) {
|
||||||
|
if (munmap(rb->address, 2 * rb->capacity))
|
||||||
|
soundio_panic("munmap failed: %s", strerror(errno));
|
||||||
|
}
|
23
src/ring_buffer.hpp
Normal file
23
src/ring_buffer.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of libsoundio, which is MIT licensed.
|
||||||
|
* See http://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOUNDIO_RING_BUFFER_HPP
|
||||||
|
#define SOUNDIO_RING_BUFFER_HPP
|
||||||
|
|
||||||
|
#include "atomics.hpp"
|
||||||
|
|
||||||
|
struct SoundIoRingBuffer {
|
||||||
|
char *address;
|
||||||
|
long capacity;
|
||||||
|
atomic_long write_offset;
|
||||||
|
atomic_long read_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
int soundio_ring_buffer_init(struct SoundIoRingBuffer *rb, int requested_capacity);
|
||||||
|
void soundio_ring_buffer_deinit(struct SoundIoRingBuffer *rb);
|
||||||
|
|
||||||
|
#endif
|
|
@ -336,3 +336,54 @@ int soundio_output_device_start(struct SoundIoOutputDevice *output_device) {
|
||||||
SoundIo *soundio = output_device->device->soundio;
|
SoundIo *soundio = output_device->device->soundio;
|
||||||
return soundio->output_device_start(soundio, output_device);
|
return soundio->output_device_start(soundio, output_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int soundio_input_device_create(struct SoundIoDevice *device,
|
||||||
|
enum SoundIoSampleFormat sample_format, double latency, void *userdata,
|
||||||
|
void (*read_callback)(struct SoundIoInputDevice *),
|
||||||
|
struct SoundIoInputDevice **out_input_device)
|
||||||
|
{
|
||||||
|
*out_input_device = nullptr;
|
||||||
|
|
||||||
|
SoundIoInputDevice *sid = create<SoundIoInputDevice>();
|
||||||
|
if (!sid) {
|
||||||
|
soundio_input_device_destroy(sid);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
soundio_device_ref(device);
|
||||||
|
sid->device = device;
|
||||||
|
sid->userdata = userdata;
|
||||||
|
sid->read_callback = read_callback;
|
||||||
|
sid->sample_format = sample_format;
|
||||||
|
sid->latency = latency;
|
||||||
|
sid->bytes_per_frame = soundio_get_bytes_per_frame(sample_format,
|
||||||
|
device->channel_layout.channel_count);
|
||||||
|
|
||||||
|
SoundIo *soundio = device->soundio;
|
||||||
|
int err = soundio->input_device_init(soundio, sid);
|
||||||
|
if (err) {
|
||||||
|
soundio_input_device_destroy(sid);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_input_device = sid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int soundio_input_device_start(struct SoundIoInputDevice *input_device) {
|
||||||
|
SoundIo *soundio = input_device->device->soundio;
|
||||||
|
return soundio->input_device_start(soundio, input_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundio_input_device_destroy(struct SoundIoInputDevice *input_device) {
|
||||||
|
if (!input_device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SoundIo *soundio = input_device->device->soundio;
|
||||||
|
|
||||||
|
if (soundio->input_device_destroy)
|
||||||
|
soundio->input_device_destroy(soundio, input_device);
|
||||||
|
|
||||||
|
soundio_device_unref(input_device->device);
|
||||||
|
destroy(input_device);
|
||||||
|
}
|
||||||
|
|
|
@ -309,16 +309,41 @@ void soundio_output_device_clear_buffer(struct SoundIoOutputDevice *output_devic
|
||||||
|
|
||||||
int soundio_input_device_create(struct SoundIoDevice *device,
|
int soundio_input_device_create(struct SoundIoDevice *device,
|
||||||
enum SoundIoSampleFormat sample_format, double latency, void *userdata,
|
enum SoundIoSampleFormat sample_format, double latency, void *userdata,
|
||||||
void (*read_callback)(struct SoundIoOutputDevice *),
|
void (*read_callback)(struct SoundIoInputDevice *),
|
||||||
struct SoundIoOutputDevice **out_input_device);
|
struct SoundIoInputDevice **out_input_device);
|
||||||
void soundio_input_device_destroy(struct SoundIoOutputDevice *input_device);
|
void soundio_input_device_destroy(struct SoundIoInputDevice *input_device);
|
||||||
|
|
||||||
int soundio_input_device_start(struct SoundIoOutputDevice *input_device);
|
int soundio_input_device_start(struct SoundIoInputDevice *input_device);
|
||||||
void soundio_input_device_peek(struct SoundIoOutputDevice *input_device,
|
void soundio_input_device_peek(struct SoundIoInputDevice *input_device,
|
||||||
const char **data, int *frame_count);
|
const char **data, int *frame_count);
|
||||||
void soundio_input_device_drop(struct SoundIoOutputDevice *input_device);
|
void soundio_input_device_drop(struct SoundIoInputDevice *input_device);
|
||||||
|
|
||||||
|
void soundio_input_device_clear_buffer(struct SoundIoInputDevice *input_device);
|
||||||
|
|
||||||
|
|
||||||
|
// Ring Buffer
|
||||||
|
struct SoundIoRingBuffer;
|
||||||
|
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity);
|
||||||
|
void soundio_ring_buffer_destroy(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
int soundio_ring_buffer_capacity(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
|
||||||
|
// don't write more than capacity
|
||||||
|
char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *ring_buffer, int count);
|
||||||
|
|
||||||
|
// don't read more than capacity
|
||||||
|
char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *ring_buffer, int count);
|
||||||
|
|
||||||
|
// how much of the buffer is used, ready for reading
|
||||||
|
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
|
||||||
|
// how much is available, ready for writing
|
||||||
|
int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
|
||||||
|
// must be called by the writer
|
||||||
|
void soundio_ring_buffer_clear(struct SoundIoRingBuffer *ring_buffer);
|
||||||
|
|
||||||
void soundio_input_device_clear_buffer(struct SoundIoOutputDevice *input_device);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
|
|
||||||
#include "soundio.h"
|
#include "soundio.hpp"
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
#include "atomics.hpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -43,6 +44,116 @@ static void test_create_output_device(void) {
|
||||||
soundio_destroy(soundio);
|
soundio_destroy(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void test_ring_buffer_basic(void) {
|
||||||
|
struct SoundIo *soundio = soundio_create();
|
||||||
|
assert(soundio);
|
||||||
|
SoundIoRingBuffer *rb = soundio_ring_buffer_create(soundio, 10);
|
||||||
|
assert(rb);
|
||||||
|
|
||||||
|
assert(soundio_ring_buffer_capacity(rb) == 4096);
|
||||||
|
|
||||||
|
char *write_ptr = soundio_ring_buffer_write_ptr(rb);
|
||||||
|
int amt = sprintf(write_ptr, "hello") + 1;
|
||||||
|
soundio_ring_buffer_advance_write_ptr(rb, amt);
|
||||||
|
|
||||||
|
assert(soundio_ring_buffer_fill_count(rb) == amt);
|
||||||
|
assert(soundio_ring_buffer_free_count(rb) == 4096 - amt);
|
||||||
|
|
||||||
|
char *read_ptr = soundio_ring_buffer_read_ptr(rb);
|
||||||
|
|
||||||
|
assert(strcmp(read_ptr, "hello") == 0);
|
||||||
|
|
||||||
|
soundio_ring_buffer_advance_read_ptr(rb, amt);
|
||||||
|
|
||||||
|
assert(soundio_ring_buffer_fill_count(rb) == 0);
|
||||||
|
assert(soundio_ring_buffer_free_count(rb) == soundio_ring_buffer_capacity(rb));
|
||||||
|
|
||||||
|
soundio_ring_buffer_advance_write_ptr(rb, 4094);
|
||||||
|
soundio_ring_buffer_advance_read_ptr(rb, 4094);
|
||||||
|
amt = sprintf(soundio_ring_buffer_write_ptr(rb), "writing past the end") + 1;
|
||||||
|
soundio_ring_buffer_advance_write_ptr(rb, amt);
|
||||||
|
|
||||||
|
assert(soundio_ring_buffer_fill_count(rb) == amt);
|
||||||
|
|
||||||
|
assert(strcmp(soundio_ring_buffer_read_ptr(rb), "writing past the end") == 0);
|
||||||
|
|
||||||
|
soundio_ring_buffer_advance_read_ptr(rb, amt);
|
||||||
|
|
||||||
|
assert(soundio_ring_buffer_fill_count(rb) == 0);
|
||||||
|
assert(soundio_ring_buffer_free_count(rb) == soundio_ring_buffer_capacity(rb));
|
||||||
|
soundio_ring_buffer_destroy(rb);
|
||||||
|
soundio_destroy(soundio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SoundIoRingBuffer *rb = nullptr;
|
||||||
|
static const int rb_size = 3528;
|
||||||
|
static long expected_write_head;
|
||||||
|
static long expected_read_head;
|
||||||
|
static atomic_bool rb_done;
|
||||||
|
static atomic_int rb_write_it;
|
||||||
|
static atomic_int rb_read_it;
|
||||||
|
|
||||||
|
// just for testing purposes; does not need to be high quality random
|
||||||
|
static double random_double(void) {
|
||||||
|
return ((double)rand() / (double)RAND_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reader_thread_run(void *) {
|
||||||
|
while (!rb_done) {
|
||||||
|
rb_read_it += 1;
|
||||||
|
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||||
|
assert(fill_count >= 0);
|
||||||
|
assert(fill_count <= rb_size);
|
||||||
|
int amount_to_read = min((int)(random_double() * 2.0 * fill_count), fill_count);
|
||||||
|
soundio_ring_buffer_advance_read_ptr(rb, amount_to_read);
|
||||||
|
expected_read_head += amount_to_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writer_thread_run(void *) {
|
||||||
|
while (!rb_done) {
|
||||||
|
rb_write_it += 1;
|
||||||
|
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||||
|
assert(fill_count >= 0);
|
||||||
|
assert(fill_count <= rb_size);
|
||||||
|
int free_count = rb_size - fill_count;
|
||||||
|
assert(free_count >= 0);
|
||||||
|
assert(free_count <= rb_size);
|
||||||
|
int value = min((int)(random_double() * 2.0 * free_count), free_count);
|
||||||
|
soundio_ring_buffer_advance_write_ptr(rb, value);
|
||||||
|
expected_write_head += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_ring_buffer_threaded(void) {
|
||||||
|
struct SoundIo *soundio = soundio_create();
|
||||||
|
assert(soundio);
|
||||||
|
rb = soundio_ring_buffer_create(soundio, rb_size);
|
||||||
|
expected_write_head = 0;
|
||||||
|
expected_read_head = 0;
|
||||||
|
rb_read_it = 0;
|
||||||
|
rb_write_it = 0;
|
||||||
|
rb_done = false;
|
||||||
|
|
||||||
|
SoundIoOsThread *reader_thread;
|
||||||
|
ok_or_panic(soundio_os_thread_create(reader_thread_run, nullptr, false, &reader_thread));
|
||||||
|
|
||||||
|
SoundIoOsThread *writer_thread;
|
||||||
|
ok_or_panic(soundio_os_thread_create(writer_thread_run, nullptr, false, &writer_thread));
|
||||||
|
|
||||||
|
while (rb_read_it < 100000 || rb_write_it < 100000) {}
|
||||||
|
rb_done = true;
|
||||||
|
|
||||||
|
soundio_os_thread_destroy(reader_thread);
|
||||||
|
soundio_os_thread_destroy(writer_thread);
|
||||||
|
|
||||||
|
int fill_count = soundio_ring_buffer_fill_count(rb);
|
||||||
|
int expected_fill_count = expected_write_head - expected_read_head;
|
||||||
|
assert(fill_count == expected_fill_count);
|
||||||
|
soundio_destroy(soundio);
|
||||||
|
}
|
||||||
|
|
||||||
struct Test {
|
struct Test {
|
||||||
const char *name;
|
const char *name;
|
||||||
void (*fn)(void);
|
void (*fn)(void);
|
||||||
|
@ -51,6 +162,8 @@ struct Test {
|
||||||
static struct Test tests[] = {
|
static struct Test tests[] = {
|
||||||
{"os_get_time", test_os_get_time},
|
{"os_get_time", test_os_get_time},
|
||||||
{"create output device", test_create_output_device},
|
{"create output device", test_create_output_device},
|
||||||
|
{"ring buffer basic", test_ring_buffer_basic},
|
||||||
|
{"ring buffer threaded", test_ring_buffer_threaded},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue