Make StreamProxy optional, prepareAsync for MediaPlayer, code fixups in StreamProxy
This commit is contained in:
parent
d8418254ef
commit
793f5b4464
|
@ -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"/>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue