Make StreamProxy optional, prepareAsync for MediaPlayer, code fixups in StreamProxy

This commit is contained in:
Joshua Bahnsen 2013-02-10 21:30:46 -07:00
parent d8418254ef
commit 793f5b4464
10 changed files with 1971 additions and 1916 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:a="http://schemas.android.com/apk/res/android" <manifest xmlns:a="http://schemas.android.com/apk/res/android"
package="net.sourceforge.subsonic.androidapp" package="net.sourceforge.subsonic.androidapp"
a:versionCode="59" a:versionCode="61"
a:versionName="3.9.9.18" a:installLocation="auto"> a:versionName="3.9.9.20" a:installLocation="auto">
<uses-permission a:name="android.permission.INTERNET"/> <uses-permission a:name="android.permission.INTERNET"/>
<uses-permission a:name="android.permission.READ_PHONE_STATE"/> <uses-permission a:name="android.permission.READ_PHONE_STATE"/>

View File

@ -349,12 +349,12 @@ public final class R {
public static final int select_album_n_songs_downloading=0x7f0a0001; public static final int select_album_n_songs_downloading=0x7f0a0001;
} }
public static final class string { public static final class string {
public static final int background_task_loading=0x7f0900ea; public static final int background_task_loading=0x7f0900ec;
public static final int background_task_network_error=0x7f0900ec; public static final int background_task_network_error=0x7f0900ee;
public static final int background_task_no_network=0x7f0900eb; public static final int background_task_no_network=0x7f0900ed;
public static final int background_task_not_found=0x7f0900ed; public static final int background_task_not_found=0x7f0900ef;
public static final int background_task_parse_error=0x7f0900ee; public static final int background_task_parse_error=0x7f0900f0;
public static final int background_task_wait=0x7f0900e9; public static final int background_task_wait=0x7f0900eb;
public static final int button_bar_browse=0x7f09000b; public static final int button_bar_browse=0x7f09000b;
public static final int button_bar_home=0x7f09000a; public static final int button_bar_home=0x7f09000a;
public static final int button_bar_now_playing=0x7f09000e; public static final int button_bar_now_playing=0x7f09000e;
@ -402,9 +402,9 @@ public final class R {
public static final int download_repeat_single=0x7f09005f; public static final int download_repeat_single=0x7f09005f;
public static final int download_visualizer_off=0x7f090061; public static final int download_visualizer_off=0x7f090061;
public static final int download_visualizer_on=0x7f090060; public static final int download_visualizer_on=0x7f090060;
public static final int equalizer_enabled=0x7f0900fb; public static final int equalizer_enabled=0x7f0900fd;
public static final int equalizer_label=0x7f0900fa; public static final int equalizer_label=0x7f0900fc;
public static final int equalizer_preset=0x7f0900fc; public static final int equalizer_preset=0x7f0900fe;
public static final int error_label=0x7f09006b; public static final int error_label=0x7f09006b;
public static final int help_back=0x7f090027; public static final int help_back=0x7f090027;
public static final int help_close=0x7f090028; public static final int help_close=0x7f090028;
@ -439,14 +439,14 @@ public final class R {
/** <string name="settings.screen_lit_title">TODO: Keep screen on</string> /** <string name="settings.screen_lit_title">TODO: Keep screen on</string>
<string name="settings.screen_lit_summary">TODO: Keeping the screen on when downloading may improve download speed</string> <string name="settings.screen_lit_summary">TODO: Keeping the screen on when downloading may improve download speed</string>
*/ */
public static final int music_service_retry=0x7f0900e8; public static final int music_service_retry=0x7f0900ea;
public static final int parser_artist_count=0x7f0900f6; public static final int parser_artist_count=0x7f0900f8;
public static final int parser_not_authenticated=0x7f0900f4; public static final int parser_not_authenticated=0x7f0900f6;
public static final int parser_not_authorized=0x7f0900f5; public static final int parser_not_authorized=0x7f0900f7;
public static final int parser_reading=0x7f0900f0; public static final int parser_reading=0x7f0900f2;
public static final int parser_reading_done=0x7f0900f1; public static final int parser_reading_done=0x7f0900f3;
public static final int parser_upgrade_client=0x7f0900f2; public static final int parser_upgrade_client=0x7f0900f4;
public static final int parser_upgrade_server=0x7f0900f3; public static final int parser_upgrade_server=0x7f0900f5;
public static final int play_video_loading=0x7f09002b; public static final int play_video_loading=0x7f09002b;
public static final int play_video_noplugin=0x7f09002c; public static final int play_video_noplugin=0x7f09002c;
/** <string name="menu.exit">TODO: Exit</string> /** <string name="menu.exit">TODO: Exit</string>
@ -481,11 +481,11 @@ public final class R {
public static final int select_album_play_all=0x7f09003f; public static final int select_album_play_all=0x7f09003f;
public static final int select_album_searching=0x7f09003e; public static final int select_album_searching=0x7f09003e;
public static final int select_album_select=0x7f090039; public static final int select_album_select=0x7f090039;
public static final int select_artist_all_folders=0x7f0900f9; public static final int select_artist_all_folders=0x7f0900fb;
public static final int select_artist_folder=0x7f0900f8; public static final int select_artist_folder=0x7f0900fa;
public static final int select_artist_refresh=0x7f0900f7; public static final int select_artist_refresh=0x7f0900f9;
public static final int select_playlist_empty=0x7f090047; public static final int select_playlist_empty=0x7f090047;
public static final int service_connecting=0x7f0900ef; public static final int service_connecting=0x7f0900f1;
public static final int settings_appearance_title=0x7f090080; public static final int settings_appearance_title=0x7f090080;
public static final int settings_buffer_length=0x7f0900b2; public static final int settings_buffer_length=0x7f0900b2;
public static final int settings_buffer_length_10=0x7f0900b7; public static final int settings_buffer_length_10=0x7f0900b7;
@ -511,9 +511,9 @@ public final class R {
public static final int settings_cache_title=0x7f090075; public static final int settings_cache_title=0x7f090075;
public static final int settings_clear_search_history=0x7f0900a5; public static final int settings_clear_search_history=0x7f0900a5;
public static final int settings_connection_failure=0x7f09007d; public static final int settings_connection_failure=0x7f09007d;
public static final int settings_default_albums=0x7f0900e6; public static final int settings_default_albums=0x7f0900e8;
public static final int settings_default_artists=0x7f0900e5; public static final int settings_default_artists=0x7f0900e7;
public static final int settings_default_songs=0x7f0900e7; public static final int settings_default_songs=0x7f0900e9;
public static final int settings_hide_media_summary=0x7f0900ac; public static final int settings_hide_media_summary=0x7f0900ac;
/** <string name="settings.scrobble_title">TODO: Scrobble to Last.fm</string> /** <string name="settings.scrobble_title">TODO: Scrobble to Last.fm</string>
<string name="settings.scrobble_summary">TODO: Remember to set up your Last.fm user and password on the Subsonic server</string> <string name="settings.scrobble_summary">TODO: Remember to set up your Last.fm user and password on the Subsonic server</string>
@ -522,26 +522,26 @@ public final class R {
public static final int settings_hide_media_toast=0x7f0900ad; public static final int settings_hide_media_toast=0x7f0900ad;
public static final int settings_invalid_url=0x7f09007e; public static final int settings_invalid_url=0x7f09007e;
public static final int settings_invalid_username=0x7f09007f; public static final int settings_invalid_username=0x7f09007f;
public static final int settings_max_albums=0x7f0900c8; public static final int settings_max_albums=0x7f0900ca;
public static final int settings_max_albums_10=0x7f0900ca; public static final int settings_max_albums_10=0x7f0900cc;
public static final int settings_max_albums_100=0x7f0900cf; public static final int settings_max_albums_100=0x7f0900d1;
public static final int settings_max_albums_20=0x7f0900cb; public static final int settings_max_albums_20=0x7f0900cd;
public static final int settings_max_albums_250=0x7f0900d0; public static final int settings_max_albums_250=0x7f0900d2;
public static final int settings_max_albums_30=0x7f0900cc; public static final int settings_max_albums_30=0x7f0900ce;
public static final int settings_max_albums_40=0x7f0900cd; public static final int settings_max_albums_40=0x7f0900cf;
public static final int settings_max_albums_5=0x7f0900c9; public static final int settings_max_albums_5=0x7f0900cb;
public static final int settings_max_albums_50=0x7f0900ce; public static final int settings_max_albums_50=0x7f0900d0;
public static final int settings_max_albums_500=0x7f0900d1; public static final int settings_max_albums_500=0x7f0900d3;
public static final int settings_max_artists=0x7f0900db; public static final int settings_max_artists=0x7f0900dd;
public static final int settings_max_artists_10=0x7f0900de; public static final int settings_max_artists_10=0x7f0900e0;
public static final int settings_max_artists_100=0x7f0900e2; public static final int settings_max_artists_100=0x7f0900e4;
public static final int settings_max_artists_200=0x7f0900e3; public static final int settings_max_artists_200=0x7f0900e5;
public static final int settings_max_artists_25=0x7f0900df; public static final int settings_max_artists_25=0x7f0900e1;
public static final int settings_max_artists_3=0x7f0900dc; public static final int settings_max_artists_3=0x7f0900de;
public static final int settings_max_artists_5=0x7f0900dd; public static final int settings_max_artists_5=0x7f0900df;
public static final int settings_max_artists_50=0x7f0900e0; public static final int settings_max_artists_50=0x7f0900e2;
public static final int settings_max_artists_500=0x7f0900e4; public static final int settings_max_artists_500=0x7f0900e6;
public static final int settings_max_artists_75=0x7f0900e1; public static final int settings_max_artists_75=0x7f0900e3;
public static final int settings_max_bitrate_112=0x7f09008d; public static final int settings_max_bitrate_112=0x7f09008d;
public static final int settings_max_bitrate_128=0x7f09008e; public static final int settings_max_bitrate_128=0x7f09008e;
public static final int settings_max_bitrate_160=0x7f09008f; public static final int settings_max_bitrate_160=0x7f09008f;
@ -555,15 +555,15 @@ public final class R {
public static final int settings_max_bitrate_mobile=0x7f090088; public static final int settings_max_bitrate_mobile=0x7f090088;
public static final int settings_max_bitrate_unlimited=0x7f090093; public static final int settings_max_bitrate_unlimited=0x7f090093;
public static final int settings_max_bitrate_wifi=0x7f090087; public static final int settings_max_bitrate_wifi=0x7f090087;
public static final int settings_max_songs=0x7f0900d2; public static final int settings_max_songs=0x7f0900d4;
public static final int settings_max_songs_10=0x7f0900d4; public static final int settings_max_songs_10=0x7f0900d6;
public static final int settings_max_songs_100=0x7f0900d8; public static final int settings_max_songs_100=0x7f0900da;
public static final int settings_max_songs_200=0x7f0900d9; public static final int settings_max_songs_200=0x7f0900db;
public static final int settings_max_songs_25=0x7f0900d5; public static final int settings_max_songs_25=0x7f0900d7;
public static final int settings_max_songs_5=0x7f0900d3; public static final int settings_max_songs_5=0x7f0900d5;
public static final int settings_max_songs_50=0x7f0900d6; public static final int settings_max_songs_50=0x7f0900d8;
public static final int settings_max_songs_500=0x7f0900da; public static final int settings_max_songs_500=0x7f0900dc;
public static final int settings_max_songs_75=0x7f0900d7; public static final int settings_max_songs_75=0x7f0900d9;
public static final int settings_media_button_summary=0x7f0900af; public static final int settings_media_button_summary=0x7f0900af;
public static final int settings_media_button_title=0x7f0900ae; public static final int settings_media_button_title=0x7f0900ae;
public static final int settings_network_timeout=0x7f0900b3; public static final int settings_network_timeout=0x7f0900b3;
@ -610,19 +610,21 @@ public final class R {
public static final int settings_theme_fullscreenlight=0x7f090083; public static final int settings_theme_fullscreenlight=0x7f090083;
public static final int settings_theme_light=0x7f090084; public static final int settings_theme_light=0x7f090084;
public static final int settings_theme_title=0x7f090081; public static final int settings_theme_title=0x7f090081;
public static final int settings_theme_wheat=0x7f090104; public static final int settings_theme_wheat=0x7f090106;
public static final int settings_title=0x7f09006c; public static final int settings_title=0x7f09006c;
public static final int settings_use_stream_proxy=0x7f0900c8;
public static final int settings_use_stream_proxy_summary=0x7f0900c9;
public static final int settings_wifi_required_summary=0x7f090095; public static final int settings_wifi_required_summary=0x7f090095;
public static final int settings_wifi_required_title=0x7f090094; public static final int settings_wifi_required_title=0x7f090094;
public static final int song_details_all=0x7f090068; public static final int song_details_all=0x7f090068;
public static final int song_details_kbps=0x7f090069; public static final int song_details_kbps=0x7f090069;
public static final int util_bytes_format_byte=0x7f090103; public static final int util_bytes_format_byte=0x7f090105;
public static final int util_bytes_format_gigabyte=0x7f090100; public static final int util_bytes_format_gigabyte=0x7f090102;
public static final int util_bytes_format_kilobyte=0x7f090102; public static final int util_bytes_format_kilobyte=0x7f090104;
public static final int util_bytes_format_megabyte=0x7f090101; public static final int util_bytes_format_megabyte=0x7f090103;
public static final int widget_initial_text=0x7f0900fd; public static final int widget_initial_text=0x7f0900ff;
public static final int widget_sdcard_busy=0x7f0900fe; public static final int widget_sdcard_busy=0x7f090100;
public static final int widget_sdcard_missing=0x7f0900ff; public static final int widget_sdcard_missing=0x7f090101;
} }
public static final class style { public static final class style {
public static final int Dark=0x7f0b0000; public static final int Dark=0x7f0b0000;

View File

@ -219,6 +219,8 @@
<string name="settings.show_notification_summary">Show now playing notification in the status bar</string> <string name="settings.show_notification_summary">Show now playing notification in the status bar</string>
<string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string> <string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string>
<string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string> <string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string>
<string name="settings.use_stream_proxy">Use Stream Proxy</string>
<string name="settings.use_stream_proxy_summary">Stream media playback through a proxy (may help stutter)</string>
<string name="settings.max_albums">Max Albums</string> <string name="settings.max_albums">Max Albums</string>
<string name="settings.max_albums_5">5</string> <string name="settings.max_albums_5">5</string>
<string name="settings.max_albums_10">10</string> <string name="settings.max_albums_10">10</string>

View File

@ -268,6 +268,12 @@
a:key="showLockScreen" a:key="showLockScreen"
a:defaultValue="true"/> a:defaultValue="true"/>
<CheckBoxPreference
a:title="@string/settings.use_stream_proxy"
a:summary="@string/settings.use_stream_proxy_summary"
a:key="useStreamProxy"
a:defaultValue="false"/>
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -117,10 +117,12 @@ public class SelectArtistActivity extends SubsonicTabActivity implements Adapter
@Override @Override
protected void done(Indexes result) { protected void done(Indexes result) {
List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size()); if (result != null) {
artists.addAll(result.getShortcuts()); List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
artists.addAll(result.getArtists()); artists.addAll(result.getShortcuts());
artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists)); artists.addAll(result.getArtists());
artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
}
// Display selected music folder // Display selected music folder
if (musicFolders != null) { if (musicFolders != null) {

View File

@ -20,6 +20,7 @@ package net.sourceforge.subsonic.androidapp.activity;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
@ -63,7 +64,8 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
private ListPreference defaultAlbums; private ListPreference defaultAlbums;
private ListPreference defaultSongs; private ListPreference defaultSongs;
private ListPreference defaultArtists; private ListPreference defaultArtists;
private CheckBoxPreference mediaButtonsEnabled;
private CheckBoxPreference lockScreenEnabled;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -84,6 +86,8 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
defaultArtists = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS); defaultArtists = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS);
defaultSongs = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_SONGS); defaultSongs = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_SONGS);
defaultAlbums = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS); defaultAlbums = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS);
mediaButtonsEnabled = (CheckBoxPreference) findPreference(Constants.PREFERENCES_KEY_MEDIA_BUTTONS);
lockScreenEnabled = (CheckBoxPreference) findPreference(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS);
findPreference("testConnection1").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { findPreference("testConnection1").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override @Override
@ -174,6 +178,11 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
defaultArtists.setSummary(defaultArtists.getEntry()); defaultArtists.setSummary(defaultArtists.getEntry());
defaultSongs.setSummary(defaultSongs.getEntry()); defaultSongs.setSummary(defaultSongs.getEntry());
if (!mediaButtonsEnabled.isChecked()) {
lockScreenEnabled.setChecked(false);
lockScreenEnabled.setEnabled(false);
}
for (ServerSettings ss : serverSettings.values()) { for (ServerSettings ss : serverSettings.values()) {
ss.update(); ss.update();
} }
@ -195,8 +204,10 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
private void setMediaButtonsEnabled(boolean enabled) { private void setMediaButtonsEnabled(boolean enabled) {
if (enabled) { if (enabled) {
lockScreenEnabled.setEnabled(true);
Util.registerMediaButtonEventReceiver(this); Util.registerMediaButtonEventReceiver(this);
} else { } else {
lockScreenEnabled.setEnabled(false);
Util.unregisterMediaButtonEventReceiver(this); Util.unregisterMediaButtonEventReceiver(this);
} }
} }

View File

@ -754,7 +754,6 @@ public class DownloadServiceImpl extends Service implements DownloadService {
audioManager.requestAudioFocus(_afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); audioManager.requestAudioFocus(_afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (remoteControlClientCompat == null) { if (remoteControlClientCompat == null) {
audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.setComponent(new ComponentName(this.getPackageName(), MediaButtonIntentReceiver.class.getName())); intent.setComponent(new ComponentName(this.getPackageName(), MediaButtonIntentReceiver.class.getName()));
remoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this, 0, intent, 0)); remoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this, 0, intent, 0));
@ -788,14 +787,14 @@ public class DownloadServiceImpl extends Service implements DownloadService {
if (currentSong != currentPlaying.getSong()) { if (currentSong != currentPlaying.getSong()) {
currentSong = currentPlaying.getSong(); currentSong = currentPlaying.getSong();
String album = currentPlaying.getSong().getAlbum(); String album = currentSong.getAlbum();
String title = currentPlaying.getSong().getArtist() + " - " + currentPlaying.getSong().getTitle(); String title = currentSong.getArtist() + " - " + currentSong.getTitle();
Integer duration = currentPlaying.getSong().getDuration(); Integer duration = currentSong.getDuration();
MusicService musicService = MusicServiceFactory.getMusicService(this); MusicService musicService = MusicServiceFactory.getMusicService(this);
DisplayMetrics metrics = this.getResources().getDisplayMetrics(); DisplayMetrics metrics = this.getResources().getDisplayMetrics();
int size = Math.min(metrics.widthPixels, metrics.heightPixels); int size = Math.min(metrics.widthPixels, metrics.heightPixels);
Bitmap bitmap = musicService.getCoverArt(this, currentPlaying.getSong(), size, true, null); Bitmap bitmap = musicService.getCoverArt(this, currentSong, size, true, null);
// Update the remote controls // Update the remote controls
remoteControlClientCompat remoteControlClientCompat
@ -821,7 +820,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
bufferTask.start(); bufferTask.start();
} }
private synchronized void doPlay(final DownloadFile downloadFile, int position, boolean start) { private synchronized void doPlay(final DownloadFile downloadFile, final int position, final boolean start) {
try { try {
final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
downloadFile.updateModificationDate(); downloadFile.updateModificationDate();
@ -834,7 +833,9 @@ public class DownloadServiceImpl extends Service implements DownloadService {
@Override @Override
public void onBufferingUpdate(MediaPlayer mp, int percent) { public void onBufferingUpdate(MediaPlayer mp, int percent) {
SeekBar progressBar = DownloadActivity.getProgressBar(); SeekBar progressBar = DownloadActivity.getProgressBar();
if (progressBar != null) { MusicDirectory.Entry song = downloadFile.getSong();
if (progressBar != null && song.getTranscodedContentType() == null && Util.getMaxBitrate(getApplicationContext()) == 0) {
int secondaryProgress = (int) (((double)percent / (double)100) * progressBar.getMax()); int secondaryProgress = (int) (((double)percent / (double)100) * progressBar.getMax());
DownloadActivity.getProgressBar().setSecondaryProgress(secondaryProgress); DownloadActivity.getProgressBar().setSecondaryProgress(secondaryProgress);
} }
@ -846,17 +847,40 @@ public class DownloadServiceImpl extends Service implements DownloadService {
String url = file.getPath(); String url = file.getPath();
String playUrl = url; String playUrl = url;
if (proxy == null) { if (Util.isStreamProxyEnabled(this)) {
proxy = new StreamProxy(this); if (proxy == null) {
proxy.start(); proxy = new StreamProxy();
} proxy.start();
}
playUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url); proxy.setDownloadFile(downloadFile);
playUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url);
}
mediaPlayer.setDataSource(playUrl); mediaPlayer.setDataSource(playUrl);
setPlayerState(PREPARING); setPlayerState(PREPARING);
mediaPlayer.prepare(); mediaPlayer.prepareAsync();
setPlayerState(PREPARED);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
setPlayerState(PREPARED);
if (position != 0) {
Log.i(TAG, "Restarting player from position " + position);
mp.seekTo(position);
}
if (start) {
mp.start();
setPlayerState(STARTED);
} else {
setPlayerState(PAUSED);
}
lifecycleSupport.serializeDownloadQueue();
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override @Override
@ -883,6 +907,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
// Work-around for apparent bug on certain phones: If close (less than ten seconds) to the end // Work-around for apparent bug on certain phones: If close (less than ten seconds) to the end
// of the song, skip to the next rather than restarting it. // of the song, skip to the next rather than restarting it.
Integer duration = downloadFile.getSong().getDuration() == null ? null : downloadFile.getSong().getDuration() * 1000; Integer duration = downloadFile.getSong().getDuration() == null ? null : downloadFile.getSong().getDuration() * 1000;
if (duration != null) { if (duration != null) {
if (Math.abs(duration - pos) < 10000) { if (Math.abs(duration - pos) < 10000) {
Log.i(TAG, "Skipping restart from " + pos + " of " + duration); Log.i(TAG, "Skipping restart from " + pos + " of " + duration);
@ -898,20 +923,6 @@ public class DownloadServiceImpl extends Service implements DownloadService {
} }
} }
}); });
if (position != 0) {
Log.i(TAG, "Restarting player from position " + position);
mediaPlayer.seekTo(position);
}
if (start) {
mediaPlayer.start();
setPlayerState(STARTED);
} else {
setPlayerState(PAUSED);
}
lifecycleSupport.serializeDownloadQueue();
} catch (Exception x) { } catch (Exception x) {
handleError(x); handleError(x);
} }

View File

@ -85,6 +85,7 @@ public final class Constants {
public static final String PREFERENCES_KEY_DEFAULT_ALBUMS = "defaultAlbums"; public static final String PREFERENCES_KEY_DEFAULT_ALBUMS = "defaultAlbums";
public static final String PREFERENCES_KEY_DEFAULT_SONGS = "defaultSongs"; public static final String PREFERENCES_KEY_DEFAULT_SONGS = "defaultSongs";
public static final String PREFERENCES_KEY_DEFAULT_ARTISTS = "defaultArtists"; public static final String PREFERENCES_KEY_DEFAULT_ARTISTS = "defaultArtists";
public static final String PREFERENCES_KEY_USE_STREAM_PROXY = "useStreamProxy";
// Name of the preferences file. // Name of the preferences file.
public static final String PREFERENCES_FILE_NAME = "net.sourceforge.subsonic.androidapp_preferences"; public static final String PREFERENCES_FILE_NAME = "net.sourceforge.subsonic.androidapp_preferences";

View File

@ -22,6 +22,7 @@ import org.apache.http.Header;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
import org.apache.http.message.BasicHttpRequest; import org.apache.http.message.BasicHttpRequest;
import net.sourceforge.subsonic.androidapp.service.DownloadFile;
import net.sourceforge.subsonic.androidapp.service.DownloadService; import net.sourceforge.subsonic.androidapp.service.DownloadService;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Looper; import android.os.Looper;
@ -34,22 +35,26 @@ public class StreamProxy implements Runnable {
private boolean isRunning; private boolean isRunning;
private ServerSocket socket; private ServerSocket socket;
private int port; private int port;
private DownloadService downloadService; private DownloadFile downloadFile;
public StreamProxy(DownloadService downloadService) { public StreamProxy() {
// Create listening socket // Create listening socket
try { try {
socket = new ServerSocket(0, 0, InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 })); socket = new ServerSocket(0, 0, InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }));
socket.setSoTimeout(5000); socket.setSoTimeout(5000);
port = socket.getLocalPort(); port = socket.getLocalPort();
this.downloadService = downloadService;
} catch (UnknownHostException e) { // impossible } catch (UnknownHostException e) { // impossible
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "IOException initializing server", e); Log.e(TAG, "IOException initializing server", e);
} }
} }
public void setDownloadFile(DownloadFile downloadFile) {
this.downloadFile = downloadFile;
}
public int getPort() { public int getPort() {
return port; return port;
} }
@ -73,31 +78,34 @@ public class StreamProxy implements Runnable {
public void run() { public void run() {
Looper.prepare(); Looper.prepare();
isRunning = true; isRunning = true;
while (isRunning) { while (isRunning) {
try { try {
Socket client = socket.accept(); Socket client = socket.accept();
if (client == null) { if (client == null) {
continue; continue;
} }
Log.d(TAG, "client connected"); Log.d(TAG, "client connected");
StreamToMediaPlayerTask task = new StreamToMediaPlayerTask(client); StreamToMediaPlayerTask task = new StreamToMediaPlayerTask(client);
if (task.processRequest()) { if (task.processRequest()) {
task.execute(); task.execute();
} }
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
// Do nothing // Do nothing
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Error connecting to client", e); Log.e(TAG, "Error connecting to client", e);
} }
} }
Log.d(TAG, "Proxy interrupted. Shutting down."); Log.d(TAG, "Proxy interrupted. Shutting down.");
} }
private class StreamToMediaPlayerTask extends AsyncTask<String, Void, Integer> { private class StreamToMediaPlayerTask extends AsyncTask<String, Void, Integer> {
File thisFile;
String localPath;
Socket client; Socket client;
int cbSkip; int cbSkip;
@ -135,23 +143,17 @@ public class StreamProxy implements Runnable {
public boolean processRequest() { public boolean processRequest() {
HttpRequest request = readRequest(); HttpRequest request = readRequest();
if (request == null) { if (request == null) {
return false; return false;
} }
// Read HTTP headers
Log.d(TAG, "Processing request"); Log.d(TAG, "Processing request");
try { thisFile = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
localPath = URLDecoder.decode(request.getRequestLine().getUri(), Constants.UTF_8);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported encoding", e);
return false;
}
File file = new File(localPath); if (!thisFile.exists()) {
if (!file.exists()) { Log.e(TAG, "File " + thisFile.getPath() + " does not exist");
Log.e(TAG, "File " + localPath + " does not exist");
return false; return false;
} }
@ -159,83 +161,96 @@ public class StreamProxy implements Runnable {
} }
@Override @Override
protected Integer doInBackground(String... params) { protected Integer doInBackground(String... params) {
long fileSize = downloadService.getCurrentPlaying().getSong().getSize(); long fileSize = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile().length() : downloadFile.getSong().getSize();
// Create HTTP header // Create HTTP header
String headers = "HTTP/1.0 200 OK\r\n"; String headers = "HTTP/1.1 200 OK\r\n";
headers += "Content-Type: " + "application/octet-stream" + "\r\n";
if (fileSize > 0) { if (fileSize > 0) {
headers += "Content-Length: " + fileSize + "\r\n"; headers += "Content-Length: " + fileSize + "\r\n";
} }
headers += "Connection: close\r\n"; headers += "Accept-Ranges: bytes\r\n";
headers += "\r\n"; headers += "Content-Type: " + "application/octet-stream" + "\r\n";
headers += "Connection: close\r\n";
headers += "\r\n";
long cbToSend = fileSize - cbSkip; long cbToSend = fileSize - cbSkip;
OutputStream output = null; long totalBytesSent = 0;
byte[] buff = new byte[64 * 1024]; OutputStream output = null;
try { byte[] buff = new byte[64 * 1024];
output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
output.write(headers.getBytes());
// Loop as long as there's stuff to send try {
while (isRunning && cbToSend>0 && !client.isClosed()) { output = new BufferedOutputStream(client.getOutputStream(), 32 * 1024);
output.write(headers.getBytes());
// See if there's more to send // Loop as long as there's stuff to send
File file = new File(localPath); while (isRunning && cbToSend > 0 && !client.isClosed()) {
int cbSentThisBatch = 0; // See if there's more to send
if (file.exists()) { int cbSentThisBatch = 0;
FileInputStream input = new FileInputStream(file);
input.skip(cbSkip);
int cbToSendThisBatch = input.available();
while (cbToSendThisBatch > 0) {
int cbToRead = Math.min(cbToSendThisBatch, buff.length);
int cbRead = input.read(buff, 0, cbToRead);
if (cbRead == -1) {
break;
}
cbToSendThisBatch -= cbRead;
cbToSend -= cbRead;
output.write(buff, 0, cbRead);
output.flush();
cbSkip += cbRead;
cbSentThisBatch += cbRead;
}
input.close();
}
// If we did nothing this batch, block for a second FileInputStream input = new FileInputStream(thisFile);
if (cbSentThisBatch == 0) { input.skip(cbSkip);
Log.d(TAG, "Blocking until more data appears"); int cbToSendThisBatch = input.available();
Thread.sleep(1000);
}
}
}
catch (SocketException socketException) {
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
}
catch (Exception e) {
Log.e(TAG, "Exception thrown from streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
e.printStackTrace();
}
// Cleanup while (cbToSendThisBatch > 0) {
try { int cbToRead = Math.min(cbToSendThisBatch, buff.length);
if (output != null) { int cbRead = input.read(buff, 0, cbToRead);
output.close();
}
client.close();
}
catch (IOException e) {
Log.e(TAG, "IOException while cleaning up streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
e.printStackTrace();
}
return 1; if (cbRead == -1) {
} break;
}
cbToSendThisBatch -= cbRead;
cbToSend -= cbRead;
output.write(buff, 0, cbRead);
output.flush();
cbSkip += cbRead;
cbSentThisBatch += cbRead;
totalBytesSent += cbRead;
}
input.close();
if (!downloadFile.isDownloading()) {
if (downloadFile.isCompleteFileAvailable()) {
if (downloadFile.getCompleteFile().length() == totalBytesSent) {
Log.d(TAG, "Track is no longer being downloaded, sent " + totalBytesSent + " / " + fileSize);
break;
}
}
}
// If we did nothing this batch, block for a second
if (cbSentThisBatch == 0) {
Log.d(TAG, "Blocking until more data appears");
Thread.sleep(500);
}
}
} catch (SocketException socketException) {
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
} catch (Exception e) {
Log.e(TAG, "Exception thrown from streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
e.printStackTrace();
}
// Cleanup
try {
if (output != null) {
output.close();
}
client.close();
} catch (IOException e) {
Log.e(TAG, "IOException while cleaning up streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
e.printStackTrace();
}
return 1;
}
} }
} }

View File

@ -147,6 +147,11 @@ public class Util extends DownloadActivity {
return prefs.getBoolean(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS, false); return prefs.getBoolean(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS, false);
} }
public static boolean isStreamProxyEnabled(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_USE_STREAM_PROXY, false);
}
public static void setActiveServer(Context context, int instance) { public static void setActiveServer(Context context, int instance) {
SharedPreferences prefs = getPreferences(context); SharedPreferences prefs = getPreferences(context);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();