android_StreamPlayer.cpp revision e52e877354b1477d5cb34d24c70417820b013521
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17//#define USE_LOG SLAndroidLogLevel_Verbose
18
19#include "sles_allinclusive.h"
20#include "android_StreamPlayer.h"
21
22#include <media/IStreamSource.h>
23#include <media/IMediaPlayerService.h>
24#include <media/stagefright/foundation/ADebug.h>
25
26//--------------------------------------------------------------------------------------------------
27// FIXME abstract out the diff between CMediaPlayer and CAudioPlayer
28
29void android_StreamPlayer_realize_l(CAudioPlayer *ap, const notif_cbf_t cbf, void* notifUser) {
30    SL_LOGV("android_StreamPlayer_realize_l(%p)", ap);
31
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*/);
38    ap->mAPlayer = splr;
39    splr->init(cbf, notifUser);
40}
41
42
43//--------------------------------------------------------------------------------------------------
44namespace android {
45
46StreamSourceAppProxy::StreamSourceAppProxy(
47        const void* user, bool userIsAudioPlayer,
48        void *context, const void *caller, const sp<CallbackProtector> &callbackProtector) :
49    mUser(user),
50    mUserIsAudioPlayer(userIsAudioPlayer),
51    mAndroidBufferQueue(NULL),
52    mAppContext(context),
53    mCaller(caller),
54    mCallbackProtector(callbackProtector)
55{
56    SL_LOGV("StreamSourceAppProxy::StreamSourceAppProxy()");
57
58    if (mUserIsAudioPlayer) {
59        mAndroidBufferQueue = &((CAudioPlayer*)mUser)->mAndroidBufferQueue;
60    } else {
61        mAndroidBufferQueue = &((CMediaPlayer*)mUser)->mAndroidBufferQueue;
62    }
63}
64
65StreamSourceAppProxy::~StreamSourceAppProxy() {
66    SL_LOGD("StreamSourceAppProxy::~StreamSourceAppProxy()");
67    mListener.clear();
68    mBuffers.clear();
69}
70
71const 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
75};
76
77//--------------------------------------------------
78// IStreamSource implementation
79void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) {
80    Mutex::Autolock _l(mLock);
81    mListener = listener;
82}
83
84void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) {
85    mBuffers = buffers;
86}
87
88void StreamSourceAppProxy::onBufferAvailable(size_t index) {
89    //SL_LOGD("StreamSourceAppProxy::onBufferAvailable(%d)", index);
90
91    CHECK_LT(index, mBuffers.size());
92    sp<IMemory> mem = mBuffers.itemAt(index);
93    SLAint64 length = (SLAint64) mem->size();
94
95    {
96        Mutex::Autolock _l(mLock);
97        mAvailableBuffers.push_back(index);
98    }
99    //SL_LOGD("onBufferAvailable() now %d buffers available in queue", mAvailableBuffers.size());
100
101    // a new shared mem buffer is available: let's try to fill immediately
102    pullFromBuffQueue();
103}
104
105void StreamSourceAppProxy::receivedCmd_l(IStreamListener::Command cmd, const sp<AMessage> &msg) {
106    if (mListener != 0) {
107        mListener->issueCommand(cmd, false /* synchronous */, msg);
108    }
109}
110
111void StreamSourceAppProxy::receivedBuffer_l(size_t buffIndex, size_t buffLength) {
112    if (mListener != 0) {
113        mListener->queueBuffer(buffIndex, buffLength);
114    }
115}
116
117//--------------------------------------------------
118// consumption from ABQ
119void StreamSourceAppProxy::pullFromBuffQueue() {
120
121  if (android::CallbackProtector::enterCbIfOk(mCallbackProtector)) {
122
123    size_t bufferId;
124    void* bufferLoc;
125    size_t buffSize;
126
127    slAndroidBufferQueueCallback callback = NULL;
128    void* pBufferContext, *pBufferData, *callbackPContext = NULL;
129    AdvancedBufferHeader *oldFront = NULL;
130    uint32_t dataSize /* , dataUsed */;
131
132    // retrieve data from the buffer queue
133    interface_lock_exclusive(mAndroidBufferQueue);
134
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);
138
139        oldFront = mAndroidBufferQueue->mFront;
140        AdvancedBufferHeader *newFront = &oldFront[1];
141
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*/);
159            }
160            oldFront->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
161        }
162
163        {
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();
172
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());
183                } else {
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;
189
190                    // move queue to next
191                    if (newFront == &mAndroidBufferQueue->
192                            mBufferArray[mAndroidBufferQueue->mNumBuffers + 1]) {
193                        // reached the end, circle back
194                        newFront = mAndroidBufferQueue->mBufferArray;
195                    }
196                    mAndroidBufferQueue->mFront = newFront;
197                    mAndroidBufferQueue->mState.count--;
198                    mAndroidBufferQueue->mState.index++;
199
200                    if (consumed > 0) {
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());
208                    }
209
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;
222                    }
223                }
224                //SL_LOGD("onBufferAvailable() %d buffers available after enqueue",
225                //     mAvailableBuffers.size());
226            }
227        }
228
229
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);
237        } else {
238            // FIXME implement headAtEnd dispatch for CMediaPlayer
239        }
240    }
241
242    interface_unlock_exclusive(mAndroidBufferQueue);
243
244    // notify client
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);
255        }
256    }
257
258    mCallbackProtector->exitCb();
259  } // enterCbIfOk
260}
261
262
263//--------------------------------------------------------------------------------------------------
264StreamPlayer::StreamPlayer(AudioPlayback_Parameters* params, bool hasVideo) :
265        GenericMediaPlayer(params, hasVideo),
266        mAppProxy(0)
267{
268    SL_LOGD("StreamPlayer::StreamPlayer()");
269
270    mPlaybackParams = *params;
271
272}
273
274StreamPlayer::~StreamPlayer() {
275    SL_LOGD("StreamPlayer::~StreamPlayer()");
276
277    mAppProxy.clear();
278}
279
280
281void StreamPlayer::onMessageReceived(const sp<AMessage> &msg) {
282    switch (msg->what()) {
283        case kWhatQueueRefilled:
284            onQueueRefilled();
285            break;
286
287        default:
288            GenericMediaPlayer::onMessageReceived(msg);
289            break;
290    }
291}
292
293
294void StreamPlayer::registerQueueCallback(
295        const void* user, bool userIsAudioPlayer,
296        void *context,
297        const void *caller) {
298    SL_LOGD("StreamPlayer::registerQueueCallback");
299    Mutex::Autolock _l(mAppProxyLock);
300
301    mAppProxy = new StreamSourceAppProxy(
302            user, userIsAudioPlayer,
303            context, caller, mCallbackProtector);
304
305    CHECK(mAppProxy != 0);
306    SL_LOGD("StreamPlayer::registerQueueCallback end");
307}
308
309
310/**
311 * Called with a lock on ABQ
312 */
313void StreamPlayer::queueRefilled_l() {
314    // async notification that the ABQ was refilled
315    (new AMessage(kWhatQueueRefilled, id()))->post();
316}
317
318
319void 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
322}
323
324
325//--------------------------------------------------
326// Event handlers
327void 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                    mPlaybackParams.sessionId);
335            if (mPlayer == NULL) {
336                SL_LOGE("media player service failed to create player by app proxy");
337            } else if (mPlayer->setDataSource(mAppProxy /*IStreamSource*/) != NO_ERROR) {
338                SL_LOGE("setDataSource failed");
339                mPlayer.clear();
340            }
341        }
342    } else {
343        SL_LOGE("Nothing to do here because there is no registered callback");
344    }
345    if (mPlayer == NULL) {
346        mStateFlags |= kFlagPreparedUnsuccessfully;
347    }
348    GenericMediaPlayer::onPrepare();
349    SL_LOGD("StreamPlayer::onPrepare() done");
350}
351
352
353void StreamPlayer::onPlay() {
354    SL_LOGD("StreamPlayer::onPlay()");
355    // enqueue a message that will cause StreamAppProxy to consume from the queue (again if the
356    // player had starved the shared memory)
357    queueRefilled_l();
358
359    GenericMediaPlayer::onPlay();
360}
361
362
363void StreamPlayer::onQueueRefilled() {
364    //SL_LOGD("StreamPlayer::onQueueRefilled()");
365    Mutex::Autolock _l(mAppProxyLock);
366    if (mAppProxy != 0) {
367        mAppProxy->pullFromBuffQueue();
368    }
369}
370
371} // namespace android
372