mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 13:02:35 +00:00
Experimental changes that use AndroidVideoCache library as a local
streaming proxy -- it, in theory, controls caching and retries better than OkHttp.
This commit is contained in:
parent
a5b7ab5107
commit
ab11376356
@ -41,13 +41,16 @@ dependencies {
|
|||||||
|
|
||||||
compile(name:'android-taskrunner-0.5', ext:'aar')
|
compile(name:'android-taskrunner-0.5', ext:'aar')
|
||||||
|
|
||||||
|
compile(name:'videocache-2.8.0-pre', ext:'aar')
|
||||||
|
compile 'org.slf4j:slf4j-android:1.7.21'
|
||||||
|
|
||||||
compile 'com.neovisionaries:nv-websocket-client:1.31'
|
compile 'com.neovisionaries:nv-websocket-client:1.31'
|
||||||
compile 'com.squareup.okhttp3:okhttp:3.6.0'
|
compile 'com.squareup.okhttp3:okhttp:3.6.0'
|
||||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
compile 'com.github.bumptech.glide:glide:3.7.0'
|
||||||
compile 'io.reactivex.rxjava2:rxjava:2.0.9'
|
compile 'io.reactivex.rxjava2:rxjava:2.0.9'
|
||||||
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
||||||
compile 'com.google.android.exoplayer:exoplayer:r2.4.0'
|
compile 'com.google.android.exoplayer:exoplayer:r2.4.1'
|
||||||
compile 'com.google.android.exoplayer:extension-okhttp:r2.4.0'
|
compile 'com.google.android.exoplayer:extension-okhttp:r2.4.1'
|
||||||
compile 'com.github.pluscubed:recycler-fast-scroll:0.3.2@aar'
|
compile 'com.github.pluscubed:recycler-fast-scroll:0.3.2@aar'
|
||||||
|
|
||||||
compile 'com.android.support:appcompat-v7:25.3.1'
|
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||||
|
BIN
src/musikdroid/app/libs/videocache-2.8.0-pre.aar
Normal file
BIN
src/musikdroid/app/libs/videocache-2.8.0-pre.aar
Normal file
Binary file not shown.
@ -1,12 +1,17 @@
|
|||||||
package io.casey.musikcube.remote;
|
package io.casey.musikcube.remote;
|
||||||
|
|
||||||
|
import io.casey.musikcube.remote.playback.StreamProxy;
|
||||||
|
import io.casey.musikcube.remote.util.NetworkUtil;
|
||||||
|
|
||||||
public class Application extends android.app.Application {
|
public class Application extends android.app.Application {
|
||||||
private static Application instance;
|
private static Application instance;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
|
||||||
instance = this;
|
instance = this;
|
||||||
|
super.onCreate();
|
||||||
|
NetworkUtil.init();
|
||||||
|
StreamProxy.init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Application getInstance() {
|
public static Application getInstance() {
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package io.casey.musikcube.remote.playback;
|
package io.casey.musikcube.remote.playback;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Base64;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
@ -11,7 +9,6 @@ import com.google.android.exoplayer2.ExoPlayerFactory;
|
|||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory;
|
|
||||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||||
@ -28,107 +25,26 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
|||||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import io.casey.musikcube.remote.Application;
|
import io.casey.musikcube.remote.Application;
|
||||||
import io.casey.musikcube.remote.util.NetworkUtil;
|
|
||||||
import io.casey.musikcube.remote.util.Preconditions;
|
import io.casey.musikcube.remote.util.Preconditions;
|
||||||
import io.casey.musikcube.remote.websocket.Prefs;
|
|
||||||
import okhttp3.Cache;
|
|
||||||
import okhttp3.Interceptor;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
public class ExoPlayerWrapper extends PlayerWrapper {
|
public class ExoPlayerWrapper extends PlayerWrapper {
|
||||||
private static OkHttpClient audioStreamHttpClient = null;
|
|
||||||
|
|
||||||
private static final long BYTES_PER_MEGABYTE = 1048576L;
|
|
||||||
private static final long BYTES_PER_GIGABYTE = 1073741824L;
|
|
||||||
private static final Map<Integer, Long> CACHE_SETTING_TO_BYTES;
|
|
||||||
|
|
||||||
static {
|
|
||||||
CACHE_SETTING_TO_BYTES = new HashMap<>();
|
|
||||||
CACHE_SETTING_TO_BYTES.put(0, BYTES_PER_MEGABYTE * 32);
|
|
||||||
CACHE_SETTING_TO_BYTES.put(1, BYTES_PER_GIGABYTE / 2);
|
|
||||||
CACHE_SETTING_TO_BYTES.put(2, BYTES_PER_GIGABYTE);
|
|
||||||
CACHE_SETTING_TO_BYTES.put(3, BYTES_PER_GIGABYTE * 2);
|
|
||||||
CACHE_SETTING_TO_BYTES.put(4, BYTES_PER_GIGABYTE * 3);
|
|
||||||
CACHE_SETTING_TO_BYTES.put(5, BYTES_PER_GIGABYTE * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DefaultBandwidthMeter bandwidth;
|
|
||||||
private DataSource.Factory datasources;
|
private DataSource.Factory datasources;
|
||||||
private ExtractorsFactory extractors;
|
private ExtractorsFactory extractors;
|
||||||
private MediaSource source;
|
private MediaSource source;
|
||||||
private SimpleExoPlayer player;
|
private SimpleExoPlayer player;
|
||||||
private boolean prefetch;
|
private boolean prefetch;
|
||||||
private Context context;
|
private Context context;
|
||||||
private SharedPreferences prefs;
|
|
||||||
|
|
||||||
public static void invalidateSettings() {
|
|
||||||
synchronized (ExoPlayerWrapper.class) {
|
|
||||||
audioStreamHttpClient = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExoPlayerWrapper() {
|
public ExoPlayerWrapper() {
|
||||||
this.context = Application.getInstance();
|
this.context = Application.getInstance();
|
||||||
this.prefs = context.getSharedPreferences(Prefs.NAME, Context.MODE_PRIVATE);
|
final DefaultBandwidthMeter bandwidth = new DefaultBandwidthMeter();
|
||||||
this.bandwidth = new DefaultBandwidthMeter();
|
|
||||||
final TrackSelection.Factory trackFactory = new AdaptiveTrackSelection.Factory(bandwidth);
|
final TrackSelection.Factory trackFactory = new AdaptiveTrackSelection.Factory(bandwidth);
|
||||||
final TrackSelector trackSelector = new DefaultTrackSelector(trackFactory);
|
final TrackSelector trackSelector = new DefaultTrackSelector(trackFactory);
|
||||||
this.player = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector);
|
this.player = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector);
|
||||||
this.extractors = new DefaultExtractorsFactory();
|
this.extractors = new DefaultExtractorsFactory();
|
||||||
this.player.addListener(eventListener);
|
this.player.addListener(eventListener);
|
||||||
}
|
this.datasources = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "musikdroid"));
|
||||||
|
|
||||||
private void initHttpClient(final String uri) {
|
|
||||||
final Context context = Application.getInstance();
|
|
||||||
|
|
||||||
synchronized (ExoPlayerWrapper.class) {
|
|
||||||
if (audioStreamHttpClient == null) {
|
|
||||||
final SharedPreferences prefs = ExoPlayerWrapper.this.prefs;
|
|
||||||
final File path = new File(context.getExternalCacheDir(), "audio");
|
|
||||||
|
|
||||||
int diskCacheIndex = this.prefs.getInt(
|
|
||||||
Prefs.Key.DISK_CACHE_SIZE_INDEX, Prefs.Default.DISK_CACHE_SIZE_INDEX);
|
|
||||||
|
|
||||||
if (diskCacheIndex < 0 || diskCacheIndex > CACHE_SETTING_TO_BYTES.size()) {
|
|
||||||
diskCacheIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
final OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
|
||||||
.cache(new Cache(path, CACHE_SETTING_TO_BYTES.get(diskCacheIndex)))
|
|
||||||
.addInterceptor((chain) -> {
|
|
||||||
Request request = chain.request();
|
|
||||||
final String userPass = "default:" + prefs.getString(Prefs.Key.PASSWORD, Prefs.Default.PASSWORD);
|
|
||||||
final String encoded = Base64.encodeToString(userPass.getBytes(), Base64.NO_WRAP);
|
|
||||||
request = request.newBuilder().addHeader("Authorization", "Basic " + encoded).build();
|
|
||||||
return chain.proceed(request);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.prefs.getBoolean(Prefs.Key.CERT_VALIDATION_DISABLED, Prefs.Default.CERT_VALIDATION_DISABLED)) {
|
|
||||||
NetworkUtil.disableCertificateValidation(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
audioStreamHttpClient = builder.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uri.startsWith("http")) {
|
|
||||||
this.datasources = new OkHttpDataSourceFactory(
|
|
||||||
audioStreamHttpClient,
|
|
||||||
Util.getUserAgent(context, "musikdroid"),
|
|
||||||
bandwidth);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.datasources = new DefaultDataSourceFactory(
|
|
||||||
context, Util.getUserAgent(context, "musikdroid"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -136,8 +52,8 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
|||||||
Preconditions.throwIfNotOnMainThread();
|
Preconditions.throwIfNotOnMainThread();
|
||||||
|
|
||||||
if (!dead()) {
|
if (!dead()) {
|
||||||
initHttpClient(uri);
|
final String proxyUri = StreamProxy.getProxyUrl(context, uri);
|
||||||
this.source = new ExtractorMediaSource(Uri.parse(uri), datasources, extractors, null, null);
|
this.source = new ExtractorMediaSource(Uri.parse(proxyUri), datasources, extractors, null, null);
|
||||||
this.player.setPlayWhenReady(true);
|
this.player.setPlayWhenReady(true);
|
||||||
this.player.prepare(this.source);
|
this.player.prepare(this.source);
|
||||||
addActivePlayer(this);
|
addActivePlayer(this);
|
||||||
@ -150,9 +66,9 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
|||||||
Preconditions.throwIfNotOnMainThread();
|
Preconditions.throwIfNotOnMainThread();
|
||||||
|
|
||||||
if (!dead()) {
|
if (!dead()) {
|
||||||
initHttpClient(uri);
|
|
||||||
this.prefetch = true;
|
this.prefetch = true;
|
||||||
this.source = new ExtractorMediaSource(Uri.parse(uri), datasources, extractors, null, null);
|
final String proxyUri = StreamProxy.getProxyUrl(context, uri);
|
||||||
|
this.source = new ExtractorMediaSource(Uri.parse(proxyUri), datasources, extractors, null, null);
|
||||||
this.player.setPlayWhenReady(false);
|
this.player.setPlayWhenReady(false);
|
||||||
this.player.prepare(this.source);
|
this.player.prepare(this.source);
|
||||||
addActivePlayer(this);
|
addActivePlayer(this);
|
||||||
@ -198,9 +114,11 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
|||||||
Preconditions.throwIfNotOnMainThread();
|
Preconditions.throwIfNotOnMainThread();
|
||||||
|
|
||||||
if (this.player.getPlaybackState() != ExoPlayer.STATE_IDLE) {
|
if (this.player.getPlaybackState() != ExoPlayer.STATE_IDLE) {
|
||||||
|
if (this.player.isCurrentWindowSeekable()) {
|
||||||
this.player.seekTo(millis);
|
this.player.seekTo(millis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPosition() {
|
public int getPosition() {
|
||||||
@ -258,7 +176,6 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
|||||||
private ExoPlayer.EventListener eventListener = new ExoPlayer.EventListener() {
|
private ExoPlayer.EventListener eventListener = new ExoPlayer.EventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -303,26 +220,6 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
|||||||
public void onPlayerError(ExoPlaybackException error) {
|
public void onPlayerError(ExoPlaybackException error) {
|
||||||
Preconditions.throwIfNotOnMainThread();
|
Preconditions.throwIfNotOnMainThread();
|
||||||
|
|
||||||
/* if we're transcoding the size of the response will be inexact, so the player
|
|
||||||
will try to pick up the last few bytes and be left with an HTTP 416. if that happens,
|
|
||||||
and we're towards the end of the track, just move to the next one */
|
|
||||||
if (error.getCause() instanceof HttpDataSource.InvalidResponseCodeException) {
|
|
||||||
final HttpDataSource.InvalidResponseCodeException ex
|
|
||||||
= (HttpDataSource.InvalidResponseCodeException) error.getCause();
|
|
||||||
|
|
||||||
if (ex.responseCode == 416) {
|
|
||||||
if (Math.abs(getDuration() - getPosition()) < 2000) {
|
|
||||||
setState(State.Finished);
|
|
||||||
dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
player.setPlayWhenReady(false);
|
|
||||||
setPosition(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (getState()) {
|
switch (getState()) {
|
||||||
case Preparing:
|
case Preparing:
|
||||||
case Prepared:
|
case Prepared:
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package io.casey.musikcube.remote.playback;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Base64;
|
||||||
|
|
||||||
|
import com.danikula.videocache.HttpProxyCacheServer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.casey.musikcube.remote.util.NetworkUtil;
|
||||||
|
import io.casey.musikcube.remote.websocket.Prefs;
|
||||||
|
|
||||||
|
public class StreamProxy {
|
||||||
|
private static final long BYTES_PER_MEGABYTE = 1048576L;
|
||||||
|
private static final long BYTES_PER_GIGABYTE = 1073741824L;
|
||||||
|
private static final Map<Integer, Long> CACHE_SETTING_TO_BYTES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
CACHE_SETTING_TO_BYTES = new HashMap<>();
|
||||||
|
CACHE_SETTING_TO_BYTES.put(0, BYTES_PER_MEGABYTE * 32);
|
||||||
|
CACHE_SETTING_TO_BYTES.put(1, BYTES_PER_GIGABYTE / 2);
|
||||||
|
CACHE_SETTING_TO_BYTES.put(2, BYTES_PER_GIGABYTE);
|
||||||
|
CACHE_SETTING_TO_BYTES.put(3, BYTES_PER_GIGABYTE * 2);
|
||||||
|
CACHE_SETTING_TO_BYTES.put(4, BYTES_PER_GIGABYTE * 3);
|
||||||
|
CACHE_SETTING_TO_BYTES.put(5, BYTES_PER_GIGABYTE * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StreamProxy INSTANCE;
|
||||||
|
|
||||||
|
private HttpProxyCacheServer proxy;
|
||||||
|
private SharedPreferences prefs;
|
||||||
|
|
||||||
|
private StreamProxy(final Context context) {
|
||||||
|
prefs = context.getSharedPreferences(Prefs.NAME, Context.MODE_PRIVATE);
|
||||||
|
|
||||||
|
if (this.prefs.getBoolean(Prefs.Key.CERT_VALIDATION_DISABLED, Prefs.Default.CERT_VALIDATION_DISABLED)) {
|
||||||
|
NetworkUtil.disableCertificateValidation();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NetworkUtil.enableCertificateValidation();
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskCacheIndex = this.prefs.getInt(
|
||||||
|
Prefs.Key.DISK_CACHE_SIZE_INDEX, Prefs.Default.DISK_CACHE_SIZE_INDEX);
|
||||||
|
|
||||||
|
if (diskCacheIndex < 0 || diskCacheIndex > CACHE_SETTING_TO_BYTES.size()) {
|
||||||
|
diskCacheIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File cachePath = new File(context.getExternalCacheDir(), "audio");
|
||||||
|
|
||||||
|
proxy = new HttpProxyCacheServer.Builder(context.getApplicationContext())
|
||||||
|
.cacheDirectory(cachePath)
|
||||||
|
.maxCacheSize(CACHE_SETTING_TO_BYTES.get(diskCacheIndex))
|
||||||
|
.headerInjector((url) -> {
|
||||||
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
final String userPass = "default:" + prefs.getString(Prefs.Key.PASSWORD, Prefs.Default.PASSWORD);
|
||||||
|
final String encoded = Base64.encodeToString(userPass.getBytes(), Base64.NO_WRAP);
|
||||||
|
headers.put("Authorization", "Basic " + encoded);
|
||||||
|
return headers;
|
||||||
|
}).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void init(final Context context) {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = new StreamProxy(context.getApplicationContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized String getProxyUrl(final Context context, final String url) {
|
||||||
|
init(context);
|
||||||
|
return INSTANCE.proxy.getProxyUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void reload() {
|
||||||
|
if (INSTANCE != null) {
|
||||||
|
INSTANCE.proxy.shutdown();
|
||||||
|
INSTANCE = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,9 +22,9 @@ import android.widget.Spinner;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import io.casey.musikcube.remote.R;
|
import io.casey.musikcube.remote.R;
|
||||||
import io.casey.musikcube.remote.playback.ExoPlayerWrapper;
|
|
||||||
import io.casey.musikcube.remote.playback.MediaPlayerWrapper;
|
import io.casey.musikcube.remote.playback.MediaPlayerWrapper;
|
||||||
import io.casey.musikcube.remote.playback.PlaybackServiceFactory;
|
import io.casey.musikcube.remote.playback.PlaybackServiceFactory;
|
||||||
|
import io.casey.musikcube.remote.playback.StreamProxy;
|
||||||
import io.casey.musikcube.remote.ui.util.Views;
|
import io.casey.musikcube.remote.ui.util.Views;
|
||||||
import io.casey.musikcube.remote.websocket.Prefs;
|
import io.casey.musikcube.remote.websocket.Prefs;
|
||||||
import io.casey.musikcube.remote.websocket.WebSocketService;
|
import io.casey.musikcube.remote.websocket.WebSocketService;
|
||||||
@ -211,7 +211,7 @@ public class SettingsActivity extends AppCompatActivity {
|
|||||||
PlaybackServiceFactory.streaming(this).stop();
|
PlaybackServiceFactory.streaming(this).stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExoPlayerWrapper.invalidateSettings();
|
StreamProxy.reload();
|
||||||
WebSocketService.getInstance(this).disconnect();
|
WebSocketService.getInstance(this).disconnect();
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
|
@ -4,6 +4,8 @@ import com.neovisionaries.ws.client.WebSocketFactory;
|
|||||||
|
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
@ -13,11 +15,31 @@ import okhttp3.OkHttpClient;
|
|||||||
|
|
||||||
public class NetworkUtil {
|
public class NetworkUtil {
|
||||||
private static SSLContext sslContext;
|
private static SSLContext sslContext;
|
||||||
private static SSLSocketFactory sslSocketFactory;
|
private static SSLSocketFactory insecureSslSocketFactory;
|
||||||
|
|
||||||
|
private static SSLSocketFactory originalHttpsUrlConnectionSocketFactory;
|
||||||
|
private static HostnameVerifier originalHttpsUrlConnectionHostnameVerifier;
|
||||||
|
|
||||||
|
public synchronized static void init() {
|
||||||
|
if (originalHttpsUrlConnectionHostnameVerifier == null) {
|
||||||
|
originalHttpsUrlConnectionSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
|
||||||
|
originalHttpsUrlConnectionHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sslContext == null) {
|
||||||
|
try {
|
||||||
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
|
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||||
|
insecureSslSocketFactory = sslContext.getSocketFactory();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void disableCertificateValidation(final OkHttpClient.Builder okHttpClient) {
|
public static void disableCertificateValidation(final OkHttpClient.Builder okHttpClient) {
|
||||||
init();
|
okHttpClient.sslSocketFactory(insecureSslSocketFactory, (X509TrustManager)trustAllCerts[0]);
|
||||||
okHttpClient.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
|
|
||||||
okHttpClient.hostnameVerifier((hostname, session) -> true);
|
okHttpClient.hostnameVerifier((hostname, session) -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,14 +47,23 @@ public class NetworkUtil {
|
|||||||
socketFactory.setSSLContext(sslContext);
|
socketFactory.setSSLContext(sslContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized static void init() {
|
public static void disableCertificateValidation() {
|
||||||
try {
|
try {
|
||||||
sslContext = SSLContext.getInstance("TLS");
|
HttpsURLConnection.setDefaultSSLSocketFactory(insecureSslSocketFactory);
|
||||||
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
|
HttpsURLConnection.setDefaultHostnameVerifier((url, session) -> true);
|
||||||
sslSocketFactory = sslContext.getSocketFactory();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception e) {
|
||||||
throw new RuntimeException (ex);
|
throw new RuntimeException("should never happen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void enableCertificateValidation() {
|
||||||
|
try {
|
||||||
|
HttpsURLConnection.setDefaultSSLSocketFactory(originalHttpsUrlConnectionSocketFactory);
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier(originalHttpsUrlConnectionHostnameVerifier);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException("should never happen");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,8 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#define HTTP_416_DISABLED true
|
||||||
|
|
||||||
using namespace musik::core::sdk;
|
using namespace musik::core::sdk;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> CONTENT_TYPE_MAP = {
|
std::unordered_map<std::string, std::string> CONTENT_TYPE_MAP = {
|
||||||
@ -357,6 +359,15 @@ int HttpServer::HandleRequest(
|
|||||||
if (range->from != 0 || range->to != range->total - 1) {
|
if (range->from != 0 || range->to != range->total - 1) {
|
||||||
delete range;
|
delete range;
|
||||||
|
|
||||||
|
if (HTTP_416_DISABLED) {
|
||||||
|
/* lots of clients don't seem to be to deal with 416 properly;
|
||||||
|
instead, ignore the range header and return the whole file,
|
||||||
|
and a 200 (not 206) */
|
||||||
|
if (file) {
|
||||||
|
range = parseRange(file, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (file) {
|
if (file) {
|
||||||
file->Destroy();
|
file->Destroy();
|
||||||
file = nullptr;
|
file = nullptr;
|
||||||
@ -379,6 +390,7 @@ int HttpServer::HandleRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
size_t length = (range->to - range->from);
|
size_t length = (range->to - range->from);
|
||||||
@ -394,6 +406,9 @@ int HttpServer::HandleRequest(
|
|||||||
if (!isOnDemandTranscoder) {
|
if (!isOnDemandTranscoder) {
|
||||||
MHD_add_response_header(response, "Accept-Ranges", "bytes");
|
MHD_add_response_header(response, "Accept-Ranges", "bytes");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
MHD_add_response_header(response, "X-musikcube-Estimated-Content-Length", "true");
|
||||||
|
}
|
||||||
|
|
||||||
if (byExternalId) {
|
if (byExternalId) {
|
||||||
/* if we're using an on-demand transcoder, ensure the client does not cache the
|
/* if we're using an on-demand transcoder, ensure the client does not cache the
|
||||||
|
Loading…
Reference in New Issue
Block a user