Support for DNS-SD cast discovery

This commit is contained in:
Adam Mills 2018-07-05 21:34:10 -04:00
parent 2368bed54b
commit 477f7b2a15
No known key found for this signature in database
GPG Key ID: 7733DCD6D0428689
3 changed files with 115 additions and 72 deletions

2
extern/GmsApi vendored

@ -1 +1 @@
Subproject commit 5af21c0ff2777e61caba5d111991cbb165167793
Subproject commit 540d2922599af4d9c3ef0174b45ebbc875aafd65

View File

@ -57,12 +57,12 @@ public class CastMediaRouteController extends MediaRouteProvider.RouteController
private String routeId;
private ChromeCast chromecast;
public CastMediaRouteController(CastMediaRouteProvider provider, String routeId, ChromeCast chromecast) {
public CastMediaRouteController(CastMediaRouteProvider provider, String routeId, String address) {
super();
this.provider = provider;
this.routeId = routeId;
this.chromecast = chromecast;
this.chromecast = new ChromeCast(address);
}
public boolean onControlRequest(Intent intent, MediaRouter.ControlRequestCallback callback) {

View File

@ -19,6 +19,8 @@ package org.microg.gms.cast;
import android.content.Context;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Bundle;
import android.os.AsyncTask;
import android.os.Handler;
@ -32,70 +34,27 @@ import android.util.Log;
import com.google.android.gms.common.images.WebImage;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.CastMediaControlIntent;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.Thread;
import java.lang.Runnable;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.ChromeCasts;
import su.litvak.chromecast.api.v2.Status;
import su.litvak.chromecast.api.v2.ChromeCastsListener;
public class CastMediaRouteProvider extends MediaRouteProvider {
private static final String TAG = CastMediaRouteProvider.class.getSimpleName();
private Map<String, ChromeCast> chromecasts = new HashMap<String, ChromeCast>();
private Map<String, MediaRouteDescriptor> routes = new HashMap<String, MediaRouteDescriptor>();
public CastMediaRouteProvider(Context context) {
super(context);
// TODO: Uncomment this to manually discover a chromecast on the local
// network. Discovery not yet implemented.
/*
InetAddress addr = null;
try {
addr = InetAddress.getByName("192.168.1.11");
} catch (UnknownHostException e) {
Log.d(TAG, "Chromecast status exception getting host: " + e.getMessage());
return;
}
onChromeCastDiscovered(addr);
*/
}
private void onChromeCastDiscovered(InetAddress address) {
ChromeCast chromecast = new ChromeCast(address.getHostAddress());
new Thread(new Runnable() {
public void run() {
Status status = null;
try {
status = chromecast.getStatus();
} catch (IOException e) {
Log.e(TAG, "Exception getting chromecast status: " + e.getMessage());
return;
}
Handler mainHandler = new Handler(CastMediaRouteProvider.this.getContext().getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
String routeId = address.getHostAddress();
CastMediaRouteProvider.this.chromecasts.put(routeId, chromecast);
publishRoutes();
}
});
}
}).start();
}
private NsdManager mNsdManager;
private NsdManager.DiscoveryListener mDiscoveryListener;
/**
* TODO: Mock control filters for chromecast; Will likely need to be
@ -105,38 +64,92 @@ public class CastMediaRouteProvider extends MediaRouteProvider {
static {
IntentFilter f2 = new IntentFilter();
f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
f2.addCategory(CastMediaControlIntent.CATEGORY_CAST);
f2.addAction(MediaControlIntent.ACTION_PLAY);
CONTROL_FILTERS = new ArrayList<IntentFilter>();
CONTROL_FILTERS.add(f2);
}
@Override
public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {
Log.d(TAG, "unimplemented Method: onDiscoveryRequestChanged");
public CastMediaRouteProvider(Context context) {
super(context);
mNsdManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
mDiscoveryListener = new NsdManager.DiscoveryListener() {
@Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "DiscoveryListener unimplemented Method: onDiscoveryStarted");
}
@Override
public void onServiceFound(NsdServiceInfo service) {
mNsdManager.resolveService(service, new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.e(TAG, "DiscoveryListener unimplemented Method: Resolve failed" + errorCode);
}
@Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
String name = serviceInfo.getServiceName();
InetAddress host = serviceInfo.getHost();
int port = serviceInfo.getPort();
try {
String id = new String(serviceInfo.getAttributes().get("id"), "UTF-8");
String deviceVersion = new String(serviceInfo.getAttributes().get("ve"), "UTF-8");
String friendlyName = new String(serviceInfo.getAttributes().get("fn"), "UTF-8");
String modelName = new String(serviceInfo.getAttributes().get("md"), "UTF-8");
String iconPath = new String(serviceInfo.getAttributes().get("ic"), "UTF-8");
int status = Integer.parseInt(new String(serviceInfo.getAttributes().get("st"), "UTF-8"));
onChromeCastDiscovered(id, name, host, port, deviceVersion, friendlyName, modelName, iconPath, status);
} catch (UnsupportedEncodingException ex) {
Log.e(TAG, "Error getting cast details from DNS-SD response", ex);
return;
}
}
});
}
@Override
public void onServiceLost(NsdServiceInfo service) {
Log.d(TAG, "DiscoveryListener unimplemented Method: onServiceLost" + service);
}
@Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "DiscoveryListener unimplemented Method: onDiscoveryStopped " + serviceType);
}
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "DiscoveryListener unimplemented Method: onStartDiscoveryFailed: Error code:" + errorCode);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "DiscoveryListener unimplemented Method: onStopDiscoveryFailed: Error code:" + errorCode);
}
};
}
@Override
public RouteController onCreateRouteController(String routeId) {
ChromeCast chromecast = this.chromecasts.get(routeId);
return new CastMediaRouteController(this, routeId, chromecast);
}
private void onChromeCastDiscovered(
String id, String name, InetAddress host, int port, String
deviceVersion, String friendlyName, String modelName, String
iconPath, int status) {
if (!this.routes.containsKey(id)) {
// TODO: Capabilities
int capabilities = CastDevice.CAPABILITY_VIDEO_OUT | CastDevice.CAPABILITY_AUDIO_OUT;
private void publishRoutes() {
MediaRouteProviderDescriptor.Builder builder = new MediaRouteProviderDescriptor.Builder();
for(Map.Entry<String, ChromeCast> entry : this.chromecasts.entrySet()) {
String routeId = entry.getKey();
ChromeCast chromecast = entry.getValue();
Bundle extras = new Bundle();
CastDevice castDevice = new CastDevice(
routeId,
chromecast.getAddress()
);
CastDevice castDevice = new CastDevice(id, name, host, port, deviceVersion, friendlyName, modelName, iconPath, status, capabilities);
castDevice.putInBundle(extras);
builder.addRoute(new MediaRouteDescriptor.Builder(
routeId,
routeId)
.setDescription("Chromecast")
this.routes.put(id, new MediaRouteDescriptor.Builder(
id,
friendlyName)
.setDescription(modelName)
.addControlFilters(CONTROL_FILTERS)
.setDeviceType(MediaRouter.RouteInfo.DEVICE_TYPE_TV)
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
@ -149,6 +162,36 @@ public class CastMediaRouteProvider extends MediaRouteProvider {
.build());
}
Handler mainHandler = new Handler(this.getContext().getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
publishRoutes();
}
});
}
@Override
public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {
if (request.isValid() && request.isActiveScan()) {
mNsdManager.discoverServices("_googlecast._tcp.", NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
} else {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
}
@Override
public RouteController onCreateRouteController(String routeId) {
MediaRouteDescriptor descriptor = this.routes.get(routeId);
CastDevice castDevice = CastDevice.getFromBundle(descriptor.getExtras());
return new CastMediaRouteController(this, routeId, castDevice.getAddress());
}
private void publishRoutes() {
MediaRouteProviderDescriptor.Builder builder = new MediaRouteProviderDescriptor.Builder();
for(MediaRouteDescriptor route : this.routes.values()) {
builder.addRoute(route);
}
this.setDescriptor(builder.build());
}
}