blob: ebe821ff1823b74d9e3e0ddbea3914021538b416 [file] [log] [blame]
The Android Open Source Project9066cfe2009-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
18#include <stdint.h>
19#include <sys/types.h>
Mathias Agopian07952722009-05-19 19:08:10 -070020#include <binder/Parcel.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include <SkBitmap.h>
22#include <media/IMediaMetadataRetriever.h>
Andreas Huber5b7ced62011-03-21 10:25:44 -070023#include <utils/String8.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
Dave Sparks0f9a53d2009-11-23 16:51:15 -080025// The binder is supposed to propagate the scheduler group across
26// the binder interface so that remote calls are executed with
27// the same priority as local calls. This is currently not working
28// so this change puts in a temporary hack to fix the issue with
29// metadata retrieval which can be a huge CPU hit if done on a
30// foreground thread.
31#ifndef DISABLE_GROUP_SCHEDULE_HACK
32
33/* desktop Linux needs a little help with gettid() */
34#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
35#define __KERNEL__
36# include <linux/unistd.h>
37#ifdef _syscall0
38_syscall0(pid_t,gettid)
39#else
40pid_t gettid() { return syscall(__NR_gettid);}
41#endif
42#undef __KERNEL__
43#endif
44
Dave Sparks16cc72b2009-11-23 19:51:33 -080045static int myTid() {
46#ifdef HAVE_GETTID
47 return gettid();
48#else
49 return getpid();
50#endif
51}
52
53#undef LOG_TAG
Dave Sparks0f9a53d2009-11-23 16:51:15 -080054#define LOG_TAG "IMediaMetadataRetriever"
55#include <utils/Log.h>
56#include <cutils/sched_policy.h>
57
58namespace android {
59
60static void sendSchedPolicy(Parcel& data)
61{
62 SchedPolicy policy;
Dave Sparks16cc72b2009-11-23 19:51:33 -080063 get_sched_policy(myTid(), &policy);
Dave Sparks0f9a53d2009-11-23 16:51:15 -080064 data.writeInt32(policy);
65}
66
67static void setSchedPolicy(const Parcel& data)
68{
69 SchedPolicy policy = (SchedPolicy) data.readInt32();
Dave Sparks16cc72b2009-11-23 19:51:33 -080070 set_sched_policy(myTid(), policy);
Dave Sparks0f9a53d2009-11-23 16:51:15 -080071}
72static void restoreSchedPolicy()
73{
Dave Sparks16cc72b2009-11-23 19:51:33 -080074 set_sched_policy(myTid(), SP_FOREGROUND);
Dave Sparks0f9a53d2009-11-23 16:51:15 -080075}
76}; // end namespace android
77#endif
78
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079namespace android {
80
81enum {
82 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
83 SET_DATA_SOURCE_URL,
84 SET_DATA_SOURCE_FD,
James Dongfaf09ba2010-12-02 17:42:08 -080085 GET_FRAME_AT_TIME,
Dave Sparks0f9a53d2009-11-23 16:51:15 -080086 EXTRACT_ALBUM_ART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 EXTRACT_METADATA,
88};
89
90class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
91{
92public:
93 BpMediaMetadataRetriever(const sp<IBinder>& impl)
94 : BpInterface<IMediaMetadataRetriever>(impl)
95 {
96 }
97
98 // disconnect from media metadata retriever service
99 void disconnect()
100 {
101 Parcel data, reply;
102 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
103 remote()->transact(DISCONNECT, data, &reply);
104 }
105
Andreas Huber5b7ced62011-03-21 10:25:44 -0700106 status_t setDataSource(
107 const char *srcUrl, const KeyedVector<String8, String8> *headers)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 {
109 Parcel data, reply;
110 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
111 data.writeCString(srcUrl);
Andreas Huber5b7ced62011-03-21 10:25:44 -0700112
113 if (headers == NULL) {
114 data.writeInt32(0);
115 } else {
116 // serialize the headers
117 data.writeInt32(headers->size());
118 for (size_t i = 0; i < headers->size(); ++i) {
119 data.writeString8(headers->keyAt(i));
120 data.writeString8(headers->valueAt(i));
121 }
122 }
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
125 return reply.readInt32();
126 }
127
128 status_t setDataSource(int fd, int64_t offset, int64_t length)
129 {
130 Parcel data, reply;
131 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
132 data.writeFileDescriptor(fd);
133 data.writeInt64(offset);
134 data.writeInt64(length);
135 remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
136 return reply.readInt32();
137 }
138
James Dongfaf09ba2010-12-02 17:42:08 -0800139 sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 {
James Dongfaf09ba2010-12-02 17:42:08 -0800141 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 Parcel data, reply;
143 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
James Dongfaf09ba2010-12-02 17:42:08 -0800144 data.writeInt64(timeUs);
145 data.writeInt32(option);
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800146#ifndef DISABLE_GROUP_SCHEDULE_HACK
147 sendSchedPolicy(data);
148#endif
James Dongfaf09ba2010-12-02 17:42:08 -0800149 remote()->transact(GET_FRAME_AT_TIME, data, &reply);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 status_t ret = reply.readInt32();
151 if (ret != NO_ERROR) {
152 return NULL;
153 }
154 return interface_cast<IMemory>(reply.readStrongBinder());
155 }
156
157 sp<IMemory> extractAlbumArt()
158 {
159 Parcel data, reply;
160 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800161#ifndef DISABLE_GROUP_SCHEDULE_HACK
162 sendSchedPolicy(data);
163#endif
164 remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 status_t ret = reply.readInt32();
166 if (ret != NO_ERROR) {
167 return NULL;
168 }
169 return interface_cast<IMemory>(reply.readStrongBinder());
170 }
171
172 const char* extractMetadata(int keyCode)
173 {
174 Parcel data, reply;
175 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800176#ifndef DISABLE_GROUP_SCHEDULE_HACK
177 sendSchedPolicy(data);
178#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 data.writeInt32(keyCode);
180 remote()->transact(EXTRACT_METADATA, data, &reply);
181 status_t ret = reply.readInt32();
182 if (ret != NO_ERROR) {
183 return NULL;
184 }
185 return reply.readCString();
186 }
187};
188
nikodcd810d2009-06-22 08:49:52 -0700189IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
191// ----------------------------------------------------------------------
192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193status_t BnMediaMetadataRetriever::onTransact(
194 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
195{
196 switch (code) {
197 case DISCONNECT: {
198 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
199 disconnect();
200 return NO_ERROR;
201 } break;
202 case SET_DATA_SOURCE_URL: {
203 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
204 const char* srcUrl = data.readCString();
Andreas Huber5b7ced62011-03-21 10:25:44 -0700205
206 KeyedVector<String8, String8> headers;
207 int32_t numHeaders = data.readInt32();
208 for (int i = 0; i < numHeaders; ++i) {
209 String8 key = data.readString8();
210 String8 value = data.readString8();
211 headers.add(key, value);
212 }
213
214 reply->writeInt32(
215 setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL));
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 return NO_ERROR;
218 } break;
219 case SET_DATA_SOURCE_FD: {
220 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
221 int fd = dup(data.readFileDescriptor());
222 int64_t offset = data.readInt64();
223 int64_t length = data.readInt64();
224 reply->writeInt32(setDataSource(fd, offset, length));
225 return NO_ERROR;
226 } break;
James Dongfaf09ba2010-12-02 17:42:08 -0800227 case GET_FRAME_AT_TIME: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
James Dongfaf09ba2010-12-02 17:42:08 -0800229 int64_t timeUs = data.readInt64();
230 int option = data.readInt32();
231 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800232#ifndef DISABLE_GROUP_SCHEDULE_HACK
233 setSchedPolicy(data);
234#endif
James Dongfaf09ba2010-12-02 17:42:08 -0800235 sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 if (bitmap != 0) { // Don't send NULL across the binder interface
237 reply->writeInt32(NO_ERROR);
238 reply->writeStrongBinder(bitmap->asBinder());
239 } else {
240 reply->writeInt32(UNKNOWN_ERROR);
241 }
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800242#ifndef DISABLE_GROUP_SCHEDULE_HACK
243 restoreSchedPolicy();
244#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 return NO_ERROR;
246 } break;
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800247 case EXTRACT_ALBUM_ART: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800249#ifndef DISABLE_GROUP_SCHEDULE_HACK
250 setSchedPolicy(data);
251#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 sp<IMemory> albumArt = extractAlbumArt();
253 if (albumArt != 0) { // Don't send NULL across the binder interface
254 reply->writeInt32(NO_ERROR);
255 reply->writeStrongBinder(albumArt->asBinder());
256 } else {
257 reply->writeInt32(UNKNOWN_ERROR);
258 }
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800259#ifndef DISABLE_GROUP_SCHEDULE_HACK
260 restoreSchedPolicy();
261#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 return NO_ERROR;
263 } break;
264 case EXTRACT_METADATA: {
265 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800266#ifndef DISABLE_GROUP_SCHEDULE_HACK
267 setSchedPolicy(data);
268#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 int keyCode = data.readInt32();
270 const char* value = extractMetadata(keyCode);
271 if (value != NULL) { // Don't send NULL across the binder interface
272 reply->writeInt32(NO_ERROR);
273 reply->writeCString(value);
274 } else {
275 reply->writeInt32(UNKNOWN_ERROR);
276 }
Dave Sparks0f9a53d2009-11-23 16:51:15 -0800277#ifndef DISABLE_GROUP_SCHEDULE_HACK
278 restoreSchedPolicy();
279#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 return NO_ERROR;
281 } break;
282 default:
283 return BBinder::onTransact(code, data, reply, flags);
284 }
285}
286
287// ----------------------------------------------------------------------------
288
289}; // namespace android