From 62e8419d6c9e3d4f65a5715e917da0e912cbff4b Mon Sep 17 00:00:00 2001 From: lsiepel Date: Sat, 7 Jan 2023 09:51:20 +0100 Subject: [PATCH] [chromecast] Fix thing go offline after stop command (#14158) * Restructure commander * Improve thing status handling on error Signed-off-by: lsiepel --- .../internal/ChromecastAudioSink.java | 2 +- .../internal/ChromecastCommander.java | 98 +++++++++++-------- .../internal/ChromecastEventReceiver.java | 5 + 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastAudioSink.java b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastAudioSink.java index 199f982426515..4319fa421d253 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastAudioSink.java +++ b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastAudioSink.java @@ -52,7 +52,7 @@ public void process(@Nullable AudioStream audioStream) throws UnsupportedAudioFo // in case the audioStream is null, this should be interpreted as a request to end any currently playing // stream. logger.trace("Stop currently playing stream."); - commander.handleStop(OnOffType.ON); + commander.handleCloseApp(OnOffType.ON); } else { final String url; if (audioStream instanceof URLAudioStream) { diff --git a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java index 0d83f96049301..a3d5206079721 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java +++ b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java @@ -70,7 +70,7 @@ public void handleCommand(final ChannelUID channelUID, final Command command) { handleControl(command); break; case CHANNEL_STOP: - handleStop(command); + handleCloseApp(command); break; case CHANNEL_VOLUME: handleVolume(command); @@ -117,7 +117,7 @@ public void handleRefresh() { if (mediaStatus != null && mediaStatus.playerState == MediaStatus.PlayerState.IDLE && mediaStatus.idleReason != null && mediaStatus.idleReason != MediaStatus.IdleReason.INTERRUPTED) { - stopMediaPlayerApp(); + closeApp(MEDIA_PLAYER); } } } catch (IOException ex) { @@ -126,6 +126,12 @@ public void handleRefresh() { } } + public void handleCloseApp(final Command command) { + if (command == OnOffType.ON) { + closeApp(MEDIA_PLAYER); + } + } + private void handlePlayUri(Command command) { if (command instanceof StringType) { playMedia(null, command.toString(), null); @@ -163,7 +169,6 @@ private void handleControl(final Command command) { if (command instanceof NextPreviousType) { // Next is implemented by seeking to the end of the current media if (command == NextPreviousType.NEXT) { - Double duration = statusUpdater.getLastDuration(); if (duration != null) { chromeCast.seek(duration.doubleValue() - 5); @@ -182,18 +187,6 @@ private void handleControl(final Command command) { } } - public void handleStop(final Command command) { - if (command == OnOffType.ON) { - try { - chromeCast.stopApp(); - statusUpdater.updateStatus(ThingStatus.ONLINE); - } catch (final IOException ex) { - logger.debug("{} command failed: {}", command, ex.getMessage()); - statusUpdater.updateStatus(ThingStatus.OFFLINE, COMMUNICATION_ERROR, ex.getMessage()); - } - } - } - public void handleVolume(final Command command) { if (command instanceof PercentType) { setVolumeInternal((PercentType) command); @@ -229,44 +222,69 @@ private void handleMute(final Command command) { } } - public void playMedia(@Nullable String title, @Nullable String url, @Nullable String mimeType) { + public void startApp(@Nullable String appId) { + if (appId == null) { + return; + } try { - if (chromeCast.isAppAvailable(MEDIA_PLAYER)) { - if (!chromeCast.isAppRunning(MEDIA_PLAYER)) { - final Application app = chromeCast.launchApp(MEDIA_PLAYER); + if (chromeCast.isAppAvailable(appId)) { + if (!chromeCast.isAppRunning(appId)) { + final Application app = chromeCast.launchApp(appId); statusUpdater.setAppSessionId(app.sessionId); - logger.debug("Application launched: {}", app); - } - if (url != null) { - // If the current track is paused, launching a new request results in nothing happening, therefore - // resume current track. - MediaStatus ms = chromeCast.getMediaStatus(); - if (ms != null && MediaStatus.PlayerState.PAUSED == ms.playerState && url.equals(ms.media.url)) { - logger.debug("Current stream paused, resuming"); - chromeCast.play(); - } else { - chromeCast.load(title, null, url, mimeType); - } + logger.debug("Application launched: {}", appId); } } else { - logger.warn("Missing media player app - cannot process media."); + logger.warn("Failed starting app, app probably not installed. Appid: {}", appId); } statusUpdater.updateStatus(ThingStatus.ONLINE); } catch (final IOException e) { - logger.debug("Failed playing media: {}", e.getMessage()); - statusUpdater.updateStatus(ThingStatus.OFFLINE, COMMUNICATION_ERROR, e.getMessage()); + logger.warn("Failed starting app: {}. Message: {}", appId, e.getMessage()); } } - private void stopMediaPlayerApp() { + public void closeApp(@Nullable String appId) { + if (appId == null) { + return; + } + try { - Application app = chromeCast.getRunningApp(); - if (app.id.equals(MEDIA_PLAYER) && app.sessionId.equals(statusUpdater.getAppSessionId())) { - chromeCast.stopApp(); - logger.debug("Media player app stopped"); + if (chromeCast.isAppRunning(appId)) { + Application app = chromeCast.getRunningApp(); + if (app.id.equals(appId) && app.sessionId.equals(statusUpdater.getAppSessionId())) { + chromeCast.stopApp(); + logger.debug("Application closed: {}", appId); + } } } catch (final IOException e) { - logger.debug("Failed stopping media player app", e); + logger.debug("Failed stopping media player app: {} with message: {}", appId, e.getMessage()); + } + } + + public void playMedia(@Nullable String title, @Nullable String url, @Nullable String mimeType) { + startApp(MEDIA_PLAYER); + try { + if (url != null && chromeCast.isAppRunning(MEDIA_PLAYER)) { + // If the current track is paused, launching a new request results in nothing happening, therefore + // resume current track. + MediaStatus ms = chromeCast.getMediaStatus(); + if (ms != null && MediaStatus.PlayerState.PAUSED == ms.playerState && url.equals(ms.media.url)) { + logger.debug("Current stream paused, resuming"); + chromeCast.play(); + } else { + chromeCast.load(title, null, url, mimeType); + } + } else { + logger.warn("Missing media player app - cannot process media."); + } + statusUpdater.updateStatus(ThingStatus.ONLINE); + } catch (final IOException e) { + if ("Unable to load media".equals(e.getMessage())) { + logger.warn("Unable to load media: {}", url); + } else { + logger.debug("Failed playing media: {}", e.getMessage()); + statusUpdater.updateStatus(ThingStatus.OFFLINE, COMMUNICATION_ERROR, + "IOException while trying to play media: " + e.getMessage()); + } } } } diff --git a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastEventReceiver.java b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastEventReceiver.java index f7fc578853af2..2906bf32603ef 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastEventReceiver.java +++ b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastEventReceiver.java @@ -56,6 +56,8 @@ public void connectionEventReceived(final @NonNullByDefault({}) ChromeCastConnec @Override public void spontaneousEventReceived(final @NonNullByDefault({}) ChromeCastSpontaneousEvent event) { + logger.trace("Received an {} event (class={})", event.getType(), event.getData()); + switch (event.getType()) { case CLOSE: statusUpdater.updateMediaStatus(null); @@ -66,6 +68,9 @@ public void spontaneousEventReceived(final @NonNullByDefault({}) ChromeCastSpont case STATUS: statusUpdater.processStatusUpdate(event.getData(Status.class)); break; + case APPEVENT: + logger.debug("Received an 'APPEVENT' event, ignoring"); + break; case UNKNOWN: logger.debug("Received an 'UNKNOWN' event (class={})", event.getType().getDataClass()); break;