2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 //#define USE_LOG SLAndroidLogLevel_Verbose
19 #include "sles_allinclusive.h"
20 #include "android_StreamPlayer.h"
22 #include <media/IStreamSource.h>
23 #include <media/IMediaPlayerService.h>
24 #include <media/stagefright/foundation/ADebug.h>
26 //--------------------------------------------------------------------------------------------------
27 // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer
29 void android_StreamPlayer_realize_l(CAudioPlayer *ap, const notif_cbf_t cbf, void* notifUser) {
30 SL_LOGV("android_StreamPlayer_realize_l(%p)", ap);
32 AudioPlayback_Parameters ap_params;
33 ap_params.sessionId = ap->mSessionId;
34 ap_params.streamType = ap->mStreamType;
35 ap_params.trackcb = NULL;
36 ap_params.trackcbUser = NULL;
37 android::StreamPlayer* splr = new android::StreamPlayer(&ap_params, false /*hasVideo*/);
39 splr->init(cbf, notifUser);
43 //--------------------------------------------------------------------------------------------------
46 StreamSourceAppProxy::StreamSourceAppProxy(
47 const void* user, bool userIsAudioPlayer,
48 void *context, const void *caller, const sp<CallbackProtector> &callbackProtector) :
50 mUserIsAudioPlayer(userIsAudioPlayer),
51 mAndroidBufferQueue(NULL),
54 mCallbackProtector(callbackProtector)
56 SL_LOGV("StreamSourceAppProxy::StreamSourceAppProxy()");
58 if (mUserIsAudioPlayer) {
59 mAndroidBufferQueue = &((CAudioPlayer*)mUser)->mAndroidBufferQueue;
61 mAndroidBufferQueue = &((CMediaPlayer*)mUser)->mAndroidBufferQueue;
65 StreamSourceAppProxy::~StreamSourceAppProxy() {
66 SL_LOGD("StreamSourceAppProxy::~StreamSourceAppProxy()");
71 const SLuint32 StreamSourceAppProxy::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
72 SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
73 sizeof(SLuint32), // item size
74 SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
77 //--------------------------------------------------
78 // IStreamSource implementation
79 void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) {
80 Mutex::Autolock _l(mLock);
84 void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) {
88 void StreamSourceAppProxy::onBufferAvailable(size_t index) {
89 //SL_LOGD("StreamSourceAppProxy::onBufferAvailable(%d)", index);
91 CHECK_LT(index, mBuffers.size());
92 sp<IMemory> mem = mBuffers.itemAt(index);
93 SLAint64 length = (SLAint64) mem->size();
96 Mutex::Autolock _l(mLock);
97 mAvailableBuffers.push_back(index);
99 //SL_LOGD("onBufferAvailable() now %d buffers available in queue", mAvailableBuffers.size());
101 // a new shared mem buffer is available: let's try to fill immediately
105 void StreamSourceAppProxy::receivedCmd_l(IStreamListener::Command cmd, const sp<AMessage> &msg) {
106 if (mListener != 0) {
107 mListener->issueCommand(cmd, false /* synchronous */, msg);
111 void StreamSourceAppProxy::receivedBuffer_l(size_t buffIndex, size_t buffLength) {
112 if (mListener != 0) {
113 mListener->queueBuffer(buffIndex, buffLength);
117 //--------------------------------------------------
118 // consumption from ABQ
119 void StreamSourceAppProxy::pullFromBuffQueue() {
121 if (android::CallbackProtector::enterCbIfOk(mCallbackProtector)) {
127 slAndroidBufferQueueCallback callback = NULL;
128 void* pBufferContext, *pBufferData, *callbackPContext = NULL;
129 AdvancedBufferHeader *oldFront = NULL;
130 uint32_t dataSize /* , dataUsed */;
132 // retrieve data from the buffer queue
133 interface_lock_exclusive(mAndroidBufferQueue);
135 if (mAndroidBufferQueue->mState.count != 0) {
136 // SL_LOGD("nbBuffers in ABQ = %u, buffSize=%u",abq->mState.count, buffSize);
137 assert(mAndroidBufferQueue->mFront != mAndroidBufferQueue->mRear);
139 oldFront = mAndroidBufferQueue->mFront;
140 AdvancedBufferHeader *newFront = &oldFront[1];
142 // consume events when starting to read data from a buffer for the first time
143 if (oldFront->mDataSizeConsumed == 0) {
144 // note this code assumes at most one event per buffer; see IAndroidBufferQueue_Enqueue
145 if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_EOS) {
146 receivedCmd_l(IStreamListener::EOS);
147 } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCONTINUITY) {
148 receivedCmd_l(IStreamListener::DISCONTINUITY);
149 } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCON_NEWPTS) {
150 sp<AMessage> msg = new AMessage();
151 msg->setInt64(IStreamListener::kKeyResumeAtPTS,
152 (int64_t)oldFront->mItems.mTsCmdData.mPts);
153 receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
154 } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_FORMAT_CHANGE) {
155 sp<AMessage> msg = new AMessage();
156 // positive value for format change key makes the discontinuity "hard", see key def
157 msg->setInt32(IStreamListener::kKeyFormatChange, (int32_t) 1);
158 receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
160 oldFront->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
164 // we're going to change the shared mem buffer queue, so lock it
165 Mutex::Autolock _l(mLock);
166 if (!mAvailableBuffers.empty()) {
167 bufferId = *mAvailableBuffers.begin();
168 CHECK_LT(bufferId, mBuffers.size());
169 sp<IMemory> mem = mBuffers.itemAt(bufferId);
170 bufferLoc = mem->pointer();
171 buffSize = mem->size();
173 char *pSrc = ((char*)oldFront->mDataBuffer) + oldFront->mDataSizeConsumed;
174 if (oldFront->mDataSizeConsumed + buffSize < oldFront->mDataSize) {
175 // more available than requested, copy as much as requested
176 // consume data: 1/ copy to given destination
177 memcpy(bufferLoc, pSrc, buffSize);
178 // 2/ keep track of how much has been consumed
179 oldFront->mDataSizeConsumed += buffSize;
180 // 3/ notify shared mem listener that new data is available
181 receivedBuffer_l(bufferId, buffSize);
182 mAvailableBuffers.erase(mAvailableBuffers.begin());
184 // requested as much available or more: consume the whole of the current
185 // buffer and move to the next
186 size_t consumed = oldFront->mDataSize - oldFront->mDataSizeConsumed;
187 //SL_LOGD("consuming rest of buffer: enqueueing=%u", consumed);
188 oldFront->mDataSizeConsumed = oldFront->mDataSize;
190 // move queue to next
191 if (newFront == &mAndroidBufferQueue->
192 mBufferArray[mAndroidBufferQueue->mNumBuffers + 1]) {
193 // reached the end, circle back
194 newFront = mAndroidBufferQueue->mBufferArray;
196 mAndroidBufferQueue->mFront = newFront;
197 mAndroidBufferQueue->mState.count--;
198 mAndroidBufferQueue->mState.index++;
201 // consume data: 1/ copy to given destination
202 memcpy(bufferLoc, pSrc, consumed);
203 // 2/ keep track of how much has been consumed
204 // here nothing to do because we are done with this buffer
205 // 3/ notify StreamPlayer that new data is available
206 receivedBuffer_l(bufferId, consumed);
207 mAvailableBuffers.erase(mAvailableBuffers.begin());
210 // data has been consumed, and the buffer queue state has been updated
211 // we will notify the client if applicable
212 if (mAndroidBufferQueue->mCallbackEventsMask &
213 SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
214 callback = mAndroidBufferQueue->mCallback;
215 // save callback data while under lock
216 callbackPContext = mAndroidBufferQueue->mContext;
217 pBufferContext = (void *)oldFront->mBufferContext;
218 pBufferData = (void *)oldFront->mDataBuffer;
219 dataSize = oldFront->mDataSize;
220 // here a buffer is only dequeued when fully consumed
221 //dataUsed = oldFront->mDataSizeConsumed;
224 //SL_LOGD("onBufferAvailable() %d buffers available after enqueue",
225 // mAvailableBuffers.size());
230 } else { // empty queue
231 SL_LOGD("ABQ empty, starving!");
232 // signal we're at the end of the content, but don't pause (see note in function)
233 if (mUserIsAudioPlayer) {
234 // FIXME declare this external
235 //audioPlayer_dispatch_headAtEnd_lockPlay((CAudioPlayer*)user,
236 // false /*set state to paused?*/, false);
238 // FIXME implement headAtEnd dispatch for CMediaPlayer
242 interface_unlock_exclusive(mAndroidBufferQueue);
245 if (NULL != callback) {
246 SLresult result = (*callback)(&mAndroidBufferQueue->mItf, callbackPContext,
247 pBufferContext, pBufferData, dataSize,
248 dataSize, /* dataUsed */
249 // no messages during playback other than marking the buffer as processed
250 (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
251 NB_BUFFEREVENT_ITEM_FIELDS *sizeof(SLuint32) /* itemsLength */ );
252 if (SL_RESULT_SUCCESS != result) {
253 // Reserved for future use
254 SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
258 mCallbackProtector->exitCb();
263 //--------------------------------------------------------------------------------------------------
264 StreamPlayer::StreamPlayer(AudioPlayback_Parameters* params, bool hasVideo) :
265 GenericMediaPlayer(params, hasVideo),
268 SL_LOGD("StreamPlayer::StreamPlayer()");
270 mPlaybackParams = *params;
274 StreamPlayer::~StreamPlayer() {
275 SL_LOGD("StreamPlayer::~StreamPlayer()");
281 void StreamPlayer::onMessageReceived(const sp<AMessage> &msg) {
282 switch (msg->what()) {
283 case kWhatQueueRefilled:
288 GenericMediaPlayer::onMessageReceived(msg);
294 void StreamPlayer::registerQueueCallback(
295 const void* user, bool userIsAudioPlayer,
297 const void *caller) {
298 SL_LOGD("StreamPlayer::registerQueueCallback");
299 Mutex::Autolock _l(mAppProxyLock);
301 mAppProxy = new StreamSourceAppProxy(
302 user, userIsAudioPlayer,
303 context, caller, mCallbackProtector);
305 CHECK(mAppProxy != 0);
306 SL_LOGD("StreamPlayer::registerQueueCallback end");
311 * Called with a lock on ABQ
313 void StreamPlayer::queueRefilled_l() {
314 // async notification that the ABQ was refilled
315 (new AMessage(kWhatQueueRefilled, id()))->post();
319 void StreamPlayer::appClear_l() {
320 // the user of StreamPlayer has cleared its AndroidBufferQueue:
321 // there's no clear() for the shared memory queue, so this is a no-op
325 //--------------------------------------------------
327 void StreamPlayer::onPrepare() {
328 SL_LOGD("StreamPlayer::onPrepare()");
329 Mutex::Autolock _l(mAppProxyLock);
330 if (mAppProxy != 0) {
331 sp<IMediaPlayerService> mediaPlayerService(getMediaPlayerService());
332 if (mediaPlayerService != NULL) {
333 mPlayer = mediaPlayerService->create(getpid(), mPlayerClient /*IMediaPlayerClient*/,
334 mAppProxy /*IStreamSource*/, mPlaybackParams.sessionId);
335 if (mPlayer == NULL) {
336 SL_LOGE("media player service failed to create player by app proxy");
340 SL_LOGE("Nothing to do here because there is no registered callback");
342 if (mPlayer == NULL) {
343 mStateFlags |= kFlagPreparedUnsuccessfully;
345 GenericMediaPlayer::onPrepare();
346 SL_LOGD("StreamPlayer::onPrepare() done");
350 void StreamPlayer::onPlay() {
351 SL_LOGD("StreamPlayer::onPlay()");
352 // enqueue a message that will cause StreamAppProxy to consume from the queue (again if the
353 // player had starved the shared memory)
356 GenericMediaPlayer::onPlay();
360 void StreamPlayer::onQueueRefilled() {
361 //SL_LOGD("StreamPlayer::onQueueRefilled()");
362 Mutex::Autolock _l(mAppProxyLock);
363 if (mAppProxy != 0) {
364 mAppProxy->pullFromBuffQueue();
368 } // namespace android