aboutsummaryrefslogtreecommitdiff
path: root/src/github/daneren2005
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2014-02-13 22:39:46 -0800
committerScott Jackson <daneren2005@gmail.com>2014-02-13 22:39:46 -0800
commitb10e89f304b75339c451ab7a4624cabe60b7ac98 (patch)
tree4a59b4805465cb08ccc0ff06c8bd0ccb6e1201d3 /src/github/daneren2005
parent0a7bae6b058cfb8098a91f1896932d591079c5ba (diff)
downloaddsub-b10e89f304b75339c451ab7a4624cabe60b7ac98.tar.gz
dsub-b10e89f304b75339c451ab7a4624cabe60b7ac98.tar.bz2
dsub-b10e89f304b75339c451ab7a4624cabe60b7ac98.zip
Added basic Cast support for a single song
Diffstat (limited to 'src/github/daneren2005')
-rw-r--r--src/github/daneren2005/dsub/fragments/DownloadFragment.java2
-rw-r--r--src/github/daneren2005/dsub/service/CachedMusicService.java7
-rw-r--r--src/github/daneren2005/dsub/service/ChromeCastController.java211
-rw-r--r--src/github/daneren2005/dsub/service/DownloadServiceImpl.java7
-rw-r--r--src/github/daneren2005/dsub/service/MusicService.java2
-rw-r--r--src/github/daneren2005/dsub/service/RESTMusicService.java13
-rw-r--r--src/github/daneren2005/dsub/util/compat/CastCompat.java7
7 files changed, 241 insertions, 8 deletions
diff --git a/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/src/github/daneren2005/dsub/fragments/DownloadFragment.java
index d3c1938e..d87d8432 100644
--- a/src/github/daneren2005/dsub/fragments/DownloadFragment.java
+++ b/src/github/daneren2005/dsub/fragments/DownloadFragment.java
@@ -762,7 +762,7 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
visualizerView.setActive(false);
}
if(getDownloadService() != null) {
- getDownloadService().startRemoteScan();
+ getDownloadService().stopRemoteScan();
}
}
diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java
index b8b440d7..4417ac78 100644
--- a/src/github/daneren2005/dsub/service/CachedMusicService.java
+++ b/src/github/daneren2005/dsub/service/CachedMusicService.java
@@ -293,7 +293,12 @@ public class CachedMusicService implements MusicService {
return musicService.getDownloadInputStream(context, song, offset, maxBitrate, task);
}
- @Override
+ @Override
+ public String getMusicUrl(Context context, MusicDirectory.Entry song, int maxBitrate) throws Exception {
+ return musicService.getMusicUrl(context, song, maxBitrate);
+ }
+
+ @Override
public Version getLocalVersion(Context context) throws Exception {
return musicService.getLocalVersion(context);
}
diff --git a/src/github/daneren2005/dsub/service/ChromeCastController.java b/src/github/daneren2005/dsub/service/ChromeCastController.java
index 467e4d7b..22563089 100644
--- a/src/github/daneren2005/dsub/service/ChromeCastController.java
+++ b/src/github/daneren2005/dsub/service/ChromeCastController.java
@@ -15,32 +15,123 @@
package github.daneren2005.dsub.service;
-import android.os.Handler;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.google.android.gms.cast.ApplicationMetadata;
+import com.google.android.gms.cast.Cast;
+import com.google.android.gms.cast.CastDevice;
+import com.google.android.gms.cast.MediaInfo;
+import com.google.android.gms.cast.MediaMetadata;
+import com.google.android.gms.cast.MediaStatus;
+import com.google.android.gms.cast.RemoteMediaPlayer;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.common.api.Status;
+
+import java.io.IOException;
+
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.util.compat.CastCompat;
/**
* Created by owner on 2/9/14.
*/
public class ChromeCastController extends RemoteController {
+ private static final String TAG = ChromeCastController.class.getSimpleName();
+
private CastDevice castDevice;
+ private GoogleApiClient apiClient;
+ private ConnectionCallbacks connectionCallbacks;
+ private ConnectionFailedListener connectionFailedListener;
+ private Cast.Listener castClientListener;
+
+ private boolean applicationStarted = false;
+ private boolean waitingForReconnect = false;
+
+ private RemoteMediaPlayer mediaPlayer;
public ChromeCastController(DownloadServiceImpl downloadService, CastDevice castDevice) {
this.downloadService = downloadService;
this.castDevice = castDevice;
+
+ connectionCallbacks = new ConnectionCallbacks();
+ connectionFailedListener = new ConnectionFailedListener();
+ castClientListener = new Cast.Listener() {
+ @Override
+ public void onApplicationStatusChanged() {
+ if (apiClient != null) {
+ Log.d(TAG, "onApplicationStatusChanged: " + Cast.CastApi.getApplicationStatus(apiClient));
+
+ }
+ }
+
+ @Override
+ public void onVolumeChanged() {
+ if (apiClient != null) {
+ Log.d(TAG, "onVolumeChanged: " + Cast.CastApi.getVolume(apiClient));
+ }
+ }
+
+ @Override
+ public void onApplicationDisconnected(int errorCode) {
+ Log.d(TAG, "onApplicationDisconnected: " + errorCode);
+ // teardown();
+ }
+
+ };
+
+ Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(castDevice, castClientListener);
+ apiClient = new GoogleApiClient.Builder(downloadService)
+ .addApi(Cast.API, apiOptionsBuilder.build())
+ .addConnectionCallbacks(connectionCallbacks)
+ .addOnConnectionFailedListener(connectionFailedListener)
+ .build();
+
+ apiClient.connect();
}
@Override
public void start() {
-
+ try {
+ mediaPlayer.play(apiClient);
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to pause");
+ }
}
@Override
public void stop() {
-
+ try {
+ mediaPlayer.pause(apiClient);
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to pause");
+ }
}
@Override
public void shutdown() {
+ try {
+ if(mediaPlayer != null) {
+ mediaPlayer.stop(apiClient);
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to stop mediaPlayer", e);
+ }
+ try {
+ Cast.CastApi.stopApplication(apiClient);
+ Cast.CastApi.removeMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace());
+ mediaPlayer = null;
+ applicationStarted = false;
+ } catch(IOException e) {
+ Log.e(TAG, "Failed to shutdown application", e);
+ }
+
+ if(apiClient.isConnected()) {
+ apiClient.disconnect();
+ }
}
@Override
@@ -67,4 +158,118 @@ public class ChromeCastController extends RemoteController {
public int getRemotePosition() {
return 0;
}
+
+ private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {
+ @Override
+ public void onConnected(Bundle connectionHint) {
+ if (waitingForReconnect) {
+ waitingForReconnect = false;
+ // reconnectChannels();
+ } else {
+ launchApplication();
+ }
+ }
+
+ @Override
+ public void onConnectionSuspended(int cause) {
+ waitingForReconnect = true;
+ }
+
+ void launchApplication() {
+ try {
+ Cast.CastApi.launchApplication(apiClient, CastCompat.APPLICATION_ID, false).setResultCallback(new ResultCallback<Cast.ApplicationConnectionResult>() {
+ @Override
+ public void onResult(Cast.ApplicationConnectionResult result) {
+ Status status = result.getStatus();
+ if (status.isSuccess()) {
+ ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
+ String sessionId = result.getSessionId();
+ String applicationStatus = result.getApplicationStatus();
+ boolean wasLaunched = result.getWasLaunched();
+
+ applicationStarted = true;
+ setupChannel();
+ } else {
+ // teardown();
+ }
+ }
+ });
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to launch application", e);
+ }
+ }
+ void setupChannel() {
+ mediaPlayer = new RemoteMediaPlayer();
+ mediaPlayer.setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener() {
+ @Override
+ public void onStatusUpdated() {
+ MediaStatus mediaStatus = mediaPlayer.getMediaStatus();
+ Log.d(TAG, "mediaPlayer status: " + mediaStatus);
+ boolean isPlaying = mediaStatus.getPlayerState() == MediaStatus.PLAYER_STATE_PLAYING;
+
+ }
+ });
+ mediaPlayer.setOnMetadataUpdatedListener(new RemoteMediaPlayer.OnMetadataUpdatedListener() {
+ @Override
+ public void onMetadataUpdated() {
+ MediaInfo mediaInfo = mediaPlayer.getMediaInfo();
+ MediaMetadata metadata = mediaInfo.getMetadata();
+ Log.d(TAG, "mediaInfo: " + mediaInfo);
+ Log.d(TAG, "metadata: " + metadata);
+ }
+ });
+
+ try {
+ Cast.CastApi.setMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace(), mediaPlayer);
+ } catch (IOException e) {
+ Log.e(TAG, "Exception while creating channel", e);
+ }
+
+ startSong();
+ }
+ void startSong() {
+ DownloadFile currentPlaying = downloadService.getCurrentPlaying();
+ if(currentPlaying == null) {
+ // Don't start anything
+ return;
+ }
+ MusicDirectory.Entry song = currentPlaying.getSong();
+
+ MusicService musicService = MusicServiceFactory.getMusicService(downloadService);
+ try {
+ String url = musicService.getMusicUrl(downloadService, song, 0);
+ Log.d(TAG, "load: " + url);
+
+ MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
+ mediaMetadata.putString(MediaMetadata.KEY_TITLE, song.getTitle());
+ MediaInfo mediaInfo = new MediaInfo.Builder(url)
+ .setContentType(song.getTranscodedContentType())
+ .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
+ .setMetadata(mediaMetadata)
+ .build();
+
+ mediaPlayer.load(apiClient, mediaInfo, true).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
+ @Override
+ public void onResult(RemoteMediaPlayer.MediaChannelResult result) {
+ if (result.getStatus().isSuccess()) {
+ Log.d(TAG, "Media loaded successfully");
+ } else {
+ Log.d(TAG, "Result: " + result.getStatus());
+ }
+ }
+ });
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Problem occurred with media during loading", e);
+ } catch (Exception e) {
+ Log.e(TAG, "Problem opening media during loading", e);
+ }
+ }
+ }
+
+ private class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
+ @Override
+ public void onConnectionFailed(ConnectionResult result) {
+ // teardown();
+ }
+ }
}
diff --git a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
index 9a85bcdd..e83be019 100644
--- a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
+++ b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
@@ -372,7 +372,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
SharedPreferences prefs = Util.getPreferences(this);
remoteState = RemoteControlState.values()[prefs.getInt(Constants.PREFERENCES_KEY_CONTROL_MODE, 0)];
if(remoteState != RemoteControlState.LOCAL) {
- setRemoteState(remoteState);
+ setRemoteState(remoteState, null);
}
boolean startShufflePlay = prefs.getBoolean(Constants.PREFERENCES_KEY_SHUFFLE_MODE, false);
download(songs, false, false, false, false);
@@ -1158,6 +1158,11 @@ public class DownloadServiceImpl extends Service implements DownloadService {
remoteController = new JukeboxController(this, handler);
break;
case CHROMECAST:
+ // TODO: Fix case where starting up with chromecast set
+ if(ref == null) {
+ remoteState = RemoteControlState.LOCAL;
+ break;
+ }
remoteController = (RemoteController) ref;
break;
case LOCAL: default:
diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java
index 3674fd01..a1e54a81 100644
--- a/src/github/daneren2005/dsub/service/MusicService.java
+++ b/src/github/daneren2005/dsub/service/MusicService.java
@@ -95,6 +95,8 @@ public interface MusicService {
HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception;
+ String getMusicUrl(Context context, MusicDirectory.Entry song, int maxBitrate) throws Exception;
+
Version getLocalVersion(Context context) throws Exception;
Version getLatestVersion(Context context, ProgressListener progressListener) throws Exception;
diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java
index 43b5f887..8555f9e2 100644
--- a/src/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/src/github/daneren2005/dsub/service/RESTMusicService.java
@@ -723,7 +723,18 @@ public class RESTMusicService implements MusicService {
return response;
}
- @Override
+ @Override
+ public String getMusicUrl(Context context, MusicDirectory.Entry song, int maxBitrate) throws Exception {
+ StringBuilder builder = new StringBuilder(getRestUrl(context, "stream", false));
+ builder.append("&id=").append(song.getId());
+ builder.append("&maxBitRate=").append(maxBitrate);
+
+ String url = rewriteUrlWithRedirect(context, builder.toString());
+ Log.i(TAG, "Using music URL: " + url);
+ return url;
+ }
+
+ @Override
public String getVideoUrl(int maxBitrate, Context context, String id) {
StringBuilder builder = new StringBuilder(getRestUrl(context, "videoPlayer"));
builder.append("&id=").append(id);
diff --git a/src/github/daneren2005/dsub/util/compat/CastCompat.java b/src/github/daneren2005/dsub/util/compat/CastCompat.java
index 0892040e..31581816 100644
--- a/src/github/daneren2005/dsub/util/compat/CastCompat.java
+++ b/src/github/daneren2005/dsub/util/compat/CastCompat.java
@@ -17,6 +17,9 @@ package github.daneren2005.dsub.util.compat;
import android.support.v7.media.MediaRouter;
+import com.google.android.gms.cast.CastDevice;
+import com.google.android.gms.cast.CastMediaControlIntent;
+
import github.daneren2005.dsub.service.ChromeCastController;
import github.daneren2005.dsub.service.DownloadServiceImpl;
import github.daneren2005.dsub.service.RemoteController;
@@ -25,6 +28,8 @@ import github.daneren2005.dsub.service.RemoteController;
* Created by owner on 2/9/14.
*/
public final class CastCompat {
+ public static final String APPLICATION_ID = "5F85EBEB";
+
static {
try {
Class.forName("com.google.android.gms.cast.CastDevice");
@@ -47,6 +52,6 @@ public final class CastCompat {
}
public static String getCastControlCategory() {
- return CastMediaControlIntent.categoryForCast("5F85EBEB");
+ return CastMediaControlIntent.categoryForCast(APPLICATION_ID);
}
}