* Called with a lock on AudioPlayer
*/
SLresult android_audioPlayer_preDestroy(CAudioPlayer *pAudioPlayer) {
- SL_LOGV("android_audioPlayer_preDestroy(%p)", pAudioPlayer);
+ SL_LOGD("android_audioPlayer_preDestroy(%p)", pAudioPlayer);
SLresult result = SL_RESULT_SUCCESS;
+ if (pAudioPlayer->mAPlayer != 0) {
+ pAudioPlayer->mAPlayer->preDestroy();
+ }
+ SL_LOGD("android_audioPlayer_preDestroy(%p) after mAPlayer->preDestroy()", pAudioPlayer);
+
object_unlock_exclusive(&pAudioPlayer->mObject);
if (pAudioPlayer->mCallbackProtector != 0) {
pAudioPlayer->mCallbackProtector->requestCbExitAndWait();
AudioSfDecoder::AudioSfDecoder(const AudioPlayback_Parameters* params) : GenericPlayer(params),
mDataSource(0),
mAudioSource(0),
+ mAudioSourceStarted(false),
mBitrate(-1),
mChannelMask(ANDROID_UNKNOWN_CHANNELMASK),
mDurationUsec(-1),
AudioSfDecoder::~AudioSfDecoder() {
SL_LOGV("AudioSfDecoder::~AudioSfDecoder()");
- if (mAudioSource != 0) {
- mAudioSource->stop();
+}
+
+
+void AudioSfDecoder::preDestroy() {
+ GenericPlayer::preDestroy();
+ SL_LOGD("AudioSfDecoder::preDestroy()");
+ {
+ Mutex::Autolock _l(mBufferSourceLock);
+
+ if (NULL != mDecodeBuffer) {
+ mDecodeBuffer->release();
+ mDecodeBuffer = NULL;
+ }
+
+ if ((mAudioSource != 0) && mAudioSourceStarted) {
+ mAudioSource->stop();
+ mAudioSourceStarted = false;
+ }
}
}
//--------------------------------------------------
// Event handlers
+// it is strictly verboten to call those methods outside of the event loop
+
+// Initializes the data and audio sources, and update the PCM format info
+// post-condition: upon successful initialization based on the player data locator
+// GenericPlayer::onPrepare() was called
+// mDataSource != 0
+// mAudioSource != 0
+// mAudioSourceStarted == true
void AudioSfDecoder::onPrepare() {
SL_LOGD("AudioSfDecoder::onPrepare()");
+ Mutex::Autolock _l(mBufferSourceLock);
+ // Initialize the PCM format info with the known parameters before the start of the decode
mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_BITSPERSAMPLE] = SL_PCMSAMPLEFORMAT_FIXED_16;
mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_CONTAINERSIZE] = 16;
mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_ENDIANNESS] = SL_BYTEORDER_LITTLEENDIAN;
- // initialization with the default values
+ // initialization with the default values: they will be replaced by the actual values
+ // once the decoder has figured them out
mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_NUMCHANNELS] = mChannelCount;
mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_SAMPLESPERSEC] = mSampleRateHz;
mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_CHANNELMASK] = mChannelMask;
+ //---------------------------------
+ // Instantiate and initialize the data source for the decoder
sp<DataSource> dataSource;
switch (mDataLocatorType) {
TRESPASS();
}
+ //---------------------------------
+ // Instanciate and initialize the decoder attached to the data source
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
SL_LOGE("AudioSfDecoder::onPrepare: Could not instantiate extractor.");
mDurationUsec = -1;
}
+ // the audio content is not raw PCM, so we need a decoder
if (!isRawAudio) {
OMXClient client;
CHECK_EQ(client.connect(), (status_t)OK);
return;
}
+ //---------------------------------
+ // The data source, and audio source (a decoder if required) are ready to be used
mDataSource = dataSource;
mAudioSource = source;
+ mAudioSourceStarted = true;
if (!hasChannelCount) {
// even though the channel count was already queried above, there are issues with some
// application set play state to paused which failed, then set play state to playing
return;
}
+
if (wantPrefetch()
&& (getCacheRemaining(&eos) == kStatusLow)
&& !eos) {
}
{
- Mutex::Autolock _l(mDecodeBufferLock);
+ Mutex::Autolock _l(mBufferSourceLock);
+
if (NULL != mDecodeBuffer) {
// the current decoded buffer hasn't been rendered, drop it
mDecodeBuffer->release();
mDecodeBuffer = NULL;
}
+ if(!mAudioSourceStarted) {
+ return;
+ }
err = mAudioSource->read(&mDecodeBuffer, &readOptions);
if (err == OK) {
CHECK(mDecodeBuffer->meta_data()->findInt64(kKeyTime, &mLastDecodedPositionUs));
void AudioSfDecoder::onRender() {
//SL_LOGV("AudioSfDecoder::onRender");
- Mutex::Autolock _l(mDecodeBufferLock);
+ Mutex::Autolock _l(mBufferSourceLock);
if (NULL == mDecodeBuffer) {
// nothing to render, move along
void AudioSfDecoder::onNotify(const sp<AMessage> &msg) {
- if (NULL == mNotifyClient) {
- return;
+ notif_cbf_t notifyClient;
+ void* notifyUser;
+ {
+ android::Mutex::Autolock autoLock(mNotifyClientLock);
+ if (NULL == mNotifyClient) {
+ return;
+ } else {
+ notifyClient = mNotifyClient;
+ notifyUser = mNotifyUser;
+ }
}
int32_t val;
if (msg->findInt32(PLAYEREVENT_PREFETCHSTATUSCHANGE, &val)) {
SL_LOGV("\tASfPlayer notifying %s = %d", PLAYEREVENT_PREFETCHSTATUSCHANGE, val);
- mNotifyClient(kEventPrefetchStatusChange, val, 0, mNotifyUser);
+ notifyClient(kEventPrefetchStatusChange, val, 0, notifyUser);
}
else if (msg->findInt32(PLAYEREVENT_PREFETCHFILLLEVELUPDATE, &val)) {
SL_LOGV("\tASfPlayer notifying %s = %d", PLAYEREVENT_PREFETCHFILLLEVELUPDATE, val);
- mNotifyClient(kEventPrefetchFillLevelUpdate, val, 0, mNotifyUser);
+ notifyClient(kEventPrefetchFillLevelUpdate, val, 0, notifyUser);
}
else if (msg->findInt32(PLAYEREVENT_ENDOFSTREAM, &val)) {
SL_LOGV("\tASfPlayer notifying %s = %d", PLAYEREVENT_ENDOFSTREAM, val);
- mNotifyClient(kEventEndOfStream, val, 0, mNotifyUser);
+ notifyClient(kEventEndOfStream, val, 0, notifyUser);
}
else {
GenericPlayer::onNotify(msg);
AudioSfDecoder(const AudioPlayback_Parameters* params);
virtual ~AudioSfDecoder();
+ virtual void preDestroy();
+
// overridden from GenericPlayer
virtual void play();
virtual void startAudioSink() = 0;
virtual void pauseAudioSink() = 0;
- sp<DataSource> mDataSource;
- sp<MediaSource> mAudioSource;
+ sp<DataSource> mDataSource; // where the raw data comes from
+ sp<MediaSource> mAudioSource;// the decoder reading from the data source
+ // used to indicate mAudioSource was successfully started, but wasn't stopped
+ bool mAudioSourceStarted;
// negative values indicate invalid value
int64_t mBitrate; // in bits/sec
// buffer passed from decoder to renderer
MediaBuffer *mDecodeBuffer;
- // mutex used to protect the decode buffer
- Mutex mDecodeBufferLock;
+
+ // mutex used to protect the decode buffer, the audio source and its running state
+ Mutex mBufferSourceLock;
private:
void AudioToCbRenderer::onRender() {
- SL_LOGV("AudioToCbRenderer::onRender");
+ SL_LOGD("AudioToCbRenderer::onRender");
- Mutex::Autolock _l(mDecodeBufferLock);
+ Mutex::Autolock _l(mBufferSourceLock);
if (NULL == mDecodeBuffer) {
// nothing to render, move along
//--------------------------------------------------
// Audio output
void AudioToCbRenderer::createAudioSink() {
- SL_LOGD("AudioToCbRenderer::createAudioSink()");
- SL_LOGV("sample rate = %d nb channels = %d", mSampleRateHz, mNumChannels);
+ SL_LOGD("AudioToCbRenderer::createAudioSink() sample rate = %d, nb channels = %d",
+ mSampleRateHz, mChannelCount);
}
void AudioToCbRenderer::updateAudioSink() {
SL_LOGD("AudioToCbRenderer::updateAudioSink()");
- if (mAudioSource != 0) {
+
+ Mutex::Autolock _l(mBufferSourceLock);
+
+ if ((mAudioSource != 0) && mAudioSourceStarted) {
sp<MetaData> meta = mAudioSource->getFormat();
SL_LOGV("old sample rate = %d", mSampleRateHz);
GenericPlayer::~GenericPlayer() {
SL_LOGV("GenericPlayer::~GenericPlayer()");
- mLooper->stop();
- mLooper->unregisterHandler(id());
- mLooper.clear();
-
}
void GenericPlayer::init(const notif_cbf_t cbf, void* notifUser) {
SL_LOGD("GenericPlayer::init()");
- mNotifyClient = cbf;
- mNotifyUser = notifUser;
+ {
+ android::Mutex::Autolock autoLock(mNotifyClientLock);
+ mNotifyClient = cbf;
+ mNotifyUser = notifUser;
+ }
mLooper->registerHandler(this);
mLooper->start(false /*runOnCallingThread*/, false /*canCallJava*/, mLooperPriority);
}
+void GenericPlayer::preDestroy() {
+ SL_LOGD("GenericPlayer::preDestroy()");
+ {
+ android::Mutex::Autolock autoLock(mNotifyClientLock);
+ mNotifyClient = NULL;
+ mNotifyUser = NULL;
+ }
+
+ mLooper->stop();
+ mLooper->unregisterHandler(id());
+}
+
+
void GenericPlayer::setDataSource(const char *uri) {
resetDataLocator();
void GenericPlayer::onNotify(const sp<AMessage> &msg) {
- if (NULL == mNotifyClient) {
- return;
+ notif_cbf_t notifClient;
+ void* notifUser;
+ {
+ android::Mutex::Autolock autoLock(mNotifyClientLock);
+ if (NULL == mNotifyClient) {
+ return;
+ } else {
+ notifClient = mNotifyClient;
+ notifUser = mNotifyUser;
+ }
}
int32_t val1, val2;
if (msg->findInt32(PLAYEREVENT_PREFETCHSTATUSCHANGE, &val1)) {
SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PREFETCHSTATUSCHANGE, val1);
- mNotifyClient(kEventPrefetchStatusChange, val1, 0, mNotifyUser);
+ notifClient(kEventPrefetchStatusChange, val1, 0, notifUser);
} else if (msg->findInt32(PLAYEREVENT_PREFETCHFILLLEVELUPDATE, &val1)) {
SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PREFETCHFILLLEVELUPDATE, val1);
- mNotifyClient(kEventPrefetchFillLevelUpdate, val1, 0, mNotifyUser);
+ notifClient(kEventPrefetchFillLevelUpdate, val1, 0, notifUser);
} else if (msg->findInt32(PLAYEREVENT_ENDOFSTREAM, &val1)) {
SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_ENDOFSTREAM, val1);
- mNotifyClient(kEventEndOfStream, val1, 0, mNotifyUser);
+ notifClient(kEventEndOfStream, val1, 0, notifUser);
} else if (msg->findInt32(PLAYEREVENT_PREPARED, &val1)) {
SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PREPARED, val1);
- mNotifyClient(kEventPrepared, val1, 0, mNotifyUser);
+ notifClient(kEventPrepared, val1, 0, notifUser);
} else if (msg->findRect(PLAYEREVENT_VIDEO_SIZE_UPDATE, &val1, &val2, &val1, &val2)) {
SL_LOGV("GenericPlayer notifying %s = %d, %d", PLAYEREVENT_VIDEO_SIZE_UPDATE, val1, val2);
- mNotifyClient(kEventHasVideoSize, val1, val2, mNotifyUser);
+ notifClient(kEventHasVideoSize, val1, val2, notifUser);
}
}
virtual ~GenericPlayer();
virtual void init(const notif_cbf_t cbf, void* notifUser);
+ virtual void preDestroy();
virtual void setDataSource(const char *uri);
virtual void setDataSource(int fd, int64_t offset, int64_t length);
// Event notification from GenericPlayer to OpenSL ES / OpenMAX AL framework
notif_cbf_t mNotifyClient;
void* mNotifyUser;
+ // lock to protect mNotifyClient and mNotifyUser updates
+ Mutex mNotifyClientLock;
enum {
kFlagPrepared = 1 <<0,
int16_t mLastNotifiedCacheFill; // last cache fill level communicated to the listener
int16_t mCacheFillNotifThreshold; // threshold in cache fill level for cache fill to be reported
-
private:
DISALLOW_EVIL_CONSTRUCTORS(GenericPlayer);
};