Changes
5 changed files (+169/-0)
-
-
@@ -394,6 +394,7 @@const BrowseListener = JsonResponseListener(BrowseService.Browse.Response, 1_000); const LoadListener = JsonResponseListener(BrowseService.Load.Response, 3_000); const ControlListener = Listener(transport.ControlResultCode, 2_000); const SeekListener = Listener(transport.SeekResultCode, 2_000); internal: *Internal,
-
@@ -412,6 +413,7 @@ load_listeners: std.AutoHashMap(u64, LoadListener),image_downloads: std.AutoHashMap(u64, *ImageDownload), image_downloads_lock: std.Thread.Mutex = .{}, control_events: std.AutoHashMap(u64, ControlListener), seek_events: std.AutoHashMap(u64, SeekListener), fn init(server: *discovery.Server, token: ?[]const u8) !Internal { var addr = std.ArrayList(u8).init(allocator);
-
@@ -443,6 +445,7 @@ .browse_listeners = undefined,.load_listeners = undefined, .image_downloads = undefined, .control_events = undefined, .seek_events = undefined, }; }
-
@@ -451,6 +454,7 @@ self.browse_listeners = std.AutoHashMap(u64, BrowseListener).init(allocator);self.load_listeners = std.AutoHashMap(u64, LoadListener).init(allocator); self.image_downloads = std.AutoHashMap(u64, *ImageDownload).init(allocator); self.control_events = std.AutoHashMap(u64, ControlListener).init(allocator); self.seek_events = std.AutoHashMap(u64, SeekListener).init(allocator); } fn deinitListeners(self: *Internal) void {
-
@@ -463,6 +467,7 @@ download.*.deinit();} self.image_downloads.deinit(); self.control_events.deinit(); self.seek_events.deinit(); } fn deinit(self: *Internal) void {
-
@@ -741,6 +746,19 @@entry.value_ptr.write( if (std.mem.eql(u8, "Success", meta.service)) .ok else .server_error, ); continue; } if (self.internal.seek_events.getEntry(header.request_id)) |entry| { std.log.debug("Received /seek response (ID={d})", .{header.request_id}); entry.value_ptr.write(code: { _ = TransportService.Seek.Response.decode(&meta) catch { break :code .server_error; }; break :code .ok; }); continue; }
-
@@ -1011,6 +1029,59 @@ return .timeout;}; } pub fn seek( ptr: ?*Connection, zone_ptr: ?*transport.Zone, seconds: i64, ) callconv(.C) transport.SeekResultCode { var self = ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); var zone = zone_ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); _ = zone.retain(); defer zone.release(); var ws = self.internal.ws orelse { std.log.err("{s}_{s} called, but WebSocket connection is not ready", .{ cname, @src().fn_name }); return .closed; }; const req_id = self.getRequestId(); std.log.debug("Sending seek request...", .{}); const req = TransportService.Seek.Request{ .zone_or_output_id = std.mem.span(zone.id), .how = .absolute, .seconds = seconds, }; const req_msg = req.encode(allocator, req_id) catch |err| { std.log.err("Unable to compose seek request: {s}", .{@errorName(err)}); return .unknown_error; }; defer allocator.free(req_msg); var entry = self.internal.seek_events.getOrPut(req_id) catch |err| { std.log.err("Unable to set listener for seek response: {s}", .{@errorName(err)}); return .unknown_error; }; entry.value_ptr.* = .{}; defer _ = self.internal.seek_events.remove(req_id); ws.writeBin(req_msg) catch |err| { std.log.err("Unable to write seek request: {s}", .{@errorName(err)}); return .failed_to_send; }; return entry.value_ptr.listen() catch { return .timeout; }; } pub fn requestBrowse( ptr: ?*Connection, hierarchy: browse.Hierarchy,
-
@@ -1272,6 +1343,7 @@ @export(&release, .{ .name = std.fmt.comptimePrint("{s}_release", .{cname}) });@export(&getEvent, .{ .name = std.fmt.comptimePrint("{s}_get_event", .{cname}) }); @export(&subscribeZones, .{ .name = std.fmt.comptimePrint("{s}_subscribe_zones", .{cname}) }); @export(&control, .{ .name = std.fmt.comptimePrint("{s}_control", .{cname}) }); @export(&seek, .{ .name = std.fmt.comptimePrint("{s}_seek", .{cname}) }); @export(&requestBrowse, .{ .name = std.fmt.comptimePrint("{s}_browse", .{cname}) }); @export(&getImage, .{ .name = std.fmt.comptimePrint("{s}_get_image", .{cname}) }); }
-
-
-
@@ -146,6 +146,17 @@ PLAC_TRANSPORT_CONTROL_RESULT_SERVER_ERROR = 6,PLAC_TRANSPORT_CONTROL_RESULT_TIMEOUT = 7, } plac_transport_control_result_code; // transport.SeekResultCode typedef enum { PLAC_TRANSPORT_SEEK_RESULT_OK = 0, PLAC_TRANSPORT_SEEK_RESULT_UNKNOWN_ERROR = 1, PLAC_TRANSPORT_SEEK_RESULT_OUT_OF_MEMORY = 2, PLAC_TRANSPORT_SEEK_RESULT_FAILED_TO_SEND = 3, PLAC_TRANSPORT_SEEK_RESULT_CLOSED = 4, PLAC_TRANSPORT_SEEK_RESULT_SERVER_ERROR = 5, PLAC_TRANSPORT_SEEK_RESULT_TIMEOUT = 6, } plac_transport_seek_result_code; // browse.Hierarchy typedef enum { PLAC_BROWSE_HIERARCHY_BROWSE = 0,
-
@@ -366,6 +377,7 @@ void plac_connection_release(plac_connection*);plac_connection_event *plac_connection_get_event(plac_connection*); void plac_connection_subscribe_zones(plac_connection*); plac_transport_control_result_code plac_connection_control(plac_connection*, plac_transport_zone*, uint16_t action); plac_transport_seek_result_code plac_connection_seek(plac_connection*, plac_transport_zone*, int64_t seconds); plac_browse_result *plac_connection_browse(plac_connection*, plac_browse_hierarchy, plac_transport_zone*, plac_browse_item*, bool pop); plac_image_get_result *plac_connection_get_image(plac_connection*, const char *image_key, plac_image_get_options*);
-
-
-
@@ -216,6 +216,21 @@ NO_ACTION_BIT_SET = 5,SERVER_ERROR = 6, TIMEOUT = 7, } [CCode ( cname = "plac_transport_seek_result_code", cprefix = "PLAC_TRANSPORT_SEEK_RESULT_", has_type_id = false )] public enum SeekResultCode { OK = 0, UNKNOWN_ERROR = 1, OUT_OF_MEMORY = 2, FAILED_TO_SEND = 3, CLOSED = 4, SERVER_ERROR = 5, TIMEOUT = 6, } } namespace Browse {
-
@@ -558,6 +573,9 @@ public void subscribe_zones();[CCode (cname = "plac_connection_control")] public void control(Transport.Zone zone, uint16 action); [CCode (cname = "plac_connection_seek")] public Transport.SeekResultCode seek(Transport.Zone zone, int64 seconds); [CCode (cname = "plac_connection_browse")] public Browse.Result? browse(Browse.Hierarchy hierarchy, Transport.Zone? zone, Browse.Item? item, bool pop);
-
-
-
@@ -210,3 +210,60 @@ return ResponseError.NonSuccessResponse;} } }; pub const Seek = struct { const method = "/seek"; pub const Request = struct { zone_or_output_id: []const u8, how: enum { relative, absolute, }, /// Can be negative when `how` is `relative` seconds: i64, pub fn encode( self: @This(), allocator: std.mem.Allocator, request_id: u64, ) ![]u8 { const meta = moo.Metadata{ .service = id ++ method, .verb = "REQUEST", }; const body = moo.JsonBody(Request).init(&self, .{}); const header = body.getHeader(request_id); const buf = try allocator.alloc( u8, meta.getEncodeSize() + header.getEncodeSize() + body.getEncodeSize(), ); errdefer allocator.free(buf); var fbs = std.io.fixedBufferStream(buf); try moo.encode(fbs.writer(), meta, header, body); return buf; } }; pub const Response = struct { pub const DecodeError = error{ NonSuccessResponse, }; pub fn decode(meta: *const moo.Metadata) !@This() { if (!std.mem.eql(u8, meta.service, "Success")) { std.log.err( "Expected \"Success\" for {s}{s}, got \"{s}\"", .{ id, method, meta.service }, ); return DecodeError.NonSuccessResponse; } return .{}; } }; };
-
-
-
@@ -510,6 +510,16 @@ server_error = 6,timeout = 7, }; pub const SeekResultCode = enum(c_int) { ok = 0, unknown_error = 1, out_of_memory = 2, failed_to_send = 3, closed = 4, server_error = 5, timeout = 6, }; pub fn export_capi() void { SeekChange.export_capi(); NowPlaying.export_capi();
-