Android 오디오 개발(3): ExoPlayer를 사용하여 오디오 재생

1. Android 오디오 개발(1): 오디오 기본 사항
2. Android 오디오 개발(2): 오디오 녹음(WAV 및 MP3 형식)
3. Android 오디오 개발(3): ExoPlayer를 사용하여 오디오 재생
4. Android 오디오 개발(4) : 오디오 재생 모드
5. 안드로이드 오디오 개발(5) : 유도(화면 끄기/밝은 화면) 관리

첨부된 GitHub 소스 코드: MultimediaExplore


비고: ExoPlayer의 디코딩은 비디오 및 오디오 디코딩을 위해 Android 시스템에서 제공하는 네이티브 디코딩 모듈 MediaCodec 에 의존합니다 . ExoPlayer에 대한 자세한 내용은 ExoPlayer를 참조하십시오.

 1. 오디오 재생 권한 및 종속성:

오디오 재생과 관련된 권한:

    <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'

2. ExoPlayer 인스턴스 생성: 

SimpleExoPlayer 인스턴스를 생성한 다음 빌드된 오디오 리소스를 재생할 오디오 플레이어로 설정합니다. 여기서 한 가지 주의할 점은 오디오의 재생 진행률을 얻으려면 아래 그림 과 같이 handlerInner Handler 인스턴스를 생성한 다음 addEventListener에 추가해야 한다는 것입니다. 그렇지 않고 외부에서 전달된 핸들러를 직접 사용하면 획득한 오디오 재생 진행률은 항상 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. 오디오 재생 수명 주기 방법:

    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. 오디오 재생 관리 AudioPlayManager :

AudioRecordManager의 역할과 유사하게 오디오 플레이어는 전역 싱글톤이며 코드는 생략됩니다.

추천

출처blog.csdn.net/u012440207/article/details/121722809