使用ExoPlayer播放res/raw中音频资源

前言

关于ExoPlayer的使用,很多前人已经帮我们翻译了官方文档,例如ExoPlayer使用,这里不再阐述。
但是上述文章一般就是将官方文档翻译一下,针对具体的使用,可能会遇到很多难以解决问题。

正文

某天,我想用ExoPlayer播放一段存放在res/raw文件夹下的ogg格式的音频,在之前代码中,使用Mediaplayer播放,一切正常。
但是,有了高逼格的ExoPlayer,肯定要放弃Mediaplayer啊,毕竟程序员都是喜新厌旧的嘛(手动滑稽)。所以,那就根据官方API开整,这里就放核心代码

        DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelection.Factory selectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
        TrackSelector trackSelector = new DefaultTrackSelector(selectionFactory);
        currentPlayer = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector);
        DataSource.Factory dataSourceFactory = buildDataSourceFactory(this.context, bandwidthMeter);
        ExtractorMediaSource mediaSource = new ExtractorMediaSource(FmManager.getUriById(context, resId),
                dataSourceFactory, new DefaultExtractorsFactory(), null, null);
        LoopingMediaSource loopingMediaSource = new LoopingMediaSource(mediaSource);  //循环播放
        currentPlayer.prepare(loopingMediaSource);
        currentPlayer.addListener(this);
        currentPlayer.setPlayWhenReady(true);  


    private DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) {
        return new DefaultDataSourceFactory(context,
                Util.getUserAgent(context, context.getString(R.string.app_name)), bandwidthMeter);
    }

    //根据raw资源ID获取URI
    public static Uri getUriById(Context context, int rawId) {
        String basePath = "android.resource://";
        StringBuilder stringBuilder = new StringBuilder(basePath);
        String uriStr = stringBuilder.append(context.getPackageName()).append("/").append(rawId).toString();
        return Uri.parse(uriStr);
    }

代码基本是根据官方Demo提供的,一运行,哎哟,报错了:

com.google.android.exoplayer.upstream.HttpDataSource$HttpDataSourceException: Unable to connect to android.resource://```
纳尼?报资源找不到,可是获取Uri的方法没错啊,打开Chrome,上Google,不搜不要紧,一搜好多人都遇到这个问题,看来代码没写错,那就一个个帖子找吧。
找来找去,大家的解决办法竟然是将raw中音频资源放到assets目录下,这真是没办法的办法,但是转念一想,Google不至于这么坑爹吧,难道放在raw中的资源就无法使用了么?
打开官方文档(http://google.github.io/ExoPlayer/doc/reference/)

![看构造函数名字](http://upload-images.jianshu.io/upload_images/2789715-07eda3215111e0ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这里肯定是和raw资源有关,继续往下看

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2789715-4e391f5c11cbae3a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

1.使用buildRawResourceUri(int rawResourceId)传入资源ID,得到Uri

public static Uri buildRawResourceUri(int rawResourceId)
Builds a Uri for the specified raw resource identifier.```
2.使用DataSpec(Uri uri),得到DataSpec对象,

DataSpec(Uri uri)
Construct a DataSpec for the given uri and with key set to null.```
3.创建RawResourceDataSource对象,最后使用 open(DataSpec dataSpec)打开之前的DataSpec对象

public long open(DataSpec dataSpec)
throws RawResourceDataSource.RawResourceDataSourceException
Description copied from interface: DataSource
Opens the source to read the specified data. ```
4.使用RawResourceDataSource的getUri();得到Uri

public Uri getUri()
Description copied from interface: DataSource
When the source is open, returns the Uri from which data is being read. The returned Uri will be identical to the one passed DataSource.open(DataSpec) in the DataSpec unless redirection has occurred. If redirection has occurred, the Uri after redirection is returned.```

那就修改根据资源ID获取Uri的方法,完整代码如下:
    DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory selectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector = new DefaultTrackSelector(selectionFactory);
    currentPlayer = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector);
    try {
        DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(this.resId));
        RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(context);
        rawResourceDataSource.open(dataSpec);
        DataSource.Factory factory = () -> rawResourceDataSource;

        ExtractorMediaSource mediaSource = new ExtractorMediaSource(rawResourceDataSource.getUri(),
                factory, new DefaultExtractorsFactory(), null, null);
        LoopingMediaSource loopingMediaSource = new LoopingMediaSource(mediaSource);
        currentPlayer.prepare(loopingMediaSource);
        currentPlayer.addListener(this);
        currentPlayer.setPlayWhenReady(true);
    } catch (RawResourceDataSource.RawResourceDataSourceException e) {
        e.printStackTrace();
    }
重新编译运行,ok,顺利播放,看来还是官方靠谱

----------------
####总结
针对ExoPlayer播放raw中资源,不同于Mediaplayer方式,需要通过下列代码获取Uri,才能成功
        DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(this.resId));
        RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(context);
        rawResourceDataSource.open(dataSpec);
        rawResourceDataSource.getUri()```
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 11,763评论 0 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,627评论 25 709
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,463评论 19 139
  • 关键词:对立面题主:女问:感谢冷爱,关注冷爱有半年,学艺未精,目前有非常大的困扰,无法自己解答,所以麻烦冷爱能够给...
    冷爱阅读 5,547评论 0 0
  • 看完张小娴的《想念》,我在想,有时候作为高级动物的人类对于爱情的坚贞有时竟不及一个动物对于自己配偶的忠诚相依,即便...
    小缘儿阅读 2,523评论 0 0