[chromecast] Fix thing go offline after stop command (#14158)

* Restructure commander
* Improve thing status handling on error

Signed-off-by: lsiepel <leosiepel@gmail.com>
This commit is contained in:
lsiepel 2023-01-07 09:51:20 +01:00 committed by GitHub
parent 576be1455c
commit de8d78403e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 44 deletions

View File

@ -52,7 +52,7 @@ public class ChromecastAudioSink {
// 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) {

View File

@ -70,7 +70,7 @@ public class ChromecastCommander {
handleControl(command);
break;
case CHANNEL_STOP:
handleStop(command);
handleCloseApp(command);
break;
case CHANNEL_VOLUME:
handleVolume(command);
@ -117,7 +117,7 @@ public class ChromecastCommander {
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 class ChromecastCommander {
}
}
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 @@ public class ChromecastCommander {
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 @@ public class ChromecastCommander {
}
}
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 @@ public class ChromecastCommander {
}
}
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);
logger.debug("Application launched: {}", appId);
}
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);
}
} else {
logger.warn("Failed starting app, app probably not installed. Appid: {}", appId);
}
statusUpdater.updateStatus(ThingStatus.ONLINE);
} catch (final IOException e) {
logger.warn("Failed starting app: {}. Message: {}", appId, e.getMessage());
}
}
public void closeApp(@Nullable String appId) {
if (appId == null) {
return;
}
try {
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: {} 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) {
logger.debug("Failed playing media: {}", e.getMessage());
statusUpdater.updateStatus(ThingStatus.OFFLINE, COMMUNICATION_ERROR, e.getMessage());
}
}
private void stopMediaPlayerApp() {
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 ("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());
}
} catch (final IOException e) {
logger.debug("Failed stopping media player app", e);
}
}
}

View File

@ -56,6 +56,8 @@ public class ChromecastEventReceiver implements ChromeCastSpontaneousEventListen
@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 class ChromecastEventReceiver implements ChromeCastSpontaneousEventListen
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;