| /* |
| * Copyright (C) 2010 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. |
| */ |
| |
| #define USE_LOG SLAndroidLogLevel_Verbose |
| |
| #include "sles_allinclusive.h" |
| #include <media/IMediaPlayerService.h> |
| |
| //-------------------------------------------------------------------------------------------------- |
| // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer |
| |
| void android_StreamPlayer_realize_l(CAudioPlayer *ap, const notif_cbf_t cbf, void* notifUser) { |
| SL_LOGI("android_StreamPlayer_realize_l(%p)", ap); |
| |
| AudioPlayback_Parameters ap_params; |
| ap_params.sessionId = ap->mSessionId; |
| ap_params.streamType = ap->mStreamType; |
| ap_params.trackcb = NULL; |
| ap_params.trackcbUser = NULL; |
| ap->mStreamPlayer = new android::StreamPlayer(&ap_params, false /*hasVideo*/); |
| ap->mStreamPlayer->init(cbf, notifUser); |
| } |
| |
| |
| // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer |
| void android_StreamPlayer_destroy(CAudioPlayer *ap) { |
| SL_LOGI("android_StreamPlayer_destroy(%p)", ap); |
| |
| ap->mStreamPlayer.clear(); |
| } |
| |
| |
| //----------------------------------------------------------------------------- |
| void android_StreamPlayer_androidBufferQueue_registerCallback(android::StreamPlayer *splr, |
| slAndroidBufferQueueCallback callback, void* context, const void* callerItf) |
| { |
| if (splr != NULL) { |
| SL_LOGI("android_Player_androidBufferQueue_registerCallback"); |
| splr->registerQueueCallback(callback, context, callerItf); |
| } |
| } |
| |
| // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer |
| void android_StreamPlayer_enqueue_l(CAudioPlayer *ap, |
| SLuint32 bufferId, SLuint32 length, SLAbufferQueueEvent event, void *pData) { |
| if (ap->mStreamPlayer != 0) { |
| ap->mStreamPlayer->appEnqueue(bufferId, length, event, pData); |
| } |
| } |
| |
| |
| // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer |
| void android_StreamPlayer_clear_l(CAudioPlayer *ap) { |
| if (ap->mStreamPlayer != 0) { |
| ap->mStreamPlayer->appClear(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------------------------------- |
| namespace android { |
| |
| StreamSourceAppProxy::StreamSourceAppProxy( |
| slAndroidBufferQueueCallback callback, void *context, const void *caller) : |
| mCallback(callback), |
| mAppContext(context), |
| mCaller(caller) |
| { |
| SL_LOGI("StreamSourceAppProxy::StreamSourceAppProxy()"); |
| } |
| |
| StreamSourceAppProxy::~StreamSourceAppProxy() { |
| SL_LOGI("StreamSourceAppProxy::~StreamSourceAppProxy()"); |
| mListener.clear(); |
| mBuffers.clear(); |
| } |
| |
| //-------------------------------------------------- |
| // IStreamSource implementation |
| void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) { |
| Mutex::Autolock _l(mListenerLock); |
| mListener = listener; |
| } |
| |
| void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) { |
| mBuffers = buffers; |
| } |
| |
| void StreamSourceAppProxy::onBufferAvailable(size_t index) { |
| SL_LOGD("StreamSourceAppProxy::onBufferAvailable(%d)", index); |
| |
| CHECK_LT(index, mBuffers.size()); |
| sp<IMemory> mem = mBuffers.itemAt(index); |
| SLAint64 length = (SLAint64) mem->size(); |
| |
| // FIXME PRIORITY1 needs to be called asynchronously, from AudioPlayer code after having |
| // obtained under lock the callback function pointer and context |
| (*mCallback)((SLAndroidBufferQueueItf)mCaller, /* SLAndroidBufferQueueItf self */ |
| mAppContext, /* void *pContext */ |
| index, /* SLuint32 bufferId */ |
| length, /* SLAint64 bufferLength */ |
| mem->pointer()/* void *pBufferDataLocation */ |
| ); |
| } |
| |
| void StreamSourceAppProxy::receivedFromAppCommand(IStreamListener::Command cmd) { |
| Mutex::Autolock _l(mListenerLock); |
| if (mListener != 0) { |
| mListener->issueCommand(cmd, false /* synchronous */); |
| } |
| } |
| |
| void StreamSourceAppProxy::receivedFromAppBuffer(size_t buffIndex, size_t buffLength) { |
| Mutex::Autolock _l(mListenerLock); |
| if (mListener != 0) { |
| mListener->queueBuffer(buffIndex, buffLength); |
| } |
| } |
| |
| |
| //-------------------------------------------------------------------------------------------------- |
| StreamPlayer::StreamPlayer(AudioPlayback_Parameters* params, bool hasVideo) : |
| GenericMediaPlayer(params, hasVideo), |
| mAppProxy(0) |
| { |
| SL_LOGI("StreamPlayer::StreamPlayer()"); |
| |
| mPlaybackParams = *params; |
| |
| } |
| |
| StreamPlayer::~StreamPlayer() { |
| SL_LOGI("StreamPlayer::~StreamPlayer()"); |
| |
| mAppProxy.clear(); |
| } |
| |
| |
| void StreamPlayer::registerQueueCallback(slAndroidBufferQueueCallback callback, void *context, |
| const void *caller) { |
| SL_LOGI("StreamPlayer::registerQueueCallback"); |
| Mutex::Autolock _l(mAppProxyLock); |
| |
| mAppProxy = new StreamSourceAppProxy(callback, context, caller); |
| |
| CHECK(mAppProxy != 0); |
| SL_LOGI("StreamPlayer::registerQueueCallback end"); |
| } |
| |
| void StreamPlayer::appEnqueue(SLuint32 bufferId, SLuint32 length, SLAbufferQueueEvent event, |
| void *pData) { |
| Mutex::Autolock _l(mAppProxyLock); |
| if (mAppProxy != 0) { |
| if (event != SL_ANDROIDBUFFERQUEUE_EVENT_NONE) { |
| if (event & SL_ANDROIDBUFFERQUEUE_EVENT_DISCONTINUITY) { |
| mAppProxy->receivedFromAppCommand(IStreamListener::DISCONTINUITY); |
| } |
| if (event & SL_ANDROIDBUFFERQUEUE_EVENT_EOS) { |
| mAppProxy->receivedFromAppCommand(IStreamListener::EOS); |
| } |
| } |
| if (length > 0) { |
| // FIXME PRIORITY1 verify given length isn't bigger than declared length in app callback |
| mAppProxy->receivedFromAppBuffer((size_t)bufferId, (size_t)length); |
| } |
| } |
| } |
| |
| void StreamPlayer::appClear() { |
| Mutex::Autolock _l(mAppProxyLock); |
| if (mAppProxy != 0) { |
| // FIXME PRIORITY1 implement |
| SL_LOGE("[ FIXME implement StreamPlayer::appClear() ]"); |
| } |
| } |
| |
| |
| //-------------------------------------------------- |
| // Event handlers |
| void StreamPlayer::onPrepare() { |
| SL_LOGI("StreamPlayer::onPrepare()"); |
| Mutex::Autolock _l(mAppProxyLock); |
| if (mAppProxy != 0) { |
| mPlayer = mMediaPlayerService->create(getpid(), mPlayerClient /*IMediaPlayerClient*/, |
| mAppProxy /*IStreamSource*/, mPlaybackParams.sessionId); |
| // blocks until mPlayer is prepared |
| GenericMediaPlayer::onPrepare(); |
| SL_LOGI("StreamPlayer::onPrepare() done"); |
| } else { |
| SL_LOGE("Nothing to do here because there is no registered callback"); |
| } |
| } |
| |
| |
| |
| } // namespace android |