Record audio to an output file.Supports specifying device and backend to use.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <unistd.h>
struct RecordContext {
struct SoundIoRingBuffer *ring_buffer;
};
};
static int prioritized_sample_rates[] = {
48000,
44100,
96000,
24000,
0,
};
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) {
struct RecordContext *rc = instream->
userdata;
int err;
if (free_count < frame_count_min) {
fprintf(stderr, "ring buffer overflow\n");
exit(1);
}
int write_frames = min_int(free_count, frame_count_max);
int frames_left = write_frames;
for (;;) {
int frame_count = frames_left;
exit(1);
}
if (!frame_count)
break;
if (!areas) {
} else {
for (int frame = 0; frame < frame_count; frame += 1) {
}
}
}
exit(1);
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
static int count = 0;
fprintf(stderr, "overflow %d\n", ++count);
}
static int usage(char *exe) {
fprintf(stderr, "Usage: %s [options] outfile\n"
"Options:\n"
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
" [--device id]\n"
" [--raw]\n"
, exe);
return 1;
}
int main(int argc, char **argv) {
char *exe = argv[0];
char *device_id = NULL;
bool is_raw = false;
char *outfile = NULL;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') {
if (strcmp(arg, "--raw") == 0) {
is_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, "--device") == 0) {
device_id = argv[i];
} else {
return usage(exe);
}
} else if (!outfile) {
outfile = argv[i];
} else {
return usage(exe);
}
}
if (!outfile)
return usage(exe);
struct RecordContext rc;
if (!soundio) {
fprintf(stderr, "out of memory\n");
return 1;
}
if (err) {
return 1;
}
if (device_id) {
selected_device = device;
break;
}
}
if (!selected_device) {
fprintf(stderr, "Invalid device id: %s\n", device_id);
return 1;
}
} else {
if (!selected_device) {
fprintf(stderr, "No input devices available.\n");
return 1;
}
}
fprintf(stderr,
"Device: %s\n", selected_device->
name);
return 1;
}
int sample_rate = 0;
int *sample_rate_ptr;
for (sample_rate_ptr = prioritized_sample_rates; *sample_rate_ptr; sample_rate_ptr += 1) {
sample_rate = *sample_rate_ptr;
break;
}
}
if (!sample_rate)
fmt = *fmt_ptr;
break;
}
}
FILE *out_f = fopen(outfile, "wb");
if (!out_f) {
fprintf(stderr, "unable to open %s: %s\n", outfile, strerror(errno));
return 1;
}
if (!instream) {
fprintf(stderr, "out of memory\n");
return 1;
}
return 1;
}
fprintf(stderr, "%s %dHz %s interleaved\n",
const int ring_buffer_duration_seconds = 30;
if (!rc.ring_buffer) {
fprintf(stderr, "out of memory\n");
return 1;
}
return 1;
}
for (;;) {
sleep(1);
size_t amt = fwrite(read_buf, 1, fill_bytes, out_f);
if ((int)amt != fill_bytes) {
fprintf(stderr, "write error: %s\n", strerror(errno));
return 1;
}
}
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
const char * soundio_format_string(enum SoundIoFormat format)
Returns string representation of format.
bool soundio_device_supports_format(struct SoundIoDevice *device, enum SoundIoFormat format)
Convenience function.
@ 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
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
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.
#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.
int probe_error
This is set to a SoundIoError representing the result of the device probe.
Definition: soundio.h:493
#define SoundIoFormatFloat32NE
Definition: soundio.h:288
enum SoundIoFormat * formats
List of formats this device supports.
Definition: soundio.h:418
#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
int max
Definition: soundio.h:315
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
char * ptr
Base address of buffer.
Definition: soundio.h:321
@ SoundIoBackendNone
Definition: soundio.h:219
struct SoundIoSampleRateRange * sample_rates
Sample rate is the number of frames per second.
Definition: soundio.h:447
char * soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *ring_buffer)
Do not write more than capacity.
@ SoundIoFormatS8
Signed 8 bit.
Definition: soundio.h:237
const char * name
Definition: soundio.h:307
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
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
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
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device)
Sorts channel layouts by channel count, descending.
void * userdata
Defaults to NULL. Put whatever you want here.
Definition: soundio.h:631
@ 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
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
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
@ SoundIoFormatU8
Unsigned 8 bit.
Definition: soundio.h:238
void(* overflow_callback)(struct SoundIoInStream *)
This optional callback happens when the sound device buffer is full, yet there is more captured audio...
Definition: soundio.h:649
struct SoundIo * soundio_create(void)
Create a SoundIo context.