sysaudio: load libasound.so dynamically
This commit is contained in:
parent
ea8ff67ae4
commit
655e061d50
2 changed files with 196 additions and 96 deletions
|
|
@ -35,9 +35,6 @@ pub fn Sdk(comptime deps: anytype) type {
|
|||
} else if (step.target.toTarget().os.tag == .linux) {
|
||||
step.addCSourceFile(sdkPath("/src/pipewire/sysaudio.c"), &.{"-std=gnu99"});
|
||||
step.linkSystemLibrary("pipewire-0.3");
|
||||
step.linkSystemLibrary("asound");
|
||||
step.linkSystemLibrary("pulse");
|
||||
step.linkSystemLibrary("jack");
|
||||
step.linkLibC();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,116 @@ const util = @import("util.zig");
|
|||
const inotify_event = std.os.linux.inotify_event;
|
||||
const is_little = @import("builtin").cpu.arch.endian() == .Little;
|
||||
|
||||
const lib = struct {
|
||||
var handle: std.DynLib = undefined;
|
||||
|
||||
var snd_lib_error_set_handler: *const fn (c.snd_lib_error_handler_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_info_malloc: *const fn ([*c]?*c.snd_pcm_info_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_info_free: *const fn (?*c.snd_pcm_info_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_open: *const fn ([*c]?*c.snd_pcm_t, [*c]const u8, c.snd_pcm_stream_t, c_int) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_close: *const fn (?*c.snd_pcm_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_state: *const fn (?*c.snd_pcm_t) callconv(.C) c.snd_pcm_state_t = undefined;
|
||||
var snd_pcm_pause: *const fn (?*c.snd_pcm_t, c_int) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_writei: *const fn (?*c.snd_pcm_t, ?*const anyopaque, c.snd_pcm_uframes_t) callconv(.C) c.snd_pcm_sframes_t = undefined;
|
||||
var snd_pcm_recover: *const fn (?*c.snd_pcm_t, c_int, c_int) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_info_set_device: *const fn (?*c.snd_pcm_info_t, c_uint) callconv(.C) void = undefined;
|
||||
var snd_pcm_info_set_subdevice: *const fn (?*c.snd_pcm_info_t, c_uint) callconv(.C) void = undefined;
|
||||
var snd_pcm_info_get_name: *const fn (?*const c.snd_pcm_info_t) callconv(.C) [*c]const u8 = undefined;
|
||||
var snd_pcm_info_set_stream: *const fn (?*c.snd_pcm_info_t, c.snd_pcm_stream_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_hw_free: *const fn (?*c.snd_pcm_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_malloc: *const fn ([*c]?*c.snd_pcm_hw_params_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_free: *const fn (?*c.snd_pcm_hw_params_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_set_params: *const fn (?*c.snd_pcm_t, c.snd_pcm_format_t, c.snd_pcm_access_t, c_uint, c_uint, c_int, c_uint) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_any: *const fn (?*c.snd_pcm_t, ?*c.snd_pcm_hw_params_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_can_pause: *const fn (?*const c.snd_pcm_hw_params_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_current: *const fn (?*c.snd_pcm_t, ?*c.snd_pcm_hw_params_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_get_format_mask: *const fn (?*c.snd_pcm_hw_params_t, ?*c.snd_pcm_format_mask_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_hw_params_get_rate_min: *const fn (?*const c.snd_pcm_hw_params_t, [*c]c_uint, [*c]c_int) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_get_rate_max: *const fn (?*const c.snd_pcm_hw_params_t, [*c]c_uint, [*c]c_int) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_hw_params_get_period_size: *const fn (?*const c.snd_pcm_hw_params_t, [*c]c.snd_pcm_uframes_t, [*c]c_int) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_query_chmaps: *const fn (?*c.snd_pcm_t) callconv(.C) [*c][*c]c.snd_pcm_chmap_query_t = undefined;
|
||||
var snd_pcm_free_chmaps: *const fn ([*c][*c]c.snd_pcm_chmap_query_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_format_mask_malloc: *const fn ([*c]?*c.snd_pcm_format_mask_t) callconv(.C) c_int = undefined;
|
||||
var snd_pcm_format_mask_free: *const fn (?*c.snd_pcm_format_mask_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_format_mask_none: *const fn (?*c.snd_pcm_format_mask_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_format_mask_set: *const fn (?*c.snd_pcm_format_mask_t, c.snd_pcm_format_t) callconv(.C) void = undefined;
|
||||
var snd_pcm_format_mask_test: *const fn (?*const c.snd_pcm_format_mask_t, c.snd_pcm_format_t) callconv(.C) c_int = undefined;
|
||||
var snd_card_next: *const fn ([*c]c_int) callconv(.C) c_int = undefined;
|
||||
var snd_ctl_open: *const fn ([*c]?*c.snd_ctl_t, [*c]const u8, c_int) callconv(.C) c_int = undefined;
|
||||
var snd_ctl_close: *const fn (?*c.snd_ctl_t) callconv(.C) c_int = undefined;
|
||||
var snd_ctl_pcm_next_device: *const fn (?*c.snd_ctl_t, [*c]c_int) callconv(.C) c_int = undefined;
|
||||
var snd_ctl_pcm_info: *const fn (?*c.snd_ctl_t, ?*c.snd_pcm_info_t) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_open: *const fn ([*c]?*c.snd_mixer_t, c_int) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_close: *const fn (?*c.snd_mixer_t) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_load: *const fn (?*c.snd_mixer_t) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_attach: *const fn (?*c.snd_mixer_t, [*c]const u8) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_find_selem: *const fn (?*c.snd_mixer_t, ?*const c.snd_mixer_selem_id_t) callconv(.C) ?*c.snd_mixer_elem_t = undefined;
|
||||
var snd_mixer_selem_register: *const fn (?*c.snd_mixer_t, [*c]c.struct_snd_mixer_selem_regopt, [*c]?*c.snd_mixer_class_t) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_selem_id_malloc: *const fn ([*c]?*c.snd_mixer_selem_id_t) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_selem_id_free: *const fn (?*c.snd_mixer_selem_id_t) callconv(.C) void = undefined;
|
||||
var snd_mixer_selem_id_set_index: *const fn (?*c.snd_mixer_selem_id_t, c_uint) callconv(.C) void = undefined;
|
||||
var snd_mixer_selem_id_set_name: *const fn (?*c.snd_mixer_selem_id_t, [*c]const u8) callconv(.C) void = undefined;
|
||||
var snd_mixer_selem_set_playback_volume_all: *const fn (?*c.snd_mixer_elem_t, c_long) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_selem_get_playback_volume: *const fn (?*c.snd_mixer_elem_t, c.snd_mixer_selem_channel_id_t, [*c]c_long) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_selem_get_playback_volume_range: *const fn (?*c.snd_mixer_elem_t, [*c]c_long, [*c]c_long) callconv(.C) c_int = undefined;
|
||||
var snd_mixer_selem_has_playback_channel: *const fn (?*c.snd_mixer_elem_t, c.snd_mixer_selem_channel_id_t) callconv(.C) c_int = undefined;
|
||||
|
||||
pub fn load() !void {
|
||||
handle = std.DynLib.openZ("libasound.so") catch return error.LibraryNotFound;
|
||||
|
||||
snd_lib_error_set_handler = handle.lookup(@TypeOf(snd_lib_error_set_handler), "snd_lib_error_set_handler") orelse return error.SymbolLookup;
|
||||
snd_pcm_info_malloc = handle.lookup(@TypeOf(snd_pcm_info_malloc), "snd_pcm_info_malloc") orelse return error.SymbolLookup;
|
||||
snd_pcm_info_free = handle.lookup(@TypeOf(snd_pcm_info_free), "snd_pcm_info_free") orelse return error.SymbolLookup;
|
||||
snd_pcm_open = handle.lookup(@TypeOf(snd_pcm_open), "snd_pcm_open") orelse return error.SymbolLookup;
|
||||
snd_pcm_close = handle.lookup(@TypeOf(snd_pcm_close), "snd_pcm_close") orelse return error.SymbolLookup;
|
||||
snd_pcm_state = handle.lookup(@TypeOf(snd_pcm_state), "snd_pcm_state") orelse return error.SymbolLookup;
|
||||
snd_pcm_pause = handle.lookup(@TypeOf(snd_pcm_pause), "snd_pcm_pause") orelse return error.SymbolLookup;
|
||||
snd_pcm_writei = handle.lookup(@TypeOf(snd_pcm_writei), "snd_pcm_writei") orelse return error.SymbolLookup;
|
||||
snd_pcm_recover = handle.lookup(@TypeOf(snd_pcm_recover), "snd_pcm_recover") orelse return error.SymbolLookup;
|
||||
snd_pcm_info_set_device = handle.lookup(@TypeOf(snd_pcm_info_set_device), "snd_pcm_info_set_device") orelse return error.SymbolLookup;
|
||||
snd_pcm_info_set_subdevice = handle.lookup(@TypeOf(snd_pcm_info_set_subdevice), "snd_pcm_info_set_subdevice") orelse return error.SymbolLookup;
|
||||
snd_pcm_info_get_name = handle.lookup(@TypeOf(snd_pcm_info_get_name), "snd_pcm_info_get_name") orelse return error.SymbolLookup;
|
||||
snd_pcm_info_set_stream = handle.lookup(@TypeOf(snd_pcm_info_set_stream), "snd_pcm_info_set_stream") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_free = handle.lookup(@TypeOf(snd_pcm_hw_free), "snd_pcm_hw_free") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_malloc = handle.lookup(@TypeOf(snd_pcm_hw_params_malloc), "snd_pcm_hw_params_malloc") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_free = handle.lookup(@TypeOf(snd_pcm_hw_params_free), "snd_pcm_hw_params_free") orelse return error.SymbolLookup;
|
||||
snd_pcm_set_params = handle.lookup(@TypeOf(snd_pcm_set_params), "snd_pcm_set_params") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_any = handle.lookup(@TypeOf(snd_pcm_hw_params_any), "snd_pcm_hw_params_any") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_can_pause = handle.lookup(@TypeOf(snd_pcm_hw_params_can_pause), "snd_pcm_hw_params_can_pause") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_current = handle.lookup(@TypeOf(snd_pcm_hw_params_current), "snd_pcm_hw_params_current") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_get_format_mask = handle.lookup(@TypeOf(snd_pcm_hw_params_get_format_mask), "snd_pcm_hw_params_get_format_mask") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_get_rate_min = handle.lookup(@TypeOf(snd_pcm_hw_params_get_rate_min), "snd_pcm_hw_params_get_rate_min") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_get_rate_max = handle.lookup(@TypeOf(snd_pcm_hw_params_get_rate_max), "snd_pcm_hw_params_get_rate_max") orelse return error.SymbolLookup;
|
||||
snd_pcm_hw_params_get_period_size = handle.lookup(@TypeOf(snd_pcm_hw_params_get_period_size), "snd_pcm_hw_params_get_period_size") orelse return error.SymbolLookup;
|
||||
snd_pcm_query_chmaps = handle.lookup(@TypeOf(snd_pcm_query_chmaps), "snd_pcm_query_chmaps") orelse return error.SymbolLookup;
|
||||
snd_pcm_free_chmaps = handle.lookup(@TypeOf(snd_pcm_free_chmaps), "snd_pcm_free_chmaps") orelse return error.SymbolLookup;
|
||||
snd_pcm_format_mask_malloc = handle.lookup(@TypeOf(snd_pcm_format_mask_malloc), "snd_pcm_format_mask_malloc") orelse return error.SymbolLookup;
|
||||
snd_pcm_format_mask_free = handle.lookup(@TypeOf(snd_pcm_format_mask_free), "snd_pcm_format_mask_free") orelse return error.SymbolLookup;
|
||||
snd_pcm_format_mask_none = handle.lookup(@TypeOf(snd_pcm_format_mask_none), "snd_pcm_format_mask_none") orelse return error.SymbolLookup;
|
||||
snd_pcm_format_mask_set = handle.lookup(@TypeOf(snd_pcm_format_mask_set), "snd_pcm_format_mask_set") orelse return error.SymbolLookup;
|
||||
snd_pcm_format_mask_test = handle.lookup(@TypeOf(snd_pcm_format_mask_test), "snd_pcm_format_mask_test") orelse return error.SymbolLookup;
|
||||
snd_card_next = handle.lookup(@TypeOf(snd_card_next), "snd_card_next") orelse return error.SymbolLookup;
|
||||
snd_ctl_open = handle.lookup(@TypeOf(snd_ctl_open), "snd_ctl_open") orelse return error.SymbolLookup;
|
||||
snd_ctl_close = handle.lookup(@TypeOf(snd_ctl_close), "snd_ctl_close") orelse return error.SymbolLookup;
|
||||
snd_ctl_pcm_next_device = handle.lookup(@TypeOf(snd_ctl_pcm_next_device), "snd_ctl_pcm_next_device") orelse return error.SymbolLookup;
|
||||
snd_ctl_pcm_info = handle.lookup(@TypeOf(snd_ctl_pcm_info), "snd_ctl_pcm_info") orelse return error.SymbolLookup;
|
||||
snd_mixer_open = handle.lookup(@TypeOf(snd_mixer_open), "snd_mixer_open") orelse return error.SymbolLookup;
|
||||
snd_mixer_close = handle.lookup(@TypeOf(snd_mixer_close), "snd_mixer_close") orelse return error.SymbolLookup;
|
||||
snd_mixer_load = handle.lookup(@TypeOf(snd_mixer_load), "snd_mixer_load") orelse return error.SymbolLookup;
|
||||
snd_mixer_attach = handle.lookup(@TypeOf(snd_mixer_attach), "snd_mixer_attach") orelse return error.SymbolLookup;
|
||||
snd_mixer_find_selem = handle.lookup(@TypeOf(snd_mixer_find_selem), "snd_mixer_find_selem") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_register = handle.lookup(@TypeOf(snd_mixer_selem_register), "snd_mixer_selem_register") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_id_malloc = handle.lookup(@TypeOf(snd_mixer_selem_id_malloc), "snd_mixer_selem_id_malloc") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_id_free = handle.lookup(@TypeOf(snd_mixer_selem_id_free), "snd_mixer_selem_id_free") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_id_set_index = handle.lookup(@TypeOf(snd_mixer_selem_id_set_index), "snd_mixer_selem_id_set_index") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_id_set_name = handle.lookup(@TypeOf(snd_mixer_selem_id_set_name), "snd_mixer_selem_id_set_name") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_set_playback_volume_all = handle.lookup(@TypeOf(snd_mixer_selem_set_playback_volume_all), "snd_mixer_selem_set_playback_volume_all") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_get_playback_volume = handle.lookup(@TypeOf(snd_mixer_selem_get_playback_volume), "snd_mixer_selem_get_playback_volume") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_get_playback_volume_range = handle.lookup(@TypeOf(snd_mixer_selem_get_playback_volume_range), "snd_mixer_selem_get_playback_volume_range") orelse return error.SymbolLookup;
|
||||
snd_mixer_selem_has_playback_channel = handle.lookup(@TypeOf(snd_mixer_selem_has_playback_channel), "snd_mixer_selem_has_playback_channel") orelse return error.SymbolLookup;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Context = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
devices_info: util.DevicesInfo,
|
||||
|
|
@ -22,7 +132,9 @@ pub const Context = struct {
|
|||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, options: main.Context.Options) !backends.BackendContext {
|
||||
_ = c.snd_lib_error_set_handler(@ptrCast(c.snd_lib_error_handler_t, &util.doNothing));
|
||||
try lib.load();
|
||||
|
||||
_ = lib.snd_lib_error_set_handler(@ptrCast(c.snd_lib_error_handler_t, &util.doNothing));
|
||||
|
||||
var self = try allocator.create(Context);
|
||||
errdefer allocator.destroy(self);
|
||||
|
|
@ -110,6 +222,7 @@ pub const Context = struct {
|
|||
freeDevice(self.allocator, d);
|
||||
self.devices_info.list.deinit(self.allocator);
|
||||
self.allocator.destroy(self);
|
||||
lib.handle.close();
|
||||
}
|
||||
|
||||
fn deviceEventsLoop(self: *Context) void {
|
||||
|
|
@ -184,11 +297,11 @@ pub const Context = struct {
|
|||
self.devices_info.clear(self.allocator);
|
||||
|
||||
var pcm_info: ?*c.snd_pcm_info_t = null;
|
||||
_ = c.snd_pcm_info_malloc(&pcm_info);
|
||||
defer c.snd_pcm_info_free(pcm_info);
|
||||
_ = lib.snd_pcm_info_malloc(&pcm_info);
|
||||
defer lib.snd_pcm_info_free(pcm_info);
|
||||
|
||||
var card_idx: c_int = -1;
|
||||
if (c.snd_card_next(&card_idx) < 0)
|
||||
if (lib.snd_card_next(&card_idx) < 0)
|
||||
return error.SystemResources;
|
||||
|
||||
while (card_idx >= 0) {
|
||||
|
|
@ -196,25 +309,25 @@ pub const Context = struct {
|
|||
const card_id = std.fmt.bufPrintZ(&card_id_buf, "hw:{d}", .{card_idx}) catch break;
|
||||
|
||||
var ctl: ?*c.snd_ctl_t = undefined;
|
||||
_ = switch (-c.snd_ctl_open(&ctl, card_id.ptr, 0)) {
|
||||
_ = switch (-lib.snd_ctl_open(&ctl, card_id.ptr, 0)) {
|
||||
0 => {},
|
||||
@enumToInt(std.os.E.NOENT) => break,
|
||||
else => return error.OpeningDevice,
|
||||
};
|
||||
defer _ = c.snd_ctl_close(ctl);
|
||||
defer _ = lib.snd_ctl_close(ctl);
|
||||
|
||||
var dev_idx: c_int = -1;
|
||||
if (c.snd_ctl_pcm_next_device(ctl, &dev_idx) < 0)
|
||||
if (lib.snd_ctl_pcm_next_device(ctl, &dev_idx) < 0)
|
||||
return error.SystemResources;
|
||||
|
||||
c.snd_pcm_info_set_device(pcm_info, @intCast(c_uint, dev_idx));
|
||||
c.snd_pcm_info_set_subdevice(pcm_info, 0);
|
||||
const name = std.mem.span(c.snd_pcm_info_get_name(pcm_info) orelse continue);
|
||||
lib.snd_pcm_info_set_device(pcm_info, @intCast(c_uint, dev_idx));
|
||||
lib.snd_pcm_info_set_subdevice(pcm_info, 0);
|
||||
const name = std.mem.span(lib.snd_pcm_info_get_name(pcm_info) orelse continue);
|
||||
|
||||
for (&[_]main.Device.Mode{ .playback, .capture }) |mode| {
|
||||
const snd_stream = modeToStream(mode);
|
||||
c.snd_pcm_info_set_stream(pcm_info, snd_stream);
|
||||
const err = c.snd_ctl_pcm_info(ctl, pcm_info);
|
||||
lib.snd_pcm_info_set_stream(pcm_info, snd_stream);
|
||||
const err = lib.snd_ctl_pcm_info(ctl, pcm_info);
|
||||
switch (@intToEnum(std.os.E, -err)) {
|
||||
.SUCCESS => {},
|
||||
.NOENT,
|
||||
|
|
@ -228,25 +341,25 @@ pub const Context = struct {
|
|||
const id = std.fmt.bufPrintZ(&buf, "hw:{d},{d}", .{ card_idx, dev_idx }) catch continue;
|
||||
|
||||
var pcm: ?*c.snd_pcm_t = null;
|
||||
if (c.snd_pcm_open(&pcm, id.ptr, snd_stream, 0) < 0)
|
||||
if (lib.snd_pcm_open(&pcm, id.ptr, snd_stream, 0) < 0)
|
||||
continue;
|
||||
defer _ = c.snd_pcm_close(pcm);
|
||||
defer _ = lib.snd_pcm_close(pcm);
|
||||
|
||||
var params: ?*c.snd_pcm_hw_params_t = null;
|
||||
_ = c.snd_pcm_hw_params_malloc(¶ms);
|
||||
defer c.snd_pcm_hw_params_free(params);
|
||||
if (c.snd_pcm_hw_params_any(pcm, params) < 0)
|
||||
_ = lib.snd_pcm_hw_params_malloc(¶ms);
|
||||
defer lib.snd_pcm_hw_params_free(params);
|
||||
if (lib.snd_pcm_hw_params_any(pcm, params) < 0)
|
||||
continue;
|
||||
|
||||
if (c.snd_pcm_hw_params_can_pause(params) == 0)
|
||||
if (lib.snd_pcm_hw_params_can_pause(params) == 0)
|
||||
continue;
|
||||
|
||||
const device = main.Device{
|
||||
.mode = mode,
|
||||
.channels = blk: {
|
||||
const chmap = c.snd_pcm_query_chmaps(pcm);
|
||||
const chmap = lib.snd_pcm_query_chmaps(pcm);
|
||||
if (chmap) |_| {
|
||||
defer c.snd_pcm_free_chmaps(chmap);
|
||||
defer lib.snd_pcm_free_chmaps(chmap);
|
||||
|
||||
if (chmap[0] == null) continue;
|
||||
|
||||
|
|
@ -260,36 +373,36 @@ pub const Context = struct {
|
|||
},
|
||||
.formats = blk: {
|
||||
var fmt_mask: ?*c.snd_pcm_format_mask_t = null;
|
||||
_ = c.snd_pcm_format_mask_malloc(&fmt_mask);
|
||||
defer c.snd_pcm_format_mask_free(fmt_mask);
|
||||
c.snd_pcm_format_mask_none(fmt_mask);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S8);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U8);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S16_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S16_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U16_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U16_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_3LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_3BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_3LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_3BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S32_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S32_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U32_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U32_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT_BE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT64_LE);
|
||||
c.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT64_BE);
|
||||
c.snd_pcm_hw_params_get_format_mask(params, fmt_mask);
|
||||
_ = lib.snd_pcm_format_mask_malloc(&fmt_mask);
|
||||
defer lib.snd_pcm_format_mask_free(fmt_mask);
|
||||
lib.snd_pcm_format_mask_none(fmt_mask);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S8);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U8);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S16_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S16_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U16_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U16_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_3LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_3BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_3LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_3BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S24_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U24_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S32_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_S32_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U32_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_U32_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT_BE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT64_LE);
|
||||
lib.snd_pcm_format_mask_set(fmt_mask, c.SND_PCM_FORMAT_FLOAT64_BE);
|
||||
lib.snd_pcm_hw_params_get_format_mask(params, fmt_mask);
|
||||
|
||||
var fmt_arr = std.ArrayList(main.Format).init(self.allocator);
|
||||
inline for (std.meta.tags(main.Format)) |format| {
|
||||
if (c.snd_pcm_format_mask_test(
|
||||
if (lib.snd_pcm_format_mask_test(
|
||||
fmt_mask,
|
||||
toAlsaFormat(format) catch unreachable,
|
||||
) != 0) {
|
||||
|
|
@ -302,9 +415,9 @@ pub const Context = struct {
|
|||
.sample_rate = blk: {
|
||||
var rate_min: c_uint = 0;
|
||||
var rate_max: c_uint = 0;
|
||||
if (c.snd_pcm_hw_params_get_rate_min(params, &rate_min, null) < 0)
|
||||
if (lib.snd_pcm_hw_params_get_rate_min(params, &rate_min, null) < 0)
|
||||
continue;
|
||||
if (c.snd_pcm_hw_params_get_rate_max(params, &rate_max, null) < 0)
|
||||
if (lib.snd_pcm_hw_params_get_rate_max(params, &rate_max, null) < 0)
|
||||
continue;
|
||||
break :blk .{
|
||||
.min = @intCast(u24, rate_min),
|
||||
|
|
@ -322,7 +435,7 @@ pub const Context = struct {
|
|||
}
|
||||
}
|
||||
|
||||
if (c.snd_card_next(&card_idx) < 0)
|
||||
if (lib.snd_card_next(&card_idx) < 0)
|
||||
return error.SystemResources;
|
||||
}
|
||||
}
|
||||
|
|
@ -344,13 +457,13 @@ pub const Context = struct {
|
|||
var mixer_elm: ?*c.snd_mixer_elem_t = null;
|
||||
var period_size: c_ulong = 0;
|
||||
|
||||
if (c.snd_pcm_open(&pcm, device.id.ptr, modeToStream(device.mode), 0) < 0)
|
||||
if (lib.snd_pcm_open(&pcm, device.id.ptr, modeToStream(device.mode), 0) < 0)
|
||||
return error.OpeningDevice;
|
||||
errdefer _ = c.snd_pcm_close(pcm);
|
||||
errdefer _ = lib.snd_pcm_close(pcm);
|
||||
{
|
||||
var hw_params: ?*c.snd_pcm_hw_params_t = null;
|
||||
|
||||
if ((c.snd_pcm_set_params(
|
||||
if ((lib.snd_pcm_set_params(
|
||||
pcm,
|
||||
toAlsaFormat(format) catch unreachable,
|
||||
c.SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
|
|
@ -360,53 +473,43 @@ pub const Context = struct {
|
|||
main.default_latency,
|
||||
)) < 0)
|
||||
return error.OpeningDevice;
|
||||
errdefer _ = c.snd_pcm_hw_free(pcm);
|
||||
errdefer _ = lib.snd_pcm_hw_free(pcm);
|
||||
|
||||
if (c.snd_pcm_hw_params_malloc(&hw_params) < 0)
|
||||
if (lib.snd_pcm_hw_params_malloc(&hw_params) < 0)
|
||||
return error.OpeningDevice;
|
||||
defer c.snd_pcm_hw_params_free(hw_params);
|
||||
defer lib.snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
if (c.snd_pcm_hw_params_current(pcm, hw_params) < 0)
|
||||
if (lib.snd_pcm_hw_params_current(pcm, hw_params) < 0)
|
||||
return error.OpeningDevice;
|
||||
|
||||
if (c.snd_pcm_hw_params_get_period_size(hw_params, &period_size, null) < 0)
|
||||
if (lib.snd_pcm_hw_params_get_period_size(hw_params, &period_size, null) < 0)
|
||||
return error.OpeningDevice;
|
||||
}
|
||||
|
||||
{
|
||||
var chmap: c.snd_pcm_chmap_t = .{ .channels = @intCast(c_uint, device.channels.len) };
|
||||
|
||||
for (device.channels) |ch, i|
|
||||
chmap.pos()[i] = toCHMAP(ch.id);
|
||||
|
||||
if (c.snd_pcm_set_chmap(pcm, &chmap) < 0)
|
||||
return error.IncompatibleDevice;
|
||||
}
|
||||
|
||||
{
|
||||
if (c.snd_mixer_open(&mixer, 0) < 0)
|
||||
if (lib.snd_mixer_open(&mixer, 0) < 0)
|
||||
return error.OutOfMemory;
|
||||
|
||||
const card_id = try self.allocator.dupeZ(u8, std.mem.sliceTo(device.id, ','));
|
||||
defer self.allocator.free(card_id);
|
||||
|
||||
if (c.snd_mixer_attach(mixer, card_id.ptr) < 0)
|
||||
if (lib.snd_mixer_attach(mixer, card_id.ptr) < 0)
|
||||
return error.IncompatibleDevice;
|
||||
|
||||
if (c.snd_mixer_selem_register(mixer, null, null) < 0)
|
||||
if (lib.snd_mixer_selem_register(mixer, null, null) < 0)
|
||||
return error.OpeningDevice;
|
||||
|
||||
if (c.snd_mixer_load(mixer) < 0)
|
||||
if (lib.snd_mixer_load(mixer) < 0)
|
||||
return error.OpeningDevice;
|
||||
|
||||
if (c.snd_mixer_selem_id_malloc(&selem) < 0)
|
||||
if (lib.snd_mixer_selem_id_malloc(&selem) < 0)
|
||||
return error.OutOfMemory;
|
||||
errdefer c.snd_mixer_selem_id_free(selem);
|
||||
errdefer lib.snd_mixer_selem_id_free(selem);
|
||||
|
||||
c.snd_mixer_selem_id_set_index(selem, 0);
|
||||
c.snd_mixer_selem_id_set_name(selem, "Master");
|
||||
lib.snd_mixer_selem_id_set_index(selem, 0);
|
||||
lib.snd_mixer_selem_id_set_name(selem, "Master");
|
||||
|
||||
mixer_elm = c.snd_mixer_find_selem(mixer, selem) orelse
|
||||
mixer_elm = lib.snd_mixer_find_selem(mixer, selem) orelse
|
||||
return error.IncompatibleDevice;
|
||||
}
|
||||
|
||||
|
|
@ -456,10 +559,10 @@ pub const Player = struct {
|
|||
self.aborted.store(true, .Unordered);
|
||||
self.thread.join();
|
||||
|
||||
_ = c.snd_mixer_close(self.mixer);
|
||||
c.snd_mixer_selem_id_free(self.selem);
|
||||
_ = c.snd_pcm_close(self.pcm);
|
||||
_ = c.snd_pcm_hw_free(self.pcm);
|
||||
_ = lib.snd_mixer_close(self.mixer);
|
||||
lib.snd_mixer_selem_id_free(self.selem);
|
||||
_ = lib.snd_pcm_close(self.pcm);
|
||||
_ = lib.snd_pcm_hw_free(self.pcm);
|
||||
|
||||
self.allocator.free(self.sample_buffer);
|
||||
self.allocator.destroy(self);
|
||||
|
|
@ -485,9 +588,9 @@ pub const Player = struct {
|
|||
var frames_left = self.period_size;
|
||||
while (frames_left > 0) {
|
||||
self.writeFn(self.user_data, frames_left);
|
||||
const n = c.snd_pcm_writei(self.pcm, self.sample_buffer.ptr, frames_left);
|
||||
const n = lib.snd_pcm_writei(self.pcm, self.sample_buffer.ptr, frames_left);
|
||||
if (n < 0) {
|
||||
if (c.snd_pcm_recover(self.pcm, @intCast(c_int, n), 1) < 0) {
|
||||
if (lib.snd_pcm_recover(self.pcm, @intCast(c_int, n), 1) < 0) {
|
||||
if (std.debug.runtime_safety) unreachable;
|
||||
return;
|
||||
}
|
||||
|
|
@ -499,21 +602,21 @@ pub const Player = struct {
|
|||
}
|
||||
|
||||
pub fn play(self: Player) !void {
|
||||
if (c.snd_pcm_state(self.pcm) == c.SND_PCM_STATE_PAUSED) {
|
||||
if (c.snd_pcm_pause(self.pcm, 0) < 0)
|
||||
if (lib.snd_pcm_state(self.pcm) == c.SND_PCM_STATE_PAUSED) {
|
||||
if (lib.snd_pcm_pause(self.pcm, 0) < 0)
|
||||
return error.CannotPlay;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pause(self: Player) !void {
|
||||
if (c.snd_pcm_state(self.pcm) != c.SND_PCM_STATE_PAUSED) {
|
||||
if (c.snd_pcm_pause(self.pcm, 1) < 0)
|
||||
if (lib.snd_pcm_state(self.pcm) != c.SND_PCM_STATE_PAUSED) {
|
||||
if (lib.snd_pcm_pause(self.pcm, 1) < 0)
|
||||
return error.CannotPause;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paused(self: Player) bool {
|
||||
return c.snd_pcm_state(self.pcm) == c.SND_PCM_STATE_PAUSED;
|
||||
return lib.snd_pcm_state(self.pcm) == c.SND_PCM_STATE_PAUSED;
|
||||
}
|
||||
|
||||
pub fn setVolume(self: *Player, vol: f32) !void {
|
||||
|
|
@ -522,11 +625,11 @@ pub const Player = struct {
|
|||
|
||||
var min_vol: c_long = 0;
|
||||
var max_vol: c_long = 0;
|
||||
if (c.snd_mixer_selem_get_playback_volume_range(self.mixer_elm, &min_vol, &max_vol) < 0)
|
||||
if (lib.snd_mixer_selem_get_playback_volume_range(self.mixer_elm, &min_vol, &max_vol) < 0)
|
||||
return error.CannotSetVolume;
|
||||
|
||||
const dist = @intToFloat(f32, max_vol - min_vol);
|
||||
if (c.snd_mixer_selem_set_playback_volume_all(
|
||||
if (lib.snd_mixer_selem_set_playback_volume_all(
|
||||
self.mixer_elm,
|
||||
@floatToInt(c_long, dist * vol) + min_vol,
|
||||
) < 0)
|
||||
|
|
@ -541,8 +644,8 @@ pub const Player = struct {
|
|||
var channel: c_int = 0;
|
||||
|
||||
while (channel < c.SND_MIXER_SCHN_LAST) : (channel += 1) {
|
||||
if (c.snd_mixer_selem_has_playback_channel(self.mixer_elm, channel) == 1) {
|
||||
if (c.snd_mixer_selem_get_playback_volume(self.mixer_elm, channel, &vol) == 0)
|
||||
if (lib.snd_mixer_selem_has_playback_channel(self.mixer_elm, channel) == 1) {
|
||||
if (lib.snd_mixer_selem_get_playback_volume(self.mixer_elm, channel, &vol) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -552,7 +655,7 @@ pub const Player = struct {
|
|||
|
||||
var min_vol: c_long = 0;
|
||||
var max_vol: c_long = 0;
|
||||
if (c.snd_mixer_selem_get_playback_volume_range(self.mixer_elm, &min_vol, &max_vol) < 0)
|
||||
if (lib.snd_mixer_selem_get_playback_volume_range(self.mixer_elm, &min_vol, &max_vol) < 0)
|
||||
return error.CannotGetVolume;
|
||||
|
||||
return @intToFloat(f32, vol) / @intToFloat(f32, max_vol - min_vol);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue