mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 18:45:29 +00:00
ALSA: open output device with parameters
This commit is contained in:
parent
59026ccba7
commit
1e4d87e608
|
@ -15,10 +15,12 @@ exposed.
|
|||
* [PortAudio](http://www.portaudio.com/)
|
||||
- It does not support [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/).
|
||||
- It logs messages to stdio and you can't turn that off.
|
||||
- It does not support channel layouts / channel maps.
|
||||
- It is not written by me.
|
||||
* [rtaudio](https://www.music.mcgill.ca/~gary/rtaudio/)
|
||||
- It is not a C library.
|
||||
- It uses [exceptions](http://stackoverflow.com/questions/1736146/why-is-exception-handling-bad).
|
||||
- It does not support channel layouts / channel maps.
|
||||
- It is not written by me.
|
||||
* [SDL](https://www.libsdl.org/)
|
||||
- It comes with a bunch of other baggage - display, windowing, input
|
||||
|
@ -26,6 +28,7 @@ exposed.
|
|||
- It is not designed with real-time low latency audio in mind.
|
||||
- Listing audio devices is [broken](https://github.com/andrewrk/node-groove/issues/13).
|
||||
- It does not support recording devices.
|
||||
- It does not support channel layouts / channel maps.
|
||||
- It is not written by me.
|
||||
|
||||
## How It Works
|
||||
|
|
|
@ -121,7 +121,7 @@ int main(int argc, char **argv) {
|
|||
instream->format = *fmt;
|
||||
instream->sample_rate = sample_rate;
|
||||
instream->layout = *layout;
|
||||
instream->latency = 0.1;
|
||||
instream->buffer_duration = 0.1;
|
||||
instream->read_callback = read_callback;
|
||||
|
||||
if ((err = soundio_instream_open(instream)))
|
||||
|
@ -133,7 +133,7 @@ int main(int argc, char **argv) {
|
|||
outstream->format = *fmt;
|
||||
outstream->sample_rate = sample_rate;
|
||||
outstream->layout = *layout;
|
||||
outstream->latency = 0.1;
|
||||
outstream->buffer_duration = 0.1;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underrun_callback = underrun_callback;
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ static void panic(const char *format, ...) {
|
|||
|
||||
static const float PI = 3.1415926535f;
|
||||
static float seconds_offset = 0.0f;
|
||||
static int target_sample_rate = 48000;
|
||||
|
||||
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
||||
float float_sample_rate = outstream->sample_rate;
|
||||
float seconds_per_frame = 1.0f / float_sample_rate;
|
||||
|
@ -45,7 +43,6 @@ static void write_callback(struct SoundIoOutStream *outstream, int requested_fra
|
|||
|
||||
float *ptr = (float *)data;
|
||||
|
||||
// 69 is A 440
|
||||
float pitch = 440.0f;
|
||||
float radians_per_second = pitch * 2.0f * PI;
|
||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||
|
@ -83,16 +80,12 @@ int main(int argc, char **argv) {
|
|||
|
||||
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
|
||||
if (!device)
|
||||
panic("could not get output device: out of memory");
|
||||
panic("out of memory");
|
||||
|
||||
fprintf(stderr, "Output device: %s: %s\n", device->name, device->description);
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
outstream->sample_rate = (device->sample_rate_min <= target_sample_rate &&
|
||||
target_sample_rate <= device->sample_rate_max) ? target_sample_rate : device->sample_rate_max;
|
||||
outstream->layout = device->layouts[0];
|
||||
outstream->latency = 0.1;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underrun_callback = underrun_callback;
|
||||
|
||||
|
|
263
src/alsa.cpp
263
src/alsa.cpp
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <math.h>
|
||||
|
||||
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
|
||||
|
||||
|
@ -31,7 +32,9 @@ struct SoundIoAlsa {
|
|||
};
|
||||
|
||||
struct SoundIoOutStreamAlsa {
|
||||
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_chmap_t *chmap;
|
||||
int chmap_size;
|
||||
};
|
||||
|
||||
static void wakeup_device_poll(SoundIoAlsa *sia) {
|
||||
|
@ -136,6 +139,47 @@ static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
|
|||
return SoundIoChannelIdInvalid;
|
||||
}
|
||||
|
||||
static int to_alsa_chmap_pos(SoundIoChannelId channel_id) {
|
||||
switch (channel_id) {
|
||||
case SoundIoChannelIdFrontLeft: return SND_CHMAP_FL;
|
||||
case SoundIoChannelIdFrontRight: return SND_CHMAP_FR;
|
||||
case SoundIoChannelIdBackLeft: return SND_CHMAP_RL;
|
||||
case SoundIoChannelIdBackRight: return SND_CHMAP_RR;
|
||||
case SoundIoChannelIdFrontCenter: return SND_CHMAP_FC;
|
||||
case SoundIoChannelIdLfe: return SND_CHMAP_LFE;
|
||||
case SoundIoChannelIdSideLeft: return SND_CHMAP_SL;
|
||||
case SoundIoChannelIdSideRight: return SND_CHMAP_SR;
|
||||
case SoundIoChannelIdBackCenter: return SND_CHMAP_RC;
|
||||
case SoundIoChannelIdFrontLeftCenter: return SND_CHMAP_FLC;
|
||||
case SoundIoChannelIdFrontRightCenter: return SND_CHMAP_FRC;
|
||||
case SoundIoChannelIdBackLeftCenter: return SND_CHMAP_RLC;
|
||||
case SoundIoChannelIdBackRightCenter: return SND_CHMAP_RRC;
|
||||
case SoundIoChannelIdFrontLeftWide: return SND_CHMAP_FLW;
|
||||
case SoundIoChannelIdFrontRightWide: return SND_CHMAP_FRW;
|
||||
case SoundIoChannelIdFrontLeftHigh: return SND_CHMAP_FLH;
|
||||
case SoundIoChannelIdFrontCenterHigh: return SND_CHMAP_FCH;
|
||||
case SoundIoChannelIdFrontRightHigh: return SND_CHMAP_FRH;
|
||||
case SoundIoChannelIdTopCenter: return SND_CHMAP_TC;
|
||||
case SoundIoChannelIdTopFrontLeft: return SND_CHMAP_TFL;
|
||||
case SoundIoChannelIdTopFrontRight: return SND_CHMAP_TFR;
|
||||
case SoundIoChannelIdTopFrontCenter: return SND_CHMAP_TFC;
|
||||
case SoundIoChannelIdTopBackLeft: return SND_CHMAP_TRL;
|
||||
case SoundIoChannelIdTopBackRight: return SND_CHMAP_TRR;
|
||||
case SoundIoChannelIdTopBackCenter: return SND_CHMAP_TRC;
|
||||
case SoundIoChannelIdTopFrontLeftCenter: return SND_CHMAP_TFLC;
|
||||
case SoundIoChannelIdTopFrontRightCenter: return SND_CHMAP_TFRC;
|
||||
case SoundIoChannelIdTopSideLeft: return SND_CHMAP_TSL;
|
||||
case SoundIoChannelIdTopSideRight: return SND_CHMAP_TSR;
|
||||
case SoundIoChannelIdLeftLfe: return SND_CHMAP_LLFE;
|
||||
case SoundIoChannelIdRightLfe: return SND_CHMAP_RLFE;
|
||||
case SoundIoChannelIdBottomCenter: return SND_CHMAP_BC;
|
||||
case SoundIoChannelIdBottomLeftCenter: return SND_CHMAP_BLC;
|
||||
case SoundIoChannelIdBottomRightCenter: return SND_CHMAP_BRC;
|
||||
case SoundIoChannelIdInvalid: return SND_CHMAP_UNKNOWN;
|
||||
}
|
||||
return SND_CHMAP_UNKNOWN;
|
||||
}
|
||||
|
||||
static void get_channel_layout(SoundIoChannelLayout *dest, snd_pcm_chmap_t *chmap) {
|
||||
int channel_count = min((unsigned int)SOUNDIO_MAX_CHANNELS, chmap->channels);
|
||||
dest->channel_count = channel_count;
|
||||
|
@ -209,15 +253,6 @@ static void test_fmt_mask(SoundIoDevice *device, const snd_pcm_format_mask_t *fm
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: look at http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html#a27
|
||||
// deterimine what do do about:
|
||||
// * hw buffer size
|
||||
// * hw period time
|
||||
// * sw start threshold
|
||||
// * sw avail min
|
||||
// TODO: device->default_latency
|
||||
|
||||
|
||||
// this function does not override device->formats, so if you want it to, deallocate and set it to NULL
|
||||
static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle,
|
||||
snd_pcm_hw_params_t *hwparams, int resample)
|
||||
|
@ -237,20 +272,67 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle,
|
|||
if ((err = snd_pcm_hw_params_set_channels_last(handle, hwparams, &channel_count)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
unsigned int min_sample_rate;
|
||||
unsigned int max_sample_rate;
|
||||
int min_dir;
|
||||
int max_dir;
|
||||
unsigned int num;
|
||||
unsigned int den;
|
||||
|
||||
if ((err = snd_pcm_hw_params_get_rate_max(hwparams, &max_sample_rate, &max_dir)) < 0)
|
||||
int dir = 0;
|
||||
if ((err = snd_pcm_hw_params_set_rate_first(handle, hwparams, &num, &dir)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
if (max_dir < 0)
|
||||
max_sample_rate -= 1;
|
||||
|
||||
if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &min_sample_rate, &min_dir)) < 0)
|
||||
if ((err = snd_pcm_hw_params_get_rate_numden(hwparams, &num, &den)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
if (min_dir > 0)
|
||||
min_sample_rate += 1;
|
||||
|
||||
if (den != 1)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
device->sample_rate_min = num;
|
||||
|
||||
dir = 0;
|
||||
if ((err = snd_pcm_hw_params_set_rate_last(handle, hwparams, &num, &dir)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
if ((err = snd_pcm_hw_params_get_rate_numden(hwparams, &num, &den)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
if (den != 1)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
device->sample_rate_max = num;
|
||||
|
||||
// Purposefully leave the parameters with the highest rate, highest channel count.
|
||||
|
||||
snd_pcm_uframes_t min_frames;
|
||||
snd_pcm_uframes_t max_frames;
|
||||
if ((err = snd_pcm_hw_params_get_buffer_size_min(hwparams, &min_frames)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
if ((err = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
// divide the frame counts by the max sample rate
|
||||
device->buffer_duration_min = ((double)min_frames) / (double)device->sample_rate_max;
|
||||
device->buffer_duration_max = ((double)max_frames) / (double)device->sample_rate_max;
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_periods_integer(handle, hwparams)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
dir = 0;
|
||||
if ((err = snd_pcm_hw_params_get_periods_min(hwparams, &num, &dir)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
if (dir != 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
device->period_count_min = num;
|
||||
|
||||
dir = 0;
|
||||
if ((err = snd_pcm_hw_params_get_periods_max(hwparams, &num, &dir)) < 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
if (dir != 0)
|
||||
return SoundIoErrorOpeningDevice;
|
||||
|
||||
device->period_count_max = num;
|
||||
|
||||
|
||||
snd_pcm_format_mask_t *fmt_mask;
|
||||
snd_pcm_format_mask_alloca(&fmt_mask);
|
||||
|
@ -304,9 +386,6 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle,
|
|||
test_fmt_mask(device, fmt_mask, SoundIoFormatFloat64BE);
|
||||
}
|
||||
|
||||
device->sample_rate_min = min_sample_rate;
|
||||
device->sample_rate_max = max_sample_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -347,8 +426,15 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
|
|||
}
|
||||
maps = nullptr;
|
||||
|
||||
if (device->sample_rate_min == device->sample_rate_max && !device->is_raw) {
|
||||
device->sample_rate_current = device->sample_rate_min;
|
||||
if (!device->is_raw) {
|
||||
if (device->sample_rate_min == device->sample_rate_max)
|
||||
device->sample_rate_current = device->sample_rate_min;
|
||||
|
||||
if (device->buffer_duration_min == device->buffer_duration_max)
|
||||
device->buffer_duration_current = device->buffer_duration_min;
|
||||
|
||||
if (device->period_count_min == device->period_count_max)
|
||||
device->period_count_current = device->period_count_min;
|
||||
|
||||
// now say that resampling is OK and see what the real min and max is.
|
||||
if ((err = probe_open_device(device, handle, hwparams, 1)) < 0) {
|
||||
|
@ -754,11 +840,17 @@ static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *
|
|||
if (!osa)
|
||||
return;
|
||||
|
||||
deallocate(osa->chmap, osa->chmap_size);
|
||||
|
||||
if (osa->handle)
|
||||
snd_pcm_close(osa->handle);
|
||||
|
||||
destroy(osa);
|
||||
os->backend_data = nullptr;
|
||||
}
|
||||
|
||||
static int outstream_init_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
SoundIoOutStreamAlsa *osa = create<SoundIoOutStreamAlsa>();
|
||||
if (!osa) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
|
@ -766,6 +858,119 @@ static int outstream_init_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
|||
}
|
||||
os->backend_data = osa;
|
||||
|
||||
osa->chmap_size = sizeof(int) + sizeof(int) * outstream->layout.channel_count;
|
||||
osa->chmap = (snd_pcm_chmap_t *)allocate<char>(osa->chmap_size);
|
||||
if (!osa->chmap) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
int err;
|
||||
|
||||
snd_pcm_hw_params_t *hwparams;
|
||||
snd_pcm_hw_params_alloca(&hwparams);
|
||||
|
||||
snd_pcm_stream_t stream = purpose_to_stream(outstream->device->purpose);
|
||||
|
||||
if ((err = snd_pcm_open(&osa->handle, outstream->device->name, stream, 0)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_any(osa->handle, hwparams)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
int want_resample = !outstream->device->is_raw;
|
||||
if ((err = snd_pcm_hw_params_set_rate_resample(osa->handle, hwparams, want_resample)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_access(osa->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_channels(osa->handle, hwparams, outstream->layout.channel_count)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_rate(osa->handle, hwparams, outstream->sample_rate, 0)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_format(osa->handle, hwparams, to_alsa_fmt(outstream->format))) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
|
||||
snd_pcm_uframes_t buffer_size_frames = ceil(outstream->buffer_duration * (double)outstream->sample_rate);
|
||||
if ((err = snd_pcm_hw_params_set_buffer_size_near(osa->handle, hwparams, &buffer_size_frames)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
outstream->buffer_duration = ((double)buffer_size_frames) / (double)outstream->sample_rate;
|
||||
|
||||
unsigned int actual_periods_count = outstream->period_count;
|
||||
if ((err = snd_pcm_hw_params_set_periods_near(osa->handle, hwparams, &actual_periods_count, nullptr)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
outstream->period_count = actual_periods_count;
|
||||
|
||||
|
||||
snd_pcm_uframes_t period_size;
|
||||
if ((snd_pcm_hw_params_get_period_size(hwparams, &period_size, nullptr)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
// write the hardware parameters to device
|
||||
if ((err = snd_pcm_hw_params(osa->handle, hwparams)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
// set channel map
|
||||
osa->chmap->channels = outstream->layout.channel_count;
|
||||
for (int i = 0; i < outstream->layout.channel_count; i += 1) {
|
||||
osa->chmap->pos[i] = to_alsa_chmap_pos(outstream->layout.channels[i]);
|
||||
}
|
||||
if (snd_pcm_set_chmap(osa->handle, osa->chmap) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
// get current swparams
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
|
||||
if ((err = snd_pcm_sw_params_current(osa->handle, swparams)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_sw_params_set_start_threshold(osa->handle, swparams, buffer_size_frames)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_sw_params_set_avail_min(osa->handle, swparams, period_size)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
// write the software parameters to device
|
||||
if ((err = snd_pcm_sw_params(osa->handle, swparams)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -795,7 +1000,7 @@ static void outstream_clear_buffer_alsa(SoundIoPrivate *si,
|
|||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static int instream_init_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
|
@ -900,7 +1105,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
|
|||
si->wait_events = wait_events;
|
||||
si->wakeup = wakeup;
|
||||
|
||||
si->outstream_init = outstream_init_alsa;
|
||||
si->outstream_open = outstream_open_alsa;
|
||||
si->outstream_destroy = outstream_destroy_alsa;
|
||||
si->outstream_start = outstream_start_alsa;
|
||||
si->outstream_free_count = outstream_free_count_alsa;
|
||||
|
@ -908,7 +1113,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
|
|||
si->outstream_write = outstream_write_alsa;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_alsa;
|
||||
|
||||
si->instream_init = instream_init_alsa;
|
||||
si->instream_open = instream_open_alsa;
|
||||
si->instream_destroy = instream_destroy_alsa;
|
||||
si->instream_start = instream_start_alsa;
|
||||
si->instream_peek = instream_peek_alsa;
|
||||
|
|
|
@ -131,7 +131,7 @@ static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
|||
os->backend_data = nullptr;
|
||||
}
|
||||
|
||||
static int outstream_init_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
SoundIoOutStreamDummy *osd = create<SoundIoOutStreamDummy>();
|
||||
if (!osd) {
|
||||
|
@ -140,9 +140,8 @@ static int outstream_init_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
|||
}
|
||||
os->backend_data = osd;
|
||||
|
||||
int buffer_frame_count = outstream->latency * outstream->sample_rate;
|
||||
osd->buffer_size = outstream->bytes_per_frame * buffer_frame_count;
|
||||
osd->period = outstream->latency * 0.5;
|
||||
osd->buffer_size = outstream->bytes_per_frame * outstream->buffer_duration;
|
||||
osd->period = outstream->buffer_duration / (double)outstream->period_count;
|
||||
|
||||
soundio_ring_buffer_init(&osd->ring_buffer, osd->buffer_size);
|
||||
|
||||
|
@ -205,7 +204,7 @@ static void outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPri
|
|||
soundio_ring_buffer_clear(&osd->ring_buffer);
|
||||
}
|
||||
|
||||
static int instream_init_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
|
@ -237,24 +236,24 @@ static int set_all_device_formats(SoundIoDevice *device) {
|
|||
if (!device->formats)
|
||||
return SoundIoErrorNoMem;
|
||||
|
||||
device->formats[0] = SoundIoFormatS8;
|
||||
device->formats[1] = SoundIoFormatU8;
|
||||
device->formats[2] = SoundIoFormatS16LE;
|
||||
device->formats[3] = SoundIoFormatS16BE;
|
||||
device->formats[4] = SoundIoFormatU16LE;
|
||||
device->formats[5] = SoundIoFormatU16BE;
|
||||
device->formats[6] = SoundIoFormatS24LE;
|
||||
device->formats[7] = SoundIoFormatS24BE;
|
||||
device->formats[8] = SoundIoFormatU24LE;
|
||||
device->formats[9] = SoundIoFormatU24BE;
|
||||
device->formats[10] = SoundIoFormatS32LE;
|
||||
device->formats[11] = SoundIoFormatS32BE;
|
||||
device->formats[12] = SoundIoFormatU32LE;
|
||||
device->formats[13] = SoundIoFormatU32BE;
|
||||
device->formats[14] = SoundIoFormatFloat32LE;
|
||||
device->formats[15] = SoundIoFormatFloat32BE;
|
||||
device->formats[16] = SoundIoFormatFloat64LE;
|
||||
device->formats[17] = SoundIoFormatFloat64BE;
|
||||
device->formats[0] = SoundIoFormatFloat32NE;
|
||||
device->formats[1] = SoundIoFormatFloat32FE;
|
||||
device->formats[2] = SoundIoFormatS32NE;
|
||||
device->formats[3] = SoundIoFormatS32FE;
|
||||
device->formats[4] = SoundIoFormatU32NE;
|
||||
device->formats[5] = SoundIoFormatU32FE;
|
||||
device->formats[6] = SoundIoFormatS24NE;
|
||||
device->formats[7] = SoundIoFormatS24FE;
|
||||
device->formats[8] = SoundIoFormatU24NE;
|
||||
device->formats[9] = SoundIoFormatU24FE;
|
||||
device->formats[10] = SoundIoFormatFloat64NE;
|
||||
device->formats[11] = SoundIoFormatFloat64FE;
|
||||
device->formats[12] = SoundIoFormatS16NE;
|
||||
device->formats[13] = SoundIoFormatS16FE;
|
||||
device->formats[14] = SoundIoFormatU16NE;
|
||||
device->formats[15] = SoundIoFormatU16FE;
|
||||
device->formats[16] = SoundIoFormatS8;
|
||||
device->formats[17] = SoundIoFormatU8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -324,10 +323,15 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
return err;
|
||||
}
|
||||
|
||||
device->default_latency = 0.01;
|
||||
device->buffer_duration_min = 0.01;
|
||||
device->buffer_duration_max = 4;
|
||||
device->buffer_duration_current = 0.1;
|
||||
device->sample_rate_min = 2;
|
||||
device->sample_rate_max = 5644800;
|
||||
device->sample_rate_current = 48000;
|
||||
device->period_count_min = 1;
|
||||
device->period_count_max = 16;
|
||||
device->period_count_current = 2;
|
||||
device->purpose = SoundIoDevicePurposeOutput;
|
||||
|
||||
if (si->safe_devices_info->output_devices.append(device)) {
|
||||
|
@ -370,10 +374,15 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
destroy_dummy(si);
|
||||
return err;
|
||||
}
|
||||
device->default_latency = 0.01;
|
||||
device->buffer_duration_min = 0.01;
|
||||
device->buffer_duration_max = 4;
|
||||
device->buffer_duration_current = 0.1;
|
||||
device->sample_rate_min = 2;
|
||||
device->sample_rate_max = 5644800;
|
||||
device->sample_rate_current = 48000;
|
||||
device->period_count_min = 1;
|
||||
device->period_count_max = 16;
|
||||
device->period_count_current = 2;
|
||||
device->purpose = SoundIoDevicePurposeInput;
|
||||
|
||||
if (si->safe_devices_info->input_devices.append(device)) {
|
||||
|
@ -389,7 +398,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
si->wait_events = wait_events;
|
||||
si->wakeup = wakeup;
|
||||
|
||||
si->outstream_init = outstream_init_dummy;
|
||||
si->outstream_open = outstream_open_dummy;
|
||||
si->outstream_destroy = outstream_destroy_dummy;
|
||||
si->outstream_start = outstream_start_dummy;
|
||||
si->outstream_free_count = outstream_free_count_dummy;
|
||||
|
@ -397,7 +406,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
si->outstream_write = outstream_write_dummy;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_dummy;
|
||||
|
||||
si->instream_init = instream_init_dummy;
|
||||
si->instream_open = instream_open_dummy;
|
||||
si->instream_destroy = instream_destroy_dummy;
|
||||
si->instream_start = instream_start_dummy;
|
||||
si->instream_peek = instream_peek_dummy;
|
||||
|
|
|
@ -695,6 +695,7 @@ void soundio_os_destroy_mirrored_memory(char *address, size_t capacity) {
|
|||
if (!address)
|
||||
return;
|
||||
#if defined(SOUNDIO_OS_WINDOWS)
|
||||
// TODO
|
||||
#else
|
||||
int err = munmap(address, 2 * capacity);
|
||||
assert(!err);
|
||||
|
|
|
@ -134,9 +134,11 @@ static void destroy_pa(SoundIoPrivate *si) {
|
|||
si->backend_data = nullptr;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
static double usec_to_sec(pa_usec_t usec) {
|
||||
return (double)usec / (double)PA_USEC_PER_SEC;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
static SoundIoFormat format_from_pulseaudio(pa_sample_spec sample_spec) {
|
||||
|
@ -162,9 +164,11 @@ static SoundIoFormat format_from_pulseaudio(pa_sample_spec sample_spec) {
|
|||
return SoundIoFormatInvalid;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
static int sample_rate_from_pulseaudio(pa_sample_spec sample_spec) {
|
||||
return sample_spec.rate;
|
||||
}
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
static SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
|
||||
|
@ -287,8 +291,10 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
|||
// TODO determine the channel layouts supported
|
||||
//TODO set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout);
|
||||
device->current_format = format_from_pulseaudio(info->sample_spec);
|
||||
device->default_latency = usec_to_sec(info->configured_latency);
|
||||
device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
|
||||
// TODO set min, max, current latency
|
||||
//device->default_latency = usec_to_sec(info->configured_latency);
|
||||
// TODO set min, max, current sample rate
|
||||
//device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
|
||||
device->purpose = SoundIoDevicePurposeOutput;
|
||||
|
||||
if (sipa->current_devices_info->output_devices.append(device))
|
||||
|
@ -319,8 +325,10 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
|||
// TODO determine the channel layouts supported
|
||||
// TODO set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout);
|
||||
device->current_format = format_from_pulseaudio(info->sample_spec);
|
||||
device->default_latency = usec_to_sec(info->configured_latency);
|
||||
device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
|
||||
// TODO set min, max, current latency
|
||||
//device->default_latency = usec_to_sec(info->configured_latency);
|
||||
// TODO set min, max, current sample rate
|
||||
//device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
|
||||
device->purpose = SoundIoDevicePurposeInput;
|
||||
|
||||
if (sipa->current_devices_info->input_devices.append(device))
|
||||
|
@ -590,8 +598,9 @@ static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
|
|||
os->backend_data = nullptr;
|
||||
}
|
||||
|
||||
static int outstream_init_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
|
||||
SoundIoOutStreamPulseAudio *ospa = create<SoundIoOutStreamPulseAudio>();
|
||||
if (!ospa) {
|
||||
outstream_destroy_pa(si, os);
|
||||
|
@ -626,7 +635,7 @@ static int outstream_init_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
|||
|
||||
int bytes_per_second = outstream->bytes_per_frame * outstream->sample_rate;
|
||||
int buffer_length = outstream->bytes_per_frame *
|
||||
ceil(outstream->latency * bytes_per_second / (double)outstream->bytes_per_frame);
|
||||
ceil(outstream->buffer_duration * bytes_per_second / (double)outstream->bytes_per_frame);
|
||||
|
||||
ospa->buffer_attr.maxlength = buffer_length;
|
||||
ospa->buffer_attr.tlength = buffer_length;
|
||||
|
@ -757,7 +766,7 @@ static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *inst
|
|||
}
|
||||
}
|
||||
|
||||
static int instream_init_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
SoundIoInStreamPulseAudio *ispa = create<SoundIoInStreamPulseAudio>();
|
||||
if (!ispa) {
|
||||
|
@ -793,7 +802,7 @@ static int instream_init_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
|||
|
||||
int bytes_per_second = instream->bytes_per_frame * instream->sample_rate;
|
||||
int buffer_length = instream->bytes_per_frame *
|
||||
ceil(instream->latency * bytes_per_second / (double)instream->bytes_per_frame);
|
||||
ceil(instream->buffer_duration * bytes_per_second / (double)instream->bytes_per_frame);
|
||||
|
||||
ispa->buffer_attr.maxlength = UINT32_MAX;
|
||||
ispa->buffer_attr.tlength = UINT32_MAX;
|
||||
|
@ -937,7 +946,7 @@ int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
|||
si->wait_events = wait_events;
|
||||
si->wakeup = wakeup;
|
||||
|
||||
si->outstream_init = outstream_init_pa;
|
||||
si->outstream_open = outstream_open_pa;
|
||||
si->outstream_destroy = outstream_destroy_pa;
|
||||
si->outstream_start = outstream_start_pa;
|
||||
si->outstream_free_count = outstream_free_count_pa;
|
||||
|
@ -945,7 +954,7 @@ int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
|||
si->outstream_write = outstream_write_pa;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_pa;
|
||||
|
||||
si->instream_init = instream_init_pa;
|
||||
si->instream_open = instream_open_pa;
|
||||
si->instream_destroy = instream_destroy_pa;
|
||||
si->instream_start = instream_start_pa;
|
||||
si->instream_peek = instream_peek_pa;
|
||||
|
|
|
@ -208,7 +208,7 @@ void soundio_disconnect(struct SoundIo *soundio) {
|
|||
si->wait_events = nullptr;
|
||||
si->wakeup = nullptr;
|
||||
|
||||
si->outstream_init = nullptr;
|
||||
si->outstream_open = nullptr;
|
||||
si->outstream_destroy = nullptr;
|
||||
si->outstream_start = nullptr;
|
||||
si->outstream_free_count = nullptr;
|
||||
|
@ -216,7 +216,7 @@ void soundio_disconnect(struct SoundIo *soundio) {
|
|||
si->outstream_write = nullptr;
|
||||
si->outstream_clear_buffer = nullptr;
|
||||
|
||||
si->instream_init = nullptr;
|
||||
si->instream_open = nullptr;
|
||||
si->instream_destroy = nullptr;
|
||||
si->instream_start = nullptr;
|
||||
si->instream_peek = nullptr;
|
||||
|
@ -304,6 +304,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
|
|||
free(device->name);
|
||||
free(device->description);
|
||||
deallocate(device->formats, device->format_count);
|
||||
deallocate(device->layouts, device->layout_count);
|
||||
destroy(device);
|
||||
}
|
||||
}
|
||||
|
@ -369,18 +370,28 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device)
|
|||
outstream->device = device;
|
||||
soundio_device_ref(device);
|
||||
|
||||
// TODO set defaults
|
||||
const SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||
|
||||
outstream->format = soundio_device_supports_format(device, SoundIoFormatFloat32NE) ?
|
||||
SoundIoFormatFloat32NE : device->formats[0];
|
||||
outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
||||
outstream->sample_rate = clamp(device->sample_rate_min, 48000, device->sample_rate_max);
|
||||
outstream->buffer_duration = clamp(device->buffer_duration_min, 1.0, device->buffer_duration_max);
|
||||
outstream->period_count = clamp(device->period_count_min, 2, device->period_count_max);
|
||||
|
||||
return outstream;
|
||||
}
|
||||
|
||||
int soundio_outstream_open(struct SoundIoOutStream *outstream) {
|
||||
if (outstream->format <= SoundIoFormatInvalid)
|
||||
return SoundIoErrorInvalid;
|
||||
|
||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
||||
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
|
||||
|
||||
SoundIo *soundio = outstream->device->soundio;
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||
return si->outstream_init(si, os);
|
||||
return si->outstream_open(si, os);
|
||||
}
|
||||
|
||||
void soundio_outstream_destroy(SoundIoOutStream *outstream) {
|
||||
|
@ -414,17 +425,26 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
|
|||
instream->device = device;
|
||||
soundio_device_ref(device);
|
||||
|
||||
// TODO set defaults
|
||||
const SoundIoChannelLayout *stereo = soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdStereo);
|
||||
|
||||
instream->format = soundio_device_supports_format(device, SoundIoFormatFloat32NE) ?
|
||||
SoundIoFormatFloat32NE : device->formats[0];
|
||||
instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
|
||||
instream->sample_rate = clamp(device->sample_rate_min, 48000, device->sample_rate_max);
|
||||
instream->buffer_duration = clamp(device->buffer_duration_min, 1.0, device->buffer_duration_max);
|
||||
instream->period_count = clamp(device->period_count_min, 8, device->period_count_max);
|
||||
|
||||
return instream;
|
||||
}
|
||||
|
||||
int soundio_instream_open(struct SoundIoInStream *instream) {
|
||||
if (instream->format <= SoundIoFormatInvalid)
|
||||
return SoundIoErrorInvalid;
|
||||
instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count);
|
||||
SoundIo *soundio = instream->device->soundio;
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_init(si, is);
|
||||
return si->instream_open(si, is);
|
||||
}
|
||||
|
||||
int soundio_instream_start(struct SoundIoInStream *instream) {
|
||||
|
@ -543,3 +563,13 @@ bool soundio_device_supports_format(struct SoundIoDevice *device, enum SoundIoFo
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool soundio_device_supports_layout(struct SoundIoDevice *device,
|
||||
const struct SoundIoChannelLayout *layout)
|
||||
{
|
||||
for (int i = 0; i < device->layout_count; i += 1) {
|
||||
if (soundio_channel_layout_equal(&device->layouts[i], layout))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -185,6 +185,7 @@ struct SoundIoChannelLayout {
|
|||
enum SoundIoChannelId channels[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
|
||||
// The size of this struct is not part of the API or ABI.
|
||||
struct SoundIoDevice {
|
||||
// Read-only. Set automatically.
|
||||
|
@ -232,7 +233,15 @@ struct SoundIoDevice {
|
|||
int sample_rate_max;
|
||||
int sample_rate_current;
|
||||
|
||||
double default_latency;
|
||||
// Buffer duration in seconds.
|
||||
double buffer_duration_min;
|
||||
double buffer_duration_max;
|
||||
double buffer_duration_current;
|
||||
|
||||
// How many slices it is possible to cut the buffer into.
|
||||
int period_count_min;
|
||||
int period_count_max;
|
||||
int period_count_current;
|
||||
|
||||
// Tells whether this device is an input device or an output device.
|
||||
enum SoundIoDevicePurpose purpose;
|
||||
|
@ -258,12 +267,34 @@ struct SoundIoDevice {
|
|||
|
||||
// The size of this struct is not part of the API or ABI.
|
||||
struct SoundIoOutStream {
|
||||
// Populated automatically when you call soundio_outstream_create.
|
||||
struct SoundIoDevice *device;
|
||||
enum SoundIoFormat format;
|
||||
int sample_rate;
|
||||
struct SoundIoChannelLayout layout;
|
||||
double latency;
|
||||
|
||||
// Defaults to SoundIoFormatFloat32NE, followed by the first one supported.
|
||||
enum SoundIoFormat format;
|
||||
|
||||
// Defaults to 48000 (and then clamped into range).
|
||||
int sample_rate;
|
||||
|
||||
// Defaults to Stereo, if available, followed by the first layout supported.
|
||||
struct SoundIoChannelLayout layout;
|
||||
|
||||
// Buffer duration in seconds.
|
||||
// (buffer_duration / period_count) is the latency; how much time it takes
|
||||
// for a sample put in the buffer to get played.
|
||||
// After you call soundio_outstream_open this value is replaced with the
|
||||
// actual duration, as near to this value as possible.
|
||||
// Defaults to 1 second (and then clamped into range).
|
||||
double buffer_duration;
|
||||
|
||||
// How many slices the buffer is cut into. The IRQ will happen every
|
||||
// (buffer_frame_count / period_count) frames.
|
||||
// After you call soundio_outstream_open this value is replaced with the
|
||||
// actual period count, as near to this value as possible.
|
||||
// Defaults to 2 (and then clamped into range).
|
||||
int period_count;
|
||||
|
||||
// Defaults to NULL.
|
||||
void *userdata;
|
||||
void (*underrun_callback)(struct SoundIoOutStream *);
|
||||
void (*write_callback)(struct SoundIoOutStream *, int frame_count);
|
||||
|
@ -274,11 +305,28 @@ struct SoundIoOutStream {
|
|||
|
||||
// The size of this struct is not part of the API or ABI.
|
||||
struct SoundIoInStream {
|
||||
// Populated automatically when you call soundio_outstream_create.
|
||||
struct SoundIoDevice *device;
|
||||
|
||||
// Defaults to SoundIoFormatFloat32NE, followed by the first one supported.
|
||||
enum SoundIoFormat format;
|
||||
|
||||
// Defaults to max(sample_rate_min, min(sample_rate_max, 48000))
|
||||
int sample_rate;
|
||||
|
||||
// Defaults to Stereo, if available, followed by the first layout supported.
|
||||
struct SoundIoChannelLayout layout;
|
||||
double latency;
|
||||
|
||||
// Buffer duration in seconds. If the captured audio frames exceeds this
|
||||
// before they are read, a buffer overrun occurs and the frames are lost.
|
||||
// Defaults to 1 second (and then clamped into range).
|
||||
double buffer_duration;
|
||||
|
||||
// How many slices the buffer is cut into. The IRQ will happen every
|
||||
// (buffer_duration / period_count) seconds, and that is the latency of the
|
||||
// captured audio. This value must be a power of 2.
|
||||
// Defaults to 8.
|
||||
int period_count;
|
||||
|
||||
void *userdata;
|
||||
void (*read_callback)(struct SoundIoInStream *);
|
||||
|
@ -413,7 +461,13 @@ enum SoundIoDevicePurpose soundio_device_purpose(const struct SoundIoDevice *dev
|
|||
void soundio_device_sort_channel_layouts(struct SoundIoDevice *device);
|
||||
|
||||
// Returns whether `format` is included in the devices supported formats.
|
||||
bool soundio_device_supports_format(struct SoundIoDevice *device, enum SoundIoFormat format);
|
||||
bool soundio_device_supports_format(struct SoundIoDevice *device,
|
||||
enum SoundIoFormat format);
|
||||
|
||||
// Returns whether `layout` is included in the devices supported channel
|
||||
// layouts.
|
||||
bool soundio_device_supports_layout(struct SoundIoDevice *device,
|
||||
const struct SoundIoChannelLayout *layout);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ struct SoundIoPrivate {
|
|||
void (*wait_events)(struct SoundIoPrivate *);
|
||||
void (*wakeup)(struct SoundIoPrivate *);
|
||||
|
||||
int (*outstream_init)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_open)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_free_count)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
|
@ -54,7 +54,7 @@ struct SoundIoPrivate {
|
|||
void (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
|
||||
|
||||
int (*instream_init)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
int (*instream_start)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
void (*instream_peek)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
|
||||
|
|
|
@ -103,4 +103,9 @@ template <typename T>
|
|||
static inline T min(T a, T b) {
|
||||
return (a <= b) ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T clamp(T min_value, T value, T max_value) {
|
||||
return max(min(value, max_value), min_value);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,7 @@ static void test_create_outstream(void) {
|
|||
outstream->format = SoundIoFormatFloat32NE;
|
||||
outstream->sample_rate = 48000;
|
||||
outstream->layout = device->layouts[0];
|
||||
outstream->latency = 0.1;
|
||||
outstream->buffer_duration = 0.1;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underrun_callback = underrun_callback;
|
||||
|
||||
|
|
|
@ -94,3 +94,20 @@
|
|||
...
|
||||
fun:snd1_dlobj_cache_get
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
fun:snd_pcm_hw_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_direct_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_generic_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_generic_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd1_pcm_generic_get_chmap
|
||||
fun:snd_pcm_get_chmap
|
||||
fun:snd_pcm_set_chmap
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue