// The contract between the Midi Harbor daemon and its clients. // // This file is the contract. Changing it is a contract change whether or not any Rust signature // moves. The version lives in the package name: a breaking change means midiharbor.v2, never a // reinterpreted field. Field numbers are never reused; removed ones are reserved. syntax = "proto3"; package midiharbor.v1; import "google/protobuf/timestamp.proto"; // Owns every endpoint and connection. Clients reach it over a Unix domain socket, or a named pipe // on Windows. service Harbor { // Identity and health. rpc GetServerInfo(GetServerInfoRequest) returns (ServerInfo); rpc GetStatus(GetStatusRequest) returns (StatusSummary); rpc GetCapabilities(GetCapabilitiesRequest) returns (GetCapabilitiesResponse); // Stops the daemon through its graceful shutdown, as SIGTERM or `service stop` does: held notes // are released and sessions ended. Added in 1.1 for the App Store app, whose sandbox forbids // signalling a daemon an earlier instance of the app started. rpc StopDaemon(StopDaemonRequest) returns (StopDaemonResponse); // Queries. rpc ListEndpoints(ListEndpointsRequest) returns (ListEndpointsResponse); rpc GetEndpoint(GetEndpointRequest) returns (Endpoint); rpc ListRoutes(ListRoutesRequest) returns (ListRoutesResponse); rpc ListPeers(ListPeersRequest) returns (ListPeersResponse); rpc ListEvents(ListEventsRequest) returns (ListEventsResponse); // Virtual ports. rpc CreateVirtualPort(CreateVirtualPortRequest) returns (Endpoint); // Changes how many MIDI In and MIDI Out connectors a virtual port has. Routes on connectors // it no longer has are removed, and the port is reopened. rpc SetVirtualPortConnectors(SetVirtualPortConnectorsRequest) returns (Endpoint); rpc RenameEndpoint(RenameEndpointRequest) returns (Endpoint); rpc DeleteVirtualPort(DeleteVirtualPortRequest) returns (DeleteVirtualPortResponse); rpc SetEndpointEnabled(SetEndpointEnabledRequest) returns (Endpoint); // Sends one note out of an endpoint, the note-on now and its note-off after length_ms, for // testing what listens there. The daemon sends the note-off itself, so a client that goes away // cannot leave the note sounding. Added in 1.2. rpc SendTestNote(SendTestNoteRequest) returns (SendTestNoteResponse); // Clears the warning that the MIDI service stopped, for every client, once someone has seen it. // Added in 1.2. rpc DismissMidiServerWarning(DismissMidiServerWarningRequest) returns (DismissMidiServerWarningResponse); // Network sessions. rpc CreateNetworkSession(CreateNetworkSessionRequest) returns (Endpoint); rpc ConnectPeer(ConnectPeerRequest) returns (Endpoint); rpc DisconnectPeer(DisconnectPeerRequest) returns (Endpoint); // Ends one machine's part in a network port, leaving the others connected. rpc DisconnectMachine(DisconnectMachineRequest) returns (Endpoint); rpc AddManualPeer(AddManualPeerRequest) returns (Peer); rpc RemovePeer(RemovePeerRequest) returns (RemovePeerResponse); // Switches whether a known machine is let in without asking. rpc SetPeerTrusted(SetPeerTrustedRequest) returns (Peer); rpc RespondToInvitation(RespondToInvitationRequest) returns (RespondToInvitationResponse); rpc SetInvitationPolicy(SetInvitationPolicyRequest) returns (Endpoint); // Deletes a network port, stopping what it carried first. rpc DeleteNetworkPort(DeleteNetworkPortRequest) returns (DeleteNetworkPortResponse); // Changes a network port's settings. A field left unset is left as it is. rpc UpdateNetworkPort(UpdateNetworkPortRequest) returns (Endpoint); // Physical devices are discovered, never created, so there is no create call. rpc ForgetPhysicalDevice(ForgetPhysicalDeviceRequest) returns (ForgetPhysicalDeviceResponse); rpc ResolveAmbiguousDevice(ResolveAmbiguousDeviceRequest) returns (Endpoint); // Bluetooth. rpc StartBluetoothScan(StartBluetoothScanRequest) returns (StartBluetoothScanResponse); rpc StopBluetoothScan(StopBluetoothScanRequest) returns (StopBluetoothScanResponse); rpc ConnectBluetoothDevice(ConnectBluetoothDeviceRequest) returns (Endpoint); rpc DisconnectBluetoothDevice(DisconnectBluetoothDeviceRequest) returns (Endpoint); rpc ForgetBluetoothDevice(ForgetBluetoothDeviceRequest) returns (ForgetBluetoothDeviceResponse); rpc SetPeripheralAdvertising(SetPeripheralAdvertisingRequest) returns (SetPeripheralAdvertisingResponse); // What the radio can see right now, which is not the same as what is configured. Reported // separately from endpoints on purpose: an entry per peripheral in range would write the // neighbourhood into the user's configuration file. rpc ListBluetoothDevices(ListBluetoothDevicesRequest) returns (ListBluetoothDevicesResponse); // Routes, which are the MIDI connections between endpoints. rpc CreateRoute(CreateRouteRequest) returns (CreateRouteResponse); // Changes a route's ends, connectors and whether it carries MIDI both ways, keeping whether it // is switched on. Its id changes when its ends do. rpc UpdateRoute(UpdateRouteRequest) returns (UpdateRouteResponse); rpc DeleteRoute(DeleteRouteRequest) returns (DeleteRouteResponse); rpc SetRouteEnabled(SetRouteEnabledRequest) returns (Route); // Configuration. rpc ExportConfiguration(ExportConfigurationRequest) returns (ExportConfigurationResponse); rpc ImportConfiguration(ImportConfigurationRequest) returns (ImportConfigurationResponse); rpc ReloadConfiguration(ReloadConfigurationRequest) returns (ReloadConfigurationResponse); rpc ExportDiagnostics(ExportDiagnosticsRequest) returns (ExportDiagnosticsResponse); // Reads Apple's own MIDI setup for a one-time import. Read by the daemon so that no client // queries CoreMIDI itself. rpc ReadAppleSetup(ReadAppleSetupRequest) returns (ReadAppleSetupResponse); // Streams. WatchState, WatchEvents and WatchInvitations are lossless; a client that falls // behind on them is disconnected with RESOURCE_EXHAUSTED rather than shown a diverging view. rpc WatchState(WatchStateRequest) returns (stream StateEvent); rpc WatchEvents(WatchEventsRequest) returns (stream Event); rpc WatchInvitations(WatchInvitationsRequest) returns (stream Invitation); // WatchTraffic and MonitorEndpoint are lossy by contract. HTTP/2 flow control would otherwise // let a stalled client apply backpressure toward the MIDI data path, which the real-time rules // forbid. Updates are dropped and counted instead of awaiting capacity. rpc WatchTraffic(WatchTrafficRequest) returns (stream TrafficUpdate); rpc MonitorEndpoint(MonitorEndpointRequest) returns (stream MonitoredMessage); } // --------------------------------------------------------------------------- // Shared enumerations // --------------------------------------------------------------------------- // What kind of thing an endpoint is. enum EndpointKind { ENDPOINT_KIND_UNSPECIFIED = 0; ENDPOINT_KIND_VIRTUAL_PORT = 1; ENDPOINT_KIND_PHYSICAL_DEVICE = 2; ENDPOINT_KIND_NETWORK_SESSION = 3; ENDPOINT_KIND_BLUETOOTH_DEVICE = 4; } // Which way MIDI can travel through an endpoint. enum Direction { DIRECTION_UNSPECIFIED = 0; DIRECTION_INPUT = 1; DIRECTION_OUTPUT = 2; DIRECTION_BIDIRECTIONAL = 3; } // Where a connection sits in its lifecycle. enum ConnectionPhase { CONNECTION_PHASE_UNSPECIFIED = 0; // Switched off by the user. The only phase that stays put on its own. CONNECTION_PHASE_DISABLED = 1; CONNECTION_PHASE_DISCONNECTED = 2; CONNECTION_PHASE_CONNECTING = 3; CONNECTION_PHASE_CONNECTED = 4; // Down for a reason the user cannot act on, waiting out a backoff delay. CONNECTION_PHASE_RETRYING = 5; // Down for a reason the user can act on. Still retried, and re-evaluated every attempt. CONNECTION_PHASE_UNAVAILABLE = 6; } // How a session treats incoming invitations. enum InvitationPolicy { INVITATION_POLICY_UNSPECIFIED = 0; INVITATION_POLICY_PROMPT = 1; INVITATION_POLICY_ACCEPT_KNOWN = 2; INVITATION_POLICY_ACCEPT_ALL = 3; INVITATION_POLICY_REJECT_ALL = 4; } // Whether a route can currently deliver. enum RouteValidity { ROUTE_VALIDITY_UNSPECIFIED = 0; ROUTE_VALIDITY_VALID = 1; // One or both endpoints are missing; the route is kept so it can resume when they return. ROUTE_VALIDITY_BROKEN = 2; // The route takes part in a cycle. Creation is still allowed, but the user is warned. ROUTE_VALIDITY_LOOP_DETECTED = 3; // Both endpoints exist, but one is not running, so nothing can pass. The configuration is // intact and delivery resumes when it is available again. ROUTE_VALIDITY_SUSPENDED = 4; } // How confidently stored hardware was matched to something attached. enum MatchConfidence { MATCH_CONFIDENCE_UNSPECIFIED = 0; MATCH_CONFIDENCE_NONE = 1; // Never rebinds a route on its own: binding the wrong hardware is worse than asking. MATCH_CONFIDENCE_AMBIGUOUS = 2; MATCH_CONFIDENCE_PROBABLE = 3; MATCH_CONFIDENCE_EXACT = 4; } // How much attention an event deserves. enum Severity { SEVERITY_UNSPECIFIED = 0; SEVERITY_INFO = 1; SEVERITY_WARNING = 2; SEVERITY_ERROR = 3; } // --------------------------------------------------------------------------- // Core messages // --------------------------------------------------------------------------- // Identifies which build and contract version the daemon serves. message ServerInfo { string daemon_version = 1; uint32 protocol_major = 2; uint32 protocol_minor = 3; google.protobuf.Timestamp started_at = 4; string config_path = 5; string socket_path = 6; // Identifies the daemon's build apart from every other build, the same version included. // Empty from a daemon older than protocol 1.3. string build_id = 7; } // Why a connection is not usable. The slug is the stable value clients switch on. message FailureReason { // Stable machine-readable slug, such as name_conflict or permission_denied. string code = 1; // Human-readable description. May change between releases; never switch on it. string message = 2; // What the user can do about it, when there is anything. string guidance = 3; // Whether clearing this requires the user to act. bool needs_user_action = 4; } // The lifecycle position of one endpoint, with the history needed to explain it. message ConnectionState { ConnectionPhase phase = 1; google.protobuf.Timestamp since = 2; // Retained after recovery, so a user can see what happened while they were not watching. FailureReason last_error = 3; uint32 attempt = 4; google.protobuf.Timestamp next_retry = 5; // Set while the link keeps connecting and dropping again within seconds. Its retries are // spaced out regardless; this says why it keeps going quiet. bool unstable = 6; // Set while a network session has no network to reach its peer by: the machine has no route // there at all, as opposed to a peer that is not answering. bool waiting_for_network = 7; } // Live traffic counts for one endpoint or route. message TrafficCounters { uint64 messages_sent = 1; uint64 messages_received = 2; uint64 bytes_sent = 3; uint64 bytes_received = 4; // Lost by the network, detected as a gap in sequence numbers. uint64 messages_lost = 5; // Rebuilt from the recovery journal. uint64 messages_recovered = 6; // Discarded by our own backpressure, kept distinct from network loss on purpose. uint64 messages_dropped = 7; google.protobuf.Timestamp last_activity = 8; // Bluetooth MIDI packets from the device that could not be decoded and were discarded whole. uint64 packets_malformed = 9; // When a message was last received, and last sent, apart because last_activity cannot say // which way traffic went. google.protobuf.Timestamp last_received = 10; google.protobuf.Timestamp last_sent = 11; } // The values used to recognise one piece of hardware again after it is replugged. message DeviceFingerprint { optional uint32 unique_id = 1; optional string usb_serial = 2; optional string manufacturer = 3; optional string model = 4; // Always present, never sufficient on its own. string name = 5; optional string topology_path = 6; } message VirtualPortDetail { // The first MIDI Out connector's platform identifier. optional uint32 platform_unique_id = 1; // MIDI In connectors, which other applications send to: one to sixteen. uint32 inputs = 2; // MIDI Out connectors, which other applications receive from: one to sixteen. uint32 outputs = 3; } message PhysicalDeviceDetail { DeviceFingerprint fingerprint = 1; bool present = 2; MatchConfidence confidence = 3; // Names the application holding the device exclusively, when one does. optional string claimed_by = 4; // Another application's port, or one macOS makes itself such as an IAC bus or an Apple // network session, rather than hardware. bool software = 5; } message NetworkSessionDetail { string local_name = 1; // The data port is always this plus one. uint32 control_port = 2; optional string peer_id = 3; InvitationPolicy invitation_policy = 4; // Time since the last successful clock exchange, the authoritative liveness signal. optional uint64 last_sync_age_ms = 5; optional int64 clock_offset_ns = 6; optional uint64 round_trip_us = 7; // Machines carried beside the peer, having invited the session while it already had one, by // the name each advertises or its address. repeated string guests = 8; // Whether other applications on this computer see it as a MIDI port of its name, joined to it // both ways. bool automatic_port = 9; // Every machine taking part, the peer first. repeated NetworkMachine machines = 10; // The automatic port's traffic, while it is open: received is what other applications sent // it, sent is what it passed on to them. TrafficCounters automatic_port_counters = 11; } // One machine taking part in a network port. message NetworkMachine { // Its control address, host:port. string address = 1; // The name it advertises, once known. optional string name = 2; // Whether this side connected to it, rather than it to this side. bool invited = 3; // Whether it has finished joining and is carrying MIDI. bool joined = 4; // The most recent round trip to it, once measured. optional uint64 round_trip_us = 5; } message BluetoothDeviceDetail { string address = 1; bool paired = 2; optional int32 rssi = 3; // True when this device connected to us rather than us connecting to it. bool peripheral_role = 4; } // Anything MIDI can flow to or from. message Endpoint { string id = 1; string name = 2; EndpointKind kind = 3; bool enabled = 4; Direction direction = 5; ConnectionState state = 6; TrafficCounters counters = 7; oneof detail { VirtualPortDetail virtual_port = 8; PhysicalDeviceDetail physical_device = 9; NetworkSessionDetail network_session = 10; BluetoothDeviceDetail bluetooth_device = 11; } } // A MIDI connection between two endpoints. message Route { string id = 1; string from_name = 2; string to_name = 3; optional string from_id = 4; optional string to_id = 5; bool enabled = 6; RouteValidity validity = 7; // Populated when validity is BROKEN: the endpoint names that matched nothing. repeated string missing = 8; // Populated when validity is LOOP_DETECTED: the route ids forming the cycle. repeated string cycle = 9; TrafficCounters counters = 10; // Populated when validity is SUSPENDED: the endpoints that exist but are not running. repeated string waiting_on = 11; // Which of the source's MIDI In connectors the route starts from, counting from one. uint32 from_connector = 12; // Which of the destination's MIDI Out connectors the route ends at, counting from one. uint32 to_connector = 13; // Whether it also carries MIDI back, from the destination's MIDI In to_connector to the // source's MIDI Out from_connector. bool both_ways = 14; } // A discovered or manually added remote party. message Peer { string id = 1; string advertised_name = 2; repeated string addresses = 3; bool discovered = 4; bool trusted = 5; google.protobuf.Timestamp last_seen = 6; } // Whether one capability is available, and why not when it is not. message Capability { // Readable, such as "bluetooth connections", and may be reworded. string name = 1; bool available = 2; string reason = 3; // Stable, such as "bluetooth_central", for clients choosing what to show. string id = 4; } // A timestamped record of something that happened. message Event { uint64 id = 1; google.protobuf.Timestamp at = 2; optional string endpoint_id = 3; optional string route_id = 4; Severity severity = 5; // Stable machine-readable name, such as endpoint_state_changed. string kind = 6; string detail = 7; } // A peer asking to establish a session with this machine. message Invitation { string invitation_id = 1; string session_endpoint_id = 2; string peer_name = 3; string peer_address = 4; google.protobuf.Timestamp received_at = 5; bool peer_known = 6; } // --------------------------------------------------------------------------- // Requests and responses // --------------------------------------------------------------------------- message GetServerInfoRequest {} message GetStatusRequest {} message StopDaemonRequest {} message StopDaemonResponse {} message StatusSummary { ServerInfo server = 1; uint32 endpoint_count = 2; uint32 connected_count = 3; uint32 route_count = 4; uint32 broken_route_count = 5; // When the platform's MIDI service was found gone, while the warning about it stands: set by the // daemon that replaced the one that lost it, and cleared by DismissMidiServerWarning. Other // applications that were using MIDI may have lost it with the service, which the daemon cannot // see or mend. google.protobuf.Timestamp midi_server_replaced_at = 6; } message GetCapabilitiesRequest {} message GetCapabilitiesResponse { repeated Capability capabilities = 1; } message ListEndpointsRequest { // Restricts the listing to one kind when set. optional EndpointKind kind = 1; // Includes remembered hardware that is currently unplugged. bool include_absent = 2; } message ListEndpointsResponse { repeated Endpoint endpoints = 1; } message GetEndpointRequest { string id = 1; } message ListRoutesRequest { bool only_broken = 1; } message ListRoutesResponse { repeated Route routes = 1; } message ListPeersRequest {} message ListPeersResponse { repeated Peer peers = 1; } message ListEventsRequest { // Returns only events newer than this identifier. optional uint64 after_id = 1; uint32 limit = 2; optional string endpoint_id = 3; } message ListEventsResponse { repeated Event events = 1; } message CreateVirtualPortRequest { string name = 1; // Not used: a virtual port always carries MIDI both ways, as MIDI In and MIDI Out connectors. Direction direction = 2; // MIDI In connectors, one to sixteen. Zero means one. uint32 inputs = 3; // MIDI Out connectors, one to sixteen. Zero means one. uint32 outputs = 4; } message SetVirtualPortConnectorsRequest { // The port, by name or identifier. string id = 1; // MIDI In connectors, one to sixteen. uint32 inputs = 2; // MIDI Out connectors, one to sixteen. uint32 outputs = 3; } message RenameEndpointRequest { string id = 1; string new_name = 2; // Without this, the call fails FAILED_PRECONDITION and reports which applications may need to // reselect the port. Renaming also rewrites every route that names this endpoint. bool confirm = 3; } message DeleteVirtualPortRequest { string id = 1; } message DeleteNetworkPortRequest { // The network port, by name or identifier. string id = 1; } message DeleteNetworkPortResponse { // Routes that referenced the deleted network port and are now broken. repeated string orphaned_routes = 1; } message DeleteVirtualPortResponse { // Routes that referenced the deleted port and are now broken. repeated string orphaned_routes = 1; } message SetEndpointEnabledRequest { string id = 1; bool enabled = 2; } message SendTestNoteRequest { // The endpoint to send out of, by name or identifier. It must be one a route could send to. string endpoint_id = 1; // 1 to 16. uint32 channel = 2; // 0 to 127; 60 is middle C. uint32 note = 3; // 1 to 127. Zero would be read as a note-off. uint32 velocity = 4; // How long the note sounds, 1 to 10000 milliseconds; 500 when unset. optional uint32 length_ms = 5; } message SendTestNoteResponse {} message DismissMidiServerWarningRequest {} message DismissMidiServerWarningResponse { // Whether there was a warning to dismiss. bool dismissed = 1; } message CreateNetworkSessionRequest { string name = 1; // Zero asks the daemon to choose. The data port is always control_port plus one. uint32 control_port = 2; InvitationPolicy invitation_policy = 3; // Whether other applications on this computer see it as a MIDI port of its name. Unset means // yes. optional bool automatic_port = 4; // The name other machines see it by, its Bonjour name. Unset means its name. optional string local_name = 5; } message UpdateNetworkPortRequest { // The network port, by name or identifier. string id = 1; optional bool automatic_port = 2; // The name other machines see it by. Machines already connected keep the name they were told. optional string local_name = 3; // The UDP port to listen on, zero to let the system choose. The network port restarts on it: // a machine it connected to is connected to again, and one that connected to it needs the new // port. optional uint32 control_port = 4; optional InvitationPolicy invitation_policy = 5; } message ConnectPeerRequest { string session_endpoint_id = 1; string peer_id = 2; // Carry the machine beside those already connected, rather than in place of the peer. It is // remembered and reconnected as the peer is, until it is disconnected. bool alongside = 3; } message DisconnectMachineRequest { string session_endpoint_id = 1; // The machine's address, as NetworkMachine reports it. string address = 2; } message DisconnectPeerRequest { string session_endpoint_id = 1; } message AddManualPeerRequest { string address = 1; uint32 port = 2; optional string name = 3; // Whether it is let in without asking. Unset means yes. optional bool trusted = 4; } message SetPeerTrustedRequest { // The machine, by identifier, name or address. string peer_id = 1; bool trusted = 2; } message RemovePeerRequest { string peer_id = 1; } message RemovePeerResponse {} message RespondToInvitationRequest { string invitation_id = 1; bool accept = 2; // Remembers the peer as trusted, so future invitations are accepted without asking. bool always = 3; } message RespondToInvitationResponse {} message SetInvitationPolicyRequest { string session_endpoint_id = 1; InvitationPolicy policy = 2; } message ForgetPhysicalDeviceRequest { string id = 1; } message ForgetPhysicalDeviceResponse { repeated string orphaned_routes = 1; // Set when the hardware is still plugged in, so it has been listed again as something never // seen before rather than disappearing. bool still_attached = 2; } message ResolveAmbiguousDeviceRequest { string id = 1; // The attached hardware the user chose for this stored entry. DeviceFingerprint chosen = 2; } message StartBluetoothScanRequest { uint32 duration_seconds = 1; } message StartBluetoothScanResponse {} message StopBluetoothScanRequest {} message StopBluetoothScanResponse {} message ConnectBluetoothDeviceRequest { string address = 1; } message DisconnectBluetoothDeviceRequest { string id = 1; } message ForgetBluetoothDeviceRequest { string id = 1; } message ForgetBluetoothDeviceResponse {} message SetPeripheralAdvertisingRequest { bool enabled = 1; optional string name = 2; } message SetPeripheralAdvertisingResponse { bool advertising = 1; // The name the advertisement was asked to carry, when advertising. string name = 2; // Whether the platform actually sends that name. macOS has room for five bytes of name beside // the MIDI service and drops a longer one, so devices show the computer's own name instead. bool name_sent = 3; } message ListBluetoothDevicesRequest {} message ListBluetoothDevicesResponse { repeated DiscoveredBluetoothDevice devices = 1; } // A peripheral the radio can currently hear. message DiscoveredBluetoothDevice { // The platform's own name for it, which is a hardware address on Linux and an opaque // identifier on macOS. Never parsed by a client. string address = 1; optional string name = 2; optional int32 rssi = 3; bool paired = 4; // Set when this device already has a configured endpoint. optional string endpoint_id = 5; } message CreateRouteRequest { // Endpoint name or identifier. Names are accepted because that is what the stored // configuration uses and what a person types. string from = 1; string to = 2; // Which of the source's MIDI In connectors, counting from one. Zero means the first. uint32 from_connector = 3; // Which of the destination's MIDI Out connectors, counting from one. Zero means the first. uint32 to_connector = 4; // Whether it also carries MIDI back through the same connector numbers the other way round. bool both_ways = 5; } message UpdateRouteRequest { // The route to change. string id = 1; // Endpoint name or identifier, as for CreateRoute. string from = 2; string to = 3; uint32 from_connector = 4; uint32 to_connector = 5; bool both_ways = 6; } message UpdateRouteResponse { Route route = 1; // Populated when the route now completes a cycle. The change still succeeds, per FR-033. repeated string loop_warning = 2; } message CreateRouteResponse { Route route = 1; // Populated when the new route completes a cycle. Creation still succeeds, per FR-033. repeated string loop_warning = 2; } message DeleteRouteRequest { string id = 1; } message DeleteRouteResponse {} message SetRouteEnabledRequest { string id = 1; bool enabled = 2; } message ExportConfigurationRequest {} message ExportConfigurationResponse { // The YAML document, exactly as it would be written to disk. string yaml = 1; } message ImportConfigurationRequest { string yaml = 1; // Replaces the whole setup rather than merging into it. bool replace = 2; } message ImportConfigurationResponse { uint32 endpoints_added = 1; uint32 routes_added = 2; // Connections that were disturbed because their configuration actually changed, by name. repeated string restarted_endpoints = 3; // Endpoints a replacing import removed, by name. A merge never removes anything. repeated string removed_endpoints = 4; // Settings that were accepted but only take effect when the daemon next starts. repeated string pending_restart = 5; } message ReloadConfigurationRequest {} message ReloadConfigurationResponse { // Connections that were disturbed because their configuration actually changed, by name. repeated string restarted_endpoints = 1; // Never set. A reload refuses a document it cannot read and leaves everything running, rather // than preserving the file and starting from defaults as the daemon does at startup. optional string repaired_from = 2; repeated string added_endpoints = 3; repeated string removed_endpoints = 4; uint32 routes_added = 5; // Settings that were accepted but only take effect when the daemon next starts. repeated string pending_restart = 6; } message ReadAppleSetupRequest {} message ReadAppleSetupResponse { // False on a platform with no Apple MIDI setup, when the other fields are empty. bool available = 1; // Whether the IAC Driver is switched on, so its buses are visible to applications now. bool iac_online = 2; // The IAC Driver's bus names. repeated string buses = 3; // The network sessions configured in Audio MIDI Setup. repeated string sessions = 4; } message ExportDiagnosticsRequest { bool include_message_log = 1; } message ExportDiagnosticsResponse { string report = 1; } message WatchStateRequest {} // Something changed about the shape or state of the system. message StateEvent { oneof change { Endpoint endpoint_changed = 1; Endpoint endpoint_added = 2; string endpoint_removed = 3; Route route_changed = 4; string route_removed = 5; GetCapabilitiesResponse capabilities_changed = 6; } } message WatchEventsRequest { optional uint64 after_id = 1; } message WatchInvitationsRequest {} message WatchTrafficRequest { // Restricts updates to these endpoints. Empty means all of them. repeated string endpoint_ids = 1; } // Coalesced counters, emitted at most every 250ms per endpoint and never per message. message TrafficUpdate { string endpoint_id = 1; TrafficCounters counters = 2; // Updates discarded for this subscriber since the last message, because this stream is lossy // by contract rather than applying backpressure toward the data path. uint64 dropped = 3; } message MonitorEndpointRequest { string endpoint_id = 1; } // One decoded MIDI message observed on an endpoint. message MonitoredMessage { google.protobuf.Timestamp at = 1; // Raw bytes, for the hex view. bytes data = 2; // Human-readable decoding, such as "note on ch1 C4 vel100". string decoded = 3; bool outbound = 4; // Messages discarded for this subscriber since the last one delivered. uint64 dropped = 5; }