package net.pms.network; import java.io.IOException; import net.pms.configuration.DeviceConfiguration; import net.pms.dlna.DLNAResource; import net.pms.util.BasicPlayer; import net.pms.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import su.litvak.chromecast.api.v2.ChromeCast; import su.litvak.chromecast.api.v2.Media; import su.litvak.chromecast.api.v2.MediaStatus; import su.litvak.chromecast.api.v2.Status; public class ChromecastPlayer extends BasicPlayer.Logical { private static final String MediaPlayer = "CC1AD845"; private static final Logger LOGGER = LoggerFactory.getLogger(ChromecastPlayer.class); private ChromeCast api; private Thread poller; public ChromecastPlayer(DeviceConfiguration d, ChromeCast api) { super(d); this.api = api; } @Override public void setURI(String uri, String metadata) { Playlist.Item item = resolveURI(uri, metadata); if (item != null) { // this is a bit circular but what the heck DLNAResource r = DLNAResource.getValidResource(item.uri, item.name, renderer); if (r == null) { LOGGER.debug("Bad media in cc seturi: " + uri); return; } try { api.launchApp(MediaPlayer); api.load("", null, item.uri, r.mimeType()); } catch (IOException e) { LOGGER.debug("Bad chromecast load: " + e); } } } @Override public void play() { try { api.play(); } catch (IOException e) { LOGGER.debug("Bad chromecast play " + e); } } @Override public void pause() { try { api.pause(); } catch (IOException e) { LOGGER.debug("Bad chromecast pause " + e); } } @Override public void stop() { try { api.stopApp(); } catch (IOException e) { LOGGER.debug("Bad chromecast stop " + e); } } public void forward() { try { api.seek(60); } catch (IOException e) { LOGGER.debug("Bad chromecast fwd " + e); } } @Override public void rewind() { try { api.seek(-60); } catch (IOException e) { LOGGER.debug("Bad chromecast rwd " + e); } } @Override public void setVolume(int volume) { try { api.setVolume(volume); } catch (IOException e) { LOGGER.debug("Bad chromecast volume " + e); } } @Override public int getControls() { return PLAYCONTROL | VOLUMECONTROL; } private int translateState(MediaStatus.PlayerState s) { switch(s) { case IDLE: return STOPPED; case PLAYING: // buffering is a kind of playing case BUFFERING: return PLAYING; case PAUSED: return PAUSED; default: return -1; } } public void startPoll() { Runnable r = new Runnable() { @Override public void run() { for(;;) { try { Thread.sleep(1000); Status s1 = api.getStatus(); if (s1 == null || !s1.isAppRunning(MediaPlayer)) { continue; } MediaStatus status = api.getMediaStatus(); if (status == null) { continue; } state.playback = translateState(status.playerState); Media m = status.media; if (m != null) { if (m.url != null) { state.uri = status.media.url; } if(m.duration != null) { state.duration = StringUtil.convertTimeToString(status.media.duration, "%02d:%02d:%02.0f"); } } state.position = StringUtil.convertTimeToString(status.currentTime, "%02d:%02d:%02.0f"); if (status.volume != null) { state.volume = status.volume.level.intValue(); state.mute = status.volume.muted; } alert(); } catch (InterruptedException | IOException e) { LOGGER.debug("Bad chromecast mediastate " + e); } } } }; poller = new Thread(r); poller.start(); } }