add a couple unit tests, fix a couple bugs
This commit is contained in:
parent
39cb1d4fde
commit
a35a2b7e0a
8 changed files with 247 additions and 34 deletions
|
@ -54,11 +54,6 @@ set(LIBSOUNDIO_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/src/dummy_ring_buffer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
||||
)
|
||||
if(SOUNDIO_HAVE_PULSEAUDIO)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${CMAKE_SOURCE_DIR}/src/pulseaudio.cpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
|
||||
set(LIBSOUNDIO_HEADERS
|
||||
|
@ -68,8 +63,23 @@ set(LIBSOUNDIO_HEADERS
|
|||
|
||||
set(TEST_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/test/unit_tests.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/util.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/soundio.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/dummy.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/dummy_ring_buffer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/channel_layout.cpp"
|
||||
)
|
||||
|
||||
if(SOUNDIO_HAVE_PULSEAUDIO)
|
||||
set(LIBSOUNDIO_SOURCES ${LIBSOUNDIO_SOURCES}
|
||||
"${CMAKE_SOURCE_DIR}/src/pulseaudio.cpp"
|
||||
)
|
||||
set(TEST_SOURCES ${TEST_SOURCES}
|
||||
"${CMAKE_SOURCE_DIR}/src/pulseaudio.cpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# GTFO, -lstdc++ !!
|
||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
||||
|
|
|
@ -5,8 +5,60 @@
|
|||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "soundio.h"
|
||||
#include <soundio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.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 write_callback(struct SoundIoOutputDevice *device, int frame_count) {
|
||||
fprintf(stderr, "write_callback\n");
|
||||
}
|
||||
|
||||
static void underrun_callback(struct SoundIoOutputDevice *device) {
|
||||
static int count = 0;
|
||||
fprintf(stderr, "underrun %d\n", count++);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
|
||||
if (!device)
|
||||
panic("could not get output device: out of memory");
|
||||
|
||||
fprintf(stderr, "Output device: %s: %s\n",
|
||||
soundio_device_name(device),
|
||||
soundio_device_description(device));
|
||||
|
||||
struct SoundIoOutputDevice *output_device;
|
||||
soundio_output_device_create(device, SoundIoSampleFormatFloat, 0.1, NULL,
|
||||
write_callback, underrun_callback, &output_device);
|
||||
|
||||
soundio_output_device_destroy(output_device);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -114,6 +114,9 @@ static void output_device_destroy_dummy(SoundIo *soundio,
|
|||
SoundIoOutputDevice *output_device)
|
||||
{
|
||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||
if (!opd)
|
||||
return;
|
||||
|
||||
if (opd->thread) {
|
||||
if (opd->thread) {
|
||||
opd->abort_flag.clear();
|
||||
|
@ -124,12 +127,24 @@ static void output_device_destroy_dummy(SoundIo *soundio,
|
|||
}
|
||||
soundio_os_cond_destroy(opd->cond);
|
||||
opd->cond = nullptr;
|
||||
|
||||
soundio_dummy_ring_buffer_deinit(&opd->ring_buffer);
|
||||
|
||||
destroy(opd);
|
||||
output_device->backend_data = nullptr;
|
||||
}
|
||||
|
||||
static int output_device_init_dummy(SoundIo *soundio,
|
||||
SoundIoOutputDevice *output_device)
|
||||
{
|
||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||
|
||||
SoundIoOutputDeviceDummy *opd = create<SoundIoOutputDeviceDummy>();
|
||||
if (!opd) {
|
||||
output_device_destroy_dummy(soundio, output_device);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
output_device->backend_data = opd;
|
||||
|
||||
SoundIoDevice *device = output_device->device;
|
||||
int buffer_frame_count = output_device->latency * device->default_sample_rate;
|
||||
opd->buffer_size = output_device->bytes_per_frame * buffer_frame_count;
|
||||
|
|
|
@ -44,7 +44,7 @@ void soundio_dummy_ring_buffer_destroy(struct SoundIoDummyRingBuffer *rb) {
|
|||
}
|
||||
|
||||
void soundio_dummy_ring_buffer_deinit(struct SoundIoDummyRingBuffer *rb) {
|
||||
deallocate(rb, rb->capacity);
|
||||
deallocate(rb->address, rb->capacity);
|
||||
rb->address = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -543,10 +543,44 @@ static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, voi
|
|||
output_device->write_callback(output_device, frame_count);
|
||||
}
|
||||
|
||||
static int output_device_init_pa(SoundIo *soundio,
|
||||
static void output_device_destroy_pa(SoundIo *soundio,
|
||||
SoundIoOutputDevice *output_device)
|
||||
{
|
||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||
if (!opd)
|
||||
return;
|
||||
|
||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
||||
pa_stream *stream = opd->stream;
|
||||
if (stream) {
|
||||
pa_threaded_mainloop_lock(ah->main_loop);
|
||||
|
||||
pa_stream_set_write_callback(stream, nullptr, nullptr);
|
||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
||||
pa_stream_set_underflow_callback(stream, nullptr, nullptr);
|
||||
pa_stream_disconnect(stream);
|
||||
|
||||
pa_stream_unref(stream);
|
||||
|
||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
||||
|
||||
opd->stream = nullptr;
|
||||
}
|
||||
|
||||
destroy(opd);
|
||||
output_device->backend_data = nullptr;
|
||||
}
|
||||
|
||||
static int output_device_init_pa(SoundIo *soundio,
|
||||
SoundIoOutputDevice *output_device)
|
||||
{
|
||||
SoundIoOutputDevicePulseAudio *opd = create<SoundIoOutputDevicePulseAudio>();
|
||||
if (!opd) {
|
||||
output_device_destroy_pa(soundio, output_device);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
output_device->backend_data = opd;
|
||||
|
||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
||||
SoundIoDevice *device = output_device->device;
|
||||
opd->stream_ready = false;
|
||||
|
@ -564,6 +598,7 @@ static int output_device_init_pa(SoundIo *soundio,
|
|||
opd->stream = pa_stream_new(ah->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
||||
if (!opd->stream) {
|
||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
||||
output_device_destroy_pa(soundio, output_device);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
pa_stream_set_state_callback(opd->stream, playback_stream_state_callback, output_device);
|
||||
|
@ -585,28 +620,6 @@ static int output_device_init_pa(SoundIo *soundio,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void output_device_destroy_pa(SoundIo *soundio,
|
||||
SoundIoOutputDevice *output_device)
|
||||
{
|
||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
||||
pa_stream *stream = opd->stream;
|
||||
if (stream) {
|
||||
pa_threaded_mainloop_lock(ah->main_loop);
|
||||
|
||||
pa_stream_set_write_callback(stream, nullptr, nullptr);
|
||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
||||
pa_stream_set_underflow_callback(stream, nullptr, nullptr);
|
||||
pa_stream_disconnect(stream);
|
||||
|
||||
pa_stream_unref(stream);
|
||||
|
||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
||||
|
||||
opd->stream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static int output_device_start_pa(SoundIo *soundio,
|
||||
SoundIoOutputDevice *output_device)
|
||||
{
|
||||
|
|
|
@ -269,3 +269,53 @@ void soundio_output_device_write(struct SoundIoOutputDevice *output_device,
|
|||
SoundIo *soundio = output_device->device->soundio;
|
||||
soundio->output_device_write(soundio, output_device, data, frame_count);
|
||||
}
|
||||
|
||||
|
||||
int soundio_output_device_create(struct SoundIoDevice *device,
|
||||
enum SoundIoSampleFormat sample_format,
|
||||
double latency, void *userdata,
|
||||
void (*write_callback)(struct SoundIoOutputDevice *, int frame_count),
|
||||
void (*underrun_callback)(struct SoundIoOutputDevice *),
|
||||
struct SoundIoOutputDevice **out_output_device)
|
||||
{
|
||||
*out_output_device = nullptr;
|
||||
|
||||
SoundIoOutputDevice *output_device = create<SoundIoOutputDevice>();
|
||||
if (!output_device) {
|
||||
soundio_output_device_destroy(output_device);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
soundio_device_ref(device);
|
||||
output_device->device = device;
|
||||
output_device->userdata = userdata;
|
||||
output_device->write_callback = write_callback;
|
||||
output_device->underrun_callback = underrun_callback;
|
||||
output_device->sample_format = sample_format;
|
||||
output_device->latency = latency;
|
||||
output_device->bytes_per_frame = soundio_get_bytes_per_frame(sample_format,
|
||||
device->channel_layout.channel_count);
|
||||
|
||||
SoundIo *soundio = device->soundio;
|
||||
int err = soundio->output_device_init(soundio, output_device);
|
||||
if (err) {
|
||||
soundio_output_device_destroy(output_device);
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_output_device = output_device;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soundio_output_device_destroy(SoundIoOutputDevice *output_device) {
|
||||
if (!output_device)
|
||||
return;
|
||||
|
||||
SoundIo *soundio = output_device->device->soundio;
|
||||
|
||||
if (soundio->output_device_destroy)
|
||||
soundio->output_device_destroy(soundio, output_device);
|
||||
|
||||
soundio_device_unref(output_device->device);
|
||||
destroy(output_device);
|
||||
}
|
||||
|
|
|
@ -284,7 +284,7 @@ enum SoundIoDevicePurpose soundio_device_purpose(const struct SoundIoDevice *dev
|
|||
int soundio_output_device_create(struct SoundIoDevice *device,
|
||||
enum SoundIoSampleFormat sample_format,
|
||||
double latency, void *userdata,
|
||||
void (*write_callback)(struct SoundIoOutputDevice *, int),
|
||||
void (*write_callback)(struct SoundIoOutputDevice *, int frame_count),
|
||||
void (*underrun_callback)(struct SoundIoOutputDevice *),
|
||||
struct SoundIoOutputDevice **out_output_device);
|
||||
void soundio_output_device_destroy(struct SoundIoOutputDevice *device);
|
||||
|
|
|
@ -1,5 +1,78 @@
|
|||
#include "soundio.h"
|
||||
#undef NDEBUG
|
||||
|
||||
#include "soundio.h"
|
||||
#include "os.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
static inline void ok_or_panic(int err) {
|
||||
if (err)
|
||||
soundio_panic("%s", soundio_error_string(err));
|
||||
}
|
||||
|
||||
static void test_os_get_time(void) {
|
||||
double prev_time = soundio_os_get_time();
|
||||
for (int i = 0; i < 1000; i += 1) {
|
||||
double time = soundio_os_get_time();
|
||||
assert(time >= prev_time);
|
||||
prev_time = time;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_callback(struct SoundIoOutputDevice *device, int frame_count) { }
|
||||
static void underrun_callback(struct SoundIoOutputDevice *device) { }
|
||||
|
||||
static void test_create_output_device(void) {
|
||||
struct SoundIo *soundio = soundio_create();
|
||||
assert(soundio);
|
||||
ok_or_panic(soundio_connect(soundio));
|
||||
int default_out_device_index = soundio_get_default_output_device_index(soundio);
|
||||
assert(default_out_device_index >= 0);
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
|
||||
assert(device);
|
||||
soundio_device_name(device);
|
||||
soundio_device_description(device);
|
||||
struct SoundIoOutputDevice *output_device;
|
||||
soundio_output_device_create(device, SoundIoSampleFormatFloat, 0.1, NULL,
|
||||
write_callback, underrun_callback, &output_device);
|
||||
soundio_output_device_destroy(output_device);
|
||||
soundio_device_unref(device);
|
||||
soundio_destroy(soundio);
|
||||
}
|
||||
|
||||
struct Test {
|
||||
const char *name;
|
||||
void (*fn)(void);
|
||||
};
|
||||
|
||||
static struct Test tests[] = {
|
||||
{"os_get_time", test_os_get_time},
|
||||
{"create output device", test_create_output_device},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static void exec_test(struct Test *test) {
|
||||
fprintf(stderr, "testing %s...", test->name);
|
||||
test->fn();
|
||||
fprintf(stderr, "OK\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *match = nullptr;
|
||||
|
||||
if (argc == 2)
|
||||
match = argv[1];
|
||||
|
||||
struct Test *test = &tests[0];
|
||||
|
||||
while (test->name) {
|
||||
if (!match || strstr(test->name, match))
|
||||
exec_test(test);
|
||||
test += 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue