ALSA backend determines channel layout of devices

This commit is contained in:
Andrew Kelley 2015-07-09 23:35:58 -07:00
parent c760bc4df7
commit fe2040da7c
8 changed files with 319 additions and 115 deletions

View file

@ -137,6 +137,7 @@ view `coverage/index.html` in a browser.
- pulseaudio has peek() drop() which sucks, but what if libsoundio lets you - pulseaudio has peek() drop() which sucks, but what if libsoundio lets you
specify how much to peek() and if you don't peek all of it, save the specify how much to peek() and if you don't peek all of it, save the
unused to a buffer for you. unused to a buffer for you.
0. add len arguments to APIs that have char *
## Planned Uses for libsoundio ## Planned Uses for libsoundio

View file

@ -15,6 +15,8 @@
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE}; static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
static const int MAX_SAMPLE_RATE = 48000;
struct SoundIoAlsa { struct SoundIoAlsa {
SoundIoOsMutex *mutex; SoundIoOsMutex *mutex;
SoundIoOsCond *cond; SoundIoOsCond *cond;
@ -81,6 +83,169 @@ static char * str_partition_on_char(char *str, char c) {
return nullptr; return nullptr;
} }
static snd_pcm_stream_t purpose_to_stream(SoundIoDevicePurpose purpose) {
switch (purpose) {
case SoundIoDevicePurposeOutput: return SND_PCM_STREAM_PLAYBACK;
case SoundIoDevicePurposeInput: return SND_PCM_STREAM_CAPTURE;
}
soundio_panic("invalid purpose");
}
static SoundIoChannelId from_alsa_chmap_pos(unsigned int pos) {
switch ((snd_pcm_chmap_position)pos) {
case SND_CHMAP_UNKNOWN: return SoundIoChannelIdInvalid;
case SND_CHMAP_NA: return SoundIoChannelIdInvalid;
case SND_CHMAP_MONO: return SoundIoChannelIdFrontCenter;
case SND_CHMAP_FL: return SoundIoChannelIdFrontLeft; // front left
case SND_CHMAP_FR: return SoundIoChannelIdFrontRight; // front right
case SND_CHMAP_RL: return SoundIoChannelIdBackLeft; // rear left
case SND_CHMAP_RR: return SoundIoChannelIdBackRight; // rear right
case SND_CHMAP_FC: return SoundIoChannelIdFrontCenter; // front center
case SND_CHMAP_LFE: return SoundIoChannelIdLfe; // LFE
case SND_CHMAP_SL: return SoundIoChannelIdSideLeft; // side left
case SND_CHMAP_SR: return SoundIoChannelIdSideRight; // side right
case SND_CHMAP_RC: return SoundIoChannelIdBackCenter; // rear center
case SND_CHMAP_FLC: return SoundIoChannelIdFrontLeftCenter; // front left center
case SND_CHMAP_FRC: return SoundIoChannelIdFrontRightCenter; // front right center
case SND_CHMAP_RLC: return SoundIoChannelIdBackLeftCenter; // rear left center
case SND_CHMAP_RRC: return SoundIoChannelIdBackRightCenter; // rear right center
case SND_CHMAP_FLW: return SoundIoChannelIdFrontLeftWide; // front left wide
case SND_CHMAP_FRW: return SoundIoChannelIdFrontRightWide; // front right wide
case SND_CHMAP_FLH: return SoundIoChannelIdFrontLeftHigh; // front left high
case SND_CHMAP_FCH: return SoundIoChannelIdFrontCenterHigh; // front center high
case SND_CHMAP_FRH: return SoundIoChannelIdFrontRightHigh; // front right high
case SND_CHMAP_TC: return SoundIoChannelIdTopCenter; // top center
case SND_CHMAP_TFL: return SoundIoChannelIdTopFrontLeft; // top front left
case SND_CHMAP_TFR: return SoundIoChannelIdTopFrontRight; // top front right
case SND_CHMAP_TFC: return SoundIoChannelIdTopFrontCenter; // top front center
case SND_CHMAP_TRL: return SoundIoChannelIdTopBackLeft; // top rear left
case SND_CHMAP_TRR: return SoundIoChannelIdTopBackRight; // top rear right
case SND_CHMAP_TRC: return SoundIoChannelIdTopBackCenter; // top rear center
case SND_CHMAP_TFLC: return SoundIoChannelIdTopFrontLeftCenter; // top front left center
case SND_CHMAP_TFRC: return SoundIoChannelIdTopFrontRightCenter; // top front right center
case SND_CHMAP_TSL: return SoundIoChannelIdTopSideLeft; // top side left
case SND_CHMAP_TSR: return SoundIoChannelIdTopSideRight; // top side right
case SND_CHMAP_LLFE: return SoundIoChannelIdLeftLfe; // left LFE
case SND_CHMAP_RLFE: return SoundIoChannelIdRightLfe; // right LFE
case SND_CHMAP_BC: return SoundIoChannelIdBottomCenter; // bottom center
case SND_CHMAP_BLC: return SoundIoChannelIdBottomLeftCenter; // bottom left center
case SND_CHMAP_BRC: return SoundIoChannelIdBottomRightCenter; // bottom right center
}
return SoundIoChannelIdInvalid;
}
static void get_channel_layout(SoundIoDevice *device, snd_pcm_chmap_t *chmap) {
int channel_count = min((unsigned int)SOUNDIO_MAX_CHANNELS, chmap->channels);
device->channel_layout.channel_count = channel_count;
device->channel_layout.name = nullptr;
for (int i = 0; i < channel_count; i += 1) {
device->channel_layout.channels[i] = from_alsa_chmap_pos(chmap->pos[i]);
}
soundio_channel_layout_detect_builtin(&device->channel_layout);
}
static void handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
if (!maps)
return;
snd_pcm_chmap_query_t **p;
snd_pcm_chmap_query_t *v;
snd_pcm_chmap_t *best = nullptr;
for (p = maps; (v = *p); p += 1) {
if (!best || v->map.channels > best->channels)
best = &v->map;
}
get_channel_layout(device, best);
snd_pcm_free_chmaps(maps);
}
static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
int err;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);
snd_pcm_stream_t stream = purpose_to_stream(device->purpose);
if ((err = snd_pcm_open(&handle, device->name, stream, 0)) < 0) {
handle_channel_maps(device, maps);
return SoundIoErrorOpeningDevice;
}
if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) {
snd_pcm_close(handle);
return SoundIoErrorOpeningDevice;
}
// disable hardware resampling because we're trying to probe
if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 0)) < 0) {
snd_pcm_close(handle);
return SoundIoErrorOpeningDevice;
}
if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
snd_pcm_close(handle);
return SoundIoErrorOpeningDevice;
}
unsigned int channel_count;
if ((err = snd_pcm_hw_params_set_channels_last(handle, hwparams, &channel_count)) < 0) {
snd_pcm_close(handle);
return SoundIoErrorOpeningDevice;
}
unsigned int min_sample_rate;
unsigned int max_sample_rate;
int min_dir;
int max_dir;
if ((err = snd_pcm_hw_params_get_rate_max(hwparams, &max_sample_rate, &max_dir)) < 0) {
snd_pcm_close(handle);
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) {
snd_pcm_close(handle);
return SoundIoErrorOpeningDevice;
}
if (min_dir > 0)
min_sample_rate += 1;
snd_pcm_chmap_t *chmap = snd_pcm_get_chmap(handle);
if (chmap) {
get_channel_layout(device, chmap);
free(chmap);
} else if (!maps) {
maps = snd_pcm_query_chmaps(handle);
}
handle_channel_maps(device, maps);
device->sample_rate_min = min_sample_rate;
device->sample_rate_min = max_sample_rate;
device->sample_rate_default =
(min_sample_rate <= MAX_SAMPLE_RATE &&
MAX_SAMPLE_RATE <= max_sample_rate) ? MAX_SAMPLE_RATE : max_sample_rate;
snd_pcm_close(handle);
return 0;
// TODO: device->default_sample_format
// TODO: device->default_latency
}
static inline bool str_has_prefix(const char *big_str, const char *prefix) {
return strncmp(big_str, prefix, strlen(prefix)) == 0;
}
static int refresh_devices(SoundIo *soundio) { static int refresh_devices(SoundIo *soundio) {
SoundIoAlsa *sia = (SoundIoAlsa *)soundio->backend_data; SoundIoAlsa *sia = (SoundIoAlsa *)soundio->backend_data;
@ -173,12 +338,6 @@ static int refresh_devices(SoundIo *soundio) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
// TODO: device->channel_layout
// TODO: device->default_sample_format
// TODO: device->default_latency
// TODO: device->default_sample_rate
SoundIoList<SoundIoDevice *> *device_list; SoundIoList<SoundIoDevice *> *device_list;
if (stream == SND_PCM_STREAM_PLAYBACK) { if (stream == SND_PCM_STREAM_PLAYBACK) {
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
@ -193,6 +352,8 @@ static int refresh_devices(SoundIo *soundio) {
devices_info->default_input_index = device_list->length; devices_info->default_input_index = device_list->length;
} }
probe_device(device, nullptr);
if (device_list->append(device)) { if (device_list->append(device)) {
soundio_device_unref(device); soundio_device_unref(device);
free(name); free(name);
@ -289,11 +450,6 @@ static int refresh_devices(SoundIo *soundio) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
// TODO: device->channel_layout
// TODO: device->default_sample_format
// TODO: device->default_latency
// TODO: device->default_sample_rate
SoundIoList<SoundIoDevice *> *device_list; SoundIoList<SoundIoDevice *> *device_list;
if (stream == SND_PCM_STREAM_PLAYBACK) { if (stream == SND_PCM_STREAM_PLAYBACK) {
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
@ -304,6 +460,9 @@ static int refresh_devices(SoundIo *soundio) {
device_list = &devices_info->input_devices; device_list = &devices_info->input_devices;
} }
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream);
probe_device(device, maps);
if (device_list->append(device)) { if (device_list->append(device)) {
soundio_device_unref(device); soundio_device_unref(device);
destroy(devices_info); destroy(devices_info);

View file

@ -31,7 +31,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
{ {
SoundIoChannelIdFrontLeft, SoundIoChannelIdFrontLeft,
SoundIoChannelIdFrontRight, SoundIoChannelIdFrontRight,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
}, },
}, },
{ {
@ -59,7 +59,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontLeft, SoundIoChannelIdFrontLeft,
SoundIoChannelIdFrontRight, SoundIoChannelIdFrontRight,
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -79,7 +79,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontLeft, SoundIoChannelIdFrontLeft,
SoundIoChannelIdFrontRight, SoundIoChannelIdFrontRight,
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -133,7 +133,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -145,7 +145,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdBackLeft, SoundIoChannelIdBackLeft,
SoundIoChannelIdBackRight, SoundIoChannelIdBackRight,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -168,8 +168,8 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontRight, SoundIoChannelIdFrontRight,
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdFrontLeftOfCenter, SoundIoChannelIdFrontLeftCenter,
SoundIoChannelIdFrontRightOfCenter, SoundIoChannelIdFrontRightCenter,
} }
}, },
{ {
@ -194,7 +194,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdBackCenter, SoundIoChannelIdBackCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -207,7 +207,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdBackLeft, SoundIoChannelIdBackLeft,
SoundIoChannelIdBackRight, SoundIoChannelIdBackRight,
SoundIoChannelIdBackCenter, SoundIoChannelIdBackCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -218,9 +218,9 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontRight, SoundIoChannelIdFrontRight,
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdFrontLeftOfCenter, SoundIoChannelIdFrontLeftCenter,
SoundIoChannelIdFrontRightOfCenter, SoundIoChannelIdFrontRightCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -245,8 +245,8 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdFrontLeftOfCenter, SoundIoChannelIdFrontLeftCenter,
SoundIoChannelIdFrontRightOfCenter, SoundIoChannelIdFrontRightCenter,
} }
}, },
{ {
@ -260,7 +260,7 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdBackLeft, SoundIoChannelIdBackLeft,
SoundIoChannelIdBackRight, SoundIoChannelIdBackRight,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -272,9 +272,9 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
SoundIoChannelIdFrontLeftOfCenter, SoundIoChannelIdFrontLeftCenter,
SoundIoChannelIdFrontRightOfCenter, SoundIoChannelIdFrontRightCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -286,9 +286,9 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdBackLeft, SoundIoChannelIdBackLeft,
SoundIoChannelIdBackRight, SoundIoChannelIdBackRight,
SoundIoChannelIdFrontLeftOfCenter, SoundIoChannelIdFrontLeftCenter,
SoundIoChannelIdFrontRightOfCenter, SoundIoChannelIdFrontRightCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
} }
}, },
{ {
@ -307,6 +307,49 @@ static struct SoundIoChannelLayout builtin_channel_layouts[] = {
}, },
}; };
const char *soundio_get_channel_name(enum SoundIoChannelId id) {
switch (id) {
case SoundIoChannelIdInvalid: return "(Invalid Channel)";
case SoundIoChannelIdCount: return "(Invalid Channel)";
case SoundIoChannelIdFrontLeft: return "Front Left";
case SoundIoChannelIdFrontRight: return "Front Right";
case SoundIoChannelIdFrontCenter: return "Front Center";
case SoundIoChannelIdLfe: return "LFE";
case SoundIoChannelIdBackLeft: return "Back Left";
case SoundIoChannelIdBackRight: return "Back Right";
case SoundIoChannelIdFrontLeftCenter: return "Front Left Center";
case SoundIoChannelIdFrontRightCenter: return "Front Right Center";
case SoundIoChannelIdBackCenter: return "Back Center";
case SoundIoChannelIdSideLeft: return "Side Left";
case SoundIoChannelIdSideRight: return "Side Right";
case SoundIoChannelIdTopCenter: return "Top Center";
case SoundIoChannelIdTopFrontLeft: return "Top Front Left";
case SoundIoChannelIdTopFrontCenter: return "Top Front Center";
case SoundIoChannelIdTopFrontRight: return "Top Front Right";
case SoundIoChannelIdTopBackLeft: return "Top Back Left";
case SoundIoChannelIdTopBackCenter: return "Top Back Center";
case SoundIoChannelIdTopBackRight: return "Top Back Right";
case SoundIoChannelIdBackLeftCenter: return "Back Left Center";
case SoundIoChannelIdBackRightCenter: return "Back Right Center";
case SoundIoChannelIdFrontLeftWide: return "Front Left Wide";
case SoundIoChannelIdFrontRightWide: return "Front Right Wide";
case SoundIoChannelIdFrontLeftHigh: return "Front Left High";
case SoundIoChannelIdFrontCenterHigh: return "Front Center High";
case SoundIoChannelIdFrontRightHigh: return "Front Right High";
case SoundIoChannelIdTopFrontLeftCenter: return "Top Front Left Center";
case SoundIoChannelIdTopFrontRightCenter: return "Top Front Right Center";
case SoundIoChannelIdTopSideLeft: return "Top Side Left";
case SoundIoChannelIdTopSideRight: return "Top Side Right";
case SoundIoChannelIdLeftLfe: return "Left LFE";
case SoundIoChannelIdRightLfe: return "Right LFE";
case SoundIoChannelIdBottomCenter: return "Bottom Center";
case SoundIoChannelIdBottomLeftCenter: return "Bottom Left Center";
case SoundIoChannelIdBottomRightCenter: return "Bottom Right Center";
}
return "(Invalid Channel)";
}
bool soundio_channel_layout_equal( bool soundio_channel_layout_equal(
const struct SoundIoChannelLayout *a, const struct SoundIoChannelLayout *a,
const struct SoundIoChannelLayout *b) const struct SoundIoChannelLayout *b)
@ -322,33 +365,6 @@ bool soundio_channel_layout_equal(
return true; return true;
} }
const char *soundio_get_channel_name(enum SoundIoChannelId id) {
switch (id) {
case SoundIoChannelIdInvalid: return "(Invalid Channel)";
case SoundIoChannelIdCount: return "(Invalid Channel)";
case SoundIoChannelIdFrontLeft: return "Front Left";
case SoundIoChannelIdFrontRight: return "Front Right";
case SoundIoChannelIdFrontCenter: return "Front Center";
case SoundIoChannelIdLowFrequency: return "Low Frequency";
case SoundIoChannelIdBackLeft: return "Back Left";
case SoundIoChannelIdBackRight: return "Back Right";
case SoundIoChannelIdFrontLeftOfCenter: return "Front Left of Center";
case SoundIoChannelIdFrontRightOfCenter: return "Front Right of Center";
case SoundIoChannelIdBackCenter: return "Back Center";
case SoundIoChannelIdSideLeft: return "Side Left";
case SoundIoChannelIdSideRight: return "Side Right";
case SoundIoChannelIdTopCenter: return "Top Center";
case SoundIoChannelIdTopFrontLeft: return "Top Front Left";
case SoundIoChannelIdTopFrontCenter: return "Top Front Center";
case SoundIoChannelIdTopFrontRight: return "Top Front Right";
case SoundIoChannelIdTopBackLeft: return "Top Back Left";
case SoundIoChannelIdTopBackCenter: return "Top Back Center";
case SoundIoChannelIdTopBackRight: return "Top Back Right";
}
return "(Invalid Channel)";
}
int soundio_channel_layout_builtin_count(void) { int soundio_channel_layout_builtin_count(void) {
return array_length(builtin_channel_layouts); return array_length(builtin_channel_layouts);
} }
@ -381,3 +397,13 @@ int soundio_channel_layout_find_channel(
return -1; return -1;
} }
bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout) {
for (int i = 0; i < array_length(builtin_channel_layouts); i += 1) {
const struct SoundIoChannelLayout *builtin_layout = &builtin_channel_layouts[i];
if (soundio_channel_layout_equal(builtin_layout, layout)) {
layout->name = builtin_layout->name;
return true;
}
}
return false;
}

View file

@ -297,7 +297,7 @@ int soundio_dummy_init(SoundIo *soundio) {
device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono); device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
device->default_sample_format = SoundIoSampleFormatFloat; device->default_sample_format = SoundIoSampleFormatFloat;
device->default_latency = 0.01; device->default_latency = 0.01;
device->default_sample_rate = 48000; device->sample_rate_default = 48000;
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
if (soundio->safe_devices_info->output_devices.append(device)) { if (soundio->safe_devices_info->output_devices.append(device)) {
@ -327,7 +327,7 @@ int soundio_dummy_init(SoundIo *soundio) {
device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono); device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
device->default_sample_format = SoundIoSampleFormatFloat; device->default_sample_format = SoundIoSampleFormatFloat;
device->default_latency = 0.01; device->default_latency = 0.01;
device->default_sample_rate = 48000; device->sample_rate_default = 48000;
device->purpose = SoundIoDevicePurposeInput; device->purpose = SoundIoDevicePurposeInput;
if (soundio->safe_devices_info->input_devices.append(device)) { if (soundio->safe_devices_info->input_devices.append(device)) {

View file

@ -161,9 +161,9 @@ static SoundIoChannelId from_pulseaudio_channel_pos(pa_channel_position_t pos) {
case PA_CHANNEL_POSITION_REAR_CENTER: return SoundIoChannelIdBackCenter; case PA_CHANNEL_POSITION_REAR_CENTER: return SoundIoChannelIdBackCenter;
case PA_CHANNEL_POSITION_REAR_LEFT: return SoundIoChannelIdBackLeft; case PA_CHANNEL_POSITION_REAR_LEFT: return SoundIoChannelIdBackLeft;
case PA_CHANNEL_POSITION_REAR_RIGHT: return SoundIoChannelIdBackRight; case PA_CHANNEL_POSITION_REAR_RIGHT: return SoundIoChannelIdBackRight;
case PA_CHANNEL_POSITION_LFE: return SoundIoChannelIdLowFrequency; case PA_CHANNEL_POSITION_LFE: return SoundIoChannelIdLfe;
case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: return SoundIoChannelIdFrontLeftOfCenter; case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: return SoundIoChannelIdFrontLeftCenter;
case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return SoundIoChannelIdFrontRightOfCenter; case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return SoundIoChannelIdFrontRightCenter;
case PA_CHANNEL_POSITION_SIDE_LEFT: return SoundIoChannelIdSideLeft; case PA_CHANNEL_POSITION_SIDE_LEFT: return SoundIoChannelIdSideLeft;
case PA_CHANNEL_POSITION_SIDE_RIGHT: return SoundIoChannelIdSideRight; case PA_CHANNEL_POSITION_SIDE_RIGHT: return SoundIoChannelIdSideRight;
case PA_CHANNEL_POSITION_TOP_CENTER: return SoundIoChannelIdTopCenter; case PA_CHANNEL_POSITION_TOP_CENTER: return SoundIoChannelIdTopCenter;
@ -268,7 +268,7 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout); set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout);
device->default_sample_format = sample_format_from_pulseaudio(info->sample_spec); device->default_sample_format = sample_format_from_pulseaudio(info->sample_spec);
device->default_latency = usec_to_sec(info->configured_latency); device->default_latency = usec_to_sec(info->configured_latency);
device->default_sample_rate = sample_rate_from_pulseaudio(info->sample_spec); device->sample_rate_default = sample_rate_from_pulseaudio(info->sample_spec);
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
if (sipa->current_devices_info->output_devices.append(device)) if (sipa->current_devices_info->output_devices.append(device))
@ -297,7 +297,7 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout); set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout);
device->default_sample_format = sample_format_from_pulseaudio(info->sample_spec); device->default_sample_format = sample_format_from_pulseaudio(info->sample_spec);
device->default_latency = usec_to_sec(info->configured_latency); device->default_latency = usec_to_sec(info->configured_latency);
device->default_sample_rate = sample_rate_from_pulseaudio(info->sample_spec); device->sample_rate_default = sample_rate_from_pulseaudio(info->sample_spec);
device->purpose = SoundIoDevicePurposeInput; device->purpose = SoundIoDevicePurposeInput;
if (sipa->current_devices_info->input_devices.append(device)) if (sipa->current_devices_info->input_devices.append(device))
@ -445,47 +445,46 @@ static pa_sample_format_t to_pulseaudio_sample_format(SoundIoSampleFormat sample
static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_id) { static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_id) {
switch (channel_id) { switch (channel_id) {
case SoundIoChannelIdInvalid: case SoundIoChannelIdFrontLeft: return PA_CHANNEL_POSITION_FRONT_LEFT;
case SoundIoChannelIdFrontRight: return PA_CHANNEL_POSITION_FRONT_RIGHT;
case SoundIoChannelIdFrontCenter: return PA_CHANNEL_POSITION_FRONT_CENTER;
case SoundIoChannelIdLfe: return PA_CHANNEL_POSITION_LFE;
case SoundIoChannelIdBackLeft: return PA_CHANNEL_POSITION_REAR_LEFT;
case SoundIoChannelIdBackRight: return PA_CHANNEL_POSITION_REAR_RIGHT;
case SoundIoChannelIdFrontLeftCenter: return PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
case SoundIoChannelIdFrontRightCenter: return PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
case SoundIoChannelIdBackCenter: return PA_CHANNEL_POSITION_REAR_CENTER;
case SoundIoChannelIdSideLeft: return PA_CHANNEL_POSITION_SIDE_LEFT;
case SoundIoChannelIdSideRight: return PA_CHANNEL_POSITION_SIDE_RIGHT;
case SoundIoChannelIdTopCenter: return PA_CHANNEL_POSITION_TOP_CENTER;
case SoundIoChannelIdTopFrontLeft: return PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
case SoundIoChannelIdTopFrontCenter: return PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
case SoundIoChannelIdTopFrontRight: return PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
case SoundIoChannelIdTopBackLeft: return PA_CHANNEL_POSITION_TOP_REAR_LEFT;
case SoundIoChannelIdTopBackCenter: return PA_CHANNEL_POSITION_TOP_REAR_CENTER;
case SoundIoChannelIdTopBackRight: return PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
case SoundIoChannelIdCount: case SoundIoChannelIdCount:
soundio_panic("invalid channel id"); case SoundIoChannelIdInvalid:
case SoundIoChannelIdFrontLeft: case SoundIoChannelIdBackLeftCenter:
return PA_CHANNEL_POSITION_FRONT_LEFT; case SoundIoChannelIdBackRightCenter:
case SoundIoChannelIdFrontRight: case SoundIoChannelIdFrontLeftWide:
return PA_CHANNEL_POSITION_FRONT_RIGHT; case SoundIoChannelIdFrontRightWide:
case SoundIoChannelIdFrontCenter: case SoundIoChannelIdFrontLeftHigh:
return PA_CHANNEL_POSITION_FRONT_CENTER; case SoundIoChannelIdFrontCenterHigh:
case SoundIoChannelIdLowFrequency: case SoundIoChannelIdFrontRightHigh:
return PA_CHANNEL_POSITION_LFE; case SoundIoChannelIdTopFrontLeftCenter:
case SoundIoChannelIdBackLeft: case SoundIoChannelIdTopFrontRightCenter:
return PA_CHANNEL_POSITION_REAR_LEFT; case SoundIoChannelIdTopSideLeft:
case SoundIoChannelIdBackRight: case SoundIoChannelIdTopSideRight:
return PA_CHANNEL_POSITION_REAR_RIGHT; case SoundIoChannelIdLeftLfe:
case SoundIoChannelIdFrontLeftOfCenter: case SoundIoChannelIdRightLfe:
return PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; case SoundIoChannelIdBottomCenter:
case SoundIoChannelIdFrontRightOfCenter: case SoundIoChannelIdBottomLeftCenter:
return PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; case SoundIoChannelIdBottomRightCenter:
case SoundIoChannelIdBackCenter: return PA_CHANNEL_POSITION_INVALID;
return PA_CHANNEL_POSITION_REAR_CENTER;
case SoundIoChannelIdSideLeft:
return PA_CHANNEL_POSITION_SIDE_LEFT;
case SoundIoChannelIdSideRight:
return PA_CHANNEL_POSITION_SIDE_RIGHT;
case SoundIoChannelIdTopCenter:
return PA_CHANNEL_POSITION_TOP_CENTER;
case SoundIoChannelIdTopFrontLeft:
return PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
case SoundIoChannelIdTopFrontCenter:
return PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
case SoundIoChannelIdTopFrontRight:
return PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
case SoundIoChannelIdTopBackLeft:
return PA_CHANNEL_POSITION_TOP_REAR_LEFT;
case SoundIoChannelIdTopBackCenter:
return PA_CHANNEL_POSITION_TOP_REAR_CENTER;
case SoundIoChannelIdTopBackRight:
return PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
} }
soundio_panic("invalid channel id"); return PA_CHANNEL_POSITION_INVALID;
} }
static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *channel_layout) { static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *channel_layout) {

View file

@ -228,7 +228,7 @@ const struct SoundIoChannelLayout *soundio_device_channel_layout(const struct So
} }
int soundio_device_sample_rate(const struct SoundIoDevice *device) { int soundio_device_sample_rate(const struct SoundIoDevice *device) {
return device->default_sample_rate; return device->sample_rate_default;
} }
void soundio_device_unref(struct SoundIoDevice *device) { void soundio_device_unref(struct SoundIoDevice *device) {

View file

@ -32,11 +32,11 @@ enum SoundIoChannelId {
SoundIoChannelIdFrontLeft, SoundIoChannelIdFrontLeft,
SoundIoChannelIdFrontRight, SoundIoChannelIdFrontRight,
SoundIoChannelIdFrontCenter, SoundIoChannelIdFrontCenter,
SoundIoChannelIdLowFrequency, SoundIoChannelIdLfe,
SoundIoChannelIdBackLeft, SoundIoChannelIdBackLeft,
SoundIoChannelIdBackRight, SoundIoChannelIdBackRight,
SoundIoChannelIdFrontLeftOfCenter, SoundIoChannelIdFrontLeftCenter,
SoundIoChannelIdFrontRightOfCenter, SoundIoChannelIdFrontRightCenter,
SoundIoChannelIdBackCenter, SoundIoChannelIdBackCenter,
SoundIoChannelIdSideLeft, SoundIoChannelIdSideLeft,
SoundIoChannelIdSideRight, SoundIoChannelIdSideRight,
@ -48,6 +48,23 @@ enum SoundIoChannelId {
SoundIoChannelIdTopBackCenter, SoundIoChannelIdTopBackCenter,
SoundIoChannelIdTopBackRight, SoundIoChannelIdTopBackRight,
SoundIoChannelIdBackLeftCenter,
SoundIoChannelIdBackRightCenter,
SoundIoChannelIdFrontLeftWide,
SoundIoChannelIdFrontRightWide,
SoundIoChannelIdFrontLeftHigh,
SoundIoChannelIdFrontCenterHigh,
SoundIoChannelIdFrontRightHigh,
SoundIoChannelIdTopFrontLeftCenter,
SoundIoChannelIdTopFrontRightCenter,
SoundIoChannelIdTopSideLeft,
SoundIoChannelIdTopSideRight,
SoundIoChannelIdLeftLfe,
SoundIoChannelIdRightLfe,
SoundIoChannelIdBottomCenter,
SoundIoChannelIdBottomLeftCenter,
SoundIoChannelIdBottomRightCenter,
SoundIoChannelIdCount, SoundIoChannelIdCount,
}; };
@ -121,7 +138,10 @@ struct SoundIoDevice {
// whether something worked until you try it. // whether something worked until you try it.
// these values can be unknown // these values can be unknown
enum SoundIoSampleFormat default_sample_format; enum SoundIoSampleFormat default_sample_format;
int default_sample_rate;
int sample_rate_min;
int sample_rate_max;
int sample_rate_default;
double default_latency; double default_latency;
enum SoundIoDevicePurpose purpose; enum SoundIoDevicePurpose purpose;
@ -232,6 +252,10 @@ void soundio_debug_print_channel_layout(const struct SoundIoChannelLayout *layou
int soundio_channel_layout_find_channel( int soundio_channel_layout_find_channel(
const struct SoundIoChannelLayout *layout, enum SoundIoChannelId channel); const struct SoundIoChannelLayout *layout, enum SoundIoChannelId channel);
// merely populates the name field of layout if it matches a builtin one.
// returns whether it found a match
bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout);
// Sample Formats // Sample Formats

View file

@ -103,9 +103,4 @@ template <typename T>
static inline T min(T a, T b) { static inline T min(T a, T b) {
return (a <= b) ? a : b; return (a <= b) ? a : b;
} }
static inline bool str_has_prefix(const char *big_str, const char *prefix) {
return strncmp(big_str, prefix, strlen(prefix)) == 0;
}
#endif #endif