|
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 /* |
|
4 * Copyright (c) 2014 The Linux Foundation. All rights reserved. |
|
5 * Copyright (C) 2009 The Android Open Source Project |
|
6 * |
|
7 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
8 * you may not use this file except in compliance with the License. |
|
9 * You may obtain a copy of the License at |
|
10 * |
|
11 * http://www.apache.org/licenses/LICENSE-2.0 |
|
12 * |
|
13 * Unless required by applicable law or agreed to in writing, software |
|
14 * distributed under the License is distributed on an "AS IS" BASIS, |
|
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
16 * See the License for the specific language governing permissions and |
|
17 * limitations under the License. |
|
18 */ |
|
19 |
|
20 #ifndef AUDIO_OFFLOAD_PLAYER_H_ |
|
21 #define AUDIO_OFFLOAD_PLAYER_H_ |
|
22 |
|
23 #include <stagefright/MediaBuffer.h> |
|
24 #include <stagefright/MediaSource.h> |
|
25 #include <stagefright/TimeSource.h> |
|
26 #include <utils/threads.h> |
|
27 #include <utils/RefBase.h> |
|
28 |
|
29 #include "AudioOutput.h" |
|
30 |
|
31 #include "MediaDecoderOwner.h" |
|
32 #include "MediaOmxDecoder.h" |
|
33 |
|
34 namespace mozilla { |
|
35 |
|
36 class MediaOmxDecoder; |
|
37 |
|
38 /** |
|
39 * AudioOffloadPlayer adds support for audio tunneling to a digital signal |
|
40 * processor (DSP) in the device chipset. With tunneling, audio decoding is |
|
41 * off-loaded to the DSP, waking the application processor less often and using |
|
42 * less battery |
|
43 * |
|
44 * This depends on offloading capability provided by Android KK AudioTrack class |
|
45 * |
|
46 * Audio playback is based on pull mechanism, whenever audio sink needs |
|
47 * data, FillBuffer() will read data from compressed audio source and provide |
|
48 * it to the sink |
|
49 * |
|
50 * Also this class passes state changes (play/pause/seek) from MediaOmxDecoder |
|
51 * to AudioSink as well as provide AudioSink status (position changed, |
|
52 * playback ended, seek complete, audio tear down) back to MediaOmxDecoder |
|
53 * |
|
54 * It acts as a bridge between MediaOmxDecoder and AudioSink during |
|
55 * offload playback |
|
56 */ |
|
57 |
|
58 class AudioOffloadPlayer : public AudioOffloadPlayerBase |
|
59 { |
|
60 typedef android::Mutex Mutex; |
|
61 typedef android::MetaData MetaData; |
|
62 typedef android::status_t status_t; |
|
63 typedef android::AudioTrack AudioTrack; |
|
64 typedef android::MediaBuffer MediaBuffer; |
|
65 typedef android::MediaSource MediaSource; |
|
66 |
|
67 public: |
|
68 enum { |
|
69 REACHED_EOS, |
|
70 SEEK_COMPLETE |
|
71 }; |
|
72 |
|
73 AudioOffloadPlayer(MediaOmxDecoder* aDecoder = nullptr); |
|
74 |
|
75 ~AudioOffloadPlayer(); |
|
76 |
|
77 // Caller retains ownership of "aSource". |
|
78 void SetSource(const android::sp<MediaSource> &aSource); |
|
79 |
|
80 // Start the source if it's not already started and open the AudioSink to |
|
81 // create an offloaded audio track |
|
82 status_t Start(bool aSourceAlreadyStarted = false); |
|
83 |
|
84 double GetMediaTimeSecs(); |
|
85 |
|
86 // To update progress bar when the element is visible |
|
87 void SetElementVisibility(bool aIsVisible); |
|
88 |
|
89 status_t ChangeState(MediaDecoder::PlayState aState); |
|
90 |
|
91 void SetVolume(double aVolume); |
|
92 |
|
93 // Update ready state based on current play state. Not checking data |
|
94 // availability since offloading is currently done only when whole compressed |
|
95 // data is available |
|
96 MediaDecoderOwner::NextFrameStatus GetNextFrameStatus(); |
|
97 |
|
98 void TimeUpdate(); |
|
99 |
|
100 // Close the audio sink, stop time updates, frees the input buffers |
|
101 void Reset(); |
|
102 |
|
103 private: |
|
104 // Set when audio source is started and audioSink is initialized |
|
105 // Used only in main thread |
|
106 bool mStarted; |
|
107 |
|
108 // Set when audio sink is started. i.e. playback started |
|
109 // Used only in main thread |
|
110 bool mPlaying; |
|
111 |
|
112 // Set when playstate is seeking and reset when FillBUffer() acknowledged |
|
113 // seeking by seeking audio source. Used in main thread and offload |
|
114 // callback thread, protected by Mutex mLock |
|
115 bool mSeeking; |
|
116 |
|
117 // Once playback reached end of stream (last ~100ms), position provided by DSP |
|
118 // may be reset/corrupted. This bool is used to avoid that. |
|
119 // Used in main thread and offload callback thread, protected by Mutex |
|
120 // mLock |
|
121 bool mReachedEOS; |
|
122 |
|
123 // Set when there is a seek request during pause. |
|
124 // Used in main thread and offload callback thread, protected by Mutex |
|
125 // mLock |
|
126 bool mSeekDuringPause; |
|
127 |
|
128 // Seek can be triggered internally or by MediaDecoder. This bool is to |
|
129 // to track seek triggered by MediaDecoder so that we can send back |
|
130 // SeekingStarted and SeekingStopped events. |
|
131 // Used in main thread and offload callback thread, protected by Mutex mLock |
|
132 bool mDispatchSeekEvents; |
|
133 |
|
134 // Set when the HTML Audio Element is visible to the user. |
|
135 // Used only in main thread |
|
136 bool mIsElementVisible; |
|
137 |
|
138 // Session id given by Android::AudioSystem and used while creating audio sink |
|
139 // Used only in main thread |
|
140 int mSessionId; |
|
141 |
|
142 // Sample rate of current audio track. Used only in main thread |
|
143 int mSampleRate; |
|
144 |
|
145 // After seeking, positions returned by offlaoded tracks (DSP) will be |
|
146 // relative to the seeked position. And seeked position may be slightly |
|
147 // different than given mSeekTimeUs, if audio source cannot find a frame at |
|
148 // that position. Store seeked position in mStartPosUs and provide |
|
149 // mStartPosUs + GetPosition() (i.e. absolute position) to MediaOmxDecoder |
|
150 // Used in main thread and offload callback thread, protected by Mutex |
|
151 // mLock |
|
152 int64_t mStartPosUs; |
|
153 |
|
154 // Given seek time when there is a request to seek |
|
155 // Used in main thread and offload callback thread, protected by Mutex |
|
156 // mLock |
|
157 int64_t mSeekTimeUs; |
|
158 |
|
159 // Positions obtained from offlaoded tracks (DSP) |
|
160 // Used in main thread and offload callback thread, protected by Mutex |
|
161 // mLock |
|
162 int64_t mPositionTimeMediaUs; |
|
163 |
|
164 // State obtained from MediaOmxDecoder. Used only in main thread |
|
165 MediaDecoder::PlayState mPlayState; |
|
166 |
|
167 // Protect accessing audio position related variables between main thread and |
|
168 // offload callback thread |
|
169 Mutex mLock; |
|
170 |
|
171 // Compressed audio source. |
|
172 // Used in main thread first and later in offload callback thread |
|
173 android::sp<MediaSource> mSource; |
|
174 |
|
175 // Audio sink wrapper to access offloaded audio tracks |
|
176 // Used in main thread and offload callback thread |
|
177 // Race conditions are protected in underlying Android::AudioTrack class |
|
178 android::sp<AudioSink> mAudioSink; |
|
179 |
|
180 // Buffer used to get date from audio source. Used in offload callback thread |
|
181 MediaBuffer* mInputBuffer; |
|
182 |
|
183 // MediaOmxDecoder object used mainly to notify the audio sink status |
|
184 MediaOmxDecoder* mObserver; |
|
185 |
|
186 TimeStamp mLastFireUpdateTime; |
|
187 |
|
188 // Timer to trigger position changed events |
|
189 nsCOMPtr<nsITimer> mTimeUpdateTimer; |
|
190 |
|
191 // Timer to reset AudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS. |
|
192 // It is triggered in Pause() and canceled when there is a Play() within |
|
193 // OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed. |
|
194 nsCOMPtr<nsITimer> mResetTimer; |
|
195 |
|
196 int64_t GetMediaTimeUs(); |
|
197 |
|
198 // Provide the playback position in microseconds from total number of |
|
199 // frames played by audio track |
|
200 int64_t GetOutputPlayPositionUs_l() const; |
|
201 |
|
202 // Fill the buffer given by audio sink with data from compressed audio |
|
203 // source. Also handles the seek by seeking audio source and stop the sink in |
|
204 // case of error |
|
205 size_t FillBuffer(void *aData, size_t aSize); |
|
206 |
|
207 // Called by AudioSink when it needs data, to notify EOS or tear down event |
|
208 static size_t AudioSinkCallback(AudioSink *aAudioSink, |
|
209 void *aData, |
|
210 size_t aSize, |
|
211 void *aMe, |
|
212 AudioSink::cb_event_t aEvent); |
|
213 |
|
214 bool IsSeeking(); |
|
215 |
|
216 // Set mSeekTime to the given position and restart the sink. Actual seek |
|
217 // happens in FillBuffer(). If aDispatchSeekEvents is true, send |
|
218 // SeekingStarted event always and SeekingStopped event when the play state is |
|
219 // paused to MediaDecoder. |
|
220 // When decoding and playing happens separately, if there is a seek during |
|
221 // pause, we can decode and keep data ready. |
|
222 // In case of offload player, no way to seek during pause. So just fake that |
|
223 // seek is done. |
|
224 status_t SeekTo(int64_t aTimeUs, bool aDispatchSeekEvents = false); |
|
225 |
|
226 // Start/Resume the audio sink so that callback will start being called to get |
|
227 // compressed data |
|
228 status_t Play(); |
|
229 |
|
230 // Stop the audio sink if we need to play till we drain the current buffer. |
|
231 // or Pause the sink in case we should stop playing immediately |
|
232 void Pause(bool aPlayPendingSamples = false); |
|
233 |
|
234 // When audio is offloaded, application processor wakes up less frequently |
|
235 // (>1sec) But when Player UI is visible we need to update progress bar |
|
236 // atleast once in 250ms. Start a timer when player UI becomes visible or |
|
237 // audio starts playing to send PlaybackPositionChanged events once in 250ms. |
|
238 // Stop the timer when UI goes invisible or play state is not playing. |
|
239 // Also make sure timer functions are always called from main thread |
|
240 nsresult StartTimeUpdate(); |
|
241 nsresult StopTimeUpdate(); |
|
242 |
|
243 // Notify end of stream by sending PlaybackEnded event to observer |
|
244 // (i.e.MediaDecoder) |
|
245 void NotifyAudioEOS(); |
|
246 |
|
247 // Notify position changed event by sending PlaybackPositionChanged event to |
|
248 // observer |
|
249 void NotifyPositionChanged(); |
|
250 |
|
251 // Offloaded audio track is invalidated due to usecase change. Notify |
|
252 // MediaDecoder to re-evaluate offloading options |
|
253 void NotifyAudioTearDown(); |
|
254 |
|
255 // Send information from MetaData to the HAL via AudioSink |
|
256 void SendMetaDataToHal(android::sp<AudioSink>& aSink, |
|
257 const android::sp<MetaData>& aMeta); |
|
258 |
|
259 AudioOffloadPlayer(const AudioOffloadPlayer &); |
|
260 AudioOffloadPlayer &operator=(const AudioOffloadPlayer &); |
|
261 }; |
|
262 |
|
263 } // namespace mozilla |
|
264 |
|
265 #endif // AUDIO_OFFLOAD_PLAYER_H_ |