android_StreamPlayer.cpp revision 2b06e20ae32388f6e1dfd088d9773c34e6b1cb45
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 <media/IStreamSource.h>
21#include <media/IMediaPlayerService.h>
22#include "android_StreamPlayer.h"
23
24//--------------------------------------------------------------------------------------------------
25// FIXME abstract out the diff between CMediaPlayer and CAudioPlayer
26
27void android_StreamPlayer_realize_l(CAudioPlayer *ap, const notif_cbf_t cbf, void* notifUser) {
28    SL_LOGI("android_StreamPlayer_realize_l(%p)", ap);
29
30    AudioPlayback_Parameters ap_params;
31    ap_params.sessionId = ap->mSessionId;
32    ap_params.streamType = ap->mStreamType;
33    ap_params.trackcb = NULL;
34    ap_params.trackcbUser = NULL;
35    android::StreamPlayer* splr = new android::StreamPlayer(&ap_params, false /*hasVideo*/);
36    ap->mAPlayer = splr;
37    splr->init(cbf, notifUser);
38}
39
40
41//--------------------------------------------------------------------------------------------------
42namespace android {
43
44StreamSourceAppProxy::StreamSourceAppProxy(
45        const void* user, bool userIsAudioPlayer,
46        void *context, const void *caller) :
47    mUser(user),
48    mUserIsAudioPlayer(userIsAudioPlayer),
49    mAndroidBufferQueue(NULL),
50    mAppContext(context),
51    mCaller(caller)
52{
53    SL_LOGI("StreamSourceAppProxy::StreamSourceAppProxy()");
54
55    if (mUserIsAudioPlayer) {
56        mAndroidBufferQueue = &((CAudioPlayer*)mUser)->mAndroidBufferQueue;
57    } else {
58        mAndroidBufferQueue = &((CMediaPlayer*)mUser)->mAndroidBufferQueue;
59    }
60}
61
62StreamSourceAppProxy::~StreamSourceAppProxy() {
63    SL_LOGD("StreamSourceAppProxy::~StreamSourceAppProxy()");
64    mListener.clear();
65    mBuffers.clear();
66}
67
68const SLuint32 StreamSourceAppProxy::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
69        SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
70        sizeof(SLuint32),                    // item size
71        SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
72};
73
74//--------------------------------------------------
75// IStreamSource implementation
76void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) {
77    Mutex::Autolock _l(mLock);
78    mListener = listener;
79}
80
81void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) {
82    mBuffers = buffers;
83}
84
85void StreamSourceAppProxy::onBufferAvailable(size_t index) {
86    //SL_LOGD("StreamSourceAppProxy::onBufferAvailable(%d)", index);
87
88    CHECK_LT(index, mBuffers.size());
89    sp<IMemory> mem = mBuffers.itemAt(index);
90    SLAint64 length = (SLAint64) mem->size();
91
92    {
93        Mutex::Autolock _l(mLock);
94        mAvailableBuffers.push_back(index);
95    }
96//SL_LOGD("onBufferAvailable() now %d buffers available in queue", mAvailableBuffers.size());
97
98    // a new shared mem buffer is available: let's try to fill immediately
99    pullFromBuffQueue();
100}
101
102void StreamSourceAppProxy::receivedCmd_l(IStreamListener::Command cmd, const sp<AMessage> &msg) {
103    if (mListener != 0) {
104        mListener->issueCommand(cmd, false /* synchronous */, msg);
105    }
106}
107
108void StreamSourceAppProxy::receivedBuffer_l(size_t buffIndex, size_t buffLength) {
109    if (mListener != 0) {
110        mListener->queueBuffer(buffIndex, buffLength);
111    }
112}
113
114//--------------------------------------------------
115// consumption from ABQ
116void StreamSourceAppProxy::pullFromBuffQueue() {
117
118    size_t bufferId;
119    void* bufferLoc;
120    size_t buffSize;
121
122    slAndroidBufferQueueCallback callback = NULL;
123    void* callbackPContext = NULL;
124    AdvancedBufferHeader *oldFront = NULL;
125
126    // retrieve data from the buffer queue
127    interface_lock_exclusive(mAndroidBufferQueue);
128
129    if (mAndroidBufferQueue->mState.count != 0) {
130        // SL_LOGD("nbBuffers in ABQ = %lu, buffSize=%lu",abq->mState.count, buffSize);
131        assert(mAndroidBufferQueue->mFront != mAndroidBufferQueue->mRear);
132
133        oldFront = mAndroidBufferQueue->mFront;
134        AdvancedBufferHeader *newFront = &oldFront[1];
135
136        // consume events when starting to read data from a buffer for the first time
137        if (oldFront->mDataSizeConsumed == 0) {
138            if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_EOS) {
139                receivedCmd_l(IStreamListener::EOS);
140            } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCONTINUITY) {
141                receivedCmd_l(IStreamListener::DISCONTINUITY);
142            } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCON_NEWPTS) {
143                sp<AMessage> msg = new AMessage();
144                msg->setInt64(IStreamListener::kKeyResumeAtPTS,
145                        (int64_t)oldFront->mItems.mTsCmdData.mPts);
146                receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
147            }
148            oldFront->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
149        }
150
151        {
152            // we're going to change the shared mem buffer queue, so lock it
153            Mutex::Autolock _l(mLock);
154            if (!mAvailableBuffers.empty()) {
155                bufferId = *mAvailableBuffers.begin();
156                CHECK_LT(bufferId, mBuffers.size());
157                sp<IMemory> mem = mBuffers.itemAt(bufferId);
158                bufferLoc = mem->pointer();
159                buffSize = mem->size();
160
161                char *pSrc = ((char*)oldFront->mDataBuffer) + oldFront->mDataSizeConsumed;
162                if (oldFront->mDataSizeConsumed + buffSize < oldFront->mDataSize) {
163                    // more available than requested, copy as much as requested
164                    // consume data: 1/ copy to given destination
165                    memcpy(bufferLoc, pSrc, buffSize);
166                    //               2/ keep track of how much has been consumed
167                    oldFront->mDataSizeConsumed += buffSize;
168                    //               3/ notify shared mem listener that new data is available
169                    receivedBuffer_l(bufferId, buffSize);
170                    mAvailableBuffers.erase(mAvailableBuffers.begin());
171                } else {
172                    // requested as much available or more: consume the whole of the current
173                    //   buffer and move to the next
174                    size_t consumed = oldFront->mDataSize - oldFront->mDataSizeConsumed;
175                    //SL_LOGD("consuming rest of buffer: enqueueing=%ld", consumed);
176                    oldFront->mDataSizeConsumed = oldFront->mDataSize;
177
178                    // move queue to next
179                    if (newFront == &mAndroidBufferQueue->
180                            mBufferArray[mAndroidBufferQueue->mNumBuffers + 1]) {
181                        // reached the end, circle back
182                        newFront = mAndroidBufferQueue->mBufferArray;
183                    }
184                    mAndroidBufferQueue->mFront = newFront;
185                    mAndroidBufferQueue->mState.count--;
186                    mAndroidBufferQueue->mState.index++;
187
188                    if (consumed > 0) {
189                        // consume data: 1/ copy to given destination
190                        memcpy(bufferLoc, pSrc, consumed);
191                        //               2/ keep track of how much has been consumed
192                        // here nothing to do because we are done with this buffer
193                        //               3/ notify StreamPlayer that new data is available
194                        receivedBuffer_l(bufferId, consumed);
195                        mAvailableBuffers.erase(mAvailableBuffers.begin());
196                    }
197
198                    // data has been consumed, and the buffer queue state has been updated
199                    // we will notify the client if applicable
200                    if (mAndroidBufferQueue->mCallbackEventsMask &
201                            SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
202                        callback = mAndroidBufferQueue->mCallback;
203                        // save callback data
204                        callbackPContext = mAndroidBufferQueue->mContext;
205                    }
206                }
207                //SL_LOGD("onBufferAvailable() %d buffers available after enqueue",
208                //     mAvailableBuffers.size());
209            }
210        }
211
212
213    } else { // empty queue
214        SL_LOGD("ABQ empty, starving!");
215        // signal we're at the end of the content, but don't pause (see note in function)
216        if (mUserIsAudioPlayer) {
217            // FIXME declare this external
218            //audioPlayer_dispatch_headAtEnd_lockPlay((CAudioPlayer*)user,
219            //        false /*set state to paused?*/, false);
220        } else {
221            // FIXME implement headAtEnd dispatch for CMediaPlayer
222        }
223    }
224
225    interface_unlock_exclusive(mAndroidBufferQueue);
226
227    // notify client
228    if (NULL != callback) {
229        (*callback)(&mAndroidBufferQueue->mItf, callbackPContext,
230                // oldFront was only initialized in the code path where callback is initialized
231                //    so no need to check if it's valid
232                (void *)oldFront->mBufferContext, /* pBufferContext */
233                (void *)oldFront->mDataBuffer,/* pBufferData  */
234                oldFront->mDataSize, /* dataSize  */
235                // here a buffer is only dequeued when fully consumed
236                oldFront->mDataSize, /* dataUsed  */
237                // no messages during playback other than marking the buffer as processed
238                (SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
239                3*sizeof(SLuint32) /* itemsLength */ );
240    }
241}
242
243
244//--------------------------------------------------------------------------------------------------
245StreamPlayer::StreamPlayer(AudioPlayback_Parameters* params, bool hasVideo) :
246        GenericMediaPlayer(params, hasVideo),
247        mAppProxy(0)
248{
249    SL_LOGD("StreamPlayer::StreamPlayer()");
250
251    mPlaybackParams = *params;
252
253}
254
255StreamPlayer::~StreamPlayer() {
256    SL_LOGD("StreamPlayer::~StreamPlayer()");
257
258    mAppProxy.clear();
259}
260
261
262void StreamPlayer::onMessageReceived(const sp<AMessage> &msg) {
263    switch (msg->what()) {
264        case kWhatQueueRefilled:
265            onQueueRefilled();
266            break;
267
268        default:
269            GenericMediaPlayer::onMessageReceived(msg);
270            break;
271    }
272}
273
274
275void StreamPlayer::registerQueueCallback(
276        const void* user, bool userIsAudioPlayer,
277        void *context,
278        const void *caller) {
279    SL_LOGD("StreamPlayer::registerQueueCallback");
280    Mutex::Autolock _l(mAppProxyLock);
281
282    mAppProxy = new StreamSourceAppProxy(
283            user, userIsAudioPlayer,
284            context, caller);
285
286    CHECK(mAppProxy != 0);
287    SL_LOGD("StreamPlayer::registerQueueCallback end");
288}
289
290
291/**
292 * Called with a lock on ABQ
293 */
294void StreamPlayer::queueRefilled_l() {
295    // async notification that the ABQ was refilled
296    (new AMessage(kWhatQueueRefilled, id()))->post();
297}
298
299
300void StreamPlayer::appClear_l() {
301    // the user of StreamPlayer has cleared its AndroidBufferQueue:
302    // there's no clear() for the shared memory queue, so this is a no-op
303}
304
305
306//--------------------------------------------------
307// Event handlers
308void StreamPlayer::onPrepare() {
309    SL_LOGD("StreamPlayer::onPrepare()");
310    Mutex::Autolock _l(mAppProxyLock);
311    if (mAppProxy != 0) {
312        mPlayer = mMediaPlayerService->create(getpid(), mPlayerClient /*IMediaPlayerClient*/,
313                mAppProxy /*IStreamSource*/, mPlaybackParams.sessionId);
314        // blocks until mPlayer is prepared
315        GenericMediaPlayer::onPrepare();
316        SL_LOGD("StreamPlayer::onPrepare() done");
317    } else {
318        SL_LOGE("Nothing to do here because there is no registered callback");
319    }
320}
321
322
323void StreamPlayer::onQueueRefilled() {
324    //SL_LOGD("StreamPlayer::onQueueRefilled()");
325    Mutex::Autolock _l(mAppProxyLock);
326    if (mAppProxy != 0) {
327        mAppProxy->pullFromBuffQueue();
328    }
329}
330
331} // namespace android
332