OSDN Git Service

f83b4dc12c6d4a85503417e514b242d07bc916b4
[android-x86/system-media.git] / wilhelm / src / android / android_StreamPlayer.cpp
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
29 void 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 //--------------------------------------------------------------------------------------------------
44 namespace android {
45
46 StreamSourceAppProxy::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
65 StreamSourceAppProxy::~StreamSourceAppProxy() {
66     SL_LOGD("StreamSourceAppProxy::~StreamSourceAppProxy()");
67     mListener.clear();
68     mBuffers.clear();
69 }
70
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
75 };
76
77 //--------------------------------------------------
78 // IStreamSource implementation
79 void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) {
80     Mutex::Autolock _l(mLock);
81     mListener = listener;
82 }
83
84 void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) {
85     mBuffers = buffers;
86 }
87
88 void 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
105 void StreamSourceAppProxy::receivedCmd_l(IStreamListener::Command cmd, const sp<AMessage> &msg) {
106     if (mListener != 0) {
107         mListener->issueCommand(cmd, false /* synchronous */, msg);
108     }
109 }
110
111 void 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
119 void 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 //--------------------------------------------------------------------------------------------------
264 StreamPlayer::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
274 StreamPlayer::~StreamPlayer() {
275     SL_LOGD("StreamPlayer::~StreamPlayer()");
276
277     mAppProxy.clear();
278 }
279
280
281 void 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
294 void 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  */
313 void StreamPlayer::queueRefilled_l() {
314     // async notification that the ABQ was refilled
315     (new AMessage(kWhatQueueRefilled, id()))->post();
316 }
317
318
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
322 }
323
324
325 //--------------------------------------------------
326 // Event handlers
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");
337             }
338         }
339     } else {
340         SL_LOGE("Nothing to do here because there is no registered callback");
341     }
342     if (mPlayer == NULL) {
343         mStateFlags |= kFlagPreparedUnsuccessfully;
344     }
345     GenericMediaPlayer::onPrepare();
346     SL_LOGD("StreamPlayer::onPrepare() done");
347 }
348
349
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)
354     queueRefilled_l();
355
356     GenericMediaPlayer::onPlay();
357 }
358
359
360 void StreamPlayer::onQueueRefilled() {
361     //SL_LOGD("StreamPlayer::onQueueRefilled()");
362     Mutex::Autolock _l(mAppProxyLock);
363     if (mAppProxy != 0) {
364         mAppProxy->pullFromBuffQueue();
365     }
366 }
367
368 } // namespace android