blob: aec6255afc436ea91e69554737acc3d686280b82 [file] [log] [blame]
Marco Nelissenb2487f02015-09-01 13:23:23 -07001/*
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 <stdint.h>
22#include <sys/types.h>
23
24#include <binder/Parcel.h>
25#include <media/IMediaSource.h>
26#include <media/stagefright/MediaBuffer.h>
27#include <media/stagefright/MediaSource.h>
28#include <media/stagefright/MetaData.h>
29
30namespace android {
31
32enum {
33 START = IBinder::FIRST_CALL_TRANSACTION,
34 STOP,
35 PAUSE,
36 GETFORMAT,
37 READ
38};
39
40class BpMediaSource : public BpInterface<IMediaSource> {
41public:
42 BpMediaSource(const sp<IBinder>& impl)
43 : BpInterface<IMediaSource>(impl)
44 {
45 }
46
47 virtual status_t start(MetaData *params) {
48 ALOGV("start");
49 Parcel data, reply;
50 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
51 if (params) {
52 params->writeToParcel(data);
53 }
54 status_t ret = remote()->transact(START, data, &reply);
55 if (ret == NO_ERROR && params) {
56 ALOGW("ignoring potentially modified MetaData from start");
57 ALOGW("input:");
58 params->dumpToLog();
59 sp<MetaData> meta = MetaData::createFromParcel(reply);
60 ALOGW("output:");
61 meta->dumpToLog();
62 }
63 return ret;
64 }
65
66 virtual status_t stop() {
67 ALOGV("stop");
68 Parcel data, reply;
69 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
70 return remote()->transact(STOP, data, &reply);
71 }
72
73 virtual sp<MetaData> getFormat() {
74 ALOGV("getFormat");
75 Parcel data, reply;
76 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
77 status_t ret = remote()->transact(GETFORMAT, data, &reply);
78 if (ret == NO_ERROR) {
79 mMetaData = MetaData::createFromParcel(reply);
80 return mMetaData;
81 }
82 return NULL;
83 }
84
85 virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
86 ALOGV("read");
87 Parcel data, reply;
88 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
89 if (options) {
90 data.writeByteArray(sizeof(*options), (uint8_t*) options);
91 }
92 status_t ret = remote()->transact(READ, data, &reply);
93 if (ret != NO_ERROR) {
94 return ret;
95 }
96 // wrap the returned data in a MediaBuffer
97 // XXX use a group, and use shared memory for transfer
98 ret = reply.readInt32();
99 int32_t len = reply.readInt32();
100 if (len < 0) {
101 ALOGV("got status %d and len %d, returning NULL buffer", ret, len);
102 *buffer = NULL;
103 } else {
104 ALOGV("got status %d and len %d", ret, len);
105 *buffer = new MediaBuffer(len);
106 reply.read((*buffer)->data(), len);
107 (*buffer)->meta_data()->updateFromParcel(reply);
108 }
109 return ret;
110 }
111
112 virtual status_t pause() {
113 ALOGV("pause");
114 Parcel data, reply;
115 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
116 return remote()->transact(PAUSE, data, &reply);
117 }
118
119 virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
120 ALOGV("setBuffers NOT IMPLEMENTED");
121 return ERROR_UNSUPPORTED; // default
122 }
123
124private:
125 // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
126 // XXX: could we use this for caching, or does metadata change on the fly?
127 sp<MetaData> mMetaData;
128
129};
130
131IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
132
133#undef LOG_TAG
134#define LOG_TAG "BnMediaSource"
135
136status_t BnMediaSource::onTransact(
137 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
138{
139 switch (code) {
140 case START: {
141 ALOGV("start");
142 CHECK_INTERFACE(IMediaSource, data, reply);
143 sp<MetaData> meta;
144 if (data.dataAvail()) {
145 meta = MetaData::createFromParcel(data);
146 }
147 status_t ret = start(meta.get());
148 if (ret == NO_ERROR && meta != NULL) {
149 meta->writeToParcel(*reply);
150 }
151 return ret;
152 }
153 case STOP: {
154 ALOGV("stop");
155 CHECK_INTERFACE(IMediaSource, data, reply);
156 return stop();
157 }
158 case PAUSE: {
159 ALOGV("pause");
160 CHECK_INTERFACE(IMediaSource, data, reply);
161 return pause();
162 }
163 case GETFORMAT: {
164 ALOGV("getFormat");
165 CHECK_INTERFACE(IMediaSource, data, reply);
166 sp<MetaData> meta = getFormat();
167 if (meta != NULL) {
168 meta->writeToParcel(*reply);
169 return NO_ERROR;
170 }
171 return UNKNOWN_ERROR;
172 }
173 case READ: {
174 ALOGV("read");
175 CHECK_INTERFACE(IMediaSource, data, reply);
176 status_t ret;
177 MediaBuffer *buf = NULL;
178 ReadOptions opts;
179 uint32_t len;
180 if (data.readUint32(&len) == NO_ERROR &&
181 len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
182 ret = read(&buf, &opts);
183 } else {
184 ret = read(&buf, NULL);
185 }
186 // return data inside binder for now
187 // XXX return data using shared memory
188 reply->writeInt32(ret);
189 if (buf != NULL) {
190 ALOGV("ret %d, buflen %zu", ret, buf->range_length());
191 reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
192 buf->meta_data()->writeToParcel(*reply);
193 buf->release();
194 } else {
195 ALOGV("ret %d, buf %p", ret, buf);
196 reply->writeInt32(-1);
197 }
198 return NO_ERROR;
199 }
200 default:
201 return BBinder::onTransact(code, data, reply, flags);
202 }
203}
204
205////////////////////////////////////////////////////////////////////////////////
206
207IMediaSource::ReadOptions::ReadOptions() {
208 reset();
209}
210
211void IMediaSource::ReadOptions::reset() {
212 mOptions = 0;
213 mSeekTimeUs = 0;
214 mLatenessUs = 0;
215 mNonBlocking = false;
216}
217
218void IMediaSource::ReadOptions::setNonBlocking() {
219 mNonBlocking = true;
220}
221
222void IMediaSource::ReadOptions::clearNonBlocking() {
223 mNonBlocking = false;
224}
225
226bool IMediaSource::ReadOptions::getNonBlocking() const {
227 return mNonBlocking;
228}
229
230void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
231 mOptions |= kSeekTo_Option;
232 mSeekTimeUs = time_us;
233 mSeekMode = mode;
234}
235
236void IMediaSource::ReadOptions::clearSeekTo() {
237 mOptions &= ~kSeekTo_Option;
238 mSeekTimeUs = 0;
239 mSeekMode = SEEK_CLOSEST_SYNC;
240}
241
242bool IMediaSource::ReadOptions::getSeekTo(
243 int64_t *time_us, SeekMode *mode) const {
244 *time_us = mSeekTimeUs;
245 *mode = mSeekMode;
246 return (mOptions & kSeekTo_Option) != 0;
247}
248
249void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
250 mLatenessUs = lateness_us;
251}
252
253int64_t IMediaSource::ReadOptions::getLateBy() const {
254 return mLatenessUs;
255}
256
257
258} // namespace android
259