Skip to content
Merged
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
21 changes: 13 additions & 8 deletions src/capture/video/linux/pipewire/pipewire.zig
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ pub const Pipewire = struct {

const vulkan_image = self.pipewire_frame_buffer_manager.?.getVulkanImage(pwb, self.info.?) catch |err| {
log.err("[streamProcessCallback] unable to get buffer: {}", .{err});
unreachable;
return;
};

const header = pw.spa_buffer_find_meta_data(pwb.buffer, pw.SPA_META_Header, @sizeOf(pw.spa_meta_header));
Expand All @@ -344,7 +344,11 @@ pub const Pipewire = struct {
const copy_data = blk: {
const capture_ring_buffer = self.vulkan.capture_ring_buffer.lock();
defer capture_ring_buffer.unlock();
break :blk capture_ring_buffer.unwrap().?.copyImageToRingBuffer(.{
const ring_buffer = capture_ring_buffer.unwrap() orelse {
// Ring buffer can be temporarily unavailable during format reconfiguration.
return;
};
break :blk ring_buffer.copyImageToRingBuffer(.{
.src_image = vulkan_image.frame_buffer.frame_buffer_image.?.image,
.src_width = self.info.?.size.width,
.src_height = self.info.?.size.height,
Expand All @@ -353,7 +357,7 @@ pub const Pipewire = struct {
.timestamp_ns = timestamp_ns,
}) catch |err| {
log.err("[streamProcessCallback] copyImageToRingBuffer error: {}", .{err});
unreachable;
return;
};
};

Expand Down Expand Up @@ -459,11 +463,12 @@ pub const Pipewire = struct {
return;
}

{
self.vulkan.destroyCaptureRingBuffer();
// TODO: Figure out how to bubble this error up and display it on the UI.
self.vulkan.initCaptureRingBuffer(self.info.?.size.width, self.info.?.size.height) catch unreachable;
}
self.vulkan.destroyCaptureRingBuffer();
// TODO: Figure out how to bubble this error up and display it on the UI.
self.vulkan.initCaptureRingBuffer(self.info.?.size.width, self.info.?.size.height) catch |err| {
log.err("[streamParamChangedCallback] initCaptureRingBuffer error: {}", .{err});
return;
};

self.sendStreamParams();

Expand Down
19 changes: 14 additions & 5 deletions src/capture/video/linux/pipewire/pipewire_frame_buffer_manager.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,18 @@ pub const PipewireFrameBufferManager = struct {
}

pub fn deinit(self: *Self) void {
if (self.vk_foreign_semaphore) |vk_foreign_semaphore| {
self.vulkan.device.destroySemaphore(vk_foreign_semaphore, null);
self.vk_foreign_semaphore = null;
}

var iter = self.frame_buffers.iterator();
while (iter.next()) |entry| {
if (entry.value_ptr.frame_buffer_image) |*frame_buffer_image| {
self.destroyBufferImage(frame_buffer_image);
}
}

// NOTE: Destroy after the images, because we know it's for sure safe to do so then.
if (self.vk_foreign_semaphore) |vk_foreign_semaphore| {
self.vulkan.device.destroySemaphore(vk_foreign_semaphore, null);
self.vk_foreign_semaphore = null;
}
self.frame_buffers.deinit();
self.allocator.destroy(self);
}
Expand Down Expand Up @@ -140,6 +141,14 @@ pub const PipewireFrameBufferManager = struct {
}

fn destroyBufferImage(self: *Self, buffer_image: *PipewireFrameBufferImage) void {
const did_wait = self.vulkan.waitForAllGraphicsFencesBegin();
defer {
if (did_wait) {
self.vulkan.waitForAllGraphicsFencesEnd();
} else |err| {
log.err("[destroyBufferImage] waitForAllGraphicsFencesBegin error: {}", .{err});
}
}
self.vulkan.device.destroyImageView(buffer_image.image_view, null);
self.vulkan.device.destroyImage(buffer_image.image, null);
self.vulkan.device.freeMemory(buffer_image.device_memory, null);
Expand Down
50 changes: 50 additions & 0 deletions src/mutex.zig
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,53 @@ pub fn Mutex(T: type) type {
}
};
}

test "Mutex lock unwrap and unlock" {
var mutex: Mutex(i32) = .init(41);

var locked = mutex.lock();
defer locked.unlock();

try std.testing.expectEqual(41, locked.unwrap());
locked.set(42);
try std.testing.expectEqual(42, locked.unwrap());
}

test "Mutex set updates value" {
var mutex: Mutex(i32) = .init(1);

mutex.set(5);

var locked = mutex.lock();
defer locked.unlock();
try std.testing.expectEqual(5, locked.unwrap());
}

test "Mutex serializes concurrent mutation" {
var mutex: Mutex(u32) = .init(0);

const thread_count = 4;
const iterations = 10_000;

const Worker = struct {
fn run(m: *Mutex(u32), n: usize) void {
for (0..n) |_| {
var locked = m.lock();
defer locked.unlock();
locked.unwrapPtr().* += 1;
}
}
};

var threads: [thread_count]std.Thread = undefined;
for (&threads) |*thread| {
thread.* = try std.Thread.spawn(.{}, Worker.run, .{ &mutex, iterations });
}
for (threads) |thread| {
thread.join();
}

var locked = mutex.lock();
defer locked.unlock();
try std.testing.expectEqual(thread_count * iterations, locked.unwrap());
}
4 changes: 2 additions & 2 deletions src/state.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ replay_seconds: u32 = 60,
fps: u32 = 60,
bit_rate: u64 = 20_000_000,

recording: bool = false,
has_source: bool = false,
is_recording_video: bool = false,
is_capturing_video: bool = false,
show_demo: bool = false,
is_video_capture_supprted: bool,
audio: AudioState,
Expand Down
2 changes: 1 addition & 1 deletion src/state/audio_state.zig
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ pub const AudioState = struct {
state_actor.ui_mutex.lock();
defer state_actor.ui_mutex.unlock();

if (!state_actor.state.recording) {
if (!state_actor.state.is_recording_video) {
break :blk null;
}

Expand Down
Loading
Loading