Skip to content

Commit

Permalink
optimize featching source data
Browse files Browse the repository at this point in the history
  • Loading branch information
danikula committed Sep 11, 2015
1 parent c0ef7dd commit f8f19c5
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 41 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repositories {
maven { url 'https://dl.bintray.com/alexeydanilov/maven' }
}
dependencies {
compile 'com.danikula:videocache:2.0.7'
compile 'com.danikula:videocache:2.0.9'
}
```

Expand Down
2 changes: 1 addition & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ publish {
userOrg = 'alexeydanilov'
groupId = 'com.danikula'
artifactId = 'videocache'
publishVersion = '2.0.7'
publishVersion = '2.0.9'
description = 'Cache support for android VideoView'
website = 'https://github.com/danikula/AndroidVideoCache'
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ private void processSocket(Socket socket) {
onError(new ProxyCacheException("Error processing request", e));
} finally {
releaseSocket(socket);
Log.d(LOG_TAG, "Opened connections: " + getClientsCount());
}
}

Expand All @@ -164,6 +165,16 @@ private HttpProxyCacheServerClients getClients(String url) throws ProxyCacheExce
}
}

private int getClientsCount() {
synchronized (clientsLock) {
int count = 0;
for (HttpProxyCacheServerClients clients : clientsMap.values()) {
count += clients.getClientsCount();
}
return count;
}
}

private void releaseSocket(Socket socket) {
closeSocketInput(socket);
closeSocketOutput(socket);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,23 @@ public HttpProxyCacheServerClients(String url, FileNameGenerator fileNameGenerat
}

public void processRequest(GetRequest request, Socket socket) throws ProxyCacheException, IOException {
proxyCache = proxyCache == null ? newHttpProxyCache() : proxyCache;
startProcessRequest();
try {
clientsCount.incrementAndGet();
proxyCache.processRequest(request, socket);
} finally {
int count = clientsCount.decrementAndGet();
if (count <= 0) {
proxyCache.shutdown();
proxyCache = null;
}
finishProcessRequest();
}
}

private synchronized void startProcessRequest() throws ProxyCacheException {
proxyCache = proxyCache == null ? newHttpProxyCache() : proxyCache;
}

private synchronized void finishProcessRequest() {
if (clientsCount.decrementAndGet() <= 0) {
proxyCache.shutdown();
proxyCache = null;
}
}

Expand All @@ -65,6 +72,10 @@ public void shutdown() {
clientsCount.set(0);
}

public int getClientsCount() {
return clientsCount.get();
}

private HttpProxyCache newHttpProxyCache() throws ProxyCacheException {
HttpUrlSource source = new HttpUrlSource(url);
FileCache cache = new FileCache(fileNameGenerator.generate(url));
Expand Down
21 changes: 12 additions & 9 deletions library/src/main/java/com/danikula/videocache/HttpUrlSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.HttpURLConnection;
import java.net.URL;

import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE;
import static com.danikula.videocache.ProxyCacheUtils.LOG_TAG;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.net.HttpURLConnection.HTTP_PARTIAL;
Expand Down Expand Up @@ -36,7 +38,7 @@ public HttpUrlSource(String url, String mime) {
}

@Override
public int available() throws ProxyCacheException {
public synchronized int available() throws ProxyCacheException {
if (available == Integer.MIN_VALUE) {
fetchContentInfo();
}
Expand All @@ -52,7 +54,7 @@ public void open(int offset) throws ProxyCacheException {
connection.setRequestProperty("Range", "bytes=" + offset + "-");
}
mime = connection.getContentType();
inputStream = connection.getInputStream();
inputStream = new BufferedInputStream(connection.getInputStream(), DEFAULT_BUFFER_SIZE);
available = readSourceAvailableBytes(connection, offset);
} catch (IOException e) {
throw new ProxyCacheException("Error opening connection for " + url + " with offset " + offset, e);
Expand Down Expand Up @@ -91,22 +93,27 @@ public int read(byte[] buffer) throws ProxyCacheException {
private void fetchContentInfo() throws ProxyCacheException {
Log.d(LOG_TAG, "Read content info from " + url);
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setConnectTimeout(10000);
urlConnection.setReadTimeout(10000);
urlConnection.setRequestMethod("HEAD");
available = urlConnection.getContentLength();
mime = urlConnection.getContentType();
Log.i(LOG_TAG, "Info read: " + this);
inputStream = urlConnection.getInputStream();
Log.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + available);
} catch (IOException e) {
throw new ProxyCacheException("Error fetching Content-Length from " + url);
} finally {
ProxyCacheUtils.close(inputStream);
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}

public String getMime() throws ProxyCacheException {
public synchronized String getMime() throws ProxyCacheException {
if (TextUtils.isEmpty(mime)) {
fetchContentInfo();
}
Expand All @@ -115,10 +122,6 @@ public String getMime() throws ProxyCacheException {

@Override
public String toString() {
return "HttpUrlSource{" +
"url='" + url + '\'' +
", available=" + available +
", mime='" + mime + '\'' +
'}';
return "HttpUrlSource{url='" + url + "}";
}
}
14 changes: 3 additions & 11 deletions library/src/main/java/com/danikula/videocache/ProxyCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,11 @@ public int read(byte[] buffer, long offset, int length) throws ProxyCacheExcepti
while (!cache.isCompleted() && cache.available() < (offset + length) && !stopped) {
readSourceAsync();
waitForSourceData();
checkIsCacheValid();
checkReadSourceErrorsCount();
}
return cache.read(buffer, offset, length);
}

private void checkIsCacheValid() throws ProxyCacheException {
int sourceAvailable = source.available();
if (sourceAvailable > 0 && cache.available() > sourceAvailable) {
throw new ProxyCacheException("Unexpected cache: cache [" + cache.available() + " bytes] > source[" + sourceAvailable + " bytes]");
}
}

private void checkReadSourceErrorsCount() throws ProxyCacheException {
int errorsCount = readSourceErrorsCount.get();
if (errorsCount >= MAX_READ_SOURCE_ATTEMPTS) {
Expand All @@ -76,10 +68,10 @@ public void shutdown() {
}
}

private void readSourceAsync() throws ProxyCacheException {
private synchronized void readSourceAsync() throws ProxyCacheException {
boolean readingInProgress = sourceReaderThread != null && sourceReaderThread.getState() != Thread.State.TERMINATED;
if (!stopped && !cache.isCompleted() && !readingInProgress) {
sourceReaderThread = new Thread(new SourceReaderRunnable(), "Source reader for ProxyCache");
sourceReaderThread = new Thread(new SourceReaderRunnable(), "Source reader for " + source);
sourceReaderThread.start();
}
}
Expand All @@ -102,7 +94,7 @@ private void notifyNewCacheDataAvailable(int cachePercentage) {
}
}

protected void onCacheAvailable(int percents){
protected void onCacheAvailable(int percents) {
}

private void readSource() {
Expand Down
12 changes: 12 additions & 0 deletions library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.danikula.videocache;

import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
Expand Down Expand Up @@ -74,4 +76,14 @@ static String decode(String url) {
throw new RuntimeException("Error decoding url", e);
}
}

static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
Log.e(LOG_TAG, "Error closing resource", e);
}
}
}
}
2 changes: 1 addition & 1 deletion sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies {
// compile project(':library')
compile 'com.android.support:support-v4:23.0.0'
compile 'org.androidannotations:androidannotations-api:3.3.2'
compile 'com.danikula:videocache:2.0.7'
compile 'com.danikula:videocache:2.0.9'
compile 'com.viewpagerindicator:library:2.4.2-SNAPSHOT@aar'
apt 'org.androidannotations:androidannotations:3.3.2'
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public void onPause() {
public void onDestroy() {
super.onDestroy();

videoView.stopPlayback();
App.getProxy(getActivity()).unregisterCacheListener(this);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public void onPause() {
public void onDestroy() {
super.onDestroy();

videoView.stopPlayback();
App.getProxy(getActivity()).unregisterCacheListener(this);
}

Expand Down
12 changes: 0 additions & 12 deletions test/src/test/java/com/danikula/videocache/ProxyCacheTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.danikula.videocache.support.PhlegmaticByteArraySource;
import com.danikula.videocache.test.BuildConfig;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
Expand Down Expand Up @@ -91,17 +90,6 @@ public void testReuseCache() throws Exception {
assertThat(fetchedData).isEqualTo(sourceCopy);
}

@Test(expected = ProxyCacheException.class)
public void testNoMoreSource() throws Exception {
int sourceSize = 942;
int cacheSize = 6157;
ByteArraySource source = new ByteArraySource(generate(sourceSize));
ByteArrayCache cache = new ByteArrayCache(generate(cacheSize));
ProxyCache proxyCache = new ProxyCache(source, cache);
proxyCache.read(new byte[sourceSize + cacheSize], sourceSize + cacheSize + 1, 10);
Assert.fail();
}

@Test
public void testProxyWithPhlegmaticSource() throws Exception {
int dataSize = 100000;
Expand Down

0 comments on commit f8f19c5

Please sign in to comment.