michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "MediaOmxDecoder.h" michael@0: #include "MediaOmxReader.h" michael@0: #include "MediaDecoderStateMachine.h" michael@0: michael@0: #include "OmxDecoder.h" michael@0: michael@0: #ifdef MOZ_AUDIO_OFFLOAD michael@0: #include "AudioOffloadPlayer.h" michael@0: #endif michael@0: michael@0: using namespace android; michael@0: michael@0: namespace mozilla { michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gMediaDecoderLog; michael@0: #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) michael@0: #else michael@0: #define DECODER_LOG(type, msg) michael@0: #endif michael@0: michael@0: MediaOmxDecoder::MediaOmxDecoder() : michael@0: MediaDecoder(), michael@0: mCanOffloadAudio(false), michael@0: mFallbackToStateMachine(false) michael@0: { michael@0: #ifdef PR_LOGGING michael@0: if (!gMediaDecoderLog) { michael@0: gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: MediaDecoder* MediaOmxDecoder::Clone() michael@0: { michael@0: return new MediaOmxDecoder(); michael@0: } michael@0: michael@0: MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine() michael@0: { michael@0: mReader = new MediaOmxReader(this); michael@0: mReader->SetAudioChannel(GetAudioChannel()); michael@0: return new MediaDecoderStateMachine(this, mReader); michael@0: } michael@0: michael@0: void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); michael@0: mCanOffloadAudio = aCanOffloadAudio; michael@0: } michael@0: michael@0: void MediaOmxDecoder::MetadataLoaded(int aChannels, michael@0: int aRate, michael@0: bool aHasAudio, michael@0: bool aHasVideo, michael@0: MetadataTags* aTags) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MediaDecoder::MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags); michael@0: michael@0: ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); michael@0: if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() || michael@0: mInitialPlaybackRate != 1.0) { michael@0: DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed", michael@0: __PRETTY_FUNCTION__)); michael@0: return; michael@0: } michael@0: michael@0: #ifdef MOZ_AUDIO_OFFLOAD michael@0: mAudioOffloadPlayer = new AudioOffloadPlayer(this); michael@0: #endif michael@0: mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack()); michael@0: status_t err = mAudioOffloadPlayer->Start(false); michael@0: if (err == OK) { michael@0: PauseStateMachine(); michael@0: // Call ChangeState() to run AudioOffloadPlayer since offload state enabled michael@0: ChangeState(mPlayState); michael@0: return; michael@0: } michael@0: michael@0: mAudioOffloadPlayer = nullptr; michael@0: DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d." michael@0: "Switching to normal mode", __PRETTY_FUNCTION__, err)); michael@0: } michael@0: michael@0: void MediaOmxDecoder::PauseStateMachine() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: GetReentrantMonitor().AssertCurrentThreadIn(); michael@0: DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); michael@0: if (!mDecoderStateMachine) { michael@0: return; michael@0: } michael@0: StopProgress(); michael@0: mDecoderStateMachine->SetDormant(true); michael@0: } michael@0: michael@0: void MediaOmxDecoder::ResumeStateMachine() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); michael@0: DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__, michael@0: mCurrentTime)); michael@0: michael@0: if (!mDecoderStateMachine) { michael@0: return; michael@0: } michael@0: michael@0: mFallbackToStateMachine = true; michael@0: mAudioOffloadPlayer = nullptr; michael@0: mRequestedSeekTarget = SeekTarget(mCurrentTime, SeekTarget::Accurate); michael@0: michael@0: mNextState = mPlayState; michael@0: ChangeState(PLAY_STATE_LOADING); michael@0: mDecoderStateMachine->SetDormant(false); michael@0: } michael@0: michael@0: void MediaOmxDecoder::AudioOffloadTearDown() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: PlaybackPositionChanged(); michael@0: DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); michael@0: { michael@0: // Audio offload player sent tear down event. Fallback to state machine michael@0: ResumeStateMachine(); michael@0: } michael@0: } michael@0: michael@0: void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream, michael@0: bool aFinishWhenEnded) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: PlaybackPositionChanged(); michael@0: michael@0: if (mAudioOffloadPlayer) { michael@0: // Offload player cannot handle MediaStream. Fallback michael@0: ResumeStateMachine(); michael@0: } michael@0: michael@0: MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded); michael@0: } michael@0: michael@0: void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: PlaybackPositionChanged(); michael@0: michael@0: if (mAudioOffloadPlayer && michael@0: ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) { michael@0: // Offload player cannot handle playback rate other than 1/0. Fallback michael@0: ResumeStateMachine(); michael@0: } michael@0: michael@0: MediaDecoder::SetPlaybackRate(aPlaybackRate); michael@0: } michael@0: michael@0: void MediaOmxDecoder::ChangeState(PlayState aState) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: // Keep MediaDecoder state in sync with MediaElement irrespective of offload michael@0: // playback so it will continue to work in normal mode when offloading fails michael@0: // in between michael@0: MediaDecoder::ChangeState(aState); michael@0: michael@0: if (mAudioOffloadPlayer) { michael@0: status_t err = mAudioOffloadPlayer->ChangeState(aState); michael@0: if (err != OK) { michael@0: ResumeStateMachine(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: // During offload playback, state machine should be in dormant state. michael@0: // ApplyStateToStateMachine() can change state machine state to michael@0: // something else or reset the seek time. So don't call this when audio is michael@0: // offloaded michael@0: if (!mAudioOffloadPlayer) { michael@0: MediaDecoder::ApplyStateToStateMachine(aState); michael@0: } michael@0: } michael@0: michael@0: void MediaOmxDecoder::PlaybackPositionChanged() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: if (!mAudioOffloadPlayer) { michael@0: MediaDecoder::PlaybackPositionChanged(); michael@0: return; michael@0: } michael@0: michael@0: if (!mOwner || mShuttingDown) { michael@0: return; michael@0: } michael@0: michael@0: double lastTime = mCurrentTime; michael@0: { michael@0: ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); michael@0: mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs(); michael@0: } michael@0: if (mOwner && lastTime != mCurrentTime) { michael@0: FireTimeUpdate(); michael@0: } michael@0: } michael@0: michael@0: void MediaOmxDecoder::SetElementVisibility(bool aIsVisible) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: if (mAudioOffloadPlayer) { michael@0: mAudioOffloadPlayer->SetElementVisibility(aIsVisible); michael@0: } michael@0: } michael@0: michael@0: void MediaOmxDecoder::UpdateReadyStateForData() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: if (!mAudioOffloadPlayer) { michael@0: MediaDecoder::UpdateReadyStateForData(); michael@0: return; michael@0: } michael@0: michael@0: if (!mOwner || mShuttingDown) michael@0: return; michael@0: mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus()); michael@0: } michael@0: michael@0: void MediaOmxDecoder::SetVolume(double aVolume) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: if (!mAudioOffloadPlayer) { michael@0: MediaDecoder::SetVolume(aVolume); michael@0: return; michael@0: } michael@0: mAudioOffloadPlayer->SetVolume(aVolume); michael@0: } michael@0: michael@0: } // namespace mozilla