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