Changes
5 changed files (+299/-13)
-
-
@@ -361,6 +361,7 @@ const BrowseListener = JsonResponseListener(BrowseService.Browse.Response, 5_000);const LoadListener = JsonResponseListener(BrowseService.Load.Response, 5_000); const ControlListener = Listener(transport.ControlResultCode, 3_000); const SeekListener = Listener(transport.SeekResultCode, 2_000); const ChangeVolumeListener = Listener(transport.VolumeControlResultCode, 2_000); const ImageDownloader = image.Downloader(.{});
-
@@ -382,6 +383,7 @@ load_listeners: std.AutoHashMap(u64, LoadListener),image_downloads: ImageDownloader, control_events: std.AutoHashMap(u64, ControlListener), seek_events: std.AutoHashMap(u64, SeekListener), change_volume_events: std.AutoHashMap(u64, ChangeVolumeListener), fn init(server: *discovery.Server, token: ?[]const u8) !Internal { var addr = std.ArrayList(u8).init(allocator);
-
@@ -414,6 +416,7 @@ .load_listeners = undefined,.image_downloads = undefined, .control_events = undefined, .seek_events = undefined, .change_volume_events = undefined, }; }
-
@@ -423,6 +426,7 @@ self.load_listeners = std.AutoHashMap(u64, LoadListener).init(allocator);self.image_downloads = ImageDownloader.init(self.tsa.allocator()); self.control_events = std.AutoHashMap(u64, ControlListener).init(allocator); self.seek_events = std.AutoHashMap(u64, SeekListener).init(allocator); self.change_volume_events = std.AutoHashMap(u64, ChangeVolumeListener).init(allocator); } fn deinitListeners(self: *Internal) void {
-
@@ -432,6 +436,7 @@self.image_downloads.deinit(); self.control_events.deinit(); self.seek_events.deinit(); self.change_volume_events.deinit(); } fn deinit(self: *Internal) void {
-
@@ -699,6 +704,19 @@ });continue; } if (self.internal.change_volume_events.getEntry(header.request_id)) |entry| { std.log.debug("Received /change_volume response (ID={d})", .{header.request_id}); entry.value_ptr.write(code: { _ = TransportService.ChangeVolume.Response.decode(&meta) catch { break :code .server_error; }; break :code .ok; }); continue; } std.log.warn("Unhandle message on {s}", .{meta.service}); std.log.debug("{s}", .{msg.data}); }
-
@@ -1019,6 +1037,163 @@ return .timeout;}; } pub fn increaseVolume( ptr: ?*Connection, output_ptr: ?*transport.Output, ) callconv(.C) transport.VolumeControlResultCode { var self = ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); var output = output_ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); _ = output.retain(); defer output.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 volume increase request...(ID={d})", .{req_id}); const req = TransportService.ChangeVolume.Request{ .output_id = std.mem.span(output.id), .how = .relative, .value = if (output.is_incremental_volume) 1.0 else output.volume.step, }; const req_msg = req.encode(allocator, req_id) catch |err| { std.log.err("Unable to compose volume increase request: {s}", .{@errorName(err)}); return .unknown_error; }; defer allocator.free(req_msg); var entry = self.internal.change_volume_events.getOrPut(req_id) catch |err| { std.log.err("Unable to set listener for volume increase response: {s}", .{@errorName(err)}); return .out_of_memory; }; entry.value_ptr.* = .{}; defer _ = self.internal.change_volume_events.remove(req_id); ws.writeBin(req_msg) catch |err| { std.log.err("Unable to write volume increase request: {s}", .{@errorName(err)}); return .failed_to_send; }; return entry.value_ptr.listen() catch { return .timeout; }; } pub fn decreaseVolume( ptr: ?*Connection, output_ptr: ?*transport.Output, ) callconv(.C) transport.VolumeControlResultCode { var self = ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); var output = output_ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); _ = output.retain(); defer output.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 volume decrease request...(ID={d})", .{req_id}); const req = TransportService.ChangeVolume.Request{ .output_id = std.mem.span(output.id), .how = .relative, .value = if (output.is_incremental_volume) -1.0 else -output.volume.step, }; const req_msg = req.encode(allocator, req_id) catch |err| { std.log.err("Unable to compose volume decrease request: {s}", .{@errorName(err)}); return .unknown_error; }; defer allocator.free(req_msg); var entry = self.internal.change_volume_events.getOrPut(req_id) catch |err| { std.log.err("Unable to set listener for volume decrease response: {s}", .{@errorName(err)}); return .out_of_memory; }; entry.value_ptr.* = .{}; defer _ = self.internal.change_volume_events.remove(req_id); ws.writeBin(req_msg) catch |err| { std.log.err("Unable to write volume decrease request: {s}", .{@errorName(err)}); return .failed_to_send; }; return entry.value_ptr.listen() catch { return .timeout; }; } pub fn changeVolume( ptr: ?*Connection, output_ptr: ?*transport.Output, abs_value: f64, ) callconv(.C) transport.VolumeControlResultCode { var self = ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); var output = output_ptr orelse @panic( std.fmt.comptimePrint("Received null pointer on {s}_{s}", .{ cname, @src().fn_name }), ); _ = output.retain(); defer output.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 volume change request...(ID={d})", .{req_id}); const req = TransportService.ChangeVolume.Request{ .output_id = std.mem.span(output.id), .how = .absolute, .value = abs_value, }; const req_msg = req.encode(allocator, req_id) catch |err| { std.log.err("Unable to compose volume change request: {s}", .{@errorName(err)}); return .unknown_error; }; defer allocator.free(req_msg); var entry = self.internal.change_volume_events.getOrPut(req_id) catch |err| { std.log.err("Unable to set listener for volume change response: {s}", .{@errorName(err)}); return .out_of_memory; }; entry.value_ptr.* = .{}; defer _ = self.internal.change_volume_events.remove(req_id); ws.writeBin(req_msg) catch |err| { std.log.err("Unable to write volume change request: {s}", .{@errorName(err)}); return .failed_to_send; }; return entry.value_ptr.listen() catch { return .timeout; }; } pub fn requestBrowse( ptr: ?*Connection, hierarchy: browse.Hierarchy,
-
@@ -1213,6 +1388,9 @@ @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(&increaseVolume, .{ .name = std.fmt.comptimePrint("{s}_increase_volume", .{cname}) }); @export(&decreaseVolume, .{ .name = std.fmt.comptimePrint("{s}_decrease_volume", .{cname}) }); @export(&changeVolume, .{ .name = std.fmt.comptimePrint("{s}_change_volume", .{cname}) }); @export(&requestBrowse, .{ .name = std.fmt.comptimePrint("{s}_browse", .{cname}) }); @export(&getImage, .{ .name = std.fmt.comptimePrint("{s}_get_image", .{cname}) }); }
-
-
-
@@ -108,9 +108,9 @@// transport.OutputVolume typedef struct { plac_transport_output_volume_unit unit; int64_t min; int64_t max; int64_t value; double min; double max; double value; double step; bool muted; } plac_transport_output_volume;
-
@@ -193,6 +193,18 @@ PLAC_TRANSPORT_SEEK_RESULT_CLOSED = 4,PLAC_TRANSPORT_SEEK_RESULT_SERVER_ERROR = 5, PLAC_TRANSPORT_SEEK_RESULT_TIMEOUT = 6, } plac_transport_seek_result_code; // transport.VolumeControlResultCode typedef enum { PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_OK = 0, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_UNKNOWN_ERROR = 1, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_OUT_OF_MEMORY = 2, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_FAILED_TO_SEND = 3, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_CLOSED = 4, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_SERVER_ERROR = 5, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_TIMEOUT = 6, PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_ILLEGAL_METHOD = 7, } plac_transport_volume_control_result_code; // browse.Hierarchy typedef enum {
-
@@ -424,6 +436,9 @@ 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_transport_volume_control_result_code plac_connection_change_volume(plac_connection*, plac_transport_output*, double abs_value); plac_transport_volume_control_result_code plac_connection_increase_volume(plac_connection*, plac_transport_output*); plac_transport_volume_control_result_code plac_connection_decrease_volume(plac_connection*, plac_transport_output*); 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*);
-
-
-
@@ -130,9 +130,9 @@[CCode (cname = "plac_transport_output_volume", has_type_id = false)] public struct OutputVolume { public OutputVolumeUnit unit; public int64 min; public int64 max; public int64 value; public double min; public double max; public double value; public double step; public bool muted; }
-
@@ -275,6 +275,22 @@ FAILED_TO_SEND = 3,CLOSED = 4, SERVER_ERROR = 5, TIMEOUT = 6, } [CCode ( cname = "plac_transport_volume_control_result_code", cprefix = "PLAC_TRANSPORT_VOLUME_CONTROL_RESULT_", has_type_id = false )] public enum VolumeControlResultCode { OK = 0, UNKNOWN_ERROR = 1, OUT_OF_MEMORY = 2, FAILED_TO_SEND = 3, CLOSED = 4, SERVER_ERROR = 5, TIMEOUT = 6, ILLEGAL_METHOD = 7, } }
-
@@ -631,6 +647,15 @@ public void subscribe_zones();[CCode (cname = "plac_connection_control")] public void control(Transport.Zone zone, uint16 action); [CCode (cname = "plac_connection_change_volume")] public Transport.VolumeControlResultCode change_volume(Transport.Output output, double abs_value); [CCode (cname = "plac_connection_increase_volume")] public Transport.VolumeControlResultCode increase_volume(Transport.Output output); [CCode (cname = "plac_connection_decrease_volume")] public Transport.VolumeControlResultCode decrease_volume(Transport.Output output); [CCode (cname = "plac_connection_seek")] public Transport.SeekResultCode seek(Transport.Zone zone, int64 seconds);
-
-
-
@@ -66,10 +66,9 @@ };pub const OutputVolume = struct { type: []const u8, // Completely no idea the range of these numeric values. min: ?i64 = null, max: ?i64 = null, value: ?i64 = null, min: ?f64 = null, max: ?f64 = null, value: ?f64 = null, step: ?f64 = null, is_muted: ?bool = null, };
-
@@ -284,3 +283,61 @@ return .{};} }; }; pub const ChangeVolume = struct { const method = "/change_volume"; pub const Request = struct { output_id: []const u8, how: enum { absolute, relative, relative_step, }, value: f64, /// Caller owns the returned memory. 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 .{}; } }; };
-
-
-
@@ -212,9 +212,9 @@ };pub const OutputVolume = extern struct { unit: OutputVolumeUnit = .unknown, min: i64 = 0, max: i64 = 0, value: i64 = 0, min: f64 = 0, max: f64 = 0, value: f64 = 0, step: f64 = 0.0, muted: bool = false, };
-
@@ -633,6 +633,17 @@ failed_to_send = 3,closed = 4, server_error = 5, timeout = 6, }; pub const VolumeControlResultCode = enum(c_int) { ok = 0, unknown_error = 1, out_of_memory = 2, failed_to_send = 3, closed = 4, server_error = 5, timeout = 6, illegal_method = 7, }; pub fn export_capi() void {
-