1/*
2 * Copyright (C) 2009 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 LOG_NDEBUG 0
18#define LOG_TAG "BpMediaSource"
19#include <utils/Log.h>
20
21#include <inttypes.h>
22#include <stdint.h>
23#include <sys/types.h>
24
25#include <binder/Parcel.h>
26#include <media/IMediaSource.h>
27#include <media/stagefright/MediaBuffer.h>
28#include <media/stagefright/MediaBufferGroup.h>
29#include <media/stagefright/MediaSource.h>
30#include <media/stagefright/MetaData.h>
31
32namespace android {
33
34enum {
35    START = IBinder::FIRST_CALL_TRANSACTION,
36    STOP,
37    PAUSE,
38    GETFORMAT,
39    READ,
40    READMULTIPLE,
41    RELEASE_BUFFER
42};
43
44enum {
45    NULL_BUFFER,
46    SHARED_BUFFER,
47    INLINE_BUFFER
48};
49
50class RemoteMediaBufferReleaser : public BBinder {
51public:
52    RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
53        mBuf = buf;
54        mOwner = owner;
55    }
56    ~RemoteMediaBufferReleaser() {
57        if (mBuf) {
58            ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
59            mBuf->release();
60        }
61    }
62    virtual status_t    onTransact( uint32_t code,
63                                    const Parcel& data,
64                                    Parcel* reply,
65                                    uint32_t flags = 0) {
66        if (code == RELEASE_BUFFER) {
67            mBuf->release();
68            mBuf = NULL;
69            return OK;
70        } else {
71            return BBinder::onTransact(code, data, reply, flags);
72        }
73    }
74private:
75    MediaBuffer *mBuf;
76    // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
77    // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
78    // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
79    sp<BnMediaSource> mOwner;
80};
81
82
83class RemoteMediaBufferWrapper : public MediaBuffer {
84public:
85    RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
86protected:
87    virtual ~RemoteMediaBufferWrapper();
88private:
89    sp<IMemory> mMemory;
90    sp<IBinder> mRemoteSource;
91};
92
93RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
94: MediaBuffer(mem->pointer(), mem->size()) {
95    mMemory = mem;
96    mRemoteSource = source;
97}
98
99RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
100    mMemory.clear();
101    // Explicitly ask the remote side to release the buffer. We could also just clear
102    // mRemoteSource, but that doesn't immediately release the reference on the remote side.
103    Parcel data, reply;
104    mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
105    mRemoteSource.clear();
106}
107
108class BpMediaSource : public BpInterface<IMediaSource> {
109public:
110    BpMediaSource(const sp<IBinder>& impl)
111        : BpInterface<IMediaSource>(impl)
112    {
113    }
114
115    virtual status_t start(MetaData *params) {
116        ALOGV("start");
117        Parcel data, reply;
118        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
119        if (params) {
120            params->writeToParcel(data);
121        }
122        status_t ret = remote()->transact(START, data, &reply);
123        if (ret == NO_ERROR && params) {
124            ALOGW("ignoring potentially modified MetaData from start");
125            ALOGW("input:");
126            params->dumpToLog();
127            sp<MetaData> meta = MetaData::createFromParcel(reply);
128            ALOGW("output:");
129            meta->dumpToLog();
130        }
131        return ret;
132    }
133
134    virtual status_t stop() {
135        ALOGV("stop");
136        Parcel data, reply;
137        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
138        return remote()->transact(STOP, data, &reply);
139    }
140
141    virtual sp<MetaData> getFormat() {
142        ALOGV("getFormat");
143        Parcel data, reply;
144        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
145        status_t ret = remote()->transact(GETFORMAT, data, &reply);
146        if (ret == NO_ERROR) {
147            mMetaData = MetaData::createFromParcel(reply);
148            return mMetaData;
149        }
150        return NULL;
151    }
152
153    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
154        ALOGV("read");
155        Parcel data, reply;
156        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
157        if (options) {
158            data.writeByteArray(sizeof(*options), (uint8_t*) options);
159        }
160        status_t ret = remote()->transact(READ, data, &reply);
161        if (ret != NO_ERROR) {
162            return ret;
163        }
164        // wrap the returned data in a MediaBuffer
165        ret = reply.readInt32();
166        int32_t buftype = reply.readInt32();
167        if (buftype == SHARED_BUFFER) {
168            sp<IBinder> remote = reply.readStrongBinder();
169            sp<IBinder> binder = reply.readStrongBinder();
170            sp<IMemory> mem = interface_cast<IMemory>(binder);
171            if (mem == NULL) {
172                ALOGE("received NULL IMemory for shared buffer");
173            }
174            size_t offset = reply.readInt32();
175            size_t length = reply.readInt32();
176            MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
177            buf->set_range(offset, length);
178            buf->meta_data()->updateFromParcel(reply);
179            *buffer = buf;
180        } else if (buftype == NULL_BUFFER) {
181            ALOGV("got status %d and NULL buffer", ret);
182            *buffer = NULL;
183        } else {
184            int32_t len = reply.readInt32();
185            ALOGV("got status %d and len %d", ret, len);
186            *buffer = new MediaBuffer(len);
187            reply.read((*buffer)->data(), len);
188            (*buffer)->meta_data()->updateFromParcel(reply);
189        }
190        return ret;
191    }
192
193    virtual status_t readMultiple(Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers) {
194        ALOGV("readMultiple");
195        if (buffers == NULL || !buffers->isEmpty()) {
196            return BAD_VALUE;
197        }
198        Parcel data, reply;
199        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
200        data.writeUint32(maxNumBuffers);
201        status_t ret = remote()->transact(READMULTIPLE, data, &reply);
202        if (ret != NO_ERROR) {
203            return ret;
204        }
205        // wrap the returned data in a vector of MediaBuffers
206        int32_t bufCount = 0;
207        while (1) {
208            if (reply.readInt32() == 0) {
209                break;
210            }
211            int32_t len = reply.readInt32();
212            ALOGV("got len %d", len);
213            MediaBuffer *buf = new MediaBuffer(len);
214            reply.read(buf->data(), len);
215            buf->meta_data()->updateFromParcel(reply);
216            buffers->push_back(buf);
217            ++bufCount;
218        }
219        ret = reply.readInt32();
220        ALOGV("got status %d, bufCount %d", ret, bufCount);
221        return ret;
222    }
223
224    virtual status_t pause() {
225        ALOGV("pause");
226        Parcel data, reply;
227        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
228        return remote()->transact(PAUSE, data, &reply);
229    }
230
231    virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
232        ALOGV("setBuffers NOT IMPLEMENTED");
233        return ERROR_UNSUPPORTED; // default
234    }
235
236private:
237    // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
238    // XXX: could we use this for caching, or does metadata change on the fly?
239    sp<MetaData> mMetaData;
240
241};
242
243IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
244
245#undef LOG_TAG
246#define LOG_TAG "BnMediaSource"
247
248BnMediaSource::BnMediaSource()
249    : mGroup(NULL) {
250}
251
252BnMediaSource::~BnMediaSource() {
253    delete mGroup;
254    mGroup = NULL;
255}
256
257status_t BnMediaSource::onTransact(
258    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
259{
260    switch (code) {
261        case START: {
262            ALOGV("start");
263            CHECK_INTERFACE(IMediaSource, data, reply);
264            sp<MetaData> meta;
265            if (data.dataAvail()) {
266                meta = MetaData::createFromParcel(data);
267            }
268            status_t ret = start(meta.get());
269            if (ret == NO_ERROR && meta != NULL) {
270                meta->writeToParcel(*reply);
271            }
272            return ret;
273        }
274        case STOP: {
275            ALOGV("stop");
276            CHECK_INTERFACE(IMediaSource, data, reply);
277            return stop();
278        }
279        case PAUSE: {
280            ALOGV("pause");
281            CHECK_INTERFACE(IMediaSource, data, reply);
282            return pause();
283        }
284        case GETFORMAT: {
285            ALOGV("getFormat");
286            CHECK_INTERFACE(IMediaSource, data, reply);
287            sp<MetaData> meta = getFormat();
288            if (meta != NULL) {
289                meta->writeToParcel(*reply);
290                return NO_ERROR;
291            }
292            return UNKNOWN_ERROR;
293        }
294        case READ: {
295            ALOGV("read");
296            CHECK_INTERFACE(IMediaSource, data, reply);
297            status_t ret;
298            MediaBuffer *buf = NULL;
299            ReadOptions opts;
300            uint32_t len;
301            if (data.readUint32(&len) == NO_ERROR &&
302                    len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
303                ret = read(&buf, &opts);
304            } else {
305                ret = read(&buf, NULL);
306            }
307
308            reply->writeInt32(ret);
309            if (buf != NULL) {
310                size_t usedSize = buf->range_length();
311                // even if we're using shared memory, we might not want to use it, since for small
312                // sizes it's faster to copy data through the Binder transaction
313                // On the other hand, if the data size is large enough, it's better to use shared
314                // memory. When data is too large, binder can't handle it.
315                if (usedSize >= MediaBuffer::kSharedMemThreshold) {
316                    ALOGV("use shared memory: %zu", usedSize);
317
318                    MediaBuffer *transferBuf = buf;
319                    size_t offset = buf->range_offset();
320                    if (transferBuf->mMemory == NULL) {
321                        if (mGroup == NULL) {
322                            mGroup = new MediaBufferGroup;
323                            size_t allocateSize = usedSize;
324                            if (usedSize < SIZE_MAX / 3) {
325                                allocateSize = usedSize * 3 / 2;
326                            }
327                            mGroup->add_buffer(new MediaBuffer(allocateSize));
328                        }
329
330                        MediaBuffer *newBuf = NULL;
331                        ret = mGroup->acquire_buffer(
332                                &newBuf, false /* nonBlocking */, usedSize);
333                        if (ret != OK || newBuf == NULL || newBuf->mMemory == NULL) {
334                            ALOGW("failed to acquire shared memory, ret %d", ret);
335                            buf->release();
336                            if (newBuf != NULL) {
337                                newBuf->release();
338                            }
339                            reply->writeInt32(NULL_BUFFER);
340                            return NO_ERROR;
341                        }
342                        transferBuf = newBuf;
343                        memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
344                                buf->range_length());
345                        offset = 0;
346                    }
347
348                    reply->writeInt32(SHARED_BUFFER);
349                    RemoteMediaBufferReleaser *wrapper =
350                        new RemoteMediaBufferReleaser(transferBuf, this);
351                    reply->writeStrongBinder(wrapper);
352                    reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
353                    reply->writeInt32(offset);
354                    reply->writeInt32(usedSize);
355                    buf->meta_data()->writeToParcel(*reply);
356                    if (buf->mMemory == NULL) {
357                        buf->release();
358                    }
359                } else {
360                    // buffer is small: copy it
361                    if (buf->mMemory != NULL) {
362                        ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
363                    }
364                    reply->writeInt32(INLINE_BUFFER);
365                    reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
366                    buf->meta_data()->writeToParcel(*reply);
367                    buf->release();
368                }
369            } else {
370                ALOGV("ret %d, buf %p", ret, buf);
371                reply->writeInt32(NULL_BUFFER);
372            }
373            return NO_ERROR;
374        }
375        case READMULTIPLE: {
376            ALOGV("readmultiple");
377            CHECK_INTERFACE(IMediaSource, data, reply);
378            uint32_t maxNumBuffers;
379            data.readUint32(&maxNumBuffers);
380            status_t ret = NO_ERROR;
381            uint32_t bufferCount = 0;
382            if (maxNumBuffers > kMaxNumReadMultiple) {
383                maxNumBuffers = kMaxNumReadMultiple;
384            }
385            while (bufferCount < maxNumBuffers) {
386                if (reply->dataSize() >= MediaBuffer::kSharedMemThreshold) {
387                    break;
388                }
389
390                MediaBuffer *buf = NULL;
391                ret = read(&buf, NULL);
392                if (ret != NO_ERROR || buf == NULL) {
393                    break;
394                }
395                ++bufferCount;
396                reply->writeInt32(1);  // indicate one more MediaBuffer.
397                reply->writeByteArray(
398                        buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
399                buf->meta_data()->writeToParcel(*reply);
400                buf->release();
401            }
402            reply->writeInt32(0);  // indicate no more MediaBuffer.
403            reply->writeInt32(ret);
404            return NO_ERROR;
405        }
406        default:
407            return BBinder::onTransact(code, data, reply, flags);
408    }
409}
410
411////////////////////////////////////////////////////////////////////////////////
412
413IMediaSource::ReadOptions::ReadOptions() {
414    reset();
415}
416
417void IMediaSource::ReadOptions::reset() {
418    mOptions = 0;
419    mSeekTimeUs = 0;
420    mLatenessUs = 0;
421    mNonBlocking = false;
422}
423
424void IMediaSource::ReadOptions::setNonBlocking() {
425    mNonBlocking = true;
426}
427
428void IMediaSource::ReadOptions::clearNonBlocking() {
429    mNonBlocking = false;
430}
431
432bool IMediaSource::ReadOptions::getNonBlocking() const {
433    return mNonBlocking;
434}
435
436void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
437    mOptions |= kSeekTo_Option;
438    mSeekTimeUs = time_us;
439    mSeekMode = mode;
440}
441
442void IMediaSource::ReadOptions::clearSeekTo() {
443    mOptions &= ~kSeekTo_Option;
444    mSeekTimeUs = 0;
445    mSeekMode = SEEK_CLOSEST_SYNC;
446}
447
448bool IMediaSource::ReadOptions::getSeekTo(
449        int64_t *time_us, SeekMode *mode) const {
450    *time_us = mSeekTimeUs;
451    *mode = mSeekMode;
452    return (mOptions & kSeekTo_Option) != 0;
453}
454
455void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
456    mLatenessUs = lateness_us;
457}
458
459int64_t IMediaSource::ReadOptions::getLateBy() const {
460    return mLatenessUs;
461}
462
463
464}  // namespace android
465
466