Stream the default input device over the default output device.Supports specifying device and backend to use.
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
struct SoundIoRingBuffer *ring_buffer = NULL;
};
static int prioritized_sample_rates[] = {
48000,
44100,
96000,
24000,
0,
};
__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 int min_int(int a, int b) {
return (a < b) ? a : b;
}
static void read_callback(
struct SoundIoInStream *instream,
int frame_count_min,
int frame_count_max) {
int err;
if (frame_count_min > free_count)
panic("ring buffer overflow");
int write_frames = min_int(free_count, frame_count_max);
int frames_left = write_frames;
for (;;) {
int frame_count = frames_left;
if (!frame_count)
break;
if (!areas) {
fprintf(stderr, "Dropped %d frames due to internal overflow\n", frame_count);
} else {
for (int frame = 0; frame < frame_count; frame += 1) {
}
}
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
static void write_callback(
struct SoundIoOutStream *outstream,
int frame_count_min,
int frame_count_max) {
int frames_left;
int frame_count;
int err;
if (frame_count_min > fill_count) {
frames_left = frame_count_min;
for (;;) {
frame_count = frames_left;
if (frame_count <= 0)
return;
if (frame_count <= 0)
return;
for (int frame = 0; frame < frame_count; frame += 1) {
}
}
frames_left -= frame_count;
}
}
int read_count = min_int(frame_count_max, fill_count);
frames_left = read_count;
while (frames_left > 0) {
int frame_count = frames_left;
if (frame_count <= 0)
break;
for (int frame = 0; frame < frame_count; frame += 1) {
}
}
frames_left -= frame_count;
}
}
static int count = 0;
fprintf(stderr, "underflow %d\n", ++count);
}
static int usage(char *exe) {
fprintf(stderr, "Usage: %s [options]\n"
"Options:\n"
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
" [--in-device id]\n"
" [--in-raw]\n"
" [--out-device id]\n"
" [--out-raw]\n"
" [--latency seconds]\n"
, exe);
return 1;
}
int main(int argc, char **argv) {
char *exe = argv[0];
char *in_device_id = NULL;
char *out_device_id = NULL;
bool in_raw = false;
bool out_raw = false;
double microphone_latency = 0.2;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') {
if (strcmp(arg, "--in-raw") == 0) {
in_raw = true;
} else if (strcmp(arg, "--out-raw") == 0) {
out_raw = true;
} else if (++i >= argc) {
return usage(exe);
} else if (strcmp(arg, "--backend") == 0) {
if (strcmp("dummy", argv[i]) == 0) {
} else if (strcmp("alsa", argv[i]) == 0) {
} else if (strcmp("pulseaudio", argv[i]) == 0) {
} else if (strcmp("jack", argv[i]) == 0) {
} else if (strcmp("coreaudio", argv[i]) == 0) {
} else if (strcmp("wasapi", argv[i]) == 0) {
} else {
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
return 1;
}
} else if (strcmp(arg, "--in-device") == 0) {
in_device_id = argv[i];
} else if (strcmp(arg, "--out-device") == 0) {
out_device_id = argv[i];
} else if (strcmp(arg, "--latency") == 0) {
microphone_latency = atof(argv[i]);
} else {
return usage(exe);
}
} else {
return usage(exe);
}
}
if (!soundio)
panic("out of memory");
if (err)
if (default_out_device_index < 0)
panic("no output device found");
if (default_in_device_index < 0)
panic("no input device found");
int in_device_index = default_in_device_index;
if (in_device_id) {
bool found = false;
if (device->
is_raw == in_raw && strcmp(device->
id, in_device_id) == 0) {
in_device_index = i;
found = true;
break;
}
}
if (!found)
panic("invalid input device id: %s", in_device_id);
}
int out_device_index = default_out_device_index;
if (out_device_id) {
bool found = false;
if (device->
is_raw == out_raw && strcmp(device->
id, out_device_id) == 0) {
out_device_index = i;
found = true;
break;
}
}
if (!found)
panic("invalid output device id: %s", out_device_id);
}
if (!out_device)
panic("could not get output device: out of memory");
if (!in_device)
panic("could not get input device: out of memory");
fprintf(stderr,
"Input device: %s\n", in_device->
name);
fprintf(stderr,
"Output device: %s\n", out_device->
name);
if (!layout)
panic("channel layouts not compatible");
int *sample_rate;
for (sample_rate = prioritized_sample_rates; *sample_rate; sample_rate += 1) {
{
break;
}
}
if (!*sample_rate)
panic("incompatible sample rates");
{
break;
}
}
panic("incompatible sample formats");
if (!instream)
panic("out of memory");
return 1;
}
if (!outstream)
panic("out of memory");
return 1;
}
if (!ring_buffer)
panic("unable to create ring buffer: out of memory");
memset(buf, 0, fill_count);
for (;;)
return 0;
}
void soundio_flush_events(struct SoundIo *soundio)
Atomically update information for all connected devices.
char * soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *ring_buffer)
Do not read more than capacity.
struct SoundIo * soundio
Read-only. Set automatically.
Definition: soundio.h:389
void(* read_callback)(struct SoundIoInStream *, int frame_count_min, int frame_count_max)
In this function call soundio_instream_begin_read and soundio_instream_end_read as many times as nece...
Definition: soundio.h:644
int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *ring_buffer)
Returns how many bytes of the buffer is free, ready for writing.
struct SoundIoDevice * soundio_get_input_device(struct SoundIo *soundio, int index)
Always returns a device.
#define SoundIoFormatU32FE
Definition: soundio.h:296
bool soundio_device_supports_format(struct SoundIoDevice *device, enum SoundIoFormat format)
Convenience function.
The size of this struct is OK to use.
Definition: soundio.h:306
double software_latency
Ignoring hardware latency, this is the number of seconds it takes for the last sample in a full buffe...
Definition: soundio.h:538
const struct SoundIoChannelLayout * soundio_best_matching_channel_layout(const struct SoundIoChannelLayout *preferred_layouts, int preferred_layout_count, const struct SoundIoChannelLayout *available_layouts, int available_layout_count)
Iterates over preferred_layouts.
@ SoundIoBackendJack
Definition: soundio.h:220
void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *ring_buffer, int count)
count in bytes.
int soundio_instream_begin_read(struct SoundIoInStream *instream, struct SoundIoChannelArea **areas, int *frame_count)
Call this function when you are ready to begin reading from the device buffer.
#define SoundIoFormatU24FE
Definition: soundio.h:294
char * name
User-friendly UTF-8 encoded text to describe the device.
Definition: soundio.h:401
struct SoundIoDevice * soundio_get_output_device(struct SoundIo *soundio, int index)
Always returns a device.
int soundio_default_output_device_index(struct SoundIo *soundio)
returns the index of the default output device returns -1 if there are no devices or if you never cal...
int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend)
Instead of calling soundio_connect you may call this function to try a specific backend.
@ SoundIoFormatInvalid
Definition: soundio.h:236
void(* write_callback)(struct SoundIoOutStream *, int frame_count_min, int frame_count_max)
In this callback, you call soundio_outstream_begin_write and soundio_outstream_end_write as many time...
Definition: soundio.h:559
int sample_rate
Sample rate is the number of frames per second.
Definition: soundio.h:610
#define SoundIoFormatS24NE
Definition: soundio.h:284
struct SoundIoChannelLayout layout
Defaults to Stereo, if available, followed by the first layout supported.
Definition: soundio.h:614
int soundio_default_input_device_index(struct SoundIo *soundio)
returns the index of the default input device returns -1 if there are no devices or if you never call...
void soundio_device_unref(struct SoundIoDevice *device)
Remove 1 to the reference count of device.
int soundio_outstream_end_write(struct SoundIoOutStream *outstream)
Commits the write that you began with soundio_outstream_begin_write.
#define SoundIoFormatFloat32FE
Definition: soundio.h:297
#define SoundIoFormatU16FE
Definition: soundio.h:292
#define SoundIoFormatU32NE
Definition: soundio.h:287
SoundIoFormat
For your convenience, Native Endian and Foreign Endian constants are defined which point to the respe...
Definition: soundio.h:235
int soundio_connect(struct SoundIo *soundio)
Tries soundio_connect_backend on all available backends in order.
#define SoundIoFormatFloat32NE
Definition: soundio.h:288
#define SoundIoFormatS24FE
Definition: soundio.h:293
#define SoundIoFormatS16FE
Definition: soundio.h:291
char * id
A string of bytes that uniquely identifies this device.
Definition: soundio.h:399
void soundio_outstream_destroy(struct SoundIoOutStream *outstream)
You may not call this function from the SoundIoOutStream::write_callback thread context.
double software_latency
Ignoring hardware latency, this is the number of seconds it takes for a captured sample to become ava...
Definition: soundio.h:628
The size of this struct is not part of the API or ABI.
Definition: soundio.h:328
The size of this struct is not part of the API or ABI.
Definition: soundio.h:600
int soundio_output_device_count(struct SoundIo *soundio)
Get the number of output devices.
struct SoundIoChannelLayout layout
Defaults to Stereo, if available, followed by the first layout supported.
Definition: soundio.h:511
char * ptr
Base address of buffer.
Definition: soundio.h:321
@ SoundIoBackendNone
Definition: soundio.h:219
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream, struct SoundIoChannelArea **areas, int *frame_count)
Call this function when you are ready to begin writing to the device buffer.
char * soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *ring_buffer)
Do not write more than capacity.
int layout_count
Definition: soundio.h:412
int bytes_per_frame
computed automatically when you call soundio_outstream_open
Definition: soundio.h:589
@ SoundIoFormatS8
Signed 8 bit.
Definition: soundio.h:237
void(* underflow_callback)(struct SoundIoOutStream *)
This optional callback happens when the sound device runs out of buffered audio data to play.
Definition: soundio.h:565
struct SoundIoChannelLayout * layouts
Channel layouts are handled similarly to SoundIoDevice::formats.
Definition: soundio.h:411
int bytes_per_frame
computed automatically when you call soundio_instream_open
Definition: soundio.h:672
int channel_count
Definition: soundio.h:308
struct SoundIoInStream * soundio_instream_create(struct SoundIoDevice *device)
Allocates memory and sets defaults.
void soundio_instream_destroy(struct SoundIoInStream *instream)
You may not call this function from SoundIoInStream::read_callback.
#define SoundIoFormatS32NE
Definition: soundio.h:286
@ SoundIoBackendAlsa
Definition: soundio.h:222
void soundio_wait_events(struct SoundIo *soundio)
This function calls soundio_flush_events then blocks until another event is ready or you call soundio...
The size of this struct is not part of the API or ABI.
Definition: soundio.h:387
int soundio_instream_end_read(struct SoundIoInStream *instream)
This will drop all of the frames from when you called soundio_instream_begin_read.
#define SoundIoFormatU16NE
Definition: soundio.h:283
void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *ring_buffer, int count)
count in bytes.
const char * soundio_strerror(int error)
Get a string representation of a SoundIoError.
#define SoundIoFormatU24NE
Definition: soundio.h:285
The size of this struct is not part of the API or ABI.
Definition: soundio.h:497
void soundio_destroy(struct SoundIo *soundio)
struct SoundIoRingBuffer * soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity)
A ring buffer is a single-reader single-writer lock-free fixed-size queue.
bool is_raw
Raw means that you are directly opening the hardware device and not going through a proxy such as dmi...
Definition: soundio.h:478
int soundio_outstream_start(struct SoundIoOutStream *outstream)
After you call this function, SoundIoOutStream::write_callback will be called.
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device)
Sorts channel layouts by channel count, descending.
@ SoundIoBackendPulseAudio
Definition: soundio.h:221
@ SoundIoBackendDummy
Definition: soundio.h:225
int soundio_input_device_count(struct SoundIo *soundio)
When you call soundio_flush_events, a snapshot of all device state is saved and these functions merel...
int step
How many bytes it takes to get from the beginning of one sample to the beginning of the next sample.
Definition: soundio.h:324
#define SoundIoFormatFloat64FE
Definition: soundio.h:298
The size of this struct is OK to use.
Definition: soundio.h:319
#define SoundIoFormatS16NE
Note that we build the documentation in Little Endian mode, so all the "NE" macros in the docs point ...
Definition: soundio.h:282
enum SoundIoFormat format
Defaults to SoundIoFormatFloat32NE, followed by the first one supported.
Definition: soundio.h:503
int sample_rate
Sample rate is the number of frames per second.
Definition: soundio.h:507
int bytes_per_sample
computed automatically when you call soundio_outstream_open
Definition: soundio.h:591
SoundIoBackend
Definition: soundio.h:218
int bytes_per_sample
computed automatically when you call soundio_instream_open
Definition: soundio.h:674
@ SoundIoBackendCoreAudio
Definition: soundio.h:223
bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sample_rate)
Convenience function.
int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *ring_buffer)
Returns how many bytes of the buffer is used, ready for reading.
@ SoundIoBackendWasapi
Definition: soundio.h:224
#define SoundIoFormatS32FE
Definition: soundio.h:295
enum SoundIoFormat format
Defaults to SoundIoFormatFloat32NE, followed by the first one supported.
Definition: soundio.h:606
struct SoundIoOutStream * soundio_outstream_create(struct SoundIoDevice *device)
Allocates memory and sets defaults.
int soundio_instream_start(struct SoundIoInStream *instream)
After you call this function, SoundIoInStream::read_callback will be called.
int soundio_instream_open(struct SoundIoInStream *instream)
After you call this function, SoundIoInStream::software_latency is set to the correct value.
#define SoundIoFormatFloat64NE
Definition: soundio.h:289
int soundio_outstream_open(struct SoundIoOutStream *outstream)
After you call this function, SoundIoOutStream::software_latency is set to the correct value.
@ SoundIoFormatU8
Unsigned 8 bit.
Definition: soundio.h:238
struct SoundIo * soundio_create(void)
Create a SoundIo context.