Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/.zig-cache/
/zig-out/
/zig-pkg/
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ Note that the video feed will be fairly low resolution as the example doesn't ha

## Status

Only the pipewire plugins/modules required for the provided examples are currently built. To use other parts of the pipewire API, you may need to add more symbols to the `libs` table in [src/wrap/dlfcn.zig](src/wrap/dlfcn.zig) and regenerate `c.zig` if additional pipewire headers are required. Contributions welcome!
Only the pipewire plugins/modules required for the provided examples are currently built. To use other parts of the pipewire API, you may need to add more symbols to the `libs` table in [src/wrap/dlfcn.zig](src/wrap/dlfcn.zig). Contributions welcome!

You can also use `-Duse_translate_c` to automatically translate the new Pipewire headers, see [this issue](https://github.com/allyourcodebase/pipewire/issues/6) for why this isn't yet the default.

## Usage

Expand Down Expand Up @@ -58,6 +60,11 @@ defer pw.pw_deinit();

See [`src/examples`](`src/examples`) for more information.


### Help, I'm getting `fatal error: `stdio.h' not found` on nixOS

You can work around this by adding libc to your nix flakes. See [our issue](https://github.com/allyourcodebase/pipewire/issues/6) and the [upstream issue](https://codeberg.org/ziglang/translate-c/issues/317) for more info.

### Help, I'm getting undefined symbols!

If you import the Pipewire zig module but don't reference it, the import won't get evaluated and the wrapper functions won't get exported.
Expand Down
153 changes: 79 additions & 74 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const std = @import("std");
const build_zon = @import("build.zig.zon");

const Translator = @import("translate_c").Translator;

pub fn build(b: *std.Build) void {
// Get the library and example build options
const target = b.standardTargetOptions(.{});
Expand Down Expand Up @@ -52,13 +54,13 @@ pub fn build(b: *std.Build) void {

{
// Add the varargs workaround
libpipewire.addCSourceFile(.{
libpipewire.root_module.addCSourceFile(.{
.file = b.path("src/wrap/va.c"),
.flags = va_flags,
});

// Add the source files
libpipewire.addCSourceFiles(.{
libpipewire.root_module.addCSourceFiles(.{
.root = upstream.path("src/pipewire"),
.files = &.{
"buffers.c",
Expand Down Expand Up @@ -278,25 +280,24 @@ pub fn build(b: *std.Build) void {
.flags = flags,
});
}
// https://github.com/allyourcodebase/pipewire/issues/10
// if (target.result.cpu.has(.x86, .sse4_1)) {
// audioconvert.root_module.addCMacro("HAVE_SSE41", "1");
// audioconvert.root_module.addCSourceFiles(.{
// .root = upstream.path("spa/plugins/audioconvert"),
// .files = &.{
// "fmt-ops-sse41.c",
// },
// .flags = flags,
// });
// }
if (target.result.cpu.has(.x86, .avx) and target.result.cpu.has(.x86, .fma)) {
if (target.result.cpu.has(.x86, .sse4_1)) {
audioconvert.root_module.addCMacro("HAVE_SSE41", "1");
audioconvert.root_module.addCSourceFiles(.{
.root = upstream.path("spa/plugins/audioconvert"),
.files = &.{
"fmt-ops-sse41.c",
},
.flags = flags,
});
}
if (target.result.cpu.has(.x86, .avx2) and target.result.cpu.has(.x86, .fma)) {
// Upstream build system also only defines either if both are present
audioconvert.root_module.addCMacro("HAVE_AVX", "1");
audioconvert.root_module.addCMacro("HAVE_AVX2", "1");
audioconvert.root_module.addCMacro("HAVE_FMA", "1");
audioconvert.root_module.addCSourceFiles(.{
.root = upstream.path("spa/plugins/audioconvert"),
.files = &.{
"resample-native-avx.c",
"resample-native-avx2.c",
},
.flags = flags,
});
Expand Down Expand Up @@ -341,8 +342,8 @@ pub fn build(b: *std.Build) void {
.link_libc = true,
}),
});
dump_coeffs_exe.addIncludePath(upstream.path("spa/include"));
dump_coeffs_exe.addCSourceFiles(.{
dump_coeffs_exe.root_module.addIncludePath(upstream.path("spa/include"));
dump_coeffs_exe.root_module.addCSourceFiles(.{
.root = upstream.path("spa/plugins/audioconvert"),
.files = &.{
"resample-native.c",
Expand All @@ -356,13 +357,14 @@ pub fn build(b: *std.Build) void {
for (resampler_precomp_tuples) |tuple| {
dump_coeffs.addArgs(&.{ "-t", tuple });
}
const resample_native_precomp_h = dump_coeffs.captureStdOut();
const resample_native_precomp_h = dump_coeffs.captureStdOut(.{});
_ = dump_coeffs.captureStdErr(.{}); // Ignore stderr
const write_coeffs = b.addWriteFiles();
_ = write_coeffs.addCopyFile(
resample_native_precomp_h,
"resample-native-precomp.h",
);
audioconvert.addIncludePath(write_coeffs.getDirectory());
audioconvert.root_module.addIncludePath(write_coeffs.getDirectory());
}

_ = PipewireModule.build(b, pm_ctx, .{
Expand Down Expand Up @@ -435,11 +437,11 @@ pub fn build(b: *std.Build) void {

// Include and install the library headers
{
libpipewire.addIncludePath(b.dependency("valgrind_h", .{}).path(""));
libpipewire.addIncludePath(upstream.path("spa/include"));
libpipewire.addIncludePath(upstream.path("src"));
libpipewire.addConfigHeader(version_h);
libpipewire.addConfigHeader(config_h);
libpipewire.root_module.addIncludePath(b.dependency("valgrind_h", .{}).path(""));
libpipewire.root_module.addIncludePath(upstream.path("spa/include"));
libpipewire.root_module.addIncludePath(upstream.path("src"));
libpipewire.root_module.addConfigHeader(version_h);
libpipewire.root_module.addConfigHeader(config_h);

libpipewire.installHeadersDirectory(upstream.path("src/pipewire"), "pipewire", .{});
libpipewire.installHeadersDirectory(upstream.path("spa/include/spa"), "spa", .{});
Expand All @@ -450,14 +452,17 @@ pub fn build(b: *std.Build) void {
b.installArtifact(libpipewire);
}

// Create the translated C module for importing pipewire headers into Zig. See the source file
// for why we're caching this rather than using translate c.
const c = b.createModule(.{
.root_source_file = b.path("src/lib/c.zig"),
// Create the translated C module for importing pipewire headers into Zig.
const translate_c = b.dependency("translate_c", .{});
const translator: Translator = .init(translate_c, .{
.c_source_file = b.path("src/lib/c.h"),
.target = target,
.optimize = optimize,
.link_libc = true,
.func_bodies = false,
.default_init = true,
});
translator.linkLibrary(libpipewire);
const c = translator.mod;

// Create the zig module. Using this rather than the static library allows for easier
// integration, and ties logging to the standard library logger.
Expand All @@ -478,44 +483,44 @@ pub fn build(b: *std.Build) void {
});
libpipewire_zig.addIncludePath(upstream.path("spa/include"));

// Build the video play example.
{
const zin = b.dependency("zin", .{}).module("zin");
// // Build the video play example.
// {
// const zin = b.dependency("zin", .{}).module("zin");

const video_play = b.addExecutable(.{
.name = "video-play",
.root_module = b.createModule(.{
.root_source_file = b.path("src/examples/video_play.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "zin", .module = zin },
},
}),
});
// const video_play = b.addExecutable(.{
// .name = "video-play",
// .root_module = b.createModule(.{
// .root_source_file = b.path("src/examples/video_play.zig"),
// .target = target,
// .optimize = optimize,
// .imports = &.{
// .{ .name = "zin", .module = zin },
// },
// }),
// });

if (use_zig_module) {
video_play.root_module.addImport("pipewire", libpipewire_zig);
} else {
video_play.linkLibrary(libpipewire);
video_play.root_module.addImport("pipewire", c);
}
// if (use_zig_module) {
// video_play.root_module.addImport("pipewire", libpipewire_zig);
// } else {
// video_play.linkLibrary(libpipewire);
// video_play.root_module.addImport("pipewire", c);
// }

video_play.root_module.addOptions("example_options", example_options);
// video_play.root_module.addOptions("example_options", example_options);

b.installArtifact(video_play);
// b.installArtifact(video_play);

const run_step = b.step("video-play", "Run the video-play example");
// const run_step = b.step("video-play", "Run the video-play example");

const run_cmd = b.addRunArtifact(video_play);
run_step.dependOn(&run_cmd.step);
// const run_cmd = b.addRunArtifact(video_play);
// run_step.dependOn(&run_cmd.step);

run_cmd.step.dependOn(b.getInstallStep());
// run_cmd.step.dependOn(b.getInstallStep());

if (b.args) |args| {
run_cmd.addArgs(args);
}
}
// if (b.args) |args| {
// run_cmd.addArgs(args);
// }
// }

// Build the audio src example.
{
Expand All @@ -531,7 +536,7 @@ pub fn build(b: *std.Build) void {
if (use_zig_module) {
audio_src.root_module.addImport("pipewire", libpipewire_zig);
} else {
audio_src.linkLibrary(libpipewire);
audio_src.root_module.linkLibrary(libpipewire);
audio_src.root_module.addImport("pipewire", c);
}

Expand Down Expand Up @@ -630,24 +635,23 @@ pub const PipewireModule = struct {
.target = ctx.target,
.optimize = ctx.optimize,
.link_libc = true,
.sanitize_c = .off, // https://github.com/allyourcodebase/pipewire/issues/3
}),
});
lib.addCSourceFiles(.{
lib.root_module.addCSourceFiles(.{
.root = ctx.upstream.path("src/modules"),
.files = self.files,
.flags = flags,
});
lib.addIncludePath(ctx.upstream.path("spa/include"));
lib.addIncludePath(ctx.upstream.path("src"));
lib.addConfigHeader(ctx.version);
lib.addConfigHeader(ctx.config);
lib.root_module.addIncludePath(ctx.upstream.path("spa/include"));
lib.root_module.addIncludePath(ctx.upstream.path("src"));
lib.root_module.addConfigHeader(ctx.version);
lib.root_module.addConfigHeader(ctx.config);

namespace(lib, "pipewire__module_init");
namespace(lib, "mod_topic");

ctx.libpipewire.addIncludePath(ctx.upstream.path("spa/include"));
ctx.libpipewire.linkLibrary(lib);
ctx.libpipewire.root_module.addIncludePath(ctx.upstream.path("spa/include"));
ctx.libpipewire.root_module.linkLibrary(lib);

return lib;
}
Expand All @@ -673,7 +677,7 @@ pub const PipewirePlugin = struct {
.link_libc = true,
}),
});
lib.addCSourceFiles(.{
lib.root_module.addCSourceFiles(.{
.root = ctx.upstream.path(b.pathJoin(&.{
"spa",
"plugins",
Expand All @@ -682,14 +686,15 @@ pub const PipewirePlugin = struct {
.files = self.files,
.flags = flags,
});
lib.addIncludePath(ctx.upstream.path("spa/include"));
lib.addConfigHeader(ctx.config);
lib.root_module.addIncludePath(ctx.upstream.path("spa/include"));
lib.root_module.addIncludePath(b.path("src/lib"));
lib.root_module.addConfigHeader(ctx.config);

namespace(lib, "spa_handle_factory_enum");
namespace(lib, "spa_log_topic_enum");

ctx.libpipewire.addIncludePath(ctx.upstream.path("spa/include"));
ctx.libpipewire.linkLibrary(lib);
ctx.libpipewire.root_module.addIncludePath(ctx.upstream.path("spa/include"));
ctx.libpipewire.root_module.linkLibrary(lib);

return lib;
}
Expand Down
20 changes: 12 additions & 8 deletions build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
.{
.name = .pipewire,
.fingerprint = 0x1c93541a4325abb4,
.version = "1.5.81",
.version = "1.6.3",
.api_version = "0.3",

.minimum_zig_version = "0.15.1",
.minimum_zig_version = "0.16.0",

.dependencies = .{
.valgrind_h = .{
.url = "https://github.com/allyourcodebase/valgrind.h/archive/refs/tags/3.23.0.tar.gz",
.hash = "N-V-__8AAMV2BgB9aKHnchADe5onASuvEqAeRRO7Ai1oTuzW",
},
.upstream = .{
.url = "git+https://gitlab.freedesktop.org/pipewire/pipewire.git#1.5.81",
.hash = "N-V-__8AAKYw2AD301ZQsWszbYSWZQF5y-q4WXJif0UGRvFh",
.url = "git+https://gitlab.freedesktop.org/pipewire/pipewire.git#1.6.3",
.hash = "N-V-__8AAEgZ3gDiNoXcVjyqu1oc89Qzq1N9lay3xr4y8rRX",
},
// Used by the examples
.zin = .{
.url = "git+https://github.com/marler8997/zin#62706713b7089b4220d8e1eb49f8d776138a9058",
.hash = "zin-0.0.0-W7QDx9BaAwC-H1uS9Cz68oMn9uh5fWuVis5b-eqhCeeq",
// .zin = .{
// .url = "git+https://github.com/marler8997/zin#fb3f32abb988ace8aeb5bdc5c3f4cf116e801810",
// .hash = "zin-0.0.0-W7QDx7GEAwCKJgCXWgxmPL1hFtLwOVanaKRTnYBCFTsf",
// .lazy = true,
// },
.translate_c = .{
.url = "git+https://codeberg.org/ziglang/translate-c#46b5609b5ac4c0a896217d1d984f3ae50e4810b5",
.hash = "translate_c-0.0.0-Q_BUWpf0BgAwrh5AM-acJcslN_YPEhcoCVKbbNjwuUTJ",
},
},
.paths = .{
Expand Down
35 changes: 17 additions & 18 deletions src/build/generate_client_conf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,30 @@ const std = @import("std");
const options = @import("options");
const assert = std.debug.assert;

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = false }){};
defer if (gpa.deinit() != .ok) @panic("leak detected");
const allocator = gpa.allocator();
pub fn main(init: std.process.Init) !void {
const gpa = init.arena.allocator();
const io = init.io;

const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
var args = try init.minimal.args.iterateAllocator(gpa);
defer args.deinit();
_ = args.skip();
const input_path = args.next().?;
const output_path = args.next().?;
assert(args.next() == null);

const input_path = args[1];
const output_path = args[2];
assert(args.len == 3);
const cwd = std.Io.Dir.cwd();

const cwd = std.fs.cwd();

const input = try cwd.openFile(input_path, .{});
defer input.close();
const input = try cwd.openFile(io, input_path, .{});
defer input.close(io);

var input_buf: [4096]u8 = undefined;
var reader = input.readerStreaming(&input_buf);
var reader = input.readerStreaming(io, &input_buf);

const output = try cwd.createFile(output_path, .{});
defer output.close();
const output = try cwd.createFile(io, output_path, .{});
defer output.close(io);

var output_buf: [4096]u8 = undefined;
var writer = output.writerStreaming(&output_buf);
var writer = output.writerStreaming(io, &output_buf);

while (true) {
_ = reader.interface.streamDelimiter(&writer.interface, '@') catch |err| switch (err) {
Expand All @@ -48,5 +47,5 @@ pub fn main() !void {
}

try writer.interface.flush();
try output.sync();
try output.sync(io);
}
Loading