blob: 68dd880054f6d9baea9a65d5360f5fb23070167a [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
18#include <stdint.h>
19#include <sys/types.h>
Mathias Agopian75624082009-05-19 19:08:10 -070020#include <binder/Parcel.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080021#include <SkBitmap.h>
22#include <media/IMediaMetadataRetriever.h>
23
Dave Sparksec4dde72009-11-23 16:51:15 -080024// The binder is supposed to propagate the scheduler group across
25// the binder interface so that remote calls are executed with
26// the same priority as local calls. This is currently not working
27// so this change puts in a temporary hack to fix the issue with
28// metadata retrieval which can be a huge CPU hit if done on a
29// foreground thread.
30#ifndef DISABLE_GROUP_SCHEDULE_HACK
31
32/* desktop Linux needs a little help with gettid() */
33#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
34#define __KERNEL__
35# include <linux/unistd.h>
36#ifdef _syscall0
37_syscall0(pid_t,gettid)
38#else
39pid_t gettid() { return syscall(__NR_gettid);}
40#endif
41#undef __KERNEL__
42#endif
43
44#define LOG_TAG "IMediaMetadataRetriever"
45#include <utils/Log.h>
46#include <cutils/sched_policy.h>
47
48namespace android {
49
50static void sendSchedPolicy(Parcel& data)
51{
52 SchedPolicy policy;
53 get_sched_policy(gettid(), &policy);
54 data.writeInt32(policy);
55}
56
57static void setSchedPolicy(const Parcel& data)
58{
59 SchedPolicy policy = (SchedPolicy) data.readInt32();
60 set_sched_policy(gettid(), policy);
61}
62static void restoreSchedPolicy()
63{
64 set_sched_policy(gettid(), SP_FOREGROUND);
65}
66}; // end namespace android
67#endif
68
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080069namespace android {
70
71enum {
72 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
73 SET_DATA_SOURCE_URL,
74 SET_DATA_SOURCE_FD,
75 SET_MODE,
76 GET_MODE,
77 CAPTURE_FRAME,
Dave Sparksec4dde72009-11-23 16:51:15 -080078 EXTRACT_ALBUM_ART,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080079 EXTRACT_METADATA,
80};
81
82class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
83{
84public:
85 BpMediaMetadataRetriever(const sp<IBinder>& impl)
86 : BpInterface<IMediaMetadataRetriever>(impl)
87 {
88 }
89
90 // disconnect from media metadata retriever service
91 void disconnect()
92 {
93 Parcel data, reply;
94 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
95 remote()->transact(DISCONNECT, data, &reply);
96 }
97
98 status_t setDataSource(const char* srcUrl)
99 {
100 Parcel data, reply;
101 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
102 data.writeCString(srcUrl);
103 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
104 return reply.readInt32();
105 }
106
107 status_t setDataSource(int fd, int64_t offset, int64_t length)
108 {
109 Parcel data, reply;
110 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
111 data.writeFileDescriptor(fd);
112 data.writeInt64(offset);
113 data.writeInt64(length);
114 remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
115 return reply.readInt32();
116 }
117
118 status_t setMode(int mode)
119 {
120 Parcel data, reply;
121 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
122 data.writeInt32(mode);
123 remote()->transact(SET_MODE, data, &reply);
124 return reply.readInt32();
125 }
126
127 status_t getMode(int* mode) const
128 {
129 Parcel data, reply;
130 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
131 remote()->transact(GET_MODE, data, &reply);
132 *mode = reply.readInt32();
133 return reply.readInt32();
134 }
135
136 sp<IMemory> captureFrame()
137 {
138 Parcel data, reply;
139 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800140#ifndef DISABLE_GROUP_SCHEDULE_HACK
141 sendSchedPolicy(data);
142#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800143 remote()->transact(CAPTURE_FRAME, data, &reply);
144 status_t ret = reply.readInt32();
145 if (ret != NO_ERROR) {
146 return NULL;
147 }
148 return interface_cast<IMemory>(reply.readStrongBinder());
149 }
150
151 sp<IMemory> extractAlbumArt()
152 {
153 Parcel data, reply;
154 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800155#ifndef DISABLE_GROUP_SCHEDULE_HACK
156 sendSchedPolicy(data);
157#endif
158 remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800159 status_t ret = reply.readInt32();
160 if (ret != NO_ERROR) {
161 return NULL;
162 }
163 return interface_cast<IMemory>(reply.readStrongBinder());
164 }
165
166 const char* extractMetadata(int keyCode)
167 {
168 Parcel data, reply;
169 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800170#ifndef DISABLE_GROUP_SCHEDULE_HACK
171 sendSchedPolicy(data);
172#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800173 data.writeInt32(keyCode);
174 remote()->transact(EXTRACT_METADATA, data, &reply);
175 status_t ret = reply.readInt32();
176 if (ret != NO_ERROR) {
177 return NULL;
178 }
179 return reply.readCString();
180 }
181};
182
niko56f0cc52009-06-22 08:49:52 -0700183IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800184
185// ----------------------------------------------------------------------
186
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800187status_t BnMediaMetadataRetriever::onTransact(
188 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
189{
190 switch (code) {
191 case DISCONNECT: {
192 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
193 disconnect();
194 return NO_ERROR;
195 } break;
196 case SET_DATA_SOURCE_URL: {
197 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
198 const char* srcUrl = data.readCString();
199 reply->writeInt32(setDataSource(srcUrl));
200 return NO_ERROR;
201 } break;
202 case SET_DATA_SOURCE_FD: {
203 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
204 int fd = dup(data.readFileDescriptor());
205 int64_t offset = data.readInt64();
206 int64_t length = data.readInt64();
207 reply->writeInt32(setDataSource(fd, offset, length));
208 return NO_ERROR;
209 } break;
210 case SET_MODE: {
211 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
212 int mode = data.readInt32();
213 reply->writeInt32(setMode(mode));
214 return NO_ERROR;
215 } break;
216 case GET_MODE: {
217 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
218 int mode;
219 status_t status = getMode(&mode);
220 reply->writeInt32(mode);
221 reply->writeInt32(status);
222 return NO_ERROR;
223 } break;
224 case CAPTURE_FRAME: {
225 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparksec4dde72009-11-23 16:51:15 -0800226#ifndef DISABLE_GROUP_SCHEDULE_HACK
227 setSchedPolicy(data);
228#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800229 sp<IMemory> bitmap = captureFrame();
230 if (bitmap != 0) { // Don't send NULL across the binder interface
231 reply->writeInt32(NO_ERROR);
232 reply->writeStrongBinder(bitmap->asBinder());
233 } else {
234 reply->writeInt32(UNKNOWN_ERROR);
235 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800236#ifndef DISABLE_GROUP_SCHEDULE_HACK
237 restoreSchedPolicy();
238#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800239 return NO_ERROR;
240 } break;
Dave Sparksec4dde72009-11-23 16:51:15 -0800241 case EXTRACT_ALBUM_ART: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800242 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparksec4dde72009-11-23 16:51:15 -0800243#ifndef DISABLE_GROUP_SCHEDULE_HACK
244 setSchedPolicy(data);
245#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800246 sp<IMemory> albumArt = extractAlbumArt();
247 if (albumArt != 0) { // Don't send NULL across the binder interface
248 reply->writeInt32(NO_ERROR);
249 reply->writeStrongBinder(albumArt->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;
258 case EXTRACT_METADATA: {
259 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 int keyCode = data.readInt32();
264 const char* value = extractMetadata(keyCode);
265 if (value != NULL) { // Don't send NULL across the binder interface
266 reply->writeInt32(NO_ERROR);
267 reply->writeCString(value);
268 } else {
269 reply->writeInt32(UNKNOWN_ERROR);
270 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800271#ifndef DISABLE_GROUP_SCHEDULE_HACK
272 restoreSchedPolicy();
273#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800274 return NO_ERROR;
275 } break;
276 default:
277 return BBinder::onTransact(code, data, reply, flags);
278 }
279}
280
281// ----------------------------------------------------------------------------
282
283}; // namespace android