add a couple unit tests, fix a couple bugs

This commit is contained in:
Andrew Kelley 2015-07-04 02:57:06 -07:00
parent 39cb1d4fde
commit a35a2b7e0a
8 changed files with 247 additions and 34 deletions

View file

@ -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 "")

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}