summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
authorMarco Nelissen <marcone@google.com>2019-10-18 11:12:30 -0700
committerMarco Nelissen <marcone@google.com>2019-10-18 11:27:49 -0700
commit1edb68c38408d06bf8f97d6884663732b7dbcce2 (patch)
tree87159f2617c58f9cb971ab48c8512d5ad14da2df /cmds
parent03379fb2cc34c93214082a0ceaf038626117554d (diff)
Move AudioPlayer to test commands
AudioPlayer was only used by the commandline utilities, so move it out of libstagefright. Test: build, run Change-Id: I561cccd323206de7415bd235b72711194080aaea
Diffstat (limited to 'cmds')
-rw-r--r--cmds/stagefright/Android.mk13
-rw-r--r--cmds/stagefright/AudioPlayer.cpp689
-rw-r--r--cmds/stagefright/AudioPlayer.h125
-rw-r--r--cmds/stagefright/audioloop.cpp2
-rw-r--r--cmds/stagefright/record.cpp3
-rw-r--r--cmds/stagefright/recordvideo.cpp4
-rw-r--r--cmds/stagefright/stagefright.cpp3
7 files changed, 828 insertions, 11 deletions
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index cc43b61612..defc94f8fd 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,6 +3,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
stagefright.cpp \
jpeg.cpp \
SineSource.cpp
@@ -10,7 +11,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmedia_codeclist libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
- libhidlbase libdatasource \
+ libhidlbase libdatasource libaudioclient \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
@@ -31,12 +32,13 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
record.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation libdatasource
+ libstagefright_foundation libdatasource libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/camera/include \
@@ -57,12 +59,12 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
+ AudioPlayer.cpp \
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -83,12 +85,13 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/AudioPlayer.cpp b/cmds/stagefright/AudioPlayer.cpp
new file mode 100644
index 0000000000..208713d950
--- /dev/null
+++ b/cmds/stagefright/AudioPlayer.cpp
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioPlayer"
+#include <utils/Log.h>
+#include <cutils/compiler.h>
+
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+#include <media/MediaSource.h>
+#include <media/openmax/OMX_Audio.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALookup.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include "AudioPlayer.h"
+
+namespace android {
+
+AudioPlayer::AudioPlayer(
+ const sp<MediaPlayerBase::AudioSink> &audioSink,
+ uint32_t flags)
+ : mInputBuffer(NULL),
+ mSampleRate(0),
+ mLatencyUs(0),
+ mFrameSize(0),
+ mNumFramesPlayed(0),
+ mNumFramesPlayedSysTimeUs(ALooper::GetNowUs()),
+ mPositionTimeMediaUs(-1),
+ mPositionTimeRealUs(-1),
+ mSeeking(false),
+ mReachedEOS(false),
+ mFinalStatus(OK),
+ mSeekTimeUs(0),
+ mStarted(false),
+ mIsFirstBuffer(false),
+ mFirstBufferResult(OK),
+ mFirstBuffer(NULL),
+ mAudioSink(audioSink),
+ mPlaying(false),
+ mStartPosUs(0),
+ mCreateFlags(flags) {
+}
+
+AudioPlayer::~AudioPlayer() {
+ if (mStarted) {
+ reset();
+ }
+}
+
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK(mSource == NULL);
+ mSource = source;
+}
+
+ALookup<audio_format_t, int32_t> sAudioFormatToPcmEncoding {
+ {
+ { AUDIO_FORMAT_PCM_16_BIT, kAudioEncodingPcm16bit },
+ { AUDIO_FORMAT_PCM_8_BIT, kAudioEncodingPcm8bit },
+ { AUDIO_FORMAT_PCM_FLOAT, kAudioEncodingPcmFloat },
+ }
+};
+
+status_t AudioPlayer::start(bool sourceAlreadyStarted) {
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
+
+ status_t err;
+ if (!sourceAlreadyStarted) {
+ err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+ // of playback, if there is one, getFormat below will retrieve the
+ // updated format, if there isn't, we'll stash away the valid buffer
+ // of data to be used on the first audio callback.
+
+ CHECK(mFirstBuffer == NULL);
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeeking = false;
+ }
+
+ mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
+ if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+ ALOGV("INFO_FORMAT_CHANGED!!!");
+
+ CHECK(mFirstBuffer == NULL);
+ mFirstBufferResult = OK;
+ mIsFirstBuffer = false;
+ } else {
+ mIsFirstBuffer = true;
+ }
+
+ sp<MetaData> format = mSource->getFormat();
+
+ if (format == NULL) {
+ ALOGE("No metadata b/118620871");
+ android_errorWriteLog(0x534e4554, "118620871");
+ return BAD_VALUE;
+ }
+
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+ CHECK(useOffload() || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ CHECK(success);
+
+ int32_t numChannels, channelMask;
+ success = format->findInt32(kKeyChannelCount, &numChannels);
+ CHECK(success);
+
+ if(!format->findInt32(kKeyChannelMask, &channelMask)) {
+ // log only when there's a risk of ambiguity of channel mask selection
+ ALOGI_IF(numChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", numChannels);
+ channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+ }
+
+ audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
+ int32_t pcmEncoding;
+ if (format->findInt32(kKeyPcmEncoding, &pcmEncoding)) {
+ sAudioFormatToPcmEncoding.map(pcmEncoding, &audioFormat);
+ }
+
+ if (useOffload()) {
+ if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
+ ALOGE("Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format", mime);
+ audioFormat = AUDIO_FORMAT_INVALID;
+ } else {
+ ALOGV("Mime type \"%s\" mapped to audio_format 0x%x", mime, audioFormat);
+ }
+
+ int32_t aacaot = -1;
+ if ((audioFormat == AUDIO_FORMAT_AAC) && format->findInt32(kKeyAACAOT, &aacaot)) {
+ // Redefine AAC format corrosponding to aac profile
+ mapAACProfileToAudioFormat(audioFormat,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ }
+ }
+
+ int avgBitRate = -1;
+ format->findInt32(kKeyBitRate, &avgBitRate);
+
+ if (mAudioSink.get() != NULL) {
+
+ uint32_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+
+ if (allowDeepBuffering()) {
+ flags |= AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ }
+ if (useOffload()) {
+ flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+
+ int64_t durationUs;
+ if (format->findInt64(kKeyDuration, &durationUs)) {
+ offloadInfo.duration_us = durationUs;
+ } else {
+ offloadInfo.duration_us = -1;
+ }
+
+ offloadInfo.sample_rate = mSampleRate;
+ offloadInfo.channel_mask = channelMask;
+ offloadInfo.format = audioFormat;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+ offloadInfo.bit_rate = avgBitRate;
+ offloadInfo.has_video = ((mCreateFlags & HAS_VIDEO) != 0);
+ offloadInfo.is_streaming = ((mCreateFlags & IS_STREAMING) != 0);
+ }
+
+ status_t err = mAudioSink->open(
+ mSampleRate, numChannels, channelMask, audioFormat,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &AudioPlayer::AudioSinkCallback,
+ this,
+ (audio_output_flags_t)flags,
+ useOffload() ? &offloadInfo : NULL);
+
+ if (err == OK) {
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ mFrameSize = mAudioSink->frameSize();
+
+ if (useOffload()) {
+ // If the playback is offloaded to h/w we pass the
+ // HAL some metadata information
+ // We don't want to do this for PCM because it will be going
+ // through the AudioFlinger mixer before reaching the hardware
+ sendMetaDataToHal(mAudioSink, format);
+ }
+
+ err = mAudioSink->start();
+ // do not alter behavior for non offloaded tracks: ignore start status.
+ if (!useOffload()) {
+ err = OK;
+ }
+ }
+
+ if (err != OK) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ return err;
+ }
+
+ } else {
+ // playing to an AudioTrack, set up mask if necessary
+ audio_channel_mask_t audioMask = channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER ?
+ audio_channel_out_mask_from_count(numChannels) : channelMask;
+ if (0 == audioMask) {
+ return BAD_VALUE;
+ }
+
+ mAudioTrack = new AudioTrack(
+ AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
+ 0 /*frameCount*/, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this,
+ 0 /*notificationFrames*/);
+
+ if ((err = mAudioTrack->initCheck()) != OK) {
+ mAudioTrack.clear();
+
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ return err;
+ }
+
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ mFrameSize = mAudioTrack->frameSize();
+
+ mAudioTrack->start();
+ }
+
+ mStarted = true;
+ mPlaying = true;
+
+ return OK;
+}
+
+void AudioPlayer::pause(bool playPendingSamples) {
+ CHECK(mStarted);
+
+ if (playPendingSamples) {
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+ }
+
+ mNumFramesPlayed = 0;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+ } else {
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->pause();
+ } else {
+ mAudioTrack->pause();
+ }
+ }
+
+ mPlaying = false;
+}
+
+status_t AudioPlayer::resume() {
+ CHECK(mStarted);
+ status_t err;
+
+ if (mAudioSink.get() != NULL) {
+ err = mAudioSink->start();
+ } else {
+ err = mAudioTrack->start();
+ }
+
+ if (err == OK) {
+ mPlaying = true;
+ }
+
+ return err;
+}
+
+void AudioPlayer::reset() {
+ CHECK(mStarted);
+
+ ALOGV("reset: mPlaying=%d mReachedEOS=%d useOffload=%d",
+ mPlaying, mReachedEOS, useOffload() );
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ // If we're closing and have reached EOS, we don't want to flush
+ // the track because if it is offloaded there could be a small
+ // amount of residual data in the hardware buffer which we must
+ // play to give gapless playback.
+ // But if we're resetting when paused or before we've reached EOS
+ // we can't be doing a gapless playback and there could be a large
+ // amount of data queued in the hardware if the track is offloaded,
+ // so we must flush to prevent a track switch being delayed playing
+ // the buffered data that we don't want now
+ if (!mPlaying || !mReachedEOS) {
+ mAudioSink->flush();
+ }
+
+ mAudioSink->close();
+ } else {
+ mAudioTrack->stop();
+
+ if (!mPlaying || !mReachedEOS) {
+ mAudioTrack->flush();
+ }
+
+ mAudioTrack.clear();
+ }
+
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (mInputBuffer != NULL) {
+ ALOGV("AudioPlayer releasing input buffer.");
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ // When offloading, the OMX component is not used so this hack
+ // is not needed
+ if (!useOffload()) {
+ wp<MediaSource> tmp = mSource;
+ mSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+ } else {
+ mSource.clear();
+ }
+ IPCThreadState::self()->flushCommands();
+
+ mNumFramesPlayed = 0;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mSeekTimeUs = 0;
+ mReachedEOS = false;
+ mFinalStatus = OK;
+ mStarted = false;
+ mPlaying = false;
+ mStartPosUs = 0;
+}
+
+// static
+void AudioPlayer::AudioCallback(int event, void *user, void *info) {
+ static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
+}
+
+bool AudioPlayer::reachedEOS(status_t *finalStatus) {
+ *finalStatus = OK;
+
+ Mutex::Autolock autoLock(mLock);
+ *finalStatus = mFinalStatus;
+ return mReachedEOS;
+}
+
+status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->setPlaybackRate(rate);
+ } else if (mAudioTrack != 0){
+ return mAudioTrack->setPlaybackRate(rate);
+ } else {
+ return NO_INIT;
+ }
+}
+
+status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->getPlaybackRate(rate);
+ } else if (mAudioTrack != 0) {
+ *rate = mAudioTrack->getPlaybackRate();
+ return OK;
+ } else {
+ return NO_INIT;
+ }
+}
+
+// static
+size_t AudioPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink * /* audioSink */,
+ void *buffer, size_t size, void *cookie,
+ MediaPlayerBase::AudioSink::cb_event_t event) {
+ AudioPlayer *me = (AudioPlayer *)cookie;
+
+ switch(event) {
+ case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
+ return me->fillBuffer(buffer, size);
+
+ case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
+ ALOGV("AudioSinkCallback: stream end");
+ me->mReachedEOS = true;
+ break;
+
+ case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
+ ALOGV("AudioSinkCallback: Tear down event");
+ break;
+ }
+
+ return 0;
+}
+
+void AudioPlayer::AudioCallback(int event, void *info) {
+ switch (event) {
+ case AudioTrack::EVENT_MORE_DATA:
+ {
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
+ buffer->size = numBytesWritten;
+ }
+ break;
+
+ case AudioTrack::EVENT_STREAM_END:
+ mReachedEOS = true;
+ break;
+ }
+}
+
+size_t AudioPlayer::fillBuffer(void *data, size_t size) {
+ if (mNumFramesPlayed == 0) {
+ ALOGV("AudioCallback");
+ }
+
+ if (mReachedEOS) {
+ return 0;
+ }
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+ bool refreshSeekTime = false;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mSeeking) {
+ if (mIsFirstBuffer) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+ mIsFirstBuffer = false;
+ }
+
+ options.setSeekTo(mSeekTimeUs);
+ refreshSeekTime = true;
+
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSeeking = false;
+ }
+ }
+
+ if (mInputBuffer == NULL) {
+ status_t err;
+
+ if (mIsFirstBuffer) {
+ mInputBuffer = mFirstBuffer;
+ mFirstBuffer = NULL;
+ err = mFirstBufferResult;
+
+ mIsFirstBuffer = false;
+ } else {
+ err = mSource->read(&mInputBuffer, &options);
+ }
+
+ CHECK((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (err != OK) {
+ if (!mReachedEOS) {
+ if (useOffload()) {
+ // no more buffers to push - stop() and wait for STREAM_END
+ // don't set mReachedEOS until stream end received
+ if (mAudioSink != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+ }
+ } else {
+ mReachedEOS = true;
+ }
+ }
+
+ mFinalStatus = err;
+ break;
+ }
+
+ if (mAudioSink != NULL) {
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ } else {
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ }
+
+ if(mInputBuffer->range_length() != 0) {
+ CHECK(mInputBuffer->meta_data().findInt64(
+ kKeyTime, &mPositionTimeMediaUs));
+ }
+
+ // need to adjust the mStartPosUs for offload decoding since parser
+ // might not be able to get the exact seek time requested.
+ if (refreshSeekTime) {
+ if (useOffload()) {
+ mStartPosUs = mPositionTimeMediaUs;
+ ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
+ }
+ // clear seek time with mLock locked and once we have valid mPositionTimeMediaUs
+ // and mPositionTimeRealUs
+ // before clearing mSeekTimeUs check if a new seek request has been received while
+ // we were reading from the source with mLock released.
+ if (!mSeeking) {
+ mSeekTimeUs = 0;
+ }
+ }
+
+ if (!useOffload()) {
+ mPositionTimeRealUs =
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
+ ALOGV("buffer->size() = %zu, "
+ "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
+ mInputBuffer->range_length(),
+ mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
+ }
+
+ }
+
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ }
+
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+ }
+
+ if (useOffload()) {
+ // We must ask the hardware what it has played
+ mPositionTimeRealUs = getOutputPlayPositionUs_l();
+ ALOGV("mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
+ mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
+ }
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ mNumFramesPlayed += size_done / mFrameSize;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+ }
+
+ return size_done;
+}
+
+int64_t AudioPlayer::getOutputPlayPositionUs_l()
+{
+ uint32_t playedSamples = 0;
+ uint32_t sampleRate;
+ if (mAudioSink != NULL) {
+ mAudioSink->getPosition(&playedSamples);
+ sampleRate = mAudioSink->getSampleRate();
+ } else {
+ mAudioTrack->getPosition(&playedSamples);
+ sampleRate = mAudioTrack->getSampleRate();
+ }
+ if (sampleRate != 0) {
+ mSampleRate = sampleRate;
+ }
+
+ int64_t playedUs;
+ if (mSampleRate != 0) {
+ playedUs = (static_cast<int64_t>(playedSamples) * 1000000 ) / mSampleRate;
+ } else {
+ playedUs = 0;
+ }
+
+ // HAL position is relative to the first buffer we sent at mStartPosUs
+ const int64_t renderedDuration = mStartPosUs + playedUs;
+ ALOGV("getOutputPlayPositionUs_l %" PRId64, renderedDuration);
+ return renderedDuration;
+}
+
+status_t AudioPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ ALOGV("seekTo( %" PRId64 " )", time_us);
+
+ mSeeking = true;
+ mPositionTimeRealUs = mPositionTimeMediaUs = -1;
+ mReachedEOS = false;
+ mSeekTimeUs = time_us;
+ mStartPosUs = time_us;
+
+ // Flush resets the number of played frames
+ mNumFramesPlayed = 0;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+
+ if (mAudioSink != NULL) {
+ if (mPlaying) {
+ mAudioSink->pause();
+ }
+ mAudioSink->flush();
+ if (mPlaying) {
+ mAudioSink->start();
+ }
+ } else {
+ if (mPlaying) {
+ mAudioTrack->pause();
+ }
+ mAudioTrack->flush();
+ if (mPlaying) {
+ mAudioTrack->start();
+ }
+ }
+
+ return OK;
+}
+
+}
diff --git a/cmds/stagefright/AudioPlayer.h b/cmds/stagefright/AudioPlayer.h
new file mode 100644
index 0000000000..7c2c36fc0e
--- /dev/null
+++ b/cmds/stagefright/AudioPlayer.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_PLAYER_H_
+
+#define AUDIO_PLAYER_H_
+
+#include <media/MediaSource.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct AudioPlaybackRate;
+class AudioTrack;
+struct AwesomePlayer;
+
+class AudioPlayer {
+public:
+ enum {
+ REACHED_EOS,
+ SEEK_COMPLETE
+ };
+
+ enum {
+ ALLOW_DEEP_BUFFERING = 0x01,
+ USE_OFFLOAD = 0x02,
+ HAS_VIDEO = 0x1000,
+ IS_STREAMING = 0x2000
+
+ };
+
+ AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
+ uint32_t flags = 0);
+
+ virtual ~AudioPlayer();
+
+ // Caller retains ownership of "source".
+ void setSource(const sp<MediaSource> &source);
+
+ status_t start(bool sourceAlreadyStarted = false);
+
+ void pause(bool playPendingSamples = false);
+ status_t resume();
+
+ status_t seekTo(int64_t time_us);
+
+ bool isSeeking();
+ bool reachedEOS(status_t *finalStatus);
+
+ status_t setPlaybackRate(const AudioPlaybackRate &rate);
+ status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
+
+private:
+ sp<MediaSource> mSource;
+ sp<AudioTrack> mAudioTrack;
+
+ MediaBufferBase *mInputBuffer;
+
+ int mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+
+ Mutex mLock;
+ int64_t mNumFramesPlayed;
+ int64_t mNumFramesPlayedSysTimeUs;
+
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+
+ bool mSeeking;
+ bool mReachedEOS;
+ status_t mFinalStatus;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ bool mIsFirstBuffer;
+ status_t mFirstBufferResult;
+ MediaBufferBase *mFirstBuffer;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ bool mPlaying;
+ int64_t mStartPosUs;
+ const uint32_t mCreateFlags;
+
+ static void AudioCallback(int event, void *user, void *info);
+ void AudioCallback(int event, void *info);
+
+ static size_t AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me,
+ MediaPlayerBase::AudioSink::cb_event_t event);
+
+ size_t fillBuffer(void *data, size_t size);
+
+ void reset();
+
+ int64_t getOutputPlayPositionUs_l();
+
+ bool allowDeepBuffering() const { return (mCreateFlags & ALLOW_DEEP_BUFFERING) != 0; }
+ bool useOffload() const { return (mCreateFlags & USE_OFFLOAD) != 0; }
+
+ AudioPlayer(const AudioPlayer &);
+ AudioPlayer &operator=(const AudioPlayer &);
+};
+
+} // namespace android
+
+#endif // AUDIO_PLAYER_H_
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index d4f2e8d8d4..bd274d8f67 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -29,11 +29,11 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SimpleDecodingSource.h>
+#include "AudioPlayer.h"
#include "SineSource.h"
using namespace android;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 498237de8d..37091c43e1 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -21,7 +21,6 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -33,6 +32,8 @@
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
+#include "AudioPlayer.h"
+
using namespace android;
static const int32_t kAudioBitRate = 12200;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index a63b9b9984..01a178e6a0 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "SineSource.h"
-
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -25,8 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d52541d2df..a1ee90483f 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -40,7 +40,6 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
@@ -67,6 +66,8 @@
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include "AudioPlayer.h"
+
using namespace android;
static long gNumRepetitions;