Skip to content

Commit

Permalink
tv-casting-app: Added WakeOnLAN support (#29443)
Browse files Browse the repository at this point in the history
  • Loading branch information
sharadb-amazon authored and pull[bot] committed Nov 2, 2023
1 parent d232e0f commit 4042472
Show file tree
Hide file tree
Showing 24 changed files with 956 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ public DiscoveredNodeData(NsdServiceInfo serviceInfo) {
this.numIPs = 1;
}

public DiscoveredNodeData(VideoPlayer player) {
this.connectableVideoPlayer = player;
this.instanceName = player.getInstanceName();
this.hostName = player.getHostName();
this.deviceName = player.getDeviceName();
this.deviceType = player.getDeviceType();
this.vendorId = player.getVendorId();
this.productId = player.getProductId();
this.numIPs = player.getNumIPs();
this.ipAddresses = player.getIpAddresses();
this.port = player.getPort();
}

void setConnectableVideoPlayer(VideoPlayer videoPlayer) {
this.connectableVideoPlayer = videoPlayer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ private void addCommissioningInfo(DiscoveredNodeData discoveredNodeData) {
TAG,
"Matching Video Player with the following information found for DiscoveredNodeData"
+ videoPlayer);
long currentUnixTimeMS = System.currentTimeMillis();
Log.d(TAG, "Updating discovery timestamp for VideoPlayer to " + currentUnixTimeMS);
videoPlayer.setLastDiscoveredMs(currentUnixTimeMS);
discoveredNodeData.setConnectableVideoPlayer(videoPlayer);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,33 @@
import chip.platform.NsdManagerServiceBrowser;
import chip.platform.NsdManagerServiceResolver;
import chip.platform.PreferencesKeyValueStoreManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;

public class TvCastingApp {
private static final String TAG = TvCastingApp.class.getSimpleName();
private static final String DISCOVERY_TARGET_SERVICE_TYPE = "_matterd._udp.";
private static final List<Long> DISCOVERY_TARGET_DEVICE_TYPE_FILTER =
Arrays.asList(35L); // Video player = 35;

// delay before which we assume undiscovered cached players may be in STR mode
private static final long CHIP_DEVICE_CONFIG_STR_DISCOVERY_DELAY_SEC = 5;

private static TvCastingApp sInstance;
private Context applicationContext;
private ChipAppServer chipAppServer;
private NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState;
private boolean discoveryStarted = false;
private Object discoveryLock = new Object();

private List<DiscoveredNodeData> discoveredPlayers;
private ScheduledFuture<?> reportSleepingVideoPlayerCommissionersFuture;

private WifiManager.MulticastLock multicastLock;
private NsdManager nsdManager;
private NsdDiscoveryListener nsdDiscoveryListener;
Expand Down Expand Up @@ -136,23 +147,127 @@ public void discoverVideoPlayerCommissioners(
multicastLock.acquire();

nsdManager = (NsdManager) applicationContext.getSystemService(Context.NSD_SERVICE);
discoveredPlayers = new ArrayList<>();
nsdDiscoveryListener =
new NsdDiscoveryListener(
nsdManager,
DISCOVERY_TARGET_SERVICE_TYPE,
DISCOVERY_TARGET_DEVICE_TYPE_FILTER,
preCommissionedVideoPlayers,
discoverySuccessCallback,
new SuccessCallback<DiscoveredNodeData>() {
@Override
public void handle(DiscoveredNodeData commissioner) {
Log.d(TAG, "Discovered commissioner added " + commissioner);
discoveredPlayers.add(commissioner);
discoverySuccessCallback.handle(commissioner);
}
},
discoveryFailureCallback,
nsdManagerResolverAvailState);

nsdManager.discoverServices(
DISCOVERY_TARGET_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, nsdDiscoveryListener);
Log.d(TAG, "TvCastingApp.discoverVideoPlayerCommissioners started");

/**
* Surface players (as DiscoveredNodeData objects on discoverySuccessCallback) that we
* previously connected to and received their WakeOnLAN MACAddress, but could not discover
* over DNS-SD this time in CHIP_DEVICE_CONFIG_STR_DISCOVERY_DELAY_SEC. This API will also
* ensure that the reported players were previously discoverable within
* CHIP_DEVICE_CONFIG_STR_CACHE_LAST_DISCOVERED_HOURS.
*
* <p>The DiscoveredNodeData object for such players will have the IsAsleep attribute set to
* true, which can optionally be used for any special UX treatment when displaying them.
*
* <p>Surfacing such players as discovered will allow displaying them to the user, who may
* want to cast to them. In such a case, the VerifyOrEstablishConnection API will turn them on
* over WakeOnLan.
*/
this.reportSleepingVideoPlayerCommissionersFuture =
Executors.newScheduledThreadPool(1)
.schedule(
() -> {
Log.d(
TAG,
"Scheduling reportSleepingCommissioners with commissioner count "
+ (preCommissionedVideoPlayers != null
? preCommissionedVideoPlayers.size()
: 0));
reportSleepingVideoPlayerCommissioners(
preCommissionedVideoPlayers, discoverySuccessCallback);
},
CHIP_DEVICE_CONFIG_STR_DISCOVERY_DELAY_SEC * 1000,
TimeUnit.MILLISECONDS);

this.discoveryStarted = true;
}
}

private void reportSleepingVideoPlayerCommissioners(
List<VideoPlayer> cachedVideoPlayers,
SuccessCallback<DiscoveredNodeData> discoverySuccessCallback) {
Log.d(
TAG,
"TvCastingApp.reportSleepingVideoPlayerCommissioners called with commissioner count "
+ (cachedVideoPlayers != null ? cachedVideoPlayers.size() : 0));
if (cachedVideoPlayers == null) {
Log.d(TAG, "No cached video players available.");
return;
}

for (VideoPlayer player : cachedVideoPlayers) {
Log.d(TAG, "Cached Video Player: " + player);
// do NOT surface this cached Player if we don't have its MACAddress
if (player.getMACAddress() == null) {
Log.d(
TAG,
"TvCastingApp.reportSleepingVideoPlayerCommissioners Skipping Player with hostName"
+ player.getHostName()
+ " but no MACAddress");
continue;
}

// do NOT surface this cached Player if it has not been discoverable recently (in
// CHIP_DEVICE_CONFIG_STR_CACHE_LAST_DISCOVERED_HOURS)
if (!WasRecentlyDiscoverable(player)) {
Log.d(
TAG,
"TvCastingApp.reportSleepingVideoPlayerCommissioners Skipping Player with hostName"
+ player.getHostName()
+ " that has not been discovered recently");
continue;
}

// do NOT surface this cached Player if it was just discovered right now (in this discovery
// call)
boolean justDiscovered =
discoveredPlayers
.stream()
.anyMatch(
new Predicate<DiscoveredNodeData>() {
@Override
public boolean test(DiscoveredNodeData discoveredNodeData) {
return player.getHostName().equals(discoveredNodeData.getHostName());
}
});
if (justDiscovered) {
Log.d(
TAG,
"TvCastingApp.reportSleepingVideoPlayerCommissioners Skipping Player with hostName"
+ player.getHostName()
+ " that was just discovered");
continue;
}

// DO surface this cached Player (as asleep)
Log.d(TAG, "Reporting sleeping player with hostName " + player.getHostName());
player.setIsAsleep(true);
discoverySuccessCallback.handle(new DiscoveredNodeData(player));
}
}

private native boolean WasRecentlyDiscoverable(VideoPlayer player);

public void stopVideoPlayerDiscovery() {
synchronized (discoveryLock) {
Log.d(TAG, "TvCastingApp trying to stop video player discovery");
Expand All @@ -173,6 +288,10 @@ public void stopVideoPlayerDiscovery() {
if (multicastLock.isHeld()) {
multicastLock.release();
}

if (reportSleepingVideoPlayerCommissionersFuture != null) {
reportSleepingVideoPlayerCommissionersFuture.cancel(false);
}
this.discoveryStarted = false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public class VideoPlayer {
private int numIPs;
private List<InetAddress> ipAddresses;
private String hostName;
private String instanceName;
private long lastDiscoveredMs;
private String MACAddress;
private boolean isAsleep = false;
private int port;

private boolean isInitialized = false;

Expand All @@ -52,6 +57,11 @@ public VideoPlayer(
int numIPs,
List<InetAddress> ipAddresses,
String hostName,
String instanceName,
int port,
long lastDiscoveredMs,
String MACAddress,
boolean isAsleep,
boolean isConnected) {
this.nodeId = nodeId;
this.fabricIndex = fabricIndex;
Expand All @@ -64,6 +74,11 @@ public VideoPlayer(
this.numIPs = numIPs;
this.ipAddresses = ipAddresses;
this.hostName = hostName;
this.MACAddress = MACAddress;
this.lastDiscoveredMs = lastDiscoveredMs;
this.instanceName = instanceName;
this.port = port;
this.isAsleep = isAsleep;
this.isInitialized = true;
}

Expand Down Expand Up @@ -116,8 +131,8 @@ public int hashCode() {
return Objects.hash(super.hashCode(), nodeId, fabricIndex);
}

@java.lang.Override
public java.lang.String toString() {
@Override
public String toString() {
return "VideoPlayer{"
+ "nodeId="
+ nodeId
Expand All @@ -140,10 +155,22 @@ public java.lang.String toString() {
+ numIPs
+ ", ipAddresses="
+ ipAddresses
+ ", isInitialized="
+ ", hostName='"
+ hostName
+ '\''
+ ", instanceName='"
+ instanceName
+ '\''
+ ", lastDiscoveredMs="
+ lastDiscoveredMs
+ ", MACAddress='"
+ MACAddress
+ '\''
+ ", isAsleep="
+ isAsleep
+ ", port="
+ port
+ ", isInitialized="
+ isInitialized
+ '}';
}
Expand Down Expand Up @@ -180,6 +207,46 @@ public int getDeviceType() {
return deviceType;
}

public int getNumIPs() {
return numIPs;
}

public List<InetAddress> getIpAddresses() {
return ipAddresses;
}

public String getHostName() {
return hostName;
}

public int getPort() {
return port;
}

public long getLastDiscoveredMs() {
return lastDiscoveredMs;
}

public void setLastDiscoveredMs(long lastDiscoveredMs) {
this.lastDiscoveredMs = lastDiscoveredMs;
}

public String getMACAddress() {
return MACAddress;
}

public String getInstanceName() {
return instanceName;
}

public void setIsAsleep(boolean asleep) {
isAsleep = asleep;
}

public boolean isAsleep() {
return isAsleep;
}

public boolean isInitialized() {
return isInitialized;
}
Expand Down
Loading

0 comments on commit 4042472

Please sign in to comment.