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