mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 14:15:47 +00:00
add a couple unit tests, fix a couple bugs
This commit is contained in:
parent
39cb1d4fde
commit
a35a2b7e0a
|
@ -54,11 +54,6 @@ set(LIBSOUNDIO_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/src/dummy_ring_buffer.cpp"
|
"${CMAKE_SOURCE_DIR}/src/dummy_ring_buffer.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/channel_layout.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(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
|
||||||
set(LIBSOUNDIO_HEADERS
|
set(LIBSOUNDIO_HEADERS
|
||||||
|
@ -68,8 +63,23 @@ set(LIBSOUNDIO_HEADERS
|
||||||
|
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/test/unit_tests.cpp"
|
"${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++ !!
|
# GTFO, -lstdc++ !!
|
||||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
||||||
|
|
|
@ -5,8 +5,60 @@
|
||||||
* See http://opensource.org/licenses/MIT
|
* 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) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,9 @@ static void output_device_destroy_dummy(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
SoundIoOutputDeviceDummy *opd = (SoundIoOutputDeviceDummy *)output_device->backend_data;
|
||||||
|
if (!opd)
|
||||||
|
return;
|
||||||
|
|
||||||
if (opd->thread) {
|
if (opd->thread) {
|
||||||
if (opd->thread) {
|
if (opd->thread) {
|
||||||
opd->abort_flag.clear();
|
opd->abort_flag.clear();
|
||||||
|
@ -124,12 +127,24 @@ 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);
|
||||||
|
|
||||||
|
destroy(opd);
|
||||||
|
output_device->backend_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int output_device_init_dummy(SoundIo *soundio,
|
static int output_device_init_dummy(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
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;
|
SoundIoDevice *device = output_device->device;
|
||||||
int buffer_frame_count = output_device->latency * device->default_sample_rate;
|
int buffer_frame_count = output_device->latency * device->default_sample_rate;
|
||||||
opd->buffer_size = output_device->bytes_per_frame * buffer_frame_count;
|
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) {
|
void soundio_dummy_ring_buffer_deinit(struct SoundIoDummyRingBuffer *rb) {
|
||||||
deallocate(rb, rb->capacity);
|
deallocate(rb->address, rb->capacity);
|
||||||
rb->address = nullptr;
|
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);
|
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)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
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;
|
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
SoundIoDevice *device = output_device->device;
|
SoundIoDevice *device = output_device->device;
|
||||||
opd->stream_ready = false;
|
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);
|
opd->stream = pa_stream_new(ah->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
||||||
if (!opd->stream) {
|
if (!opd->stream) {
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(ah->main_loop);
|
||||||
|
output_device_destroy_pa(soundio, output_device);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
pa_stream_set_state_callback(opd->stream, playback_stream_state_callback, output_device);
|
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;
|
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,
|
static int output_device_start_pa(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
|
|
|
@ -269,3 +269,53 @@ void soundio_output_device_write(struct SoundIoOutputDevice *output_device,
|
||||||
SoundIo *soundio = output_device->device->soundio;
|
SoundIo *soundio = output_device->device->soundio;
|
||||||
soundio->output_device_write(soundio, output_device, data, frame_count);
|
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,
|
int soundio_output_device_create(struct SoundIoDevice *device,
|
||||||
enum SoundIoSampleFormat sample_format,
|
enum SoundIoSampleFormat sample_format,
|
||||||
double latency, void *userdata,
|
double latency, void *userdata,
|
||||||
void (*write_callback)(struct SoundIoOutputDevice *, int),
|
void (*write_callback)(struct SoundIoOutputDevice *, int frame_count),
|
||||||
void (*underrun_callback)(struct SoundIoOutputDevice *),
|
void (*underrun_callback)(struct SoundIoOutputDevice *),
|
||||||
struct SoundIoOutputDevice **out_output_device);
|
struct SoundIoOutputDevice **out_output_device);
|
||||||
void soundio_output_device_destroy(struct SoundIoOutputDevice *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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue