Android audio development (3): use ExoPlayer to play audio

1. Android audio development (1): audio basics
2. Android audio development (2): recording audio (WAV and MP3 format)
3. Android audio development (3): using ExoPlayer to play audio
4. Android audio development (4) : Audio playback mode
5. Android audio development (5): Induction (screen off/bright screen) management

Attached GitHub source code: MultimediaExplore


Remarks: The decoding of ExoPlayer relies on the native decoding module MediaCodec provided by the Android system for video and audio decoding. For details about ExoPlayer, please refer to: ExoPlayer

 1. Audio playback permissions and dependencies:

Permissions that may be involved in audio playback:

    <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"/>

The audio player needs to depend on: 

    // 多媒体播放器
    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'

2. ExoPlayer instance generation: 

Generate a SimpleExoPlayer instance, and then set the built audio resources to the audio player to play. One thing to note here is that if you want to get the playback progress of the audio, you need to generate a handlerInner Handler instance as shown in the figure below , and then add it to the addEventListener. Otherwise, if you directly use the hander passed from the outside , the obtained audio playback progress will always be 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();
    }

3. Audio playback lifecycle method:

    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;
    }

4. Audio playback management AudioPlayManager :

Similar to the role of AudioRecordManager, the audio player is a global singleton, and the code is omitted.

Guess you like

Origin blog.csdn.net/u012440207/article/details/121722809