package net.pms.network;
import ch.qos.logback.classic.Level;
import java.io.IOException;
import java.net.InetAddress;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import net.pms.PMS;
import net.pms.configuration.DeviceConfiguration;
import net.pms.configuration.RendererConfiguration;
import net.pms.util.BasicPlayer;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import su.litvak.chromecast.api.v2.ChromeCast;
public class ChromecastMgr implements ServiceListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ChromecastMgr.class);
private JmDNS mDNS;
private ArrayList<ChromeDevice> chromeCasts;
private RendererConfiguration renderer;
public ChromecastMgr(JmDNS mDNS) throws IOException {
this.mDNS = mDNS;
renderer = RendererConfiguration.getRendererConfigurationByName("Chromecast");
mDNS.addServiceListener(ChromeCast.SERVICE_TYPE, this);
chromeCasts = new ArrayList<>();
if (!PMS.getConfiguration().isChromecastDbg()) {
ch.qos.logback.classic.Logger logger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger("su.litvak.chromecast.api.v2");
logger.setLevel(Level.OFF);
}
}
@Override
public void serviceAdded(ServiceEvent event) {
if (event.getInfo() == null) {
LOGGER.debug("Bad Chromcast event: {}", event.toString());
return;
}
LOGGER.debug("Found chromecast: {}", event.getInfo().getName());
ServiceInfo serviceInfo = mDNS.getServiceInfo(ChromeCast.SERVICE_TYPE, event.getInfo().getName());
ChromeCast chromeCast = new ChromeCast(serviceInfo.getInet4Addresses()[0].getHostAddress(), serviceInfo.getPort());
chromeCast.setName(event.getInfo().getName());
chromeCast.setAppsURL(serviceInfo.getURLs().length == 0 ? null : serviceInfo.getURLs()[0]);
chromeCast.setApplication(serviceInfo.getApplication());
try {
chromeCast.connect();
chromeCasts.add(new ChromeDevice(chromeCast, renderer, InetAddress.getByName(chromeCast.getAddress())));
} catch (IOException | GeneralSecurityException | ConfigurationException e) {
LOGGER.error("Chromecast registration failed with the following error: {}", e);
LOGGER.trace("", e);
}
}
@Override
public void serviceRemoved(ServiceEvent event) {
if (event.getInfo() == null) {
// silent
return;
}
String name = event.getInfo().getName();
if (StringUtils.isEmpty(name)) {
name = renderer.getConfName();
}
ArrayList<ChromeDevice> devices = new ArrayList<>();
for (ChromeDevice device : chromeCasts) {
if (name.equals(device.getRendererName())) {
// Make the icon grey and delete after 5 seconds
device.delete(5000);
LOGGER.debug("Chromecast \"{}\" is gone.", name);
continue;
}
devices.add(device);
}
chromeCasts = devices;
}
@Override
public void serviceResolved(ServiceEvent event) {
}
static class ChromeDevice extends DeviceConfiguration {
public ChromeCast chromeCast;
public ChromeDevice(
ChromeCast chromeCast,
RendererConfiguration renderer,
InetAddress inetAddress
) throws ConfigurationException {
super(renderer, inetAddress);
this.chromeCast = chromeCast;
uuid = chromeCast.getAddress();
controls = UPNPControl.ANY;
active = true;
associateIP(inetAddress);
PMS.get().setRendererFound(this);
}
@Override
public String getRendererName() {
try {
if (StringUtils.isNotEmpty(chromeCast.getName())) {
return chromeCast.getName();
}
} catch (Exception e) {
LOGGER.debug("Failed to find name for Chromecast \"{}\"", chromeCast);
LOGGER.trace("", e);
}
return getConfName();
}
@Override
public BasicPlayer getPlayer() {
if (player == null) {
player = new ChromecastPlayer(this, chromeCast);
((ChromecastPlayer)player).startPoll();
}
return player;
}
@Override
public InetAddress getAddress() {
try {
return InetAddress.getByName(chromeCast.getAddress());
} catch (Exception e) {
LOGGER.debug("Failed to find address for Chromecast \"{}\"", chromeCast);
LOGGER.trace("", e);
return null;
}
}
}
}