Android音频开发(三):使用ExoPlayer播放音频

一、Android音频开发(一):音频基础知识
二、Android音频开发(二):录制音频(WAV及MP3格式)
三、Android音频开发(三):使用ExoPlayer播放音频
四、Android音频开发(四):音频播放模式
五、Android音频开发(五):感应(息屏/亮屏)管理

附GitHub源码:MultimediaExplore


备注:ExoPlayer的解码是依赖Android系统提供的原生解码模块MediaCodec进行视频和音频解码的。关于ExoPlayer具体可参考:ExoPlayer

 一、音频播放的权限及依赖:

音频播放可能涉及到的权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <!--音频模式切换权限-->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

    <!--唤屏/息屏权限-->
    <uses-permission android:name="android.Manifest.permission.DEVICE_POWER"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

音频播放器所需依赖: 

    // 多媒体播放器
    implementation 'com.google.android.exoplayer:exoplayer-core:2.15.0'
    implementation 'com.google.android.exoplayer:exoplayer-ui:2.15.0'
    implementation 'com.google.android.exoplayer:exoplayer-hls:2.15.0'
    implementation 'com.google.android.exoplayer:exoplayer-dash:2.15.0'
    implementation 'com.google.android.exoplayer:exoplayer-transformer:2.15.0'
    implementation 'com.google.android.exoplayer:exoplayer-rtsp:2.15.0'
    implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.15.0'

二、ExoPlayer实例生成: 

生成SimpleExoPlayer实例,然后将build好的音频资源set到音频播放器即可进行播放。这里需要注意一点的是如果要获取音频的播放进度,需要生成一个如下图的handlerInner Handler实例,然后将其addEventListener中。否则如果直接使用从外部传过来的hander,所得到的音频播放进度会一直是0。

    public void prepareAudioPlayer(Context context, Handler handler, Uri uri) {
        if (player == null) {
            player = new SimpleExoPlayer.Builder(context).build();
        }
        mediaSource = AudioMediaSourceManager.getInstance().buildMediaSource(uri, isLocalResource);
        if (mediaSource == null || player == null) {
            return;
        }

        if (handlerInner == null) {
            handlerInner = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Message msgOuter = new Message();
                    if (msg.what == WHAT_POSITION) {
                        currentPosition = player.getCurrentPosition() / 1000;
                        contentPosition = player.getContentPosition() / 1000;
                        contentBufferedPosition = player.getContentBufferedPosition() / 1000;
                        Log.d(TAG, "-----> currentPosition:" + currentPosition + " contentPosition:" + contentPosition + " contentBufferedPosition:" + contentBufferedPosition);
                        HashMap<String, Long> hashMap = new HashMap<>();
                        hashMap.put("currentPosition", currentPosition);
                        hashMap.put("contentPosition", contentPosition);
                        hashMap.put("contentBufferedPosition", contentBufferedPosition);
                        msgOuter.what = WHAT_POSITION;
                        msgOuter.obj = hashMap;
                        handler.sendMessage(msgOuter);
                        if (currentPosition < duration) {
                            sendEmptyMessageDelayed(WHAT_POSITION, 300);
                        }
                    } else if (msg.what == WHAT_DURATION) {
                        msgOuter.obj = msg.obj;
                        handler.sendMessage(msgOuter);
                    }
                }
            };
        }

        mediaSource.addEventListener(handlerInner, new MediaSourceEventListener() {

            @Override
            public void onLoadStarted(int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
                Log.d(TAG, "onLoadStarted ---> duration:" + duration);
            }

            @Override
            public void onLoadCompleted(int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
                mediaSource.removeEventListener(this);

                //发送时长消息
                duration = player.getDuration() / 1000;
                Message msg = new Message();
                msg.what = WHAT_DURATION;
                msg.obj = duration;
                handlerInner.sendMessage(msg);

                //发送position消息
                Message msgPos = new Message();
                msgPos.what = WHAT_POSITION;
                handlerInner.sendMessage(msgPos);

                Log.d(TAG, "onLoadCompleted ---> duration:" + duration);
            }
        });
        player.setMediaSource(mediaSource);
        player.addListener(new Player.Listener() {

            @Override
            public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) {
                Log.d(TAG, "onPlayWhenReadyChanged---> playWhenReady:" + playWhenReady);
                AudioPlayer.this.playWhenReady = playWhenReady;
            }

            @Override
            public void onPlaybackStateChanged(int playbackState) {
                Log.d(TAG, "onPlaybackStateChanged---> playbackState:" + playbackState);
                switch (playbackState) {
                    case Player.STATE_READY:
                        Log.d(TAG, "STATE_READY");
                        break;
                    case Player.STATE_BUFFERING:
                        Log.d(TAG, "STATE_BUFFERING");
                        break;
                    case Player.STATE_ENDED:
                        Log.d(TAG, "STATE_ENDED");
                        audioStatus = AudioPlayStatus.AUDIO_STOP;
                        AudioModeManager.getInstance().abandonAudioFocus();
                        break;
                    case Player.STATE_IDLE:
                        Log.d(TAG, "STATE_IDLE");
                        audioStatus = AudioPlayStatus.AUDIO_IDLE;
                        AudioModeManager.getInstance().abandonAudioFocus();
                        break;
                }
            }

            @Override
            public void onIsPlayingChanged(boolean isPlaying) {
                Log.d(TAG, "onIsPlayingChanged---> isPlaying:" + isPlaying);
                if (isPlaying) {
                    audioStatus = AudioPlayStatus.AUDIO_START;
                } else {

                }
            }
        });

        player.prepare();
    }

三、音频播放生命周期方法:

    public void play() {
        Log.d(TAG, "play");
        if (player == null) {
            return;
        }
        AudioModeManager.getInstance().requestAudioFocus();
        if (playWhenReady) {
            if (!player.isPlaying()) {
                player.setPlayWhenReady(true);
            }
        } else {
            player.prepare();
            player.setPlayWhenReady(true);
        }
        audioStatus = AudioPlayStatus.AUDIO_START;
    }

    public void pause() {
        Log.d(TAG, "pause");
        if (player == null) {
            return;
        }
        AudioModeManager.getInstance().abandonAudioFocus();
        if (player.isPlaying()) {
            player.pause();
        }
        audioStatus = AudioPlayStatus.AUDIO_PAUSE;
    }

    public void stop() {
        Log.d(TAG, "stop");
        if (player == null) {
            return;
        }
        AudioModeManager.getInstance().abandonAudioFocus();
        player.stop();
        audioStatus = AudioPlayStatus.AUDIO_STOP;
    }

    public void cancel() {
        Log.d(TAG, "cancel");
    }

    public void release() {
        Log.d(TAG, "release");
        if (player == null) {
            return;
        }
        AudioModeManager.getInstance().abandonAudioFocus();
        player.release();
        if (handlerInner != null) {
            handlerInner.removeCallbacksAndMessages(null);
        }
        audioStatus = AudioPlayStatus.AUDIO_RELEASE;
    }

四、音频播放管理AudioPlayManager

类似AudioRecordManager的作用,音频播放器全局单例,代码略。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Android ExoPlayer 是一款强大的多媒体播放器库,可以用于在Android设备上播放各种媒体格式的音频和视频文件。不过,ExoPlayer 默认不支持直接播放FLV格式的视频文件。但我们可以通过使用支持FLV格式的ExoPlayer扩展来实现FLV视频的播放。 在使用Android ExoPlayer播放FLV格式的视频文件之前,我们需要先导入支持FLV格式的ExoPlayer扩展库。可以使用 ExoPlayer 中的 ExtensionRegistry 类来注册 FLV 扩展。具体步骤如下: 1. 在项目的 build.gradle 文件中添加 ExoPlayer 的依赖: ```gradle implementation 'com.google.android.exoplayer:exoplayer-core:2.x.x' implementation 'com.google.android.exoplayer:exoplayer-ui:2.x.x' implementation 'com.google.android.exoplayer:extension-<format>:2.x.x' ``` 这里的 `<format>` 是指注册的FLV扩展库的格式名称。 2. 在代码中注册 FLV 扩展: ```java val extensionRegistry = DefaultRenderersFactory(context).extensionRendererMode extensionRegistry.registerExtension(FLVExtractorRendererBuilder.FACTORY) ``` 3. 创建 SimpleExoPlayer 实例,并设置数据源: ```java val exoPlayer = ExoPlayerFactory.newSimpleInstance(context) val dataSourceFactory = DefaultDataSourceFactory(context, userAgent) val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(videoUri) exoPlayer.prepare(mediaSource) ``` 这里的 `videoUri` 是FLV视频文件的URI。 4. 将 ExoPlayer 实例与 SurfaceView 进行关联,并开始播放: ```java exoPlayer.setVideoSurfaceView(surfaceView) exoPlayer.playWhenReady = true ``` 这里的 `surfaceView` 是用于显示视频内容的 SurfaceView。 通过以上步骤,我们可以在 Android 设备上使用 ExoPlayer 播放 FLV 格式的视频文件了。 需要注意的是,FLV 视频格式可能导致一些兼容性问题,因此在使用 ExoPlayer 播放 FLV 视频时,可以先进行测试和调试,确保视频正常播放

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红日666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值