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
12 changes: 8 additions & 4 deletions src/state/actor.zig
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,11 @@ pub const Actor = struct {

const thread_2 = try std.Thread.spawn(.{}, struct {
fn run(_self: *Self) void {
_self.handle_action(.restore_capture_session) catch |err| {
log.err("[capture_startup] restore_capture_session error: {}\n", .{err});
};
if (_self.state.user_settings.settings.restore_capture_source_on_startup) {
_self.handle_action(.restore_capture_session) catch |err| {
log.err("[capture_startup] restore_capture_session error: {}\n", .{err});
};
}
}
}.run, .{self});
errdefer thread_2.join();
Expand All @@ -149,7 +151,9 @@ pub const Actor = struct {
fn run(_self: *Self, t1: std.Thread, t2: std.Thread) void {
t1.join();
t2.join();
if (_self.state.user_settings.settings.start_replay_buffer_on_startup) {
if (_self.state.user_settings.settings.restore_capture_source_on_startup and
_self.state.user_settings.settings.start_replay_buffer_on_startup)
{
_self.start_record() catch |err| {
log.err("[capture_startup] start_record error: {}", .{err});
};
Expand Down
81 changes: 81 additions & 0 deletions src/state/user_settings.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const std = @import("std");
const Allocator = std.mem.Allocator;

/// NOTE: This MUST remain serializable.
pub const UserSettings = struct {
const AudioDeviceSettings = struct {
id: []const u8,
selected: bool = false,
gain: f32 = 1.0,
};

// NOTE: Default values here are default user settings.
gui_foreground_fps: u32 = 120,
gui_background_fps: u32 = 30,
capture_fps: u32 = 60,
/// In bits per second (bps).
capture_bit_rate: u64 = 10_000_000,
replay_seconds: u32 = 30,
start_replay_buffer_on_startup: bool = false,
restore_capture_source_on_startup: bool = true,
audio_devices: std.json.ArrayHashMap(AudioDeviceSettings) = .{},

pub fn deinit(self: *@This(), allocator: Allocator) void {
self.clear_audio_device_settings(allocator);
self.audio_devices.deinit(allocator);
}

pub fn update_audio_device_settings(
self: *@This(),
allocator: Allocator,
id: []const u8,
selected: bool,
gain: f32,
) !void {
const id_copy = try allocator.dupe(u8, id);
errdefer allocator.free(id_copy);

const audio_device_settings = try self.audio_devices.map.getOrPut(allocator, id_copy);
if (audio_device_settings.found_existing) {
allocator.free(id_copy);
const audio_device = audio_device_settings.value_ptr;
audio_device.selected = selected;
audio_device.gain = gain;
} else {
audio_device_settings.value_ptr.* = .{
.id = audio_device_settings.key_ptr.*,
.selected = selected,
.gain = gain,
};
}
}

fn clear_audio_device_settings(self: *@This(), allocator: Allocator) void {
var iter = self.audio_devices.map.iterator();
while (iter.next()) |entry| {
allocator.free(entry.key_ptr.*);
}
self.audio_devices.map.clearRetainingCapacity();
}

/// Deep copy user settings.
pub fn clone(self: @This(), allocator: Allocator) !@This() {
var settings_copy = self;
settings_copy.audio_devices = .{};
errdefer settings_copy.deinit(allocator);

var iter = self.audio_devices.map.iterator();
while (iter.next()) |entry| {
const audio_device = entry.value_ptr.*;
const device_id = if (audio_device.id.len > 0) audio_device.id else entry.key_ptr.*;
try settings_copy.update_audio_device_settings(
allocator,
device_id,
audio_device.selected,
audio_device.gain,
);
}

return settings_copy;
}
};
82 changes: 5 additions & 77 deletions src/state/user_settings_state.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Actor = @import("./actor.zig").Actor;
const ActionPayload = @import("./action_payload.zig").ActionPayload;
const util = @import("../util.zig");
const Actions = @import("./actor.zig").Actions;
const UserSettings = @import("./user_settings.zig").UserSettings;

const log = std.log.scoped(.user_settings_state);

Expand All @@ -13,6 +14,7 @@ pub const UserSettingsActions = union(enum) {
set_replay_seconds: u32,
set_gui_foreground_fps: u32,
set_gui_background_fps: u32,
set_restore_capture_source_on_startup: bool,
set_start_replay_buffer_on_startup: bool,
set_audio_device_settings: *ActionPayload(struct {
device_id: []u8,
Expand Down Expand Up @@ -75,6 +77,9 @@ pub const UserSettingsState = struct {
.set_start_replay_buffer_on_startup => |start_replay_buffer_on_startup| {
try self.set_state(actor, "start_replay_buffer_on_startup", start_replay_buffer_on_startup);
},
.set_restore_capture_source_on_startup => |restore_capture_source_on_startup| {
try self.set_state(actor, "restore_capture_source_on_startup", restore_capture_source_on_startup);
},
.set_audio_device_settings => |_action| {
defer _action.deinit();
const payload = _action.payload;
Expand Down Expand Up @@ -186,80 +191,3 @@ pub const UserSettingsState = struct {
try stringify.write(settings.*);
}
};

/// NOTE: This MUST remain serializable.
const UserSettings = struct {
const AudioDeviceSettings = struct {
id: []const u8,
selected: bool = false,
gain: f32 = 1.0,
};

gui_foreground_fps: u32 = 120,
gui_background_fps: u32 = 30,
capture_fps: u32 = 60,
/// In bits per second (bps).
capture_bit_rate: u64 = 10_000_000,
replay_seconds: u32 = 30,
start_replay_buffer_on_startup: bool = false,
audio_devices: std.json.ArrayHashMap(AudioDeviceSettings) = .{},

fn deinit(self: *@This(), allocator: Allocator) void {
self.clear_audio_device_settings(allocator);
self.audio_devices.deinit(allocator);
}

fn update_audio_device_settings(
self: *@This(),
allocator: Allocator,
id: []const u8,
selected: bool,
gain: f32,
) !void {
const id_copy = try allocator.dupe(u8, id);
errdefer allocator.free(id_copy);

const audio_device_settings = try self.audio_devices.map.getOrPut(allocator, id_copy);
if (audio_device_settings.found_existing) {
allocator.free(id_copy);
const audio_device = audio_device_settings.value_ptr;
audio_device.selected = selected;
audio_device.gain = gain;
} else {
audio_device_settings.value_ptr.* = .{
.id = audio_device_settings.key_ptr.*,
.selected = selected,
.gain = gain,
};
}
}

fn clear_audio_device_settings(self: *@This(), allocator: Allocator) void {
var iter = self.audio_devices.map.iterator();
while (iter.next()) |entry| {
allocator.free(entry.key_ptr.*);
}
self.audio_devices.map.clearRetainingCapacity();
}

/// Deep copy user settings.
fn clone(self: @This(), allocator: Allocator) !@This() {
var settings_copy = self;
settings_copy.audio_devices = .{};
errdefer settings_copy.deinit(allocator);

var iter = self.audio_devices.map.iterator();
while (iter.next()) |entry| {
const audio_device = entry.value_ptr.*;
const device_id = if (audio_device.id.len > 0) audio_device.id else entry.key_ptr.*;
try settings_copy.update_audio_device_settings(
allocator,
device_id,
audio_device.selected,
audio_device.gain,
);
}

return settings_copy;
}
};
32 changes: 25 additions & 7 deletions src/ui/draw_left_column.zig
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,12 @@ pub fn draw_left_column(allocator: std.mem.Allocator, actor: *Actor) !void {
// c.ImGui_SameLineEx(0, spacing);
// imgui_util.help_marker("This button may not work. Configure shortcuts with your system settings.");

c.ImGui_SeparatorText("IMGUI Debug");
if (util.DEBUG) {
c.ImGui_SeparatorText("IMGUI Debug");

if (c.ImGui_ButtonEx("Show Demo", .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) {
try actor.dispatch(.show_demo);
if (c.ImGui_ButtonEx("Show Demo", .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) {
try actor.dispatch(.show_demo);
}
}
}
}
Expand Down Expand Up @@ -456,11 +458,27 @@ fn draw_capture_settings(allocator: std.mem.Allocator, actor: *Actor) !void {
c.ImGui_PopTextWrapPos();
}

c.ImGui_Text("Start replay buffer on startup");
var start_replay_buffer_on_startup = actor.state.user_settings.settings.start_replay_buffer_on_startup;
if (c.ImGui_Checkbox("##start_replay_buffer_on_startup", &start_replay_buffer_on_startup)) {
c.ImGui_Text("Restore capture source on startup");
c.ImGui_SameLine();
imgui_util.help_marker("Try to restore the last capture source when Spacecap starts.");
var restore_capture_source_on_startup = actor.state.user_settings.settings.restore_capture_source_on_startup;
if (c.ImGui_Checkbox("##restore_capture_source_on_startup", &restore_capture_source_on_startup)) {
try actor.dispatch(.{ .user_settings = .{
.set_start_replay_buffer_on_startup = start_replay_buffer_on_startup,
.set_restore_capture_source_on_startup = restore_capture_source_on_startup,
} });
}

{
c.ImGui_Text("Start replay buffer on startup");
c.ImGui_SameLine();
imgui_util.help_marker("Start the replay buffer when Spacecap starts. Requires 'Restore capture source on startup'.");
c.ImGui_BeginDisabled(!actor.state.user_settings.settings.restore_capture_source_on_startup);
defer c.ImGui_EndDisabled();
var start_replay_buffer_on_startup = actor.state.user_settings.settings.start_replay_buffer_on_startup;
if (c.ImGui_Checkbox("##start_replay_buffer_on_startup", &start_replay_buffer_on_startup)) {
try actor.dispatch(.{ .user_settings = .{
.set_start_replay_buffer_on_startup = start_replay_buffer_on_startup,
} });
}
}
}
2 changes: 2 additions & 0 deletions src/util.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const std = @import("std");

pub const DEBUG = @import("builtin").mode == .Debug;

pub fn is_windows() bool {
return @import("builtin").os.tag == .windows;
}
Expand Down
8 changes: 3 additions & 5 deletions src/vulkan/vulkan.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ pub const Device = vk.DeviceProxy;
pub const CommandBuffer = vk.CommandBufferProxy;
pub const API_VERSION = vk.API_VERSION_1_4;

const DEBUG = @import("builtin").mode == .Debug;

const INSTANCE_EXTENSIONS = [_][*:0]const u8{
vk.extensions.khr_get_physical_device_properties_2.name,
};
Expand Down Expand Up @@ -149,15 +147,15 @@ pub const Vulkan = struct {
// enable with vkEnumerateInstanceExtensionProperties.
// See imgui example_sdl3_vulkan for reference.

if (DEBUG) {
if (util.DEBUG) {
try extension_names.append(allocator, vk.extensions.ext_debug_utils.name);
// TODO: check if this extension is enabled
//try extension_names.append(vk.extensions.ext_device_address_binding_report.name);
// try extension_names.append(vk.extensions.ext_debug_report.name);
}

const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
const enabled_layers: []const [*:0]const u8 = if (DEBUG) &validation_layers else &.{};
const enabled_layers: []const [*:0]const u8 = if (util.DEBUG) &validation_layers else &.{};

const instance_def = try vkbd.createInstance(&.{
.p_application_info = &app_info,
Expand All @@ -177,7 +175,7 @@ pub const Vulkan = struct {

var debug_messenger: ?vk.DebugUtilsMessengerEXT = null;

if (DEBUG) {
if (util.DEBUG) {
debug_messenger = try instance.createDebugUtilsMessengerEXT(&.{
.message_severity = .{
.error_bit_ext = true,
Expand Down
Loading