blob: b45f9bf119eca120d72c4fbc57458585e0d7a26d [file] [log] [blame]
James Dongc9dedc42011-05-01 12:36:22 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AudioPlayerBase"
19#include <utils/Log.h>
20
21#include <binder/IPCThreadState.h>
22#include <media/AudioTrack.h>
23#include <media/stagefright/MediaDebug.h>
24#include <media/stagefright/MediaDefs.h>
25#include <media/stagefright/MediaErrors.h>
26#include <media/stagefright/MediaSource.h>
27#include <media/stagefright/MetaData.h>
28
29#include "AudioPlayerBase.h"
30#include "PreviewPlayerBase.h"
31
32namespace android {
33
34AudioPlayerBase::AudioPlayerBase(
35 const sp<MediaPlayerBase::AudioSink> &audioSink,
36 PreviewPlayerBase *observer)
37 : mAudioTrack(NULL),
38 mInputBuffer(NULL),
39 mSampleRate(0),
40 mLatencyUs(0),
41 mFrameSize(0),
42 mNumFramesPlayed(0),
43 mPositionTimeMediaUs(-1),
44 mPositionTimeRealUs(-1),
45 mSeeking(false),
46 mReachedEOS(false),
47 mFinalStatus(OK),
48 mStarted(false),
49 mIsFirstBuffer(false),
50 mFirstBufferResult(OK),
51 mFirstBuffer(NULL),
52 mAudioSink(audioSink),
53 mObserver(observer) {
54}
55
56AudioPlayerBase::~AudioPlayerBase() {
57 if (mStarted) {
58 reset();
59 }
60}
61
62void AudioPlayerBase::setSource(const sp<MediaSource> &source) {
63 CHECK_EQ(mSource, NULL);
64 mSource = source;
65}
66
67status_t AudioPlayerBase::start(bool sourceAlreadyStarted) {
68 CHECK(!mStarted);
69 CHECK(mSource != NULL);
70
71 status_t err;
72 if (!sourceAlreadyStarted) {
73 err = mSource->start();
74
75 if (err != OK) {
76 return err;
77 }
78 }
79
80 // We allow an optional INFO_FORMAT_CHANGED at the very beginning
81 // of playback, if there is one, getFormat below will retrieve the
82 // updated format, if there isn't, we'll stash away the valid buffer
83 // of data to be used on the first audio callback.
84
85 CHECK(mFirstBuffer == NULL);
86
87 mFirstBufferResult = mSource->read(&mFirstBuffer);
88 if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
Steve Block2703f232011-10-20 11:56:09 +010089 ALOGV("INFO_FORMAT_CHANGED!!!");
James Dongc9dedc42011-05-01 12:36:22 -070090
91 CHECK(mFirstBuffer == NULL);
92 mFirstBufferResult = OK;
93 mIsFirstBuffer = false;
94 } else {
95 mIsFirstBuffer = true;
96 }
97
98 sp<MetaData> format = mSource->getFormat();
99 const char *mime;
100 bool success = format->findCString(kKeyMIMEType, &mime);
101 CHECK(success);
102 CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
103
104 success = format->findInt32(kKeySampleRate, &mSampleRate);
105 CHECK(success);
106
107 int32_t numChannels;
108 success = format->findInt32(kKeyChannelCount, &numChannels);
109 CHECK(success);
110
111 if (mAudioSink.get() != NULL) {
112 status_t err = mAudioSink->open(
113 mSampleRate, numChannels, AUDIO_FORMAT_PCM_16_BIT,
114 DEFAULT_AUDIOSINK_BUFFERCOUNT,
115 &AudioPlayerBase::AudioSinkCallback, this);
116 if (err != OK) {
117 if (mFirstBuffer != NULL) {
118 mFirstBuffer->release();
119 mFirstBuffer = NULL;
120 }
121
122 if (!sourceAlreadyStarted) {
123 mSource->stop();
124 }
125
126 return err;
127 }
128
129 mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
130 mFrameSize = mAudioSink->frameSize();
131
132 mAudioSink->start();
133 } else {
134 mAudioTrack = new AudioTrack(
135 AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
136 (numChannels == 2)
137 ? AUDIO_CHANNEL_OUT_STEREO
138 : AUDIO_CHANNEL_OUT_MONO,
139 0, 0, &AudioCallback, this, 0);
140
141 if ((err = mAudioTrack->initCheck()) != OK) {
142 delete mAudioTrack;
143 mAudioTrack = NULL;
144
145 if (mFirstBuffer != NULL) {
146 mFirstBuffer->release();
147 mFirstBuffer = NULL;
148 }
149
150 if (!sourceAlreadyStarted) {
151 mSource->stop();
152 }
153
154 return err;
155 }
156
157 mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
158 mFrameSize = mAudioTrack->frameSize();
159
160 mAudioTrack->start();
161 }
162
163 mStarted = true;
164
165 return OK;
166}
167
168void AudioPlayerBase::pause(bool playPendingSamples) {
169 CHECK(mStarted);
170
171 if (playPendingSamples) {
172 if (mAudioSink.get() != NULL) {
173 mAudioSink->stop();
174 } else {
175 mAudioTrack->stop();
176 }
177 } else {
178 if (mAudioSink.get() != NULL) {
179 mAudioSink->pause();
180 } else {
181 mAudioTrack->pause();
182 }
183 }
184}
185
186void AudioPlayerBase::resume() {
187 CHECK(mStarted);
188
189 if (mAudioSink.get() != NULL) {
190 mAudioSink->start();
191 } else {
192 mAudioTrack->start();
193 }
194}
195
196void AudioPlayerBase::reset() {
197 CHECK(mStarted);
198
199 if (mAudioSink.get() != NULL) {
200 mAudioSink->stop();
201 mAudioSink->close();
202 } else {
203 mAudioTrack->stop();
204
205 delete mAudioTrack;
206 mAudioTrack = NULL;
207 }
208
209 // Make sure to release any buffer we hold onto so that the
210 // source is able to stop().
211
212 if (mFirstBuffer != NULL) {
213 mFirstBuffer->release();
214 mFirstBuffer = NULL;
215 }
216
217 if (mInputBuffer != NULL) {
Steve Block2703f232011-10-20 11:56:09 +0100218 ALOGV("AudioPlayerBase releasing input buffer.");
James Dongc9dedc42011-05-01 12:36:22 -0700219
220 mInputBuffer->release();
221 mInputBuffer = NULL;
222 }
223
224 mSource->stop();
225
226 // The following hack is necessary to ensure that the OMX
227 // component is completely released by the time we may try
228 // to instantiate it again.
229 wp<MediaSource> tmp = mSource;
230 mSource.clear();
231 while (tmp.promote() != NULL) {
232 usleep(1000);
233 }
234 IPCThreadState::self()->flushCommands();
235
236 mNumFramesPlayed = 0;
237 mPositionTimeMediaUs = -1;
238 mPositionTimeRealUs = -1;
239 mSeeking = false;
240 mReachedEOS = false;
241 mFinalStatus = OK;
242 mStarted = false;
243}
244
245// static
Glenn Kasten72e95e72011-06-01 15:20:41 -0700246void AudioPlayerBase::AudioCallback(int event, void *user, void *info) {
James Dongc9dedc42011-05-01 12:36:22 -0700247 static_cast<AudioPlayerBase *>(user)->AudioCallback(event, info);
248}
249
250bool AudioPlayerBase::isSeeking() {
251 Mutex::Autolock autoLock(mLock);
252 return mSeeking;
253}
254
255bool AudioPlayerBase::reachedEOS(status_t *finalStatus) {
256 *finalStatus = OK;
257
258 Mutex::Autolock autoLock(mLock);
259 *finalStatus = mFinalStatus;
260 return mReachedEOS;
261}
262
263// static
264size_t AudioPlayerBase::AudioSinkCallback(
265 MediaPlayerBase::AudioSink *audioSink,
266 void *buffer, size_t size, void *cookie) {
267 AudioPlayerBase *me = (AudioPlayerBase *)cookie;
268
269 return me->fillBuffer(buffer, size);
270}
271
Glenn Kasten72e95e72011-06-01 15:20:41 -0700272void AudioPlayerBase::AudioCallback(int event, void *info) {
James Dongc9dedc42011-05-01 12:36:22 -0700273 if (event != AudioTrack::EVENT_MORE_DATA) {
274 return;
275 }
276
277 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
278 size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
279
280 buffer->size = numBytesWritten;
281}
282
283uint32_t AudioPlayerBase::getNumFramesPendingPlayout() const {
284 uint32_t numFramesPlayedOut;
285 status_t err;
286
287 if (mAudioSink != NULL) {
288 err = mAudioSink->getPosition(&numFramesPlayedOut);
289 } else {
290 err = mAudioTrack->getPosition(&numFramesPlayedOut);
291 }
292
293 if (err != OK || mNumFramesPlayed < numFramesPlayedOut) {
294 return 0;
295 }
296
297 // mNumFramesPlayed is the number of frames submitted
298 // to the audio sink for playback, but not all of them
299 // may have played out by now.
300 return mNumFramesPlayed - numFramesPlayedOut;
301}
302
303size_t AudioPlayerBase::fillBuffer(void *data, size_t size) {
304 if (mNumFramesPlayed == 0) {
Steve Block2703f232011-10-20 11:56:09 +0100305 ALOGV("AudioCallback");
James Dongc9dedc42011-05-01 12:36:22 -0700306 }
307
308 if (mReachedEOS) {
309 return 0;
310 }
311
312 bool postSeekComplete = false;
313 bool postEOS = false;
314 int64_t postEOSDelayUs = 0;
315
316 size_t size_done = 0;
317 size_t size_remaining = size;
318 while (size_remaining > 0) {
319 MediaSource::ReadOptions options;
320
321 {
322 Mutex::Autolock autoLock(mLock);
323
324 if (mSeeking) {
325 if (mIsFirstBuffer) {
326 if (mFirstBuffer != NULL) {
327 mFirstBuffer->release();
328 mFirstBuffer = NULL;
329 }
330 mIsFirstBuffer = false;
331 }
332
333 options.setSeekTo(mSeekTimeUs);
334
335 if (mInputBuffer != NULL) {
336 mInputBuffer->release();
337 mInputBuffer = NULL;
338 }
339
340 mSeeking = false;
341 if (mObserver) {
342 postSeekComplete = true;
343 }
344 }
345 }
346
347 if (mInputBuffer == NULL) {
348 status_t err;
349
350 if (mIsFirstBuffer) {
351 mInputBuffer = mFirstBuffer;
352 mFirstBuffer = NULL;
353 err = mFirstBufferResult;
354
355 mIsFirstBuffer = false;
356 } else {
357 err = mSource->read(&mInputBuffer, &options);
358 }
359
360 CHECK((err == OK && mInputBuffer != NULL)
361 || (err != OK && mInputBuffer == NULL));
362
363 Mutex::Autolock autoLock(mLock);
364
365 if (err != OK) {
366 if (mObserver && !mReachedEOS) {
367 // We don't want to post EOS right away but only
368 // after all frames have actually been played out.
369
370 // These are the number of frames submitted to the
371 // AudioTrack that you haven't heard yet.
372 uint32_t numFramesPendingPlayout =
373 getNumFramesPendingPlayout();
374
375 // These are the number of frames we're going to
376 // submit to the AudioTrack by returning from this
377 // callback.
378 uint32_t numAdditionalFrames = size_done / mFrameSize;
379
380 numFramesPendingPlayout += numAdditionalFrames;
381
382 int64_t timeToCompletionUs =
383 (1000000ll * numFramesPendingPlayout) / mSampleRate;
384
Steve Block2703f232011-10-20 11:56:09 +0100385 ALOGV("total number of frames played: %lld (%lld us)",
James Dongc9dedc42011-05-01 12:36:22 -0700386 (mNumFramesPlayed + numAdditionalFrames),
387 1000000ll * (mNumFramesPlayed + numAdditionalFrames)
388 / mSampleRate);
389
Steve Block2703f232011-10-20 11:56:09 +0100390 ALOGV("%d frames left to play, %lld us (%.2f secs)",
James Dongc9dedc42011-05-01 12:36:22 -0700391 numFramesPendingPlayout,
392 timeToCompletionUs, timeToCompletionUs / 1E6);
393
394 postEOS = true;
395 postEOSDelayUs = timeToCompletionUs + mLatencyUs;
396 }
397
398 mReachedEOS = true;
399 mFinalStatus = err;
400 break;
401 }
402
403 CHECK(mInputBuffer->meta_data()->findInt64(
404 kKeyTime, &mPositionTimeMediaUs));
405
406 mPositionTimeRealUs =
407 ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
408 / mSampleRate;
409
Steve Block2703f232011-10-20 11:56:09 +0100410 ALOGV("buffer->size() = %d, "
James Dongc9dedc42011-05-01 12:36:22 -0700411 "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
412 mInputBuffer->range_length(),
413 mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
414 }
415
416 if (mInputBuffer->range_length() == 0) {
417 mInputBuffer->release();
418 mInputBuffer = NULL;
419
420 continue;
421 }
422
423 size_t copy = size_remaining;
424 if (copy > mInputBuffer->range_length()) {
425 copy = mInputBuffer->range_length();
426 }
427
428 memcpy((char *)data + size_done,
429 (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
430 copy);
431
432 mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
433 mInputBuffer->range_length() - copy);
434
435 size_done += copy;
436 size_remaining -= copy;
437 }
438
439 {
440 Mutex::Autolock autoLock(mLock);
441 mNumFramesPlayed += size_done / mFrameSize;
442 }
443
444 if (postEOS) {
445 mObserver->postAudioEOS(postEOSDelayUs);
446 }
447
448 if (postSeekComplete) {
449 mObserver->postAudioSeekComplete();
450 }
451
452 return size_done;
453}
454
455int64_t AudioPlayerBase::getRealTimeUs() {
456 Mutex::Autolock autoLock(mLock);
457 return getRealTimeUsLocked();
458}
459
460int64_t AudioPlayerBase::getRealTimeUsLocked() const {
461 return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
462}
463
464int64_t AudioPlayerBase::getMediaTimeUs() {
465 Mutex::Autolock autoLock(mLock);
466
467 if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
468 if (mSeeking) {
469 return mSeekTimeUs;
470 }
471
472 return 0;
473 }
474
475 int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs;
476 if (realTimeOffset < 0) {
477 realTimeOffset = 0;
478 }
479
480 return mPositionTimeMediaUs + realTimeOffset;
481}
482
483bool AudioPlayerBase::getMediaTimeMapping(
484 int64_t *realtime_us, int64_t *mediatime_us) {
485 Mutex::Autolock autoLock(mLock);
486
487 *realtime_us = mPositionTimeRealUs;
488 *mediatime_us = mPositionTimeMediaUs;
489
490 return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
491}
492
493status_t AudioPlayerBase::seekTo(int64_t time_us) {
494 Mutex::Autolock autoLock(mLock);
495
496 mSeeking = true;
497 mPositionTimeRealUs = mPositionTimeMediaUs = -1;
498 mReachedEOS = false;
499 mSeekTimeUs = time_us;
500
501 if (mAudioSink != NULL) {
502 mAudioSink->flush();
503 } else {
504 mAudioTrack->flush();
505 }
506
507 return OK;
508}
509
510}