|
32 | 32 | import androidx.media3.datasource.DataSourceException;
|
33 | 33 | import androidx.media3.datasource.DataSpec;
|
34 | 34 | import androidx.media3.datasource.HttpDataSource;
|
| 35 | +import androidx.media3.datasource.HttpDataSource.HttpDataSourceException; |
| 36 | +import androidx.media3.datasource.HttpDataSource.InvalidContentTypeException; |
| 37 | +import androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException; |
35 | 38 | import androidx.media3.datasource.HttpUtil;
|
36 | 39 | import androidx.media3.datasource.TransferListener;
|
37 | 40 | import com.google.common.base.Predicate;
|
38 | 41 | import com.google.common.net.HttpHeaders;
|
| 42 | +import com.google.common.util.concurrent.SettableFuture; |
39 | 43 | import java.io.IOException;
|
40 | 44 | import java.io.InputStream;
|
41 | 45 | import java.io.InterruptedIOException;
|
42 | 46 | import java.util.Collections;
|
43 | 47 | import java.util.HashMap;
|
44 | 48 | import java.util.List;
|
45 | 49 | import java.util.Map;
|
| 50 | +import java.util.concurrent.ExecutionException; |
46 | 51 | import okhttp3.CacheControl;
|
47 | 52 | import okhttp3.Call;
|
| 53 | +import okhttp3.Callback; |
48 | 54 | import okhttp3.HttpUrl;
|
49 | 55 | import okhttp3.MediaType;
|
50 | 56 | import okhttp3.OkHttpClient;
|
@@ -299,8 +305,9 @@ public long open(DataSpec dataSpec) throws HttpDataSourceException {
|
299 | 305 | Request request = makeRequest(dataSpec);
|
300 | 306 | Response response;
|
301 | 307 | ResponseBody responseBody;
|
| 308 | + Call call = callFactory.newCall(request); |
302 | 309 | try {
|
303 |
| - this.response = callFactory.newCall(request).execute(); |
| 310 | + this.response = executeCall(call); |
304 | 311 | response = this.response;
|
305 | 312 | responseBody = Assertions.checkNotNull(response.body());
|
306 | 313 | responseByteStream = responseBody.byteStream();
|
@@ -448,6 +455,35 @@ private Request makeRequest(DataSpec dataSpec) throws HttpDataSourceException {
|
448 | 455 | return builder.build();
|
449 | 456 | }
|
450 | 457 |
|
| 458 | + /** |
| 459 | + * This method is an interrupt safe replacement of OkHttp Call.execute() which can get in bad |
| 460 | + * states if interrupted while writing to the shared connection socket. |
| 461 | + */ |
| 462 | + private Response executeCall(Call call) throws IOException { |
| 463 | + SettableFuture<Response> future = SettableFuture.create(); |
| 464 | + call.enqueue( |
| 465 | + new Callback() { |
| 466 | + @Override |
| 467 | + public void onFailure(Call call, IOException e) { |
| 468 | + future.setException(e); |
| 469 | + } |
| 470 | + |
| 471 | + @Override |
| 472 | + public void onResponse(Call call, Response response) { |
| 473 | + future.set(response); |
| 474 | + } |
| 475 | + }); |
| 476 | + |
| 477 | + try { |
| 478 | + return future.get(); |
| 479 | + } catch (InterruptedException e) { |
| 480 | + call.cancel(); |
| 481 | + throw new InterruptedIOException(); |
| 482 | + } catch (ExecutionException ee) { |
| 483 | + throw new IOException(ee); |
| 484 | + } |
| 485 | + } |
| 486 | + |
451 | 487 | /**
|
452 | 488 | * Attempts to skip the specified number of bytes in full.
|
453 | 489 | *
|
|
0 commit comments