RPC update

This commit is contained in:
badaix 2017-02-24 18:25:10 +01:00
parent ca6a7e35f8
commit 0472f78b60
7 changed files with 499 additions and 185 deletions

View file

@ -25,7 +25,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

View file

@ -57,6 +57,7 @@ import de.badaix.snapcast.control.json.Client;
import de.badaix.snapcast.control.json.Group;
import de.badaix.snapcast.control.json.ServerStatus;
import de.badaix.snapcast.control.json.Stream;
import de.badaix.snapcast.control.json.Volume;
import de.badaix.snapcast.utils.NsdHelper;
import de.badaix.snapcast.utils.Settings;
import de.badaix.snapcast.utils.Setup;
@ -82,6 +83,7 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
private int nativeSampleRate = 0;
private CoordinatorLayout coordinatorLayout;
private Button btnConnect = null;
private boolean batchActive = false;
/**
@ -431,63 +433,6 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
}
}
@Override
public void onConnected(RemoteControl remoteControl) {
setActionbarSubtitle(remoteControl.getHost());
remoteControl.getServerStatus();
updateMenuItems(true);
}
@Override
public void onConnecting(RemoteControl remoteControl) {
setActionbarSubtitle("connecting: " + remoteControl.getHost());
}
@Override
public void onDisconnected(RemoteControl remoteControl, Exception e) {
Log.d(TAG, "onDisconnected");
serverStatus = new ServerStatus();
groupListFragment.updateServer(serverStatus);
if (e != null) {
if (e instanceof UnknownHostException)
setActionbarSubtitle("error: unknown host");
else
setActionbarSubtitle("error: " + e.getMessage());
} else {
setActionbarSubtitle("not connected");
}
updateMenuItems(false);
}
@Override
public void onClientEvent(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, Client client, RemoteControl.ClientEvent event) {
Log.d(TAG, "onClientEvent: " + event.toString());
/// update only in case of notifications
if (rpcEvent == RemoteControl.RpcEvent.response)
return;
serverStatus.updateClient(client);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onServerUpdate(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, ServerStatus serverStatus) {
this.serverStatus = serverStatus;
groupListFragment.updateServer(serverStatus);
}
@Override
public void onStreamUpdate(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, Stream stream) {
serverStatus.updateStream(stream);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onGroupUpdate(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, Group group) {
serverStatus.updateGroup(group);
groupListFragment.updateServer(serverStatus);
}
private void setActionbarSubtitle(final String subtitle) {
MainActivity.this.runOnUiThread(new Runnable() {
@ -609,5 +554,172 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
startActivityForResult(intent, GROUP_PROPERTIES_REQUEST);
}
@Override
public void onConnected(RemoteControl remoteControl) {
setActionbarSubtitle(remoteControl.getHost());
remoteControl.getServerStatus();
updateMenuItems(true);
}
@Override
public void onConnecting(RemoteControl remoteControl) {
setActionbarSubtitle("connecting: " + remoteControl.getHost());
}
@Override
public void onDisconnected(RemoteControl remoteControl, Exception e) {
Log.d(TAG, "onDisconnected");
serverStatus = new ServerStatus();
groupListFragment.updateServer(serverStatus);
if (e != null) {
if (e instanceof UnknownHostException)
setActionbarSubtitle("error: unknown host");
else
setActionbarSubtitle("error: " + e.getMessage());
} else {
setActionbarSubtitle("not connected");
}
updateMenuItems(false);
}
@Override
public void onBatchStart() {
batchActive = true;
}
@Override
public void onBatchEnd() {
batchActive = false;
groupListFragment.updateServer(serverStatus);
}
/*
@Override
public void onClientEvent(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, Client client, RemoteControl.ClientEvent event) {
Log.d(TAG, "onClientEvent: " + event.toString());
/// update only in case of notifications
if (rpcEvent == RemoteControl.RpcEvent.response)
return;
serverStatus.updateClient(client);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onServerUpdate(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, ServerStatus serverStatus) {
this.serverStatus = serverStatus;
groupListFragment.updateServer(serverStatus);
}
@Override
public void onStreamUpdate(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, Stream stream) {
serverStatus.updateStream(stream);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onGroupUpdate(RemoteControl remoteControl, RemoteControl.RpcEvent rpcEvent, Group group) {
serverStatus.updateGroup(group);
groupListFragment.updateServer(serverStatus);
}
*/
@Override
public void onConnect(Client client) {
serverStatus.getClient(client.getId());
if (client == null)
return;
client.setConnected(true);
serverStatus.updateClient(client);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onDisconnect(String clientId) {
Client client = serverStatus.getClient(clientId);
if (client == null)
return;
client.setConnected(false);
serverStatus.updateClient(client);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onUpdate(Client client) {
serverStatus.updateClient(client);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onVolumeChanged(RemoteControl.RPCEvent event, String clientId, Volume volume) {
if (event == RemoteControl.RPCEvent.response)
return;
Client client = serverStatus.getClient(clientId);
if (client == null)
return;
client.setVolume(volume);
if (!batchActive)
groupListFragment.updateServer(serverStatus);
}
@Override
public void onLatencyChanged(RemoteControl.RPCEvent event, String clientId, long latency) {
Client client = serverStatus.getClient(clientId);
if (client == null)
return;
client.getConfig().setLatency((int)latency);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onNameChanged(RemoteControl.RPCEvent event, String clientId, String name) {
Client client = serverStatus.getClient(clientId);
if (client == null)
return;
client.getConfig().setName(name);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onUpdate(Group group) {
serverStatus.updateGroup(group);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onMute(RemoteControl.RPCEvent event, String groupId, boolean mute) {
Group g = serverStatus.getGroup(groupId);
if (g == null)
return;
g.setMuted(mute);
serverStatus.updateGroup(g);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onStreamChanged(RemoteControl.RPCEvent event, String groupId, String streamId) {
Group g = serverStatus.getGroup(groupId);
if (g == null)
return;
g.setStreamId(streamId);
serverStatus.updateGroup(g);
groupListFragment.updateServer(serverStatus);
}
@Override
public void onUpdate(ServerStatus server) {
this.serverStatus = server;
groupListFragment.updateServer(serverStatus);
}
@Override
public void onUpdate(String streamId, Stream stream) {
serverStatus.updateStream(stream);
groupListFragment.updateServer(serverStatus);
}
}

View file

@ -0,0 +1,175 @@
/*
* This file is part of snapcast
* Copyright (C) 2014-2017 Johannes Pohl
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.badaix.snapcast.control;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by johannes on 19.02.17.
*/
class RPCRequest {
RPCRequest(JSONObject json) throws JSONException {
fromJson(json);
}
RPCRequest(String json) throws JSONException {
this(new JSONObject(json));
}
RPCRequest(String method, long id, JSONObject params) {
this.method = method;
this.id = id;
this.params = params;
}
@Override
public String toString() {
return toJson().toString();
}
JSONObject toJson() {
JSONObject request = new JSONObject();
try {
request.put("jsonrpc", "2.0");
request.put("method", method);
request.put("id", id);
if (params != null)
request.put("params", params);
return request;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
void fromJson(JSONObject json) throws JSONException {
id = json.getLong("id");
method = json.getString("method");
if (json.has("params"))
params = json.getJSONObject("params");
else
params = null;
}
String method;
long id;
JSONObject params;
}
class RPCNotification {
RPCNotification(JSONObject json) throws JSONException {
fromJson(json);
}
RPCNotification(String json) throws JSONException {
this(new JSONObject(json));
}
RPCNotification(String method, long id, JSONObject params) {
this.method = method;
this.params = params;
}
@Override
public String toString() {
return toJson().toString();
}
JSONObject toJson() {
JSONObject request = new JSONObject();
try {
request.put("jsonrpc", "2.0");
request.put("method", method);
if (params != null)
request.put("params", params);
return request;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
void fromJson(JSONObject json) throws JSONException {
method = json.getString("method");
if (json.has("params"))
params = json.getJSONObject("params");
else
params = null;
}
String method;
JSONObject params;
}
class RPCResponse {
RPCResponse(JSONObject json) throws JSONException {
fromJson(json);
}
RPCResponse(String json) throws JSONException {
this(new JSONObject(json));
}
@Override
public String toString() {
return toJson().toString();
}
JSONObject toJson() {
JSONObject response = new JSONObject();
try {
response.put("jsonrpc", "2.0");
if (error != null)
response.put("error", error);
else if (result != null)
response.put("result", result);
else
throw new JSONException("error and result are null");
response.put("id", id);
return response;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
void fromJson(JSONObject json) throws JSONException {
id = json.getLong("id");
if (json.has("error")) {
error = json.getJSONObject("error");
result = null;
}
else if (json.has("result")) {
result = json.getJSONObject("result");
error = null;
}
else
throw new JSONException("error and result are null");
}
long id;
JSONObject result;
JSONObject error;
}

View file

@ -18,7 +18,6 @@
package de.badaix.snapcast.control;
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONArray;
@ -39,6 +38,11 @@ import de.badaix.snapcast.control.json.Volume;
*/
public class RemoteControl implements TcpClient.TcpClientListener {
public enum RPCEvent {
response,
notification
}
private static final String TAG = "RC";
private TcpClient tcpClient;
@ -113,14 +117,14 @@ public class RemoteControl implements TcpClient.TcpClientListener {
if (json.has("id")) {
/// Response
RPCResponse response = new RPCResponse(json);
// Log.d(TAG, "ID: " + json.getString("id"));
long id = json.getLong("id");
String requestMethod = "";
RPCRequest request = null;
synchronized (pendingRequests) {
if (pendingRequests.containsKey(id)) {
requestMethod = pendingRequests.get(id);
// Log.d(TAG, "Response to: " + request);
pendingRequests.remove(id);
if (pendingRequests.containsKey(response.id)) {
request = new RPCRequest(new JSONObject(pendingRequests.get(response.id)));
Log.d(TAG, "Response to: " + request.method);
pendingRequests.remove(response.id);
}
}
@ -132,68 +136,57 @@ public class RemoteControl implements TcpClient.TcpClientListener {
Log.e(TAG, "error " + error.getInt("code") + ": " + error.getString("message") + "; data: " + error.getString("data"));
}
if (TextUtils.isEmpty(requestMethod)) {
Log.e(TAG, "request for id " + id + " not found");
if (request == null) {
Log.e(TAG, "request for id " + response.id + " not found");
return;
}
RpcEvent rpcEvent = RpcEvent.response;
RPCEvent rpcEvent = RPCEvent.response;
/// Response to a "Object.GetStatus" message
if (requestMethod.equals("Client.GetStatus")) {
listener.onClientEvent(this, rpcEvent, new Client(json.getJSONObject("result")), ClientEvent.updated);
} else if (requestMethod.equals("Client.SetVolume")) {
} else if (requestMethod.equals("Client.SetLatency")) {
} else if (requestMethod.equals("Client.SetName")) {
} else if (requestMethod.equals("Group.GetStatus")) {
listener.onGroupUpdate(this, rpcEvent, new Group(json.getJSONObject("result")));
} else if (requestMethod.equals("Group.SetMute")) {
} else if (requestMethod.equals("Group.SetStream")) {
} else if (requestMethod.equals("Group.SetClients")) {
listener.onServerUpdate(this, rpcEvent, new ServerStatus(json.getJSONObject("result").getJSONObject("server")));
} else if (requestMethod.equals("Server.GetStatus")) {
listener.onServerUpdate(this, rpcEvent, new ServerStatus(json.getJSONObject("result")));
} else if (requestMethod.equals("Server.DeleteClient")) {
// } else if (json.getJSONObject("result").has("method") && json.getJSONObject("result").has("params")) {
/// Response to a "Object.Set" message
JSONObject result = json.getJSONObject("result");
String method = result.getString("method");
if ("Client.OnUpdate".equals(method)) {
listener.onClientEvent(this, rpcEvent, new Client(result.getJSONObject("params")), ClientEvent.updated);
} else if ("Group.OnUpdate".equals(method)) {
listener.onGroupUpdate(this, rpcEvent, new Group(result.getJSONObject("params")));
} else if ("Server.OnUpdate".equals(method)) {
listener.onServerUpdate(this, rpcEvent, new ServerStatus(result.getJSONObject("params")));
}
if (request.method.equals("Client.GetStatus")) {
listener.onUpdate(new Client(json.getJSONObject("result")));
} else if (request.method.equals("Client.SetVolume")) {
} else if (request.method.equals("Client.SetLatency")) {
} else if (request.method.equals("Client.SetName")) {
} else if (request.method.equals("Group.GetStatus")) {
listener.onUpdate(new Group(json.getJSONObject("result")));
} else if (request.method.equals("Group.SetMute")) {
// listener.onMute(rpcEvent, request.params.getString("id"), response.result.getBoolean("mute"));
} else if (request.method.equals("Group.SetStream")) {
} else if (request.method.equals("Group.SetClients")) {
listener.onUpdate(new ServerStatus(json.getJSONObject("result").getJSONObject("server")));
} else if (request.method.equals("Server.GetStatus")) {
listener.onUpdate(new ServerStatus(json.getJSONObject("result")));
} else if (request.method.equals("Server.DeleteClient")) {
listener.onUpdate(new ServerStatus(json.getJSONObject("result").getJSONObject("server")));
}
} else {
/// Notification
if (listener == null)
return;
RpcEvent rpcEvent = RpcEvent.notification;
String method = json.getString("method");
RPCEvent rpcEvent = RPCEvent.notification;
RPCNotification notification = new RPCNotification(json);
if (method.equals("Client.OnConnect")) {
} else if (method.equals("Client.OnDisconnect")) {
} else if (method.equals("Client.OnVolumeChanged")) {
} else if (method.equals("Client.OnLatencyChanged")) {
} else if (method.equals("Client.OnNameChanged")) {
} else if (method.equals("Group.OnMute")) {
} else if (method.equals("Group.OnStreamChanged")) {
} else if (method.equals("Stream.OnUpdate")) {
} else if (method.equals("Server.OnUpdate")) {
} else if (method.contains("Client.On")) {
listener.onClientEvent(this, rpcEvent, new Client(json.getJSONObject("params").getJSONObject("client")), ClientEvent.fromString(method));
} else if (method.equals("Stream.OnUpdate")) {
listener.onStreamUpdate(this, rpcEvent, new Stream(json.getJSONObject("params").getJSONObject("stream")));
} else if (method.equals("Group.OnUpdate")) {
listener.onGroupUpdate(this, rpcEvent, new Group(json.getJSONObject("params").getJSONObject("group")));
} else if (method.equals("Server.OnUpdate")) {
listener.onServerUpdate(this, rpcEvent, new ServerStatus(json.getJSONObject("params").getJSONObject("server")));
if (notification.method.equals("Client.OnConnect")) {
listener.onConnect(new Client(notification.params.getJSONObject("client")));
} else if (notification.method.equals("Client.OnDisconnect")) {
listener.onDisconnect(notification.params.getString("id"));
} else if (notification.method.equals("Client.OnVolumeChanged")) {
listener.onVolumeChanged(rpcEvent, notification.params.getString("id"), new Volume(notification.params.getJSONObject("volume")));
} else if (notification.method.equals("Client.OnLatencyChanged")) {
listener.onLatencyChanged(rpcEvent, notification.params.getString("id"), notification.params.getInt("latency"));
} else if (notification.method.equals("Client.OnNameChanged")) {
listener.onNameChanged(rpcEvent, notification.params.getString("id"), notification.params.getString("name"));
} else if (notification.method.equals("Group.OnMute")) {
listener.onMute(rpcEvent, notification.params.getString("id"), notification.params.getBoolean("mute"));
} else if (notification.method.equals("Group.OnStreamChanged")) {
listener.onStreamChanged(rpcEvent, notification.params.getString("id"), notification.params.getString("stream_id"));
} else if (notification.method.equals("Stream.OnUpdate")) {
listener.onUpdate(notification.params.getString("id"), new Stream(notification.params.getJSONObject("stream")));
} else if (notification.method.equals("Group.OnUpdate")) {
listener.onUpdate(new Group(notification.params.getJSONObject("group")));
} else if (notification.method.equals("Server.OnUpdate")) {
listener.onUpdate(new ServerStatus(notification.params.getJSONObject("server")));
}
}
@ -223,35 +216,26 @@ public class RemoteControl implements TcpClient.TcpClientListener {
listener.onDisconnected(this, e);
}
private JSONObject jsonRequest(String method, JSONObject params) {
JSONObject request = new JSONObject();
try {
request.put("jsonrpc", "2.0");
request.put("method", method);
request.put("id", msgId);
if (params != null)
request.put("params", params);
private RPCRequest jsonRequest(String method, JSONObject params) {
RPCRequest request = new RPCRequest(method, msgId, params);
synchronized (pendingRequests) {
pendingRequests.put(msgId, method);
pendingRequests.put(msgId, request.toString());
}
msgId++;
} catch (JSONException e) {
e.printStackTrace();
}
return request;
}
public void getServerStatus() {
JSONObject request = jsonRequest("Server.GetStatus", null);
RPCRequest request = jsonRequest("Server.GetStatus", null);
tcpClient.sendMessage(request.toString());
}
public void setName(Client client, String name) {
try {
JSONObject body = new JSONObject();
body.put("id", client.getId());
body.put("name", name);
JSONObject request = jsonRequest("Client.SetName", body);
JSONObject params = new JSONObject();
params.put("id", client.getId());
params.put("name", name);
RPCRequest request = jsonRequest("Client.SetName", params);
tcpClient.sendMessage(request.toString());
} catch (JSONException e) {
e.printStackTrace();
@ -260,10 +244,10 @@ public class RemoteControl implements TcpClient.TcpClientListener {
public void setLatency(Client client, int latency) {
try {
JSONObject body = new JSONObject();
body.put("id", client.getId());
body.put("latency", latency);
JSONObject request = jsonRequest("Client.SetLatency", body);
JSONObject params = new JSONObject();
params.put("id", client.getId());
params.put("latency", latency);
RPCRequest request = jsonRequest("Client.SetLatency", params);
tcpClient.sendMessage(request.toString());
} catch (JSONException e) {
e.printStackTrace();
@ -279,10 +263,10 @@ public class RemoteControl implements TcpClient.TcpClientListener {
JSONArray clients = new JSONArray();
for (String clientId : clientIds)
clients.put(clientId);
JSONObject body = new JSONObject();
body.put("id", groupId);
body.put("clients", clients);
JSONObject request = jsonRequest("Group.SetClients", body);
JSONObject params = new JSONObject();
params.put("id", groupId);
params.put("clients", clients);
RPCRequest request = jsonRequest("Group.SetClients", params);
tcpClient.sendMessage(request.toString());
} catch (JSONException e) {
e.printStackTrace();
@ -291,10 +275,10 @@ public class RemoteControl implements TcpClient.TcpClientListener {
public void setStream(String groupId, String streamId) {
try {
JSONObject body = new JSONObject();
body.put("id", groupId);
body.put("stream_id", streamId);
JSONObject request = jsonRequest("Group.SetStream", body);
JSONObject params = new JSONObject();
params.put("id", groupId);
params.put("stream_id", streamId);
RPCRequest request = jsonRequest("Group.SetStream", params);
tcpClient.sendMessage(request.toString());
} catch (JSONException e) {
e.printStackTrace();
@ -303,10 +287,10 @@ public class RemoteControl implements TcpClient.TcpClientListener {
public void setGroupMuted(Group group, boolean muted) {
try {
JSONObject body = new JSONObject();
body.put("id", group.getId());
body.put("mute", muted);
JSONObject request = jsonRequest("Group.SetMute", body);
JSONObject params = new JSONObject();
params.put("id", group.getId());
params.put("mute", muted);
RPCRequest request = jsonRequest("Group.SetMute", params);
tcpClient.sendMessage(request.toString());
} catch (JSONException e) {
e.printStackTrace();
@ -318,8 +302,8 @@ public class RemoteControl implements TcpClient.TcpClientListener {
JSONArray batch = new JSONArray();
for (Client client : group.getClients()) {
Volume volume = client.getConfig().getVolume();
JSONObject volumeRequest = getVolumeRequest(client, volume.getPercent(), volume.isMuted());
batch.put(volumeRequest);
RPCRequest volumeRequest = getVolumeRequest(client, volume.getPercent(), volume.isMuted());
batch.put(volumeRequest.toJson());
}
tcpClient.sendMessage(batch.toString());
} catch (JSONException e) {
@ -327,12 +311,12 @@ public class RemoteControl implements TcpClient.TcpClientListener {
}
}
private JSONObject getVolumeRequest(Client client, int percent, boolean mute) throws JSONException {
private RPCRequest getVolumeRequest(Client client, int percent, boolean mute) throws JSONException {
Volume volume = new Volume(percent, mute);
JSONObject body = new JSONObject();
body.put("id", client.getId());
body.put("volume", volume.toJson());
return jsonRequest("Client.SetVolume", body);
JSONObject params = new JSONObject();
params.put("id", client.getId());
params.put("volume", volume.toJson());
return jsonRequest("Client.SetVolume", params);
}
public void setVolume(Client client, int percent, boolean mute) {
@ -345,9 +329,9 @@ public class RemoteControl implements TcpClient.TcpClientListener {
public void delete(Client client) {
try {
JSONObject body = new JSONObject();
body.put("id", client.getId());
JSONObject request = jsonRequest("Server.DeleteClient", body);
JSONObject params = new JSONObject();
params.put("id", client.getId());
RPCRequest request = jsonRequest("Server.DeleteClient", params);
tcpClient.sendMessage(request.toString());
} catch (JSONException e) {
e.printStackTrace();
@ -381,24 +365,49 @@ public class RemoteControl implements TcpClient.TcpClientListener {
}
}
public enum RpcEvent {
response,
notification
public interface ClientListener {
void onConnect(Client client);
void onDisconnect(String clientId);
void onUpdate(Client client);
void onVolumeChanged(RPCEvent event, String clientId, Volume volume);
void onLatencyChanged(RPCEvent event, String clientId, long latency);
void onNameChanged(RPCEvent event, String clientId, String name);
}
public interface RemoteControlListener {
public interface GroupListener {
void onUpdate(Group group);
void onMute(RPCEvent event, String groupId, boolean mute);
void onStreamChanged(RPCEvent event, String groupId, String streamId);
}
public interface StreamListener {
void onUpdate(String streamId, Stream stream);
}
public interface ServerListener {
void onUpdate(ServerStatus server);
}
public interface RemoteControlListener extends ServerListener, StreamListener, GroupListener, ClientListener {
void onConnected(RemoteControl remoteControl);
void onConnecting(RemoteControl remoteControl);
void onDisconnected(RemoteControl remoteControl, Exception e);
void onClientEvent(RemoteControl remoteControl, RpcEvent rpcEvent, Client client, ClientEvent event);
void onBatchStart();
void onBatchEnd();
/*
void onClientEvent(RemoteControl remoteControl, RPCEvent rpcEvent, Client client, ClientEvent event);
void onServerUpdate(RemoteControl remoteControl, RpcEvent rpcEvent, ServerStatus serverStatus);
void onServerUpdate(RemoteControl remoteControl, RPCEvent rpcEvent, ServerStatus serverStatus);
void onStreamUpdate(RemoteControl remoteControl, RpcEvent rpcEvent, Stream stream);
void onStreamUpdate(RemoteControl remoteControl, RPCEvent rpcEvent, Stream stream);
void onGroupUpdate(RemoteControl remoteControl, RpcEvent rpcEvent, Group group);
void onGroupUpdate(RemoteControl remoteControl, RPCEvent rpcEvent, Group group);
*/
}
}

View file

@ -105,6 +105,10 @@ public class Client implements JsonSerialisable, Comparable<Client> {
return connected;
}
public void setConnected(boolean connected) {
this.connected = connected;
}
public String getId() {
return clientId;
}

View file

@ -152,6 +152,15 @@ public class ServerStatus implements JsonSerialisable {
return true;
}
public Client getClient(String id) {
for (Group group: groups) {
Client client = group.getClient(id);
if (client != null)
return client;
}
return null;
}
public ArrayList<Group> getGroups() {
return groups;
}

View file

@ -130,16 +130,18 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
}
else if (request->method == "Client.SetVolume")
{
/// -> {"jsonrpc":"2.0","method":"Client.SetVolume","id":5,"params":{"id":"00:21:6a:7d:74:fc#2","volume":{"percent":56,"muted":false}}}
/// <- {"id":5,"jsonrpc":"2.0","result":{"volume":{"muted":false,"percent":56}}}
/// Request: {"id":2,"jsonrpc":"2.0","method":"Client.SetVolume","params":{"id":"00:21:6a:7d:74:fc","volume":{"muted":false,"percent":36}}}
/// Response: {"id":2,"jsonrpc":"2.0","result":{"volume":{"muted":false,"percent":36}}}
/// Notification: {"jsonrpc":"2.0","method":"Client.OnVolumeChanged","params":{"id":"00:21:6a:7d:74:fc","volume":{"muted":false,"percent":36}}}
clientInfo->config.volume.fromJson(request->params.get("volume"));
result["volume"] = clientInfo->config.volume.toJson();
notification.reset(new jsonrpcpp::Notification("Client.OnVolumeChanged", jsonrpcpp::Parameter("id", clientInfo->id, "volume", clientInfo->config.volume.toJson())));
}
else if (request->method == "Client.SetLatency")
{
/// -> {"jsonrpc":"2.0","method":"Client.SetLatency","id":4,"params":{"id":"00:21:6a:7d:74:fc#2","latency":50}}
/// <- {"id":4,"jsonrpc":"2.0","result":{"latency":50}}
/// Request: {"id":4,"jsonrpc":"2.0","method":"Client.SetLatency","params":{"id":"00:21:6a:7d:74:fc","latency":20}}
/// Response: {"id":4,"jsonrpc":"2.0","result":{"latency":20}}
/// Notification: {"jsonrpc":"2.0","method":"Client.OnLatencyChanged","params":{"id":"00:21:6a:7d:74:fc","latency":20}}
int latency = request->params.get("latency");
if (latency < -10000)
latency = -10000;
@ -151,8 +153,9 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
}
else if (request->method == "Client.SetName")
{
/// -> {"jsonrpc":"2.0","method":"Client.SetName","id":3,"params":{"id":"00:21:6a:7d:74:fc#2","name":"test"}}
/// <- {"id":3,"jsonrpc":"2.0","result":{"name":"test"}}
/// Request: {"id":3,"jsonrpc":"2.0","method":"Client.SetName","params":{"id":"00:21:6a:7d:74:fc","name":"teat"}}
/// Response: {"id":3,"jsonrpc":"2.0","result":{"name":"teat"}}
/// Notification: {"jsonrpc":"2.0","method":"Client.OnNameChanged","params":{"id":"00:21:6a:7d:74:fc","name":"teat"}}
clientInfo->config.name = request->params.get("name");
result["name"] = clientInfo->config.name;
notification.reset(new jsonrpcpp::Notification("Client.OnNameChanged", jsonrpcpp::Parameter("id", clientInfo->id, "name", clientInfo->config.name)));
@ -189,8 +192,9 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
}
else if (request->method == "Group.SetMute")
{
/// -> {"jsonrpc":"2.0","method":"Group.SetMute","id":3,"params":{"id":"296ddff1-56fd-f2e4-232e-62c44faba7aa","mute":true}}
/// <- {"id":3,"jsonrpc":"2.0","result":{"mute":true}}
/// Request: {"id":6,"jsonrpc":"2.0","method":"Group.SetMute","params":{"id":"8e374310-b1a7-d410-d80e-ff29cf504657","mute":true}}
/// Response: {"id":6,"jsonrpc":"2.0","result":{"mute":true}}
/// Notification: {"jsonrpc":"2.0","method":"Group.OnMute","params":{"id":"8e374310-b1a7-d410-d80e-ff29cf504657","mute":true}}
bool muted = request->params.get<bool>("mute");
group->muted = muted;
@ -215,8 +219,9 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
}
else if (request->method == "Group.SetStream")
{
/// -> {"jsonrpc":"2.0","method":"Group.SetStream","id":1,"params":{"id":"296ddff1-56fd-f2e4-232e-62c44faba7aa","stream_id":"stream 2"}}
/// <- {"id":1,"jsonrpc":"2.0","result":{"stream_id":"stream 2"}}
/// Request: {"id":8,"jsonrpc":"2.0","method":"Group.SetStream","params":{"id":"8e374310-b1a7-d410-d80e-ff29cf504657","stream_id":"stream 2"}}
/// Response: {"id":8,"jsonrpc":"2.0","result":{"stream_id":"stream 2"}}
/// Notification: {"jsonrpc":"2.0","method":"Group.OnStreamChanged","params":{"id":"8e374310-b1a7-d410-d80e-ff29cf504657","stream_id":"stream 2"}}
string streamId = request->params.get("stream_id");
PcmStreamPtr stream = streamManager_->getStream(streamId);
if (stream == nullptr)
@ -241,8 +246,9 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
}
else if (request->method == "Group.SetClients")
{
/// -> {"jsonrpc":"2.0","method":"Group.SetClients","id":6,"params":{"id":"25d719fd-3a4b-2090-2ac4-b17f62b7b18b","clients":["00:21:6a:7d:74:fc","00:21:6a:7d:74:fc#2"]}}
/// <- {"id":6,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1487521394,"usec":253219},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":2,"latency":50,"name":"test","volume":{"muted":false,"percent":56}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1487521393,"usec":332977},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"25d719fd-3a4b-2090-2ac4-b17f62b7b18b","muted":false,"name":"","stream_id":"default"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"default","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"default","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=default","scheme":"pipe"}}]}}}
/// Request: {"id":5,"jsonrpc":"2.0","method":"Group.SetClients","params":{"clients":["00:21:6a:7d:74:fc#2","00:21:6a:7d:74:fc"],"id":"8e374310-b1a7-d410-d80e-ff29cf504657"}}
/// Response: {"id":5,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":1,"latency":20,"name":"teat","volume":{"muted":false,"percent":36}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1487524341,"usec":500664},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":2,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1487524340,"usec":557095},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"8e374310-b1a7-d410-d80e-ff29cf504657","muted":false,"name":"","stream_id":"stream 1"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
/// Notification: {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":1,"latency":20,"name":"teat","volume":{"muted":false,"percent":36}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1487524341,"usec":500664},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":2,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1487524340,"usec":557095},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"8e374310-b1a7-d410-d80e-ff29cf504657","muted":false,"name":"","stream_id":"stream 1"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
vector<string> clients = request->params.get("clients");
/// Remove clients from group
for (auto iter = group->clients.begin(); iter != group->clients.end();)
@ -366,16 +372,16 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
if (entity->is_request())
{
jsonrpcpp::request_ptr request = dynamic_pointer_cast<jsonrpcpp::Request>(entity);
cout << "Request:\n" << request->to_json().dump(4) << "\n";
ProcessRequest(request, response, notification);
cout << "Request: " << request->to_json().dump() << "\n";
if (response)
{
cout << "Response:\n" << response->to_json().dump(4) << "\n";
cout << "Response: " << response->to_json().dump() << "\n";
controlSession->send(response->to_json().dump());
}
if (notification)
{
cout << "Notification:\n" << notification->to_json().dump(4) << "\n";
cout << "Notification: " << notification->to_json().dump() << "\n";
controlServer_->send(notification->to_json().dump(), controlSession);
}
}