Implementation of stagefright-enabled MediaPlayerService::decode functionality
related-to-bug: 2359268
This commit is contained in:
@@ -62,7 +62,8 @@ public:
|
||||
// AudioSink: abstraction layer for audio output
|
||||
class AudioSink : public RefBase {
|
||||
public:
|
||||
typedef void (*AudioCallback)(
|
||||
// Callback returns the number of bytes actually written to the buffer.
|
||||
typedef size_t (*AudioCallback)(
|
||||
AudioSink *audioSink, void *buffer, size_t size, void *cookie);
|
||||
|
||||
virtual ~AudioSink() {}
|
||||
@@ -77,8 +78,7 @@ public:
|
||||
virtual status_t getPosition(uint32_t *position) = 0;
|
||||
|
||||
// If no callback is specified, use the "write" API below to submit
|
||||
// audio data. Otherwise return a full buffer of audio data on each
|
||||
// callback.
|
||||
// audio data.
|
||||
virtual status_t open(
|
||||
uint32_t sampleRate, int channelCount,
|
||||
int format=AudioSystem::PCM_16_BIT,
|
||||
|
||||
@@ -90,11 +90,11 @@ private:
|
||||
static void AudioCallback(int event, void *user, void *info);
|
||||
void AudioCallback(int event, void *info);
|
||||
|
||||
static void AudioSinkCallback(
|
||||
static size_t AudioSinkCallback(
|
||||
MediaPlayerBase::AudioSink *audioSink,
|
||||
void *data, size_t size, void *me);
|
||||
|
||||
void fillBuffer(void *data, size_t size);
|
||||
size_t fillBuffer(void *data, size_t size);
|
||||
|
||||
int64_t getRealTimeUsLocked() const;
|
||||
|
||||
|
||||
@@ -1597,9 +1597,12 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
|
||||
AudioOutput *me = (AudioOutput *)cookie;
|
||||
AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
|
||||
|
||||
(*me->mCallback)(
|
||||
size_t actualSize = (*me->mCallback)(
|
||||
me, buffer->raw, buffer->size, me->mCallbackCookie);
|
||||
me->snoopWrite(buffer->raw, buffer->size);
|
||||
|
||||
if (actualSize > 0) {
|
||||
me->snoopWrite(buffer->raw, actualSize);
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_TAG
|
||||
@@ -1629,14 +1632,75 @@ status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position)
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct CallbackThread : public Thread {
|
||||
CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
|
||||
MediaPlayerBase::AudioSink::AudioCallback cb,
|
||||
void *cookie);
|
||||
|
||||
protected:
|
||||
virtual ~CallbackThread();
|
||||
|
||||
virtual bool threadLoop();
|
||||
|
||||
private:
|
||||
wp<MediaPlayerBase::AudioSink> mSink;
|
||||
MediaPlayerBase::AudioSink::AudioCallback mCallback;
|
||||
void *mCookie;
|
||||
void *mBuffer;
|
||||
size_t mBufferSize;
|
||||
|
||||
CallbackThread(const CallbackThread &);
|
||||
CallbackThread &operator=(const CallbackThread &);
|
||||
};
|
||||
|
||||
CallbackThread::CallbackThread(
|
||||
const wp<MediaPlayerBase::AudioSink> &sink,
|
||||
MediaPlayerBase::AudioSink::AudioCallback cb,
|
||||
void *cookie)
|
||||
: mSink(sink),
|
||||
mCallback(cb),
|
||||
mCookie(cookie),
|
||||
mBuffer(NULL),
|
||||
mBufferSize(0) {
|
||||
}
|
||||
|
||||
CallbackThread::~CallbackThread() {
|
||||
if (mBuffer) {
|
||||
free(mBuffer);
|
||||
mBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CallbackThread::threadLoop() {
|
||||
sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
|
||||
if (sink == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mBuffer == NULL) {
|
||||
mBufferSize = sink->bufferSize();
|
||||
mBuffer = malloc(mBufferSize);
|
||||
}
|
||||
|
||||
size_t actualSize =
|
||||
(*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
|
||||
|
||||
if (actualSize > 0) {
|
||||
sink->write(mBuffer, actualSize);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t MediaPlayerService::AudioCache::open(
|
||||
uint32_t sampleRate, int channelCount, int format, int bufferCount,
|
||||
AudioCallback cb, void *cookie)
|
||||
{
|
||||
LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
|
||||
if (cb != NULL) {
|
||||
return UNKNOWN_ERROR; // TODO: implement this.
|
||||
}
|
||||
if (mHeap->getHeapID() < 0) {
|
||||
return NO_INIT;
|
||||
}
|
||||
@@ -1645,9 +1709,25 @@ status_t MediaPlayerService::AudioCache::open(
|
||||
mChannelCount = (uint16_t)channelCount;
|
||||
mFormat = (uint16_t)format;
|
||||
mMsecsPerFrame = 1.e3 / (float) sampleRate;
|
||||
|
||||
if (cb != NULL) {
|
||||
mCallbackThread = new CallbackThread(this, cb, cookie);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void MediaPlayerService::AudioCache::start() {
|
||||
if (mCallbackThread != NULL) {
|
||||
mCallbackThread->run("AudioCache callback");
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayerService::AudioCache::stop() {
|
||||
if (mCallbackThread != NULL) {
|
||||
mCallbackThread->requestExitAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
|
||||
{
|
||||
LOGV("write(%p, %u)", buffer, size);
|
||||
|
||||
@@ -139,9 +139,9 @@ class MediaPlayerService : public BnMediaPlayerService
|
||||
int bufferCount = 1,
|
||||
AudioCallback cb = NULL, void *cookie = NULL);
|
||||
|
||||
virtual void start() {}
|
||||
virtual void start();
|
||||
virtual ssize_t write(const void* buffer, size_t size);
|
||||
virtual void stop() {}
|
||||
virtual void stop();
|
||||
virtual void flush() {}
|
||||
virtual void pause() {}
|
||||
virtual void close() {}
|
||||
@@ -171,6 +171,8 @@ class MediaPlayerService : public BnMediaPlayerService
|
||||
uint32_t mSize;
|
||||
int mError;
|
||||
bool mCommandComplete;
|
||||
|
||||
sp<Thread> mCallbackThread;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@@ -187,12 +187,12 @@ bool AudioPlayer::reachedEOS() {
|
||||
}
|
||||
|
||||
// static
|
||||
void AudioPlayer::AudioSinkCallback(
|
||||
size_t AudioPlayer::AudioSinkCallback(
|
||||
MediaPlayerBase::AudioSink *audioSink,
|
||||
void *buffer, size_t size, void *cookie) {
|
||||
AudioPlayer *me = (AudioPlayer *)cookie;
|
||||
|
||||
me->fillBuffer(buffer, size);
|
||||
return me->fillBuffer(buffer, size);
|
||||
}
|
||||
|
||||
void AudioPlayer::AudioCallback(int event, void *info) {
|
||||
@@ -201,17 +201,18 @@ void AudioPlayer::AudioCallback(int event, void *info) {
|
||||
}
|
||||
|
||||
AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
|
||||
fillBuffer(buffer->raw, buffer->size);
|
||||
size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
|
||||
|
||||
buffer->size = numBytesWritten;
|
||||
}
|
||||
|
||||
void AudioPlayer::fillBuffer(void *data, size_t size) {
|
||||
size_t AudioPlayer::fillBuffer(void *data, size_t size) {
|
||||
if (mNumFramesPlayed == 0) {
|
||||
LOGV("AudioCallback");
|
||||
}
|
||||
|
||||
if (mReachedEOS) {
|
||||
memset(data, 0, size);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t size_done = 0;
|
||||
@@ -244,7 +245,6 @@ void AudioPlayer::fillBuffer(void *data, size_t size) {
|
||||
|
||||
if (err != OK) {
|
||||
mReachedEOS = true;
|
||||
memset((char *)data + size_done, 0, size_remaining);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,9 @@ void AudioPlayer::fillBuffer(void *data, size_t size) {
|
||||
}
|
||||
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
mNumFramesPlayed += size / mFrameSize;
|
||||
mNumFramesPlayed += size_done / mFrameSize;
|
||||
|
||||
return size_done;
|
||||
}
|
||||
|
||||
int64_t AudioPlayer::getRealTimeUs() {
|
||||
|
||||
@@ -43,10 +43,9 @@ public class SoundPoolTest extends Activity
|
||||
private TestThread mThread;
|
||||
|
||||
private static final int[] mTestFiles = new int[] {
|
||||
// FIXME: Restore when Stagefright bug is fixed
|
||||
R.raw.organ441,
|
||||
R.raw.sine441,
|
||||
//R.raw.test1,
|
||||
R.raw.test1,
|
||||
R.raw.test2,
|
||||
R.raw.test3,
|
||||
R.raw.test4,
|
||||
|
||||
Reference in New Issue
Block a user