2022-10-29 21:49:44 +02:00
|
|
|
const std = @import("std");
|
|
|
|
const c = @import("ffi.zig").c;
|
|
|
|
const config = @import("config.zig");
|
2022-11-02 22:35:51 +01:00
|
|
|
const log = std.log.scoped(.state);
|
|
|
|
|
2022-11-22 23:58:49 +01:00
|
|
|
pub const Entry = union(enum) {
|
|
|
|
channel: ChannelEntry,
|
|
|
|
|
|
|
|
/// a seperator in the channel list, the optional string is a heading.
|
|
|
|
separator: ?[]const u8,
|
|
|
|
};
|
|
|
|
|
2022-11-02 22:35:51 +01:00
|
|
|
pub const ChannelEntry = struct {
|
|
|
|
name: []const u8,
|
|
|
|
comment: ?[]const u8,
|
2022-11-05 13:02:30 +01:00
|
|
|
live: Live = .loading,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Live = enum {
|
|
|
|
live,
|
|
|
|
offline,
|
|
|
|
loading,
|
2022-11-23 22:43:45 +01:00
|
|
|
err,
|
2022-11-02 22:35:51 +01:00
|
|
|
};
|
2022-10-29 21:49:44 +02:00
|
|
|
|
|
|
|
mutex: std.Thread.Mutex,
|
|
|
|
win: *c.GLFWwindow,
|
|
|
|
|
|
|
|
/// start chatty if true
|
|
|
|
chatty: bool,
|
|
|
|
chatty_alive: bool,
|
|
|
|
|
|
|
|
/// an array of channels, composed of slices into `channels_file_data`
|
2022-11-22 23:58:49 +01:00
|
|
|
channels: ?[]Entry,
|
2022-10-29 21:49:44 +02:00
|
|
|
|
|
|
|
/// the data of the channels configuration file
|
|
|
|
channels_file_data: ?[]u8,
|
|
|
|
|
|
|
|
quality_buf: [64]u8,
|
|
|
|
channel_name_buf: [64]u8,
|
|
|
|
|
|
|
|
streamlink_memfd: ?std.fs.File,
|
|
|
|
streamlink_out: ?[]align(std.mem.page_size) u8,
|
|
|
|
|
2022-11-05 13:02:30 +01:00
|
|
|
/// If the status of the channels is being loaded currently
|
|
|
|
live_status_loading: bool,
|
|
|
|
|
2022-10-29 21:49:44 +02:00
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
pub fn init(win: *c.GLFWwindow) !*Self {
|
2022-11-02 22:35:51 +01:00
|
|
|
log.info("creating state", .{});
|
|
|
|
|
2022-10-29 21:49:44 +02:00
|
|
|
// on the heap so this thing doesn't move.
|
|
|
|
const self = try std.heap.c_allocator.create(Self);
|
|
|
|
self.* = .{
|
|
|
|
.mutex = .{},
|
|
|
|
.win = win,
|
|
|
|
|
|
|
|
.chatty = true,
|
|
|
|
.chatty_alive = false,
|
|
|
|
|
|
|
|
// initialized by config loader thread
|
|
|
|
.channels = null,
|
|
|
|
.channels_file_data = null,
|
|
|
|
|
|
|
|
.quality_buf = std.mem.zeroes([64]u8),
|
|
|
|
.channel_name_buf = std.mem.zeroes([64]u8),
|
|
|
|
|
|
|
|
.streamlink_memfd = null,
|
|
|
|
.streamlink_out = null,
|
2022-11-05 13:02:30 +01:00
|
|
|
|
|
|
|
.live_status_loading = true,
|
2022-10-29 21:49:44 +02:00
|
|
|
};
|
|
|
|
|
2023-12-03 17:16:49 +01:00
|
|
|
@memcpy(self.quality_buf[0..4], "best");
|
2022-10-29 21:49:44 +02:00
|
|
|
|
|
|
|
const thread = try std.Thread.spawn(.{}, config.configLoaderThread, .{self});
|
|
|
|
thread.detach();
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn freeStreamlinkMemfd(self: *Self) void {
|
|
|
|
if (self.streamlink_out) |mem| {
|
2022-11-02 22:35:51 +01:00
|
|
|
log.info("unmapping streamlink output", .{});
|
2022-10-29 21:49:44 +02:00
|
|
|
std.os.munmap(mem);
|
|
|
|
self.streamlink_out = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.streamlink_memfd) |fd| {
|
2022-11-02 22:35:51 +01:00
|
|
|
log.info("closing streamlink output", .{});
|
2022-10-29 21:49:44 +02:00
|
|
|
fd.close();
|
|
|
|
self.streamlink_memfd = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deinit(self: *Self) void {
|
|
|
|
self.freeStreamlinkMemfd();
|
|
|
|
|
|
|
|
if (self.channels) |ch| {
|
|
|
|
std.heap.c_allocator.free(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.channels_file_data) |d| {
|
|
|
|
std.heap.c_allocator.free(d);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.* = undefined;
|
|
|
|
}
|