blob: 38f717c782eb704361ebffff04c7dfaa879320bc [file] [log] [blame]
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001/*
2**
3** Copyright (C) 2008 The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
Mark Salyzyn34fb2962014-06-18 16:30:56 -070018#include <inttypes.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080019#include <stdint.h>
20#include <sys/types.h>
Mark Salyzyn34fb2962014-06-18 16:30:56 -070021
Mathias Agopian75624082009-05-19 19:08:10 -070022#include <binder/Parcel.h>
Andreas Huber1b86fe02014-01-29 11:13:26 -080023#include <media/IMediaHTTPService.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080024#include <media/IMediaMetadataRetriever.h>
Andreas Huberaf8791e2011-03-21 10:25:44 -070025#include <utils/String8.h>
Sangkyu Leed01c1482013-02-08 16:26:39 +090026#include <utils/KeyedVector.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080027
Dave Sparksec4dde72009-11-23 16:51:15 -080028// The binder is supposed to propagate the scheduler group across
29// the binder interface so that remote calls are executed with
30// the same priority as local calls. This is currently not working
31// so this change puts in a temporary hack to fix the issue with
32// metadata retrieval which can be a huge CPU hit if done on a
33// foreground thread.
34#ifndef DISABLE_GROUP_SCHEDULE_HACK
35
Dave Sparksf311c552009-11-23 19:51:33 -080036#undef LOG_TAG
Dave Sparksec4dde72009-11-23 16:51:15 -080037#define LOG_TAG "IMediaMetadataRetriever"
38#include <utils/Log.h>
39#include <cutils/sched_policy.h>
40
41namespace android {
42
43static void sendSchedPolicy(Parcel& data)
44{
45 SchedPolicy policy;
Glenn Kasten0512ab52011-05-04 17:58:57 -070046 get_sched_policy(gettid(), &policy);
Dave Sparksec4dde72009-11-23 16:51:15 -080047 data.writeInt32(policy);
48}
49
50static void setSchedPolicy(const Parcel& data)
51{
52 SchedPolicy policy = (SchedPolicy) data.readInt32();
Glenn Kasten0512ab52011-05-04 17:58:57 -070053 set_sched_policy(gettid(), policy);
Dave Sparksec4dde72009-11-23 16:51:15 -080054}
55static void restoreSchedPolicy()
56{
Glenn Kasten0512ab52011-05-04 17:58:57 -070057 set_sched_policy(gettid(), SP_FOREGROUND);
Dave Sparksec4dde72009-11-23 16:51:15 -080058}
59}; // end namespace android
60#endif
61
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080062namespace android {
63
64enum {
65 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
66 SET_DATA_SOURCE_URL,
67 SET_DATA_SOURCE_FD,
James Dong16afe2f2010-12-02 17:42:08 -080068 GET_FRAME_AT_TIME,
Dave Sparksec4dde72009-11-23 16:51:15 -080069 EXTRACT_ALBUM_ART,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080070 EXTRACT_METADATA,
71};
72
73class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
74{
75public:
76 BpMediaMetadataRetriever(const sp<IBinder>& impl)
77 : BpInterface<IMediaMetadataRetriever>(impl)
78 {
79 }
80
81 // disconnect from media metadata retriever service
82 void disconnect()
83 {
84 Parcel data, reply;
85 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
86 remote()->transact(DISCONNECT, data, &reply);
87 }
88
Andreas Huberaf8791e2011-03-21 10:25:44 -070089 status_t setDataSource(
Andreas Huber1b86fe02014-01-29 11:13:26 -080090 const sp<IMediaHTTPService> &httpService,
91 const char *srcUrl,
92 const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080093 {
94 Parcel data, reply;
95 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Andreas Huber1b86fe02014-01-29 11:13:26 -080096 data.writeInt32(httpService != NULL);
97 if (httpService != NULL) {
98 data.writeStrongBinder(httpService->asBinder());
99 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800100 data.writeCString(srcUrl);
Andreas Huberaf8791e2011-03-21 10:25:44 -0700101
102 if (headers == NULL) {
103 data.writeInt32(0);
104 } else {
105 // serialize the headers
Glenn Kastene03dd222014-01-28 11:04:39 -0800106 data.writeInt64(headers->size());
Andreas Huberaf8791e2011-03-21 10:25:44 -0700107 for (size_t i = 0; i < headers->size(); ++i) {
108 data.writeString8(headers->keyAt(i));
109 data.writeString8(headers->valueAt(i));
110 }
111 }
112
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800113 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
114 return reply.readInt32();
115 }
116
117 status_t setDataSource(int fd, int64_t offset, int64_t length)
118 {
119 Parcel data, reply;
120 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
121 data.writeFileDescriptor(fd);
122 data.writeInt64(offset);
123 data.writeInt64(length);
124 remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
125 return reply.readInt32();
126 }
127
James Dong16afe2f2010-12-02 17:42:08 -0800128 sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800129 {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700130 ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800131 Parcel data, reply;
132 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
James Dong16afe2f2010-12-02 17:42:08 -0800133 data.writeInt64(timeUs);
134 data.writeInt32(option);
Dave Sparksec4dde72009-11-23 16:51:15 -0800135#ifndef DISABLE_GROUP_SCHEDULE_HACK
136 sendSchedPolicy(data);
137#endif
James Dong16afe2f2010-12-02 17:42:08 -0800138 remote()->transact(GET_FRAME_AT_TIME, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800139 status_t ret = reply.readInt32();
140 if (ret != NO_ERROR) {
141 return NULL;
142 }
143 return interface_cast<IMemory>(reply.readStrongBinder());
144 }
145
146 sp<IMemory> extractAlbumArt()
147 {
148 Parcel data, reply;
149 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800150#ifndef DISABLE_GROUP_SCHEDULE_HACK
151 sendSchedPolicy(data);
152#endif
153 remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800154 status_t ret = reply.readInt32();
155 if (ret != NO_ERROR) {
156 return NULL;
157 }
158 return interface_cast<IMemory>(reply.readStrongBinder());
159 }
160
161 const char* extractMetadata(int keyCode)
162 {
163 Parcel data, reply;
164 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800165#ifndef DISABLE_GROUP_SCHEDULE_HACK
166 sendSchedPolicy(data);
167#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800168 data.writeInt32(keyCode);
169 remote()->transact(EXTRACT_METADATA, data, &reply);
170 status_t ret = reply.readInt32();
171 if (ret != NO_ERROR) {
172 return NULL;
173 }
Sangkyu Leed01c1482013-02-08 16:26:39 +0900174 const char* str = reply.readCString();
175 if (str != NULL) {
176 String8 value(str);
177 if (mMetadata.indexOfKey(keyCode) < 0) {
178 mMetadata.add(keyCode, value);
179 } else {
180 mMetadata.replaceValueFor(keyCode, value);
181 }
182 return mMetadata.valueFor(keyCode).string();
183 } else {
184 return NULL;
185 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800186 }
Sangkyu Leed01c1482013-02-08 16:26:39 +0900187
188private:
189 KeyedVector<int, String8> mMetadata;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800190};
191
niko56f0cc52009-06-22 08:49:52 -0700192IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800193
194// ----------------------------------------------------------------------
195
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800196status_t BnMediaMetadataRetriever::onTransact(
197 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
198{
199 switch (code) {
200 case DISCONNECT: {
201 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
202 disconnect();
203 return NO_ERROR;
204 } break;
205 case SET_DATA_SOURCE_URL: {
206 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Andreas Huber1b86fe02014-01-29 11:13:26 -0800207
208 sp<IMediaHTTPService> httpService;
209 if (data.readInt32()) {
210 httpService =
211 interface_cast<IMediaHTTPService>(data.readStrongBinder());
212 }
213
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800214 const char* srcUrl = data.readCString();
Andreas Huberaf8791e2011-03-21 10:25:44 -0700215
216 KeyedVector<String8, String8> headers;
Glenn Kastene03dd222014-01-28 11:04:39 -0800217 size_t numHeaders = (size_t) data.readInt64();
218 for (size_t i = 0; i < numHeaders; ++i) {
Andreas Huberaf8791e2011-03-21 10:25:44 -0700219 String8 key = data.readString8();
220 String8 value = data.readString8();
221 headers.add(key, value);
222 }
223
224 reply->writeInt32(
Andreas Huber1b86fe02014-01-29 11:13:26 -0800225 setDataSource(
226 httpService, srcUrl, numHeaders > 0 ? &headers : NULL));
Andreas Huberaf8791e2011-03-21 10:25:44 -0700227
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800228 return NO_ERROR;
229 } break;
230 case SET_DATA_SOURCE_FD: {
231 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
232 int fd = dup(data.readFileDescriptor());
233 int64_t offset = data.readInt64();
234 int64_t length = data.readInt64();
235 reply->writeInt32(setDataSource(fd, offset, length));
236 return NO_ERROR;
237 } break;
James Dong16afe2f2010-12-02 17:42:08 -0800238 case GET_FRAME_AT_TIME: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800239 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
James Dong16afe2f2010-12-02 17:42:08 -0800240 int64_t timeUs = data.readInt64();
241 int option = data.readInt32();
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700242 ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option);
Dave Sparksec4dde72009-11-23 16:51:15 -0800243#ifndef DISABLE_GROUP_SCHEDULE_HACK
244 setSchedPolicy(data);
245#endif
James Dong16afe2f2010-12-02 17:42:08 -0800246 sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800247 if (bitmap != 0) { // Don't send NULL across the binder interface
248 reply->writeInt32(NO_ERROR);
249 reply->writeStrongBinder(bitmap->asBinder());
250 } else {
251 reply->writeInt32(UNKNOWN_ERROR);
252 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800253#ifndef DISABLE_GROUP_SCHEDULE_HACK
254 restoreSchedPolicy();
255#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800256 return NO_ERROR;
257 } break;
Dave Sparksec4dde72009-11-23 16:51:15 -0800258 case EXTRACT_ALBUM_ART: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800259 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparksec4dde72009-11-23 16:51:15 -0800260#ifndef DISABLE_GROUP_SCHEDULE_HACK
261 setSchedPolicy(data);
262#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800263 sp<IMemory> albumArt = extractAlbumArt();
264 if (albumArt != 0) { // Don't send NULL across the binder interface
265 reply->writeInt32(NO_ERROR);
266 reply->writeStrongBinder(albumArt->asBinder());
267 } else {
268 reply->writeInt32(UNKNOWN_ERROR);
269 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800270#ifndef DISABLE_GROUP_SCHEDULE_HACK
271 restoreSchedPolicy();
272#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800273 return NO_ERROR;
274 } break;
275 case EXTRACT_METADATA: {
276 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparksec4dde72009-11-23 16:51:15 -0800277#ifndef DISABLE_GROUP_SCHEDULE_HACK
278 setSchedPolicy(data);
279#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800280 int keyCode = data.readInt32();
281 const char* value = extractMetadata(keyCode);
282 if (value != NULL) { // Don't send NULL across the binder interface
283 reply->writeInt32(NO_ERROR);
284 reply->writeCString(value);
285 } else {
286 reply->writeInt32(UNKNOWN_ERROR);
287 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800288#ifndef DISABLE_GROUP_SCHEDULE_HACK
289 restoreSchedPolicy();
290#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800291 return NO_ERROR;
292 } break;
293 default:
294 return BBinder::onTransact(code, data, reply, flags);
295 }
296}
297
298// ----------------------------------------------------------------------------
299
300}; // namespace android