Skip to content

Commit

Permalink
[chromecast] Refactoring of binding (openhab#7367)
Browse files Browse the repository at this point in the history
* Refactoring of binding
* Incorporated comments from review

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
Signed-off-by: Eugen Freiter <freiter@gmx.de>
  • Loading branch information
cweitkamp authored and Eugen Freiter committed Apr 27, 2020
1 parent 291d5c3 commit 00be328
Show file tree
Hide file tree
Showing 14 changed files with 548 additions and 209 deletions.
4 changes: 3 additions & 1 deletion bundles/org.openhab.binding.chromecast/pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.chromecast-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>

<feature name="openhab-binding-chromecast" description="Chromecast Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-mdns</feature>
<feature dependency="true">openhab.tp-jackson</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.chromecast/${project.version}</bundle>
</feature>
<feature name="openhab-binding-chromecast" description="Chromecast Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-mdns</feature>
<feature dependency="true">openhab.tp-jackson</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.chromecast/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/
package org.openhab.binding.chromecast.internal;

import java.util.Objects;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioHTTPServer;
import org.eclipse.smarthome.core.audio.AudioStream;
Expand All @@ -25,30 +25,36 @@
import org.slf4j.LoggerFactory;

/**
* Handles the AudioSink portion of the Chromecast plugin. Note that we store volume in
* Handles the AudioSink portion of the Chromecast add-on.
*
* @author Jason Holmes - Initial contribution
*/
@NonNullByDefault
public class ChromecastAudioSink {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Logger logger = LoggerFactory.getLogger(ChromecastAudioSink.class);

private static final String MIME_TYPE_AUDIO_WAV = "audio/wav";
private static final String MIME_TYPE_AUDIO_MPEG = "audio/mpeg";

private final ChromecastCommander commander;
private final AudioHTTPServer audioHTTPServer;
private final String callbackUrl;
private final @Nullable String callbackUrl;

public ChromecastAudioSink(ChromecastCommander commander, AudioHTTPServer audioHTTPServer, String callbackUrl) {
public ChromecastAudioSink(ChromecastCommander commander, AudioHTTPServer audioHTTPServer,
@Nullable String callbackUrl) {
this.commander = commander;
this.audioHTTPServer = audioHTTPServer;
this.callbackUrl = callbackUrl;
}

public void process(AudioStream audioStream) throws UnsupportedAudioFormatException {
public void process(@Nullable AudioStream audioStream) throws UnsupportedAudioFormatException {
if (audioStream == null) {
// 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);
} else {
String url;
final String url;
if (audioStream instanceof URLAudioStream) {
// it is an external URL, the speaker can access it itself and play it.
URLAudioStream urlAudioStream = (URLAudioStream) audioStream;
Expand All @@ -68,11 +74,8 @@ public void process(AudioStream audioStream) throws UnsupportedAudioFormatExcept
return;
}
}

String mimeType = Objects.equals(audioStream.getFormat().getCodec(), AudioFormat.CODEC_MP3) ? "audio/mpeg"
: "audio/wav";

commander.playMedia("Notification", url, mimeType);
commander.playMedia("Notification", url,
AudioFormat.MP3.isCompatible(audioStream.getFormat()) ? MIME_TYPE_AUDIO_MPEG : MIME_TYPE_AUDIO_WAV);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ public class ChromecastBindingConstants {
// Config Parameters
public static final String HOST = "ipAddress";
public static final String PORT = "port";
public static final String REFRESH_RATE_SECONDS = "refreshRate";
public static final String DEVICE_ID = "deviceId";

// Channel IDs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.io.IOException;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType;
import org.eclipse.smarthome.core.library.types.NextPreviousType;
import org.eclipse.smarthome.core.library.types.OnOffType;
Expand All @@ -40,8 +42,10 @@
*
* @author Jason Holmes - Initial contribution
*/
@NonNullByDefault
public class ChromecastCommander {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Logger logger = LoggerFactory.getLogger(ChromecastCommander.class);

private final ChromeCast chromeCast;
private final ChromecastScheduler scheduler;
private final ChromecastStatusUpdater statusUpdater;
Expand All @@ -56,10 +60,6 @@ public ChromecastCommander(ChromeCast chromeCast, ChromecastScheduler scheduler,
}

public void handleCommand(final ChannelUID channelUID, final Command command) {
if (chromeCast == null) {
return;
}

if (command instanceof RefreshType) {
scheduler.scheduleRefresh();
return;
Expand Down Expand Up @@ -219,7 +219,7 @@ private void handleMute(final Command command) {
}
}

void playMedia(String title, String url, String mimeType) {
void playMedia(@Nullable String title, @Nullable String url, @Nullable String mimeType) {
try {
if (chromeCast.isAppAvailable(MEDIA_PLAYER)) {
if (!chromeCast.isAppRunning(MEDIA_PLAYER)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.binding.chromecast.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -28,8 +29,10 @@
*
* @author Jason Holmes - Initial contribution
*/
@NonNullByDefault
public class ChromecastEventReceiver implements ChromeCastSpontaneousEventListener, ChromeCastConnectionEventListener {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Logger logger = LoggerFactory.getLogger(ChromecastEventReceiver.class);

private final ChromecastScheduler scheduler;
private final ChromecastStatusUpdater statusUpdater;

Expand All @@ -39,21 +42,20 @@ public ChromecastEventReceiver(ChromecastScheduler scheduler, ChromecastStatusUp
}

@Override
public void connectionEventReceived(ChromeCastConnectionEvent event) {
public void connectionEventReceived(final @NonNullByDefault({}) ChromeCastConnectionEvent event) {
if (event.isConnected()) {
statusUpdater.updateStatus(ThingStatus.ONLINE);
scheduler.scheduleRefresh();
} else {
scheduler.cancelRefresh();
statusUpdater.updateStatus(ThingStatus.OFFLINE);

// We might have just had a connection problem, let's try to reconnect.
scheduler.scheduleConnect();
}
}

@Override
public void spontaneousEventReceived(final ChromeCastSpontaneousEvent event) {
public void spontaneousEventReceived(final @NonNullByDefault({}) ChromeCastSpontaneousEvent event) {
switch (event.getType()) {
case CLOSE:
statusUpdater.updateMediaStatus(null);
Expand All @@ -72,5 +74,4 @@ public void spontaneousEventReceived(final ChromeCastSpontaneousEvent event) {
break;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
*/
package org.openhab.binding.chromecast.internal;

import static java.util.concurrent.TimeUnit.SECONDS;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -26,20 +27,21 @@
* @author Jason Holmes - Initial contribution
* @author Wouter Born - Make sure only at most one refresh job is scheduled and running
*/
@NonNullByDefault
public class ChromecastScheduler {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Logger logger = LoggerFactory.getLogger(ChromecastScheduler.class);

private final ScheduledExecutorService scheduler;
private final Integer connectDelay;
private final Integer refreshRate;
private final long connectDelay;
private final long refreshRate;
private final Runnable connectRunnable;
private final Runnable refreshRunnable;

private ScheduledFuture<?> connectFuture;
private ScheduledFuture<?> refreshFuture;
private @Nullable ScheduledFuture<?> connectFuture;
private @Nullable ScheduledFuture<?> refreshFuture;

public ChromecastScheduler(ScheduledExecutorService scheduler, Integer connectDelay, Runnable connectRunnable,
Integer refreshRate, Runnable refreshRunnable) {
public ChromecastScheduler(ScheduledExecutorService scheduler, long connectDelay, Runnable connectRunnable,
long refreshRate, Runnable refreshRunnable) {
this.scheduler = scheduler;
this.connectDelay = connectDelay;
this.connectRunnable = connectRunnable;
Expand All @@ -53,31 +55,34 @@ public synchronized void destroy() {
}

public synchronized void scheduleConnect() {
logger.debug("Scheduling connection");
cancelConnect();
connectFuture = scheduler.schedule(connectRunnable, connectDelay, SECONDS);
logger.debug("Scheduling connection");
connectFuture = scheduler.schedule(connectRunnable, connectDelay, TimeUnit.SECONDS);
}

private synchronized void cancelConnect() {
logger.debug("Canceling connection");
if (connectFuture != null) {
connectFuture.cancel(true);
ScheduledFuture<?> localConnectFuture = connectFuture;
if (localConnectFuture != null) {
localConnectFuture.cancel(true);
connectFuture = null;
}
}

public synchronized void scheduleRefresh() {
cancelRefresh();
logger.debug("Scheduling refresh in {} seconds", refreshRate);
// With an initial delay of 1 second the refresh job can be restarted when several channels
// are refreshed at once e.g. due to channel linking
refreshFuture = scheduler.scheduleWithFixedDelay(refreshRunnable, 1, refreshRate, SECONDS);
// With an initial delay of 1 second the refresh job can be restarted when several channels are refreshed at
// once e.g. due to channel linking
refreshFuture = scheduler.scheduleWithFixedDelay(refreshRunnable, 1, refreshRate, TimeUnit.SECONDS);
}

public synchronized void cancelRefresh() {
logger.debug("Canceling refresh");
if (refreshFuture != null) {
refreshFuture.cancel(true);
ScheduledFuture<?> localRefreshFuture = refreshFuture;
if (localRefreshFuture != null) {
localRefreshFuture.cancel(true);
refreshFuture = null;
}
}
}
Loading

0 comments on commit 00be328

Please sign in to comment.