sysaudio: load libjack.so dynamically
This commit is contained in:
parent
13ad66b7ad
commit
ea8ff67ae4
1 changed files with 84 additions and 23 deletions
|
|
@ -4,6 +4,62 @@ const main = @import("main.zig");
|
|||
const backends = @import("backends.zig");
|
||||
const util = @import("util.zig");
|
||||
|
||||
const lib = struct {
|
||||
var handle: std.DynLib = undefined;
|
||||
|
||||
var jack_free: *const fn (ptr: ?*anyopaque) callconv(.C) void = undefined;
|
||||
var jack_set_error_function: *const fn (?*const fn ([*c]const u8) callconv(.C) void) callconv(.C) void = undefined;
|
||||
var jack_set_info_function: *const fn (?*const fn ([*c]const u8) callconv(.C) void) callconv(.C) void = undefined;
|
||||
var jack_client_open: *const fn ([*c]const u8, c.jack_options_t, [*c]c.jack_status_t, ...) callconv(.C) ?*c.jack_client_t = undefined;
|
||||
var jack_client_close: *const fn (?*c.jack_client_t) callconv(.C) c_int = undefined;
|
||||
var jack_connect: *const fn (?*c.jack_client_t, [*c]const u8, [*c]const u8) callconv(.C) c_int = undefined;
|
||||
var jack_disconnect: *const fn (?*c.jack_client_t, [*c]const u8, [*c]const u8) callconv(.C) c_int = undefined;
|
||||
var jack_activate: *const fn (?*c.jack_client_t) callconv(.C) c_int = undefined;
|
||||
var jack_deactivate: *const fn (?*c.jack_client_t) callconv(.C) c_int = undefined;
|
||||
var jack_port_by_name: *const fn (?*c.jack_client_t, [*c]const u8) callconv(.C) ?*c.jack_port_t = undefined;
|
||||
var jack_port_register: *const fn (?*c.jack_client_t, [*c]const u8, [*c]const u8, c_ulong, c_ulong) callconv(.C) ?*c.jack_port_t = undefined;
|
||||
var jack_set_sample_rate_callback: *const fn (?*c.jack_client_t, c.JackSampleRateCallback, ?*anyopaque) callconv(.C) c_int = undefined;
|
||||
var jack_set_port_registration_callback: *const fn (?*c.jack_client_t, c.JackPortRegistrationCallback, ?*anyopaque) callconv(.C) c_int = undefined;
|
||||
var jack_set_process_callback: *const fn (?*c.jack_client_t, c.JackProcessCallback, ?*anyopaque) callconv(.C) c_int = undefined;
|
||||
var jack_set_port_rename_callback: *const fn (?*c.jack_client_t, c.JackPortRenameCallback, ?*anyopaque) callconv(.C) c_int = undefined;
|
||||
var jack_get_sample_rate: *const fn (?*c.jack_client_t) callconv(.C) c.jack_nframes_t = undefined;
|
||||
var jack_get_ports: *const fn (?*c.jack_client_t, [*c]const u8, [*c]const u8, c_ulong) callconv(.C) [*c][*c]const u8 = undefined;
|
||||
var jack_port_type: *const fn (port: ?*const c.jack_port_t) callconv(.C) [*c]const u8 = undefined;
|
||||
var jack_port_flags: *const fn (port: ?*const c.jack_port_t) callconv(.C) c_int = undefined;
|
||||
var jack_port_name: *const fn (?*const c.jack_port_t) callconv(.C) [*c]const u8 = undefined;
|
||||
var jack_port_get_buffer: *const fn (?*c.jack_port_t, c.jack_nframes_t) callconv(.C) ?*anyopaque = undefined;
|
||||
var jack_port_connected_to: *const fn (?*const c.jack_port_t, [*c]const u8) callconv(.C) c_int = undefined;
|
||||
var jack_port_type_size: *const fn () c_int = undefined;
|
||||
|
||||
pub fn load() !void {
|
||||
handle = std.DynLib.openZ("libjack.so") catch return error.LibraryNotFound;
|
||||
|
||||
jack_free = handle.lookup(@TypeOf(jack_free), "jack_free") orelse return error.SymbolLookup;
|
||||
jack_set_error_function = handle.lookup(@TypeOf(jack_set_error_function), "jack_set_error_function") orelse return error.SymbolLookup;
|
||||
jack_set_info_function = handle.lookup(@TypeOf(jack_set_info_function), "jack_set_info_function") orelse return error.SymbolLookup;
|
||||
jack_client_open = handle.lookup(@TypeOf(jack_client_open), "jack_client_open") orelse return error.SymbolLookup;
|
||||
jack_client_close = handle.lookup(@TypeOf(jack_client_close), "jack_client_close") orelse return error.SymbolLookup;
|
||||
jack_connect = handle.lookup(@TypeOf(jack_connect), "jack_connect") orelse return error.SymbolLookup;
|
||||
jack_disconnect = handle.lookup(@TypeOf(jack_disconnect), "jack_disconnect") orelse return error.SymbolLookup;
|
||||
jack_activate = handle.lookup(@TypeOf(jack_activate), "jack_activate") orelse return error.SymbolLookup;
|
||||
jack_deactivate = handle.lookup(@TypeOf(jack_deactivate), "jack_deactivate") orelse return error.SymbolLookup;
|
||||
jack_port_by_name = handle.lookup(@TypeOf(jack_port_by_name), "jack_port_by_name") orelse return error.SymbolLookup;
|
||||
jack_port_register = handle.lookup(@TypeOf(jack_port_register), "jack_port_register") orelse return error.SymbolLookup;
|
||||
jack_set_sample_rate_callback = handle.lookup(@TypeOf(jack_set_sample_rate_callback), "jack_set_sample_rate_callback") orelse return error.SymbolLookup;
|
||||
jack_set_port_registration_callback = handle.lookup(@TypeOf(jack_set_port_registration_callback), "jack_set_port_registration_callback") orelse return error.SymbolLookup;
|
||||
jack_set_process_callback = handle.lookup(@TypeOf(jack_set_process_callback), "jack_set_process_callback") orelse return error.SymbolLookup;
|
||||
jack_set_port_rename_callback = handle.lookup(@TypeOf(jack_set_port_rename_callback), "jack_set_port_rename_callback") orelse return error.SymbolLookup;
|
||||
jack_get_sample_rate = handle.lookup(@TypeOf(jack_get_sample_rate), "jack_get_sample_rate") orelse return error.SymbolLookup;
|
||||
jack_get_ports = handle.lookup(@TypeOf(jack_get_ports), "jack_get_ports") orelse return error.SymbolLookup;
|
||||
jack_port_type = handle.lookup(@TypeOf(jack_port_type), "jack_port_type") orelse return error.SymbolLookup;
|
||||
jack_port_flags = handle.lookup(@TypeOf(jack_port_flags), "jack_port_flags") orelse return error.SymbolLookup;
|
||||
jack_port_name = handle.lookup(@TypeOf(jack_port_name), "jack_port_name") orelse return error.SymbolLookup;
|
||||
jack_port_get_buffer = handle.lookup(@TypeOf(jack_port_get_buffer), "jack_port_get_buffer") orelse return error.SymbolLookup;
|
||||
jack_port_connected_to = handle.lookup(@TypeOf(jack_port_connected_to), "jack_port_connected_to") orelse return error.SymbolLookup;
|
||||
jack_port_type_size = handle.lookup(@TypeOf(jack_port_type_size), "jack_port_type_size") orelse return error.SymbolLookup;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Context = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
devices_info: util.DevicesInfo,
|
||||
|
|
@ -16,8 +72,10 @@ pub const Context = struct {
|
|||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, options: main.Context.Options) !backends.BackendContext {
|
||||
c.jack_set_error_function(@ptrCast(?*const fn ([*c]const u8) callconv(.C) void, &util.doNothing));
|
||||
c.jack_set_info_function(@ptrCast(?*const fn ([*c]const u8) callconv(.C) void, &util.doNothing));
|
||||
try lib.load();
|
||||
|
||||
lib.jack_set_error_function(@ptrCast(?*const fn ([*c]const u8) callconv(.C) void, &util.doNothing));
|
||||
lib.jack_set_info_function(@ptrCast(?*const fn ([*c]const u8) callconv(.C) void, &util.doNothing));
|
||||
|
||||
var status: c.jack_status_t = 0;
|
||||
var self = try allocator.create(Context);
|
||||
|
|
@ -25,7 +83,7 @@ pub const Context = struct {
|
|||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.devices_info = util.DevicesInfo.init(),
|
||||
.client = c.jack_client_open(options.app_name.ptr, c.JackNoStartServer, &status) orelse {
|
||||
.client = lib.jack_client_open(options.app_name.ptr, c.JackNoStartServer, &status) orelse {
|
||||
std.debug.assert(status & c.JackInvalidOption == 0);
|
||||
return if (status & c.JackShmFailure != 0)
|
||||
error.SystemResources
|
||||
|
|
@ -39,9 +97,9 @@ pub const Context = struct {
|
|||
};
|
||||
|
||||
if (options.deviceChangeFn) |_| {
|
||||
if (c.jack_set_sample_rate_callback(self.client, sampleRateCallback, self) != 0 or
|
||||
c.jack_set_port_registration_callback(self.client, portRegistrationCallback, self) != 0 or
|
||||
c.jack_set_port_rename_callback(self.client, portRenameCalllback, self) != 0)
|
||||
if (lib.jack_set_sample_rate_callback(self.client, sampleRateCallback, self) != 0 or
|
||||
lib.jack_set_port_registration_callback(self.client, portRegistrationCallback, self) != 0 or
|
||||
lib.jack_set_port_rename_callback(self.client, portRenameCalllback, self) != 0)
|
||||
return error.ConnectionRefused;
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +110,9 @@ pub const Context = struct {
|
|||
for (self.devices_info.list.items) |device|
|
||||
freeDevice(self.allocator, device);
|
||||
self.devices_info.list.deinit(self.allocator);
|
||||
_ = lib.jack_client_close(self.client);
|
||||
self.allocator.destroy(self);
|
||||
lib.handle.close();
|
||||
}
|
||||
|
||||
pub fn refresh(self: *Context) !void {
|
||||
|
|
@ -60,20 +120,20 @@ pub const Context = struct {
|
|||
freeDevice(self.allocator, d);
|
||||
self.devices_info.clear(self.allocator);
|
||||
|
||||
const sample_rate = @intCast(u24, c.jack_get_sample_rate(self.client));
|
||||
const sample_rate = @intCast(u24, lib.jack_get_sample_rate(self.client));
|
||||
|
||||
const port_names = c.jack_get_ports(self.client, null, null, 0) orelse
|
||||
const port_names = lib.jack_get_ports(self.client, null, null, 0) orelse
|
||||
return error.OutOfMemory;
|
||||
defer c.jack_free(@ptrCast(?*anyopaque, port_names));
|
||||
defer lib.jack_free(@ptrCast(?*anyopaque, port_names));
|
||||
|
||||
var i: usize = 0;
|
||||
outer: while (port_names[i] != null) : (i += 1) {
|
||||
const port = c.jack_port_by_name(self.client, port_names[i]) orelse break;
|
||||
const port_type = c.jack_port_type(port)[0..@intCast(usize, c.jack_port_type_size())];
|
||||
const port = lib.jack_port_by_name(self.client, port_names[i]) orelse break;
|
||||
const port_type = lib.jack_port_type(port)[0..@intCast(usize, lib.jack_port_type_size())];
|
||||
if (!std.mem.startsWith(u8, port_type, c.JACK_DEFAULT_AUDIO_TYPE))
|
||||
continue;
|
||||
|
||||
const flags = c.jack_port_flags(port);
|
||||
const flags = lib.jack_port_flags(port);
|
||||
const mode: main.Device.Mode = if (flags & c.JackPortIsInput != 0) .capture else .playback;
|
||||
|
||||
const name = std.mem.span(port_names[i]);
|
||||
|
|
@ -107,8 +167,8 @@ pub const Context = struct {
|
|||
};
|
||||
|
||||
try self.devices_info.list.append(self.allocator, device);
|
||||
if (std.mem.eql(u8, "system", id)) {
|
||||
self.devices_info.setDefault(device.mode, self.devices_info.list.items.len - 1);
|
||||
if (self.devices_info.default(mode) == null) {
|
||||
self.devices_info.setDefault(mode, self.devices_info.list.items.len - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -144,7 +204,7 @@ pub const Context = struct {
|
|||
for (device.channels) |_, i| {
|
||||
const port_name = std.fmt.bufPrintZ(&buf, "playback_{d}", .{i + 1}) catch unreachable;
|
||||
const dest_name = try std.fmt.allocPrintZ(self.allocator, "{s}:{s}", .{ device.id, port_name });
|
||||
ports[i] = c.jack_port_register(self.client, port_name.ptr, c.JACK_DEFAULT_AUDIO_TYPE, c.JackPortIsOutput, 0) orelse
|
||||
ports[i] = lib.jack_port_register(self.client, port_name.ptr, c.JACK_DEFAULT_AUDIO_TYPE, c.JackPortIsOutput, 0) orelse
|
||||
return error.OpeningDevice;
|
||||
dest_ports[i] = dest_name;
|
||||
}
|
||||
|
|
@ -188,18 +248,19 @@ pub const Player = struct {
|
|||
for (self.dest_ports) |d|
|
||||
self.allocator.free(d);
|
||||
self.allocator.free(self.dest_ports);
|
||||
_ = lib.jack_deactivate(self.client);
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn start(self: *Player) !void {
|
||||
if (c.jack_set_process_callback(self.client, processCallback, self) != 0)
|
||||
if (lib.jack_set_process_callback(self.client, processCallback, self) != 0)
|
||||
return error.CannotPlay;
|
||||
|
||||
if (c.jack_activate(self.client) != 0)
|
||||
if (lib.jack_activate(self.client) != 0)
|
||||
return error.CannotPlay;
|
||||
|
||||
for (self.ports) |port, i| {
|
||||
if (c.jack_connect(self.client, c.jack_port_name(port), self.dest_ports[i].ptr) != 0)
|
||||
if (lib.jack_connect(self.client, lib.jack_port_name(port), self.dest_ports[i].ptr) != 0)
|
||||
return error.CannotPlay;
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +269,7 @@ pub const Player = struct {
|
|||
const self = @ptrCast(*Player, @alignCast(@alignOf(*Player), self_opaque.?));
|
||||
|
||||
for (self.channels) |*ch, i| {
|
||||
ch.*.ptr = @ptrCast([*]u8, c.jack_port_get_buffer(self.ports[i], n_frames));
|
||||
ch.*.ptr = @ptrCast([*]u8, lib.jack_port_get_buffer(self.ports[i], n_frames));
|
||||
}
|
||||
self.writeFn(self.user_data, n_frames);
|
||||
|
||||
|
|
@ -219,7 +280,7 @@ pub const Player = struct {
|
|||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
for (self.ports) |port, i| {
|
||||
if (c.jack_connect(self.client, c.jack_port_name(port), self.dest_ports[i].ptr) != 0)
|
||||
if (lib.jack_connect(self.client, lib.jack_port_name(port), self.dest_ports[i].ptr) != 0)
|
||||
return error.CannotPlay;
|
||||
}
|
||||
}
|
||||
|
|
@ -228,7 +289,7 @@ pub const Player = struct {
|
|||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
for (self.ports) |port, i| {
|
||||
if (c.jack_disconnect(self.client, c.jack_port_name(port), self.dest_ports[i].ptr) != 0)
|
||||
if (lib.jack_disconnect(self.client, lib.jack_port_name(port), self.dest_ports[i].ptr) != 0)
|
||||
return error.CannotPause;
|
||||
}
|
||||
}
|
||||
|
|
@ -237,7 +298,7 @@ pub const Player = struct {
|
|||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
for (self.ports) |port, i| {
|
||||
if (c.jack_port_connected_to(port, self.dest_ports[i].ptr) == 1)
|
||||
if (lib.jack_port_connected_to(port, self.dest_ports[i].ptr) == 1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -252,7 +313,7 @@ pub const Player = struct {
|
|||
}
|
||||
|
||||
pub fn sampleRate(self: Player) u24 {
|
||||
return @intCast(u24, c.jack_get_sample_rate(self.client));
|
||||
return @intCast(u24, lib.jack_get_sample_rate(self.client));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue