Skip to content

Commit

Permalink
[expo-av] allow playing media files from apk res folder (#8936)
Browse files Browse the repository at this point in the history
# Why

ref #8888 -- expo-av currently does not support playing media files from an android apk's `res/raw` folder, which is where the RN packager embeds required assets by default.

# How

RN's asset source resolver sets the `uri` for assets embedded in `res` to simply the resource name with no scheme. Therefore, if the url provided to expo-av has no scheme, we can assume it comes from RN's asset source resolver and is a resource name. ([We do the same thing in expo-file-system.](https://github.com/expo/expo/blob/1b61af26782c89da45ba559e60ebb2a38b6e80b3/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.java#L312-L314))

# Test Plan

Tested using the repo provided in #8888 and confirmed that with expo-updates disabled, after this change, the audio file played as expected both with ExoPlayer and with `androidImplementation: 'MediaPlayer'`.
  • Loading branch information
esamelson committed Jun 25, 2020
1 parent 63d5724 commit 450147a
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/expo-av/CHANGELOG.md
Expand Up @@ -11,6 +11,8 @@

### 🐛 Bug fixes

- Allow playing media files embedded as resources in an Android APK. ([#8936](https://github.com/expo/expo/pull/8936) by [@esamelson](https://github.com/esamelson))

## 8.2.1 — 2020-05-29

_This version does not introduce any user-facing changes._
Expand Down
Expand Up @@ -69,8 +69,13 @@ public void load(final Bundle status,
final MediaPlayer unpreparedPlayer = new MediaPlayer();

try {
Uri uri = mUri;
if (uri.getScheme() == null) {
int resourceId = mAVModule.getContext().getResources().getIdentifier(uri.toString(), "raw", mAVModule.getContext().getPackageName());
uri = Uri.parse("android.resource://" + mAVModule.getContext().getPackageName() + "/" + resourceId);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
unpreparedPlayer.setDataSource(mAVModule.getContext(), mUri, null, getHttpCookiesList());
unpreparedPlayer.setDataSource(mAVModule.getContext(), uri, null, getHttpCookiesList());
} else {
Map<String, String> headers = new HashMap<>(1);
StringBuilder cookieBuilder = new StringBuilder();
Expand All @@ -89,7 +94,7 @@ public void load(final Bundle status,
}
}
}
unpreparedPlayer.setDataSource(mAVModule.getContext(), mUri, headers);
unpreparedPlayer.setDataSource(mAVModule.getContext(), uri, headers);
}
} catch (final Throwable throwable) {
loadCompletionListener.onLoadError("Load encountered an error: setDataSource() threw an exception was thrown with message: " + throwable.toString());
Expand Down
Expand Up @@ -8,6 +8,7 @@
import androidx.annotation.Nullable;

import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;

Expand Down Expand Up @@ -40,6 +41,7 @@
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.RawResourceDataSource;
import com.google.android.exoplayer2.util.Util;

import java.io.IOException;
Expand All @@ -54,6 +56,7 @@ class SimpleExoPlayerData extends PlayerData
implements Player.EventListener, ExtractorMediaSource.EventListener, SimpleExoPlayer.VideoListener, AdaptiveMediaSourceEventListener {

private static final String IMPLEMENTATION_NAME = "SimpleExoPlayer";
private static final String TAG = SimpleExoPlayerData.class.getSimpleName();

private SimpleExoPlayer mSimpleExoPlayer = null;
private String mOverridingExtension;
Expand Down Expand Up @@ -367,6 +370,17 @@ public void onRenderedFirstFrame() {

// https://github.com/google/ExoPlayer/blob/2b20780482a9c6b07416bcbf4de829532859d10a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java#L365-L393
private MediaSource buildMediaSource(Uri uri, String overrideExtension, Handler mainHandler, DataSource.Factory factory) {
try {
if (uri.getScheme() == null) {
int resourceId = mReactContext.getResources().getIdentifier(uri.toString(), "raw", mReactContext.getPackageName());
DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(resourceId));
final RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(mReactContext);
rawResourceDataSource.open(dataSpec);
uri = rawResourceDataSource.getUri();
}
} catch (Exception e) {
Log.e(TAG, "Error reading raw resource from ExoPlayer", e);
}
@C.ContentType int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(String.valueOf(uri)) : Util.inferContentType("." + overrideExtension);
switch (type) {
case C.TYPE_SS:
Expand Down

0 comments on commit 450147a

Please sign in to comment.