Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MediaOmxDecoder.h"
8 #include "MediaOmxReader.h"
9 #include "MediaDecoderStateMachine.h"
11 #include "OmxDecoder.h"
13 #ifdef MOZ_AUDIO_OFFLOAD
14 #include "AudioOffloadPlayer.h"
15 #endif
17 using namespace android;
19 namespace mozilla {
21 #ifdef PR_LOGGING
22 extern PRLogModuleInfo* gMediaDecoderLog;
23 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
24 #else
25 #define DECODER_LOG(type, msg)
26 #endif
28 MediaOmxDecoder::MediaOmxDecoder() :
29 MediaDecoder(),
30 mCanOffloadAudio(false),
31 mFallbackToStateMachine(false)
32 {
33 #ifdef PR_LOGGING
34 if (!gMediaDecoderLog) {
35 gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
36 }
37 #endif
38 }
40 MediaDecoder* MediaOmxDecoder::Clone()
41 {
42 return new MediaOmxDecoder();
43 }
45 MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine()
46 {
47 mReader = new MediaOmxReader(this);
48 mReader->SetAudioChannel(GetAudioChannel());
49 return new MediaDecoderStateMachine(this, mReader);
50 }
52 void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
53 {
54 ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
55 mCanOffloadAudio = aCanOffloadAudio;
56 }
58 void MediaOmxDecoder::MetadataLoaded(int aChannels,
59 int aRate,
60 bool aHasAudio,
61 bool aHasVideo,
62 MetadataTags* aTags)
63 {
64 MOZ_ASSERT(NS_IsMainThread());
65 MediaDecoder::MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags);
67 ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
68 if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() ||
69 mInitialPlaybackRate != 1.0) {
70 DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed",
71 __PRETTY_FUNCTION__));
72 return;
73 }
75 #ifdef MOZ_AUDIO_OFFLOAD
76 mAudioOffloadPlayer = new AudioOffloadPlayer(this);
77 #endif
78 mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
79 status_t err = mAudioOffloadPlayer->Start(false);
80 if (err == OK) {
81 PauseStateMachine();
82 // Call ChangeState() to run AudioOffloadPlayer since offload state enabled
83 ChangeState(mPlayState);
84 return;
85 }
87 mAudioOffloadPlayer = nullptr;
88 DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
89 "Switching to normal mode", __PRETTY_FUNCTION__, err));
90 }
92 void MediaOmxDecoder::PauseStateMachine()
93 {
94 MOZ_ASSERT(NS_IsMainThread());
95 GetReentrantMonitor().AssertCurrentThreadIn();
96 DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
97 if (!mDecoderStateMachine) {
98 return;
99 }
100 StopProgress();
101 mDecoderStateMachine->SetDormant(true);
102 }
104 void MediaOmxDecoder::ResumeStateMachine()
105 {
106 MOZ_ASSERT(NS_IsMainThread());
107 ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
108 DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__,
109 mCurrentTime));
111 if (!mDecoderStateMachine) {
112 return;
113 }
115 mFallbackToStateMachine = true;
116 mAudioOffloadPlayer = nullptr;
117 mRequestedSeekTarget = SeekTarget(mCurrentTime, SeekTarget::Accurate);
119 mNextState = mPlayState;
120 ChangeState(PLAY_STATE_LOADING);
121 mDecoderStateMachine->SetDormant(false);
122 }
124 void MediaOmxDecoder::AudioOffloadTearDown()
125 {
126 MOZ_ASSERT(NS_IsMainThread());
127 PlaybackPositionChanged();
128 DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
129 {
130 // Audio offload player sent tear down event. Fallback to state machine
131 ResumeStateMachine();
132 }
133 }
135 void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream,
136 bool aFinishWhenEnded)
137 {
138 MOZ_ASSERT(NS_IsMainThread());
139 PlaybackPositionChanged();
141 if (mAudioOffloadPlayer) {
142 // Offload player cannot handle MediaStream. Fallback
143 ResumeStateMachine();
144 }
146 MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
147 }
149 void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate)
150 {
151 MOZ_ASSERT(NS_IsMainThread());
152 PlaybackPositionChanged();
154 if (mAudioOffloadPlayer &&
155 ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) {
156 // Offload player cannot handle playback rate other than 1/0. Fallback
157 ResumeStateMachine();
158 }
160 MediaDecoder::SetPlaybackRate(aPlaybackRate);
161 }
163 void MediaOmxDecoder::ChangeState(PlayState aState)
164 {
165 MOZ_ASSERT(NS_IsMainThread());
166 // Keep MediaDecoder state in sync with MediaElement irrespective of offload
167 // playback so it will continue to work in normal mode when offloading fails
168 // in between
169 MediaDecoder::ChangeState(aState);
171 if (mAudioOffloadPlayer) {
172 status_t err = mAudioOffloadPlayer->ChangeState(aState);
173 if (err != OK) {
174 ResumeStateMachine();
175 }
176 }
177 }
179 void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState)
180 {
181 MOZ_ASSERT(NS_IsMainThread());
182 // During offload playback, state machine should be in dormant state.
183 // ApplyStateToStateMachine() can change state machine state to
184 // something else or reset the seek time. So don't call this when audio is
185 // offloaded
186 if (!mAudioOffloadPlayer) {
187 MediaDecoder::ApplyStateToStateMachine(aState);
188 }
189 }
191 void MediaOmxDecoder::PlaybackPositionChanged()
192 {
193 MOZ_ASSERT(NS_IsMainThread());
194 if (!mAudioOffloadPlayer) {
195 MediaDecoder::PlaybackPositionChanged();
196 return;
197 }
199 if (!mOwner || mShuttingDown) {
200 return;
201 }
203 double lastTime = mCurrentTime;
204 {
205 ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
206 mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs();
207 }
208 if (mOwner && lastTime != mCurrentTime) {
209 FireTimeUpdate();
210 }
211 }
213 void MediaOmxDecoder::SetElementVisibility(bool aIsVisible)
214 {
215 MOZ_ASSERT(NS_IsMainThread());
216 if (mAudioOffloadPlayer) {
217 mAudioOffloadPlayer->SetElementVisibility(aIsVisible);
218 }
219 }
221 void MediaOmxDecoder::UpdateReadyStateForData()
222 {
223 MOZ_ASSERT(NS_IsMainThread());
224 if (!mAudioOffloadPlayer) {
225 MediaDecoder::UpdateReadyStateForData();
226 return;
227 }
229 if (!mOwner || mShuttingDown)
230 return;
231 mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus());
232 }
234 void MediaOmxDecoder::SetVolume(double aVolume)
235 {
236 MOZ_ASSERT(NS_IsMainThread());
237 if (!mAudioOffloadPlayer) {
238 MediaDecoder::SetVolume(aVolume);
239 return;
240 }
241 mAudioOffloadPlayer->SetVolume(aVolume);
242 }
244 } // namespace mozilla