diff --git a/app/build.gradle b/app/build.gradle
index 89655e7f6..df03a0c71 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,11 +8,11 @@ android {
}
defaultConfig {
applicationId "net.programmierecke.radiodroid2"
- minSdkVersion 9
+ minSdkVersion 14
targetSdkVersion 23
- versionCode 42
- versionName "0.32"
+ versionCode 46
+ versionName "0.36"
}
buildTypes {
release {
@@ -27,10 +27,13 @@ android {
}
dependencies {
- compile 'com.android.support:support-v4:25.3.1'
- compile 'com.android.support:appcompat-v7:25.3.1'
- compile 'com.android.support:design:25.3.1'
- compile 'com.android.support:preference-v7:25.3.1'
+ compile 'com.android.support:support-v4:25.2.0'
+ compile 'com.android.support:appcompat-v7:25.2.0'
+ compile 'com.android.support:design:25.2.0'
+ compile 'com.android.support:preference-v7:25.2.0'
+ compile 'com.android.support:mediarouter-v7:25.2.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.google.android.exoplayer:exoplayer:r2.3.1'
+ compile 'com.google.android.gms:play-services-cast:11.0.1'
+ compile 'com.google.android.gms:play-services-cast-framework:11.0.1'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2d4062d5..13436527a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -45,5 +45,11 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/ActivityMain.java b/app/src/main/java/net/programmierecke/radiodroid2/ActivityMain.java
index f6c337fcd..1f4e36e6a 100644
--- a/app/src/main/java/net/programmierecke/radiodroid2/ActivityMain.java
+++ b/app/src/main/java/net/programmierecke/radiodroid2/ActivityMain.java
@@ -4,6 +4,7 @@
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.os.Handler;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@@ -21,6 +22,12 @@
import android.view.MenuItem;
import android.widget.Toast;
+import com.google.android.gms.cast.framework.CastButtonFactory;
+import com.google.android.gms.cast.framework.CastContext;
+import com.google.android.gms.cast.framework.Session;
+import com.google.android.gms.cast.framework.SessionManager;
+import com.google.android.gms.cast.framework.SessionManagerListener;
+
import net.programmierecke.radiodroid2.interfaces.IFragmentRefreshable;
import net.programmierecke.radiodroid2.interfaces.IFragmentSearchable;
@@ -28,7 +35,7 @@
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
-public class ActivityMain extends AppCompatActivity implements SearchView.OnQueryTextListener {
+public class ActivityMain extends AppCompatActivity implements SearchView.OnQueryTextListener, IMPDClientStatusChange {
private SearchView mSearchView;
private static final String TAG = "RadioDroid";
@@ -45,13 +52,82 @@ public class ActivityMain extends AppCompatActivity implements SearchView.OnQuer
MenuItem menuItemRefresh;
private SharedPreferences sharedPref;
-
- @Override
+ private CastContext mCastContext;
+ private MenuItem mediaRouteMenuItem;
+ private SessionManager mSessionManager;
+
+ private final SessionManagerListener mSessionManagerListener =
+ new SessionManagerListenerImpl();
+ private MenuItem menuItemMPDOK;
+ private MenuItem menuItemMPDNok;
+
+ @Override
+ public void changed() {
+ Handler mainHandler = new Handler(getMainLooper());
+ Runnable myRunnable = new Runnable() {
+ @Override
+ public void run() {
+ invalidateOptionsMenu();
+ }
+ };
+ mainHandler.post(myRunnable);
+ }
+
+ private class SessionManagerListenerImpl implements SessionManagerListener {
+ @Override
+ public void onSessionStarting(Session session) {
+
+ }
+
+ @Override
+ public void onSessionStarted(Session session, String sessionId) {
+ invalidateOptionsMenu();
+ Utils.mCastSession = mSessionManager.getCurrentCastSession();
+ }
+
+ @Override
+ public void onSessionStartFailed(Session session, int i) {
+
+ }
+
+ @Override
+ public void onSessionEnding(Session session) {
+ }
+
+ @Override
+ public void onSessionResumed(Session session, boolean wasSuspended) {
+ invalidateOptionsMenu();
+ Utils.mCastSession = mSessionManager.getCurrentCastSession();
+ }
+
+ @Override
+ public void onSessionResumeFailed(Session session, int i) {
+ Utils.mCastSession = null;
+ }
+
+ @Override
+ public void onSessionSuspended(Session session, int i) {
+ Utils.mCastSession = null;
+ }
+
+ @Override
+ public void onSessionEnded(Session session, int error) {
+ Utils.mCastSession = null;
+ }
+
+ @Override
+ public void onSessionResuming(Session session, String s) {
+
+ }
+ }
+
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
- try {
+ try {
File dir = new File(getFilesDir().getAbsolutePath());
if (dir.isDirectory()) {
String[] children = dir.list();
@@ -159,7 +235,12 @@ public boolean onNavigationItemSelected(MenuItem menuItem) {
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout, R.string.app_name,R.string.app_name);
mDrawerLayout.addDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
- }
+
+ mCastContext = CastContext.getSharedInstance(this);
+ mSessionManager = mCastContext.getSessionManager();
+
+ MPDClient.StartDiscovery(this, this);
+ }
@Override
public void onRequestPermissionsResult(int requestCode,
@@ -186,15 +267,21 @@ public void onRequestPermissionsResult(int requestCode,
public void onDestroy() {
super.onDestroy();
PlayerServiceUtil.unBind(this);
+ MPDClient.StopDiscovery();
}
@Override
protected void onPause() {
+ Log.i(TAG,"PAUSED");
super.onPause();
- }
+ mSessionManager.removeSessionManagerListener(mSessionManagerListener);
+ Utils.mCastSession = null;
+ MPDClient.StopDiscovery();
+ }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
@@ -203,6 +290,8 @@ public boolean onCreateOptionsMenu(Menu menu) {
mSearchView.setOnQueryTextListener(this);
menuItemRefresh = menu.findItem(R.id.action_refresh);
+ menuItemMPDNok = menu.findItem(R.id.action_mpd_nok);
+ menuItemMPDOK = menu.findItem(R.id.action_mpd_ok);
if (fragSearchable == null) {
menuItemSearch.setVisible(false);
@@ -212,7 +301,14 @@ public boolean onCreateOptionsMenu(Menu menu) {
menuItemRefresh.setVisible(false);
}
- return true;
+ menuItemMPDOK.setVisible(MPDClient.Discovered() && MPDClient.Connected());
+ menuItemMPDNok.setVisible(MPDClient.Discovered() && !MPDClient.Connected());
+
+ mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
+ menu,
+ R.id.media_route_menu_item);
+
+ return true;
}
@Override
@@ -226,6 +322,12 @@ public boolean onOptionsItemSelected(MenuItem item) {
fragRefreshable.Refresh();
}
return true;
+ case R.id.action_mpd_nok:
+ MPDClient.Connect(this);
+ return true;
+ case R.id.action_mpd_ok:
+ MPDClient.Disconnect(this, this);
+ return true;
}
return super.onOptionsItemSelected(item);
}
@@ -255,7 +357,13 @@ protected void onResume() {
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.replace(R.id.containerView,first).commit();
- }
+
+ Utils.mCastSession = mSessionManager.getCurrentCastSession();
+ mSessionManager.addSessionManagerListener(mSessionManagerListener);
+
+ Log.i(TAG,"RESUMED");
+ MPDClient.StartDiscovery(this, this);
+ }
public void Search(String query){
if (fragSearchable != null) {
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/CastOptionsProvider.java b/app/src/main/java/net/programmierecke/radiodroid2/CastOptionsProvider.java
new file mode 100644
index 000000000..ab07d0bf5
--- /dev/null
+++ b/app/src/main/java/net/programmierecke/radiodroid2/CastOptionsProvider.java
@@ -0,0 +1,24 @@
+package net.programmierecke.radiodroid2;
+
+import android.content.Context;
+
+import com.google.android.gms.cast.framework.CastOptions;
+import com.google.android.gms.cast.framework.OptionsProvider;
+import com.google.android.gms.cast.framework.SessionProvider;
+
+import java.util.List;
+
+public class CastOptionsProvider implements OptionsProvider {
+
+ @Override
+ public CastOptions getCastOptions(Context context) {
+ return new CastOptions.Builder()
+ .setReceiverApplicationId(context.getString(R.string.app_id))
+ .build();
+ }
+
+ @Override
+ public List getAdditionalSessionProviders(Context context) {
+ return null;
+ }
+}
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/MPDClient.java b/app/src/main/java/net/programmierecke/radiodroid2/MPDClient.java
new file mode 100644
index 000000000..06b09423d
--- /dev/null
+++ b/app/src/main/java/net/programmierecke/radiodroid2/MPDClient.java
@@ -0,0 +1,214 @@
+package net.programmierecke.radiodroid2;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.support.v7.preference.PreferenceManager;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+
+interface IMPDClientStatusChange{
+ void changed();
+}
+
+public class MPDClient {
+ static final String TAG = "MPD";
+ private static boolean connected;
+
+ public static int StringToInt(String str, int defaultValue){
+ try{
+ return Integer.parseInt(str);
+ }
+ catch (Exception e){
+ }
+ return defaultValue;
+ }
+
+ public static void Connect(IMPDClientStatusChange listener){
+ connected = true;
+ listener.changed();
+ }
+
+ public static void Disconnect(Context context, IMPDClientStatusChange listener){
+ connected = false;
+ listener.changed();
+ Stop(context);
+ }
+
+ public static void Play(final String url, final Context context) {
+ SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
+ final String mpd_hostname = sharedPref.getString("mpd_hostname", null);
+ final int mpd_port = StringToInt(sharedPref.getString("mpd_port", "6600"), 6600);
+
+ new AsyncTask() {
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ return PlayRemoteMPD(mpd_hostname, mpd_port, url);
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ super.onPostExecute(result);
+ }
+ }.execute();
+ }
+
+ static boolean discovered = false;
+ static Thread t = null;
+ static boolean discoveryActive = false;
+
+ public static boolean Discovered(){
+ return discovered;
+ }
+
+ public static void StartDiscovery(final Context context, final IMPDClientStatusChange listener){
+ final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (t == null) {
+ discoveryActive = true;
+ t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while(discoveryActive){
+ try {
+ final String mpd_hostname = sharedPref.getString("mpd_hostname", "").trim();
+ final int mpd_port = StringToInt(sharedPref.getString("mpd_port", "6600"), 6600);
+
+ if (mpd_hostname != ""){
+ SetDiscoveredStatus(CheckConnection(mpd_hostname, mpd_port), listener);
+ }
+ // check every 5 seconds
+ Thread.sleep(5*1000);
+ } catch (Exception e) {
+ SetDiscoveredStatus(false, listener);
+ }
+ }
+ SetDiscoveredStatus(false, listener);
+ t = null;
+ }
+ });
+ t.start();
+ }
+ }
+
+ private static void SetDiscoveredStatus(boolean status, IMPDClientStatusChange listener){
+ if (status != discovered){
+ discovered = status;
+ listener.changed();
+ }
+ }
+
+ private static boolean CheckConnection(String mpd_hostname, int mpd_port) {
+ Boolean result = false;
+
+ try {
+ Log.i(TAG, "Check connection...");
+ Socket s = new Socket(mpd_hostname, mpd_port);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
+ String info = reader.readLine();
+ Log.i(TAG, info);
+ if (info.startsWith("OK")){
+ result = true;
+ }
+ reader.close();
+ writer.close();
+ s.close();
+ } catch (Exception e) {
+ Log.e(TAG,e.toString());
+ }
+ Log.i(TAG, "Connection status:"+result);
+ return result;
+ }
+
+
+ public static void Stop(Context context) {
+ SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
+ final String mpd_hostname = sharedPref.getString("mpd_hostname", "").trim();
+ final int mpd_port = StringToInt(sharedPref.getString("mpd_port", "6600"), 6600);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ StopInternal(mpd_hostname, mpd_port);
+ }
+ }).start();
+ }
+
+ private static boolean StopInternal(String mpd_hostname, int mpd_port) {
+ Boolean result = false;
+
+ try {
+ Log.i(TAG, "Check connection...");
+ Socket s = new Socket(mpd_hostname, mpd_port);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
+ String info = reader.readLine();
+ Log.i(TAG, info);
+ if (info.startsWith("OK")) {
+ String cmd = "stop";
+ writer.write(cmd);
+ writer.newLine();
+ writer.flush();
+ result = true;
+ }
+ reader.close();
+ writer.close();
+ s.close();
+ } catch (Exception e) {
+ Log.e(TAG,e.toString());
+ }
+ Log.i(TAG, "Connection status:"+result);
+ return result;
+ }
+
+ public static void StopDiscovery(){
+ discoveryActive = false;
+ discovered = false;
+ t = null;
+ }
+
+ private static Boolean PlayRemoteMPD(String mpd_hostname, int mpd_port, String url){
+ Boolean result = false;
+ try {
+ Log.i("MPD", "Start");
+ Socket s = new Socket(mpd_hostname, mpd_port);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
+ String info = reader.readLine();
+ Log.i("MPD", info);
+ if (info.startsWith("OK")){
+ String cmd = "addid "+url;
+ writer.write(cmd);
+ writer.newLine();
+ writer.flush();
+
+ info = reader.readLine();
+ Log.i("MPD", info);
+ if (info.startsWith("Id:")){
+ int songid = Integer.parseInt(info.substring(3).trim());
+ cmd = "playid "+songid;
+ writer.write(cmd);
+ writer.newLine();
+ writer.flush();
+ Log.i("MPD", "OK");
+ result = true;
+ }
+ }
+ reader.close();
+ writer.close();
+ s.close();
+ } catch (Exception e) {
+ Log.e("MPD",e.toString());
+ }
+ return result;
+ }
+
+ public static boolean Connected() {
+ return connected;
+ }
+}
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/PlayerService.java b/app/src/main/java/net/programmierecke/radiodroid2/PlayerService.java
index 3875b98bd..2d6641599 100644
--- a/app/src/main/java/net/programmierecke/radiodroid2/PlayerService.java
+++ b/app/src/main/java/net/programmierecke/radiodroid2/PlayerService.java
@@ -80,6 +80,7 @@ public class PlayerService extends Service implements IStreamProxyEventReceiver
private WifiManager.WifiLock wifiLock;
private boolean isHls = false;
boolean useExo = false;
+ private boolean isAlarm = false;
enum PlayStatus{
Idle,
@@ -384,6 +385,7 @@ public void onAudioFocusChange(int focusChange) {
public void ReplayCurrent(final boolean isAlarm) {
liveInfo = null;
streamInfo = null;
+ this.isAlarm = isAlarm;
SetPlayStatus(PlayStatus.Idle);
if (wakeLock == null) {
@@ -417,9 +419,9 @@ public void ReplayCurrent(final boolean isAlarm) {
useExo = false;
}
- new Thread(new Runnable() {
+ /*new Thread(new Runnable() {
@Override
- public void run() {
+ public void run() {*/
if (proxy != null){
Log.i(TAG,"stop old proxy");
proxy.stop();
@@ -428,77 +430,10 @@ public void run() {
SetPlayStatus(PlayStatus.CreateProxy);
proxy = new StreamProxy(PlayerService.this, itsStationURL, PlayerService.this);
- String proxyConnection = proxy.getLocalAdress();
- Log.v(TAG, "Stream url:" + proxyConnection);
- SetPlayStatus(PlayStatus.ClearOld);
-
- if (useExo){
- if (player != null){
- player.stop();
- }
-
- Looper.prepare();
-
- if (player == null){
- // 1. Create a default TrackSelector
- //Handler mainHandler = new Handler();
- DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
- TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
- TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
-
- // 2. Create a default LoadControl
- LoadControl loadControl = new DefaultLoadControl();
-
- // 3. Create the player
- player = ExoPlayerFactory.newSimpleInstance(itsContext, trackSelector, loadControl);
- player.setAudioStreamType(isAlarm ? AudioManager.STREAM_ALARM : AudioManager.STREAM_MUSIC);
- }
- // Produces DataSource instances through which media data is loaded.
- DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(itsContext, Util.getUserAgent(itsContext, "yourApplicationName"), null);
- // Produces Extractor instances for parsing the media data.
- ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
- // This is the MediaSource representing the media to be played.
- MediaSource videoSource = null;
- videoSource = new ExtractorMediaSource(Uri.parse(proxyConnection), dataSourceFactory, extractorsFactory, null, null);
- player.prepare(videoSource);
- player.setPlayWhenReady(true);
-
- SetPlayStatus(PlayStatus.Playing);
-
- Looper.loop();
- }else
- {
- if (itsMediaPlayer == null) {
- itsMediaPlayer = new MediaPlayer();
- }
- if (itsMediaPlayer.isPlaying()) {
- itsMediaPlayer.stop();
- itsMediaPlayer.reset();
- }
- try {
- SetPlayStatus(PlayStatus.PrepareStream);
- itsMediaPlayer.setAudioStreamType(isAlarm ? AudioManager.STREAM_ALARM : AudioManager.STREAM_MUSIC);
- itsMediaPlayer.setDataSource(proxyConnection);
- itsMediaPlayer.prepare();
- SetPlayStatus(PlayStatus.PrePlaying);
- itsMediaPlayer.start();
- SetPlayStatus(PlayStatus.Playing);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "" + e);
- ToastOnUi(R.string.error_stream_url);
- Stop();
- } catch (IOException e) {
- Log.e(TAG, "" + e);
- ToastOnUi(R.string.error_caching_stream);
- Stop();
- } catch (Exception e) {
- Log.e(TAG, "" + e);
- ToastOnUi(R.string.error_play_stream);
- Stop();
- }
- }
+ /*
}
}).start();
+ */
}
void ToastOnUi(final int messageId){
@@ -581,6 +516,83 @@ public void foundLiveStreamInfo(Map liveInfo) {
UpdateNotification();
}
+ @Override
+ public void streamCreated(final String proxyConnection) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ Log.v(TAG, "Stream url:" + proxyConnection);
+ SetPlayStatus(PlayStatus.ClearOld);
+
+ if (useExo){
+ if (player != null){
+ player.stop();
+ }
+
+ Looper.prepare();
+
+ if (player == null){
+ // 1. Create a default TrackSelector
+ //Handler mainHandler = new Handler();
+ DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
+ TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
+ TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
+
+ // 2. Create a default LoadControl
+ LoadControl loadControl = new DefaultLoadControl();
+
+ // 3. Create the player
+ player = ExoPlayerFactory.newSimpleInstance(itsContext, trackSelector, loadControl);
+ player.setAudioStreamType(isAlarm ? AudioManager.STREAM_ALARM : AudioManager.STREAM_MUSIC);
+ }
+ // Produces DataSource instances through which media data is loaded.
+ DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(itsContext, Util.getUserAgent(itsContext, "yourApplicationName"), null);
+ // Produces Extractor instances for parsing the media data.
+ ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
+ // This is the MediaSource representing the media to be played.
+ MediaSource videoSource = null;
+ videoSource = new ExtractorMediaSource(Uri.parse(proxyConnection), dataSourceFactory, extractorsFactory, null, null);
+ player.prepare(videoSource);
+ player.setPlayWhenReady(true);
+
+ SetPlayStatus(PlayStatus.Playing);
+
+ Looper.loop();
+ }else
+ {
+ if (itsMediaPlayer == null) {
+ itsMediaPlayer = new MediaPlayer();
+ }
+ if (itsMediaPlayer.isPlaying()) {
+ itsMediaPlayer.stop();
+ itsMediaPlayer.reset();
+ }
+ try {
+ SetPlayStatus(PlayStatus.PrepareStream);
+ itsMediaPlayer.setAudioStreamType(isAlarm ? AudioManager.STREAM_ALARM : AudioManager.STREAM_MUSIC);
+ itsMediaPlayer.setDataSource(proxyConnection);
+ itsMediaPlayer.prepare();
+ SetPlayStatus(PlayStatus.PrePlaying);
+ itsMediaPlayer.start();
+ SetPlayStatus(PlayStatus.Playing);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "" + e);
+ ToastOnUi(R.string.error_stream_url);
+ Stop();
+ } catch (IOException e) {
+ Log.e(TAG, "" + e);
+ ToastOnUi(R.string.error_caching_stream);
+ Stop();
+ } catch (Exception e) {
+ Log.e(TAG, "" + e);
+ ToastOnUi(R.string.error_play_stream);
+ Stop();
+ }
+ }
+ }
+ }).start();
+ }
+
@Override
public void streamStopped() {
Stop();
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/StreamProxy.java b/app/src/main/java/net/programmierecke/radiodroid2/StreamProxy.java
index 14d36a42a..59f767545 100644
--- a/app/src/main/java/net/programmierecke/radiodroid2/StreamProxy.java
+++ b/app/src/main/java/net/programmierecke/radiodroid2/StreamProxy.java
@@ -49,6 +49,7 @@ public StreamProxy(Context context, String uri, IStreamProxyEventReceiver callba
private void createProxy() {
Log.i(TAG,"thread started");
+ /*
ServerSocket proxyServer = null;
try {
proxyServer = new ServerSocket(0, 1, InetAddress.getLocalHost());
@@ -57,34 +58,22 @@ private void createProxy() {
} catch (IOException e) {
Log.e(TAG,"createProxy() create server socket: "+e);
}
+ */
- if (proxyServer != null) {
- final ServerSocket finalProxyServer = proxyServer;
+ //if (proxyServer != null) {
+// final ServerSocket finalProxyServer = proxyServer;
new Thread(new Runnable() {
@Override
public void run() {
try {
- Log.i(TAG, "waiting..");
- socketProxy = finalProxyServer.accept();
- finalProxyServer.close();
-
doConnectToStream();
-
Log.i(TAG, "createProxy() ended");
- } catch (IOException e) {
+ } catch (Exception e) {
Log.e(TAG, "" + e);
}
}
}).start();
-
- while (localAdress == null) {
- try {
- Log.i(TAG, "starting serversock...");
- Thread.sleep(100);
- } catch (Exception e) {
- }
- }
- }
+ //}
}
InputStream in;
@@ -272,19 +261,29 @@ private void hlsStream(URL path, int size, InputStream inM3U) throws Exception{
private void doConnectToStream() {
try{
- final int MaxRetries = 30;
+ final int MaxRetries = 100;
int retry = MaxRetries;
while (!isStopped && retry > 0) {
try {
// connect to stream
- Log.i(TAG,"doConnectToStream:"+uri);
+ Log.i(TAG,"doConnectToStream (try="+retry+"):"+uri);
URL u = new URL(uri);
URLConnection connection = u.openConnection();
- connection.setConnectTimeout(5000);
- connection.setReadTimeout(10000);
+ connection.setConnectTimeout(2000);
+ connection.setReadTimeout(2000);
connection.setRequestProperty("Icy-MetaData", "1");
connection.connect();
+ Log.i(TAG, "create serversocket..");
+ ServerSocket proxyServer = null;
+ proxyServer = new ServerSocket(0, 1, InetAddress.getLocalHost());
+ int port = proxyServer.getLocalPort();
+ localAdress = String.format(Locale.US,"http://localhost:%d",port);
+ Log.i(TAG, "waiting..");
+ callback.streamCreated(localAdress);
+ socketProxy = proxyServer.accept();
+ proxyServer.close();
+
// send ok message to local mediaplayer
out = socketProxy.getOutputStream();
out.write(("HTTP/1.0 200 OK\r\n" +
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/Utils.java b/app/src/main/java/net/programmierecke/radiodroid2/Utils.java
index 8074fd4b0..7d35f3b67 100644
--- a/app/src/main/java/net/programmierecke/radiodroid2/Utils.java
+++ b/app/src/main/java/net/programmierecke/radiodroid2/Utils.java
@@ -12,13 +12,17 @@
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.preference.PreferenceManager;
-import android.util.Base64;
import android.util.Log;
import android.widget.Toast;
+import com.google.android.gms.cast.MediaInfo;
+import com.google.android.gms.cast.MediaMetadata;
+import com.google.android.gms.cast.framework.CastSession;
+import com.google.android.gms.cast.framework.media.RemoteMediaClient;
+import com.google.android.gms.common.images.WebImage;
+
import net.programmierecke.radiodroid2.data.DataRadioStation;
-import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
@@ -31,13 +35,13 @@
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
-import java.util.Dictionary;
-import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
public class Utils {
- public static String getCacheFile(Context ctx, String theURI) {
+ public static CastSession mCastSession;
+
+ public static String getCacheFile(Context ctx, String theURI) {
StringBuffer chaine = new StringBuffer("");
try{
String aFileName = theURI.toLowerCase().replace("http://","");
@@ -180,12 +184,24 @@ protected void onPostExecute(String result) {
itsProgressLoading.dismiss();
if (result != null) {
- if (external){
- Intent share = new Intent(Intent.ACTION_VIEW);
- share.setDataAndType(Uri.parse(result), "audio/*");
- context.startActivity(share);
- }else {
- PlayerServiceUtil.play(result, station.Name, station.ID, true);
+ boolean externalActive = false;
+ if (MPDClient.Connected() && MPDClient.Discovered()){
+ MPDClient.Play(result, context);
+ externalActive = true;
+ }
+ if (mCastSession != null){
+ PlayRemote(station.Name, result, station.IconUrl);
+ externalActive = true;
+ }
+
+ if (!externalActive){
+ if (external){
+ Intent share = new Intent(Intent.ACTION_VIEW);
+ share.setDataAndType(Uri.parse(result), "audio/*");
+ context.startActivity(share);
+ }else {
+ PlayerServiceUtil.play(result, station.Name, station.ID, true);
+ }
}
} else {
Toast toast = Toast.makeText(context.getApplicationContext(), context.getResources().getText(R.string.error_station_load), Toast.LENGTH_SHORT);
@@ -196,6 +212,25 @@ protected void onPostExecute(String result) {
}.execute();
}
+ private static void PlayRemote(String title, String url, String iconurl){
+ MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
+
+ movieMetadata.putString(MediaMetadata.KEY_TITLE, title);
+ //movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, "MySubTitle");
+ movieMetadata.addImage(new WebImage(Uri.parse(iconurl)));
+ //movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(1))));
+
+
+ MediaInfo mediaInfo = new MediaInfo.Builder(url)
+ .setStreamType(MediaInfo.STREAM_TYPE_LIVE)
+ .setContentType("audio/ogg")
+ .setMetadata(movieMetadata)
+ //.setStreamDuration(mSelectedMedia.getDuration() * 1000)
+ .build();
+ RemoteMediaClient remoteMediaClient = Utils.mCastSession.getRemoteMediaClient();
+ remoteMediaClient.load(mediaInfo, true);
+ }
+
// Storage Permissions
public static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
diff --git a/app/src/main/java/net/programmierecke/radiodroid2/interfaces/IStreamProxyEventReceiver.java b/app/src/main/java/net/programmierecke/radiodroid2/interfaces/IStreamProxyEventReceiver.java
index aee42c1c2..8330d708d 100644
--- a/app/src/main/java/net/programmierecke/radiodroid2/interfaces/IStreamProxyEventReceiver.java
+++ b/app/src/main/java/net/programmierecke/radiodroid2/interfaces/IStreamProxyEventReceiver.java
@@ -7,5 +7,6 @@
public interface IStreamProxyEventReceiver {
void foundShoutcastStream(ShoutcastInfo bitrate, boolean isHls);
void foundLiveStreamInfo(Map liveInfo);
+ void streamCreated(String proxyConnection);
void streamStopped();
}
diff --git a/app/src/main/res/drawable/mpd_nok.png b/app/src/main/res/drawable/mpd_nok.png
new file mode 100644
index 000000000..25c9e6e49
Binary files /dev/null and b/app/src/main/res/drawable/mpd_nok.png differ
diff --git a/app/src/main/res/drawable/mpd_ok.png b/app/src/main/res/drawable/mpd_ok.png
new file mode 100644
index 000000000..e2b0a44bb
Binary files /dev/null and b/app/src/main/res/drawable/mpd_ok.png differ
diff --git a/app/src/main/res/layout/layout_main.xml b/app/src/main/res/layout/layout_main.xml
index 3fa60247b..207843ee6 100644
--- a/app/src/main/res/layout/layout_main.xml
+++ b/app/src/main/res/layout/layout_main.xml
@@ -19,6 +19,14 @@
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 168076fa3..ef3597eeb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -90,6 +90,16 @@
Delete
More
+ GoogleCast
+ 5A97BAE4
+
+ Music Player Daemon
+ Hostname
+ Port
+ MPD not connected
+ MPD connected
+ Refresh
+
- S
- M
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 37f24df9f..90907358d 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -58,4 +58,15 @@
android:title="@string/settings_alarm_sleep_timer" />
+
+
+
+
+
\ No newline at end of file