/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaOmxCommonDecoder.h" #include #include "AudioOffloadPlayerBase.h" #include "MediaDecoderStateMachine.h" #include "MediaOmxCommonReader.h" #ifdef MOZ_AUDIO_OFFLOAD #include "AudioOffloadPlayer.h" #endif using namespace android; namespace mozilla { extern PRLogModuleInfo* gMediaDecoderLog; #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) MediaOmxCommonDecoder::MediaOmxCommonDecoder() : MediaDecoder() , mReader(nullptr) , mCanOffloadAudio(false) , mFallbackToStateMachine(false) { if (!gMediaDecoderLog) { gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); } } MediaOmxCommonDecoder::~MediaOmxCommonDecoder() {} void MediaOmxCommonDecoder::SetPlatformCanOffloadAudio(bool aCanOffloadAudio) { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mCanOffloadAudio = aCanOffloadAudio; } bool MediaOmxCommonDecoder::CheckDecoderCanOffloadAudio() { return (mCanOffloadAudio && !mFallbackToStateMachine && !mOutputStreams.Length() && mPlaybackRate == 1.0); } void MediaOmxCommonDecoder::FirstFrameLoaded(nsAutoPtr aInfo, MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) { return; } MediaDecoder::FirstFrameLoaded(aInfo, aEventVisibility); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); if (!CheckDecoderCanOffloadAudio()) { DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed", __PRETTY_FUNCTION__)); return; } #ifdef MOZ_AUDIO_OFFLOAD mAudioOffloadPlayer = new AudioOffloadPlayer(this); #endif if (!mAudioOffloadPlayer) { return; } mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack()); status_t err = mAudioOffloadPlayer->Start(false); if (err != OK) { mAudioOffloadPlayer = nullptr; mFallbackToStateMachine = true; DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d." "Switching to normal mode", __PRETTY_FUNCTION__, err)); return; } PauseStateMachine(); if (mLogicallySeeking) { SeekTarget target = SeekTarget(mLogicalPosition, SeekTarget::Accurate, MediaDecoderEventVisibility::Observable); mSeekRequest.DisconnectIfExists(); mSeekRequest.Begin(mAudioOffloadPlayer->Seek(target) ->RefableThen(AbstractThread::MainThread(), __func__, static_cast(this), &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)); } // Call ChangeState() to run AudioOffloadPlayer since offload state enabled ChangeState(mPlayState); } void MediaOmxCommonDecoder::PauseStateMachine() { MOZ_ASSERT(NS_IsMainThread()); GetReentrantMonitor().AssertCurrentThreadIn(); DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); if (mShuttingDown) { return; } if (!GetStateMachine()) { return; } // enter dormant state RefPtr event = NS_NewRunnableMethodWithArg( GetStateMachine(), &MediaDecoderStateMachine::SetDormant, true); GetStateMachine()->TaskQueue()->Dispatch(event); } void MediaOmxCommonDecoder::ResumeStateMachine() { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__, mLogicalPosition)); if (mShuttingDown) { return; } if (!GetStateMachine()) { return; } mFallbackToStateMachine = true; mAudioOffloadPlayer = nullptr; SeekTarget target = SeekTarget(mLogicalPosition, SeekTarget::Accurate, MediaDecoderEventVisibility::Suppressed); // Call Seek of MediaDecoderStateMachine to suppress seek events. RefPtr event = NS_NewRunnableMethodWithArg( GetStateMachine(), &MediaDecoderStateMachine::Seek, target); GetStateMachine()->TaskQueue()->Dispatch(event); mNextState = mPlayState; ChangeState(PLAY_STATE_LOADING); // exit dormant state event = NS_NewRunnableMethodWithArg( GetStateMachine(), &MediaDecoderStateMachine::SetDormant, false); GetStateMachine()->TaskQueue()->Dispatch(event); UpdateLogicalPosition(); } void MediaOmxCommonDecoder::AudioOffloadTearDown() { MOZ_ASSERT(NS_IsMainThread()); DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); // mAudioOffloadPlayer can be null here if ResumeStateMachine was called // just before because of some other error. if (mAudioOffloadPlayer) { ResumeStateMachine(); } } void MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded) { MOZ_ASSERT(NS_IsMainThread()); if (mAudioOffloadPlayer) { ResumeStateMachine(); } MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded); } void MediaOmxCommonDecoder::SetPlaybackRate(double aPlaybackRate) { MOZ_ASSERT(NS_IsMainThread()); if (mAudioOffloadPlayer && ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) { ResumeStateMachine(); } MediaDecoder::SetPlaybackRate(aPlaybackRate); } void MediaOmxCommonDecoder::ChangeState(PlayState aState) { MOZ_ASSERT(NS_IsMainThread()); // Keep MediaDecoder state in sync with MediaElement irrespective of offload // playback so it will continue to work in normal mode when offloading fails // in between MediaDecoder::ChangeState(aState); if (!mAudioOffloadPlayer) { return; } status_t err = mAudioOffloadPlayer->ChangeState(aState); if (err != OK) { ResumeStateMachine(); return; } } void MediaOmxCommonDecoder::CallSeek(const SeekTarget& aTarget) { if (!mAudioOffloadPlayer) { MediaDecoder::CallSeek(aTarget); return; } mSeekRequest.DisconnectIfExists(); mSeekRequest.Begin(mAudioOffloadPlayer->Seek(aTarget) ->RefableThen(AbstractThread::MainThread(), __func__, static_cast(this), &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)); } int64_t MediaOmxCommonDecoder::CurrentPosition() { MOZ_ASSERT(NS_IsMainThread()); if (!mAudioOffloadPlayer) { return MediaDecoder::CurrentPosition(); } ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); return mAudioOffloadPlayer->GetMediaTimeSecs(); } void MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible) { MOZ_ASSERT(NS_IsMainThread()); if (mAudioOffloadPlayer) { mAudioOffloadPlayer->SetElementVisibility(aIsVisible); } } MediaDecoderOwner::NextFrameStatus MediaOmxCommonDecoder::NextFrameStatus() { MOZ_ASSERT(NS_IsMainThread()); return mAudioOffloadPlayer ? mAudioOffloadPlayer->GetNextFrameStatus() : MediaDecoder::NextFrameStatus(); } void MediaOmxCommonDecoder::SetVolume(double aVolume) { MOZ_ASSERT(NS_IsMainThread()); if (!mAudioOffloadPlayer) { MediaDecoder::SetVolume(aVolume); return; } mAudioOffloadPlayer->SetVolume(aVolume); } MediaDecoderStateMachine* MediaOmxCommonDecoder::CreateStateMachine() { mReader = CreateReader(); if (mReader != nullptr) { mReader->SetAudioChannel(GetAudioChannel()); } return CreateStateMachineFromReader(mReader); } } // namespace mozilla