blob: 0193e25247e7fd4ecb83e736677e4a73c4b529e8 [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
Dave Sparksf311c552009-11-23 19:51:33 -080044static int myTid() {
45#ifdef HAVE_GETTID
46 return gettid();
47#else
48 return getpid();
49#endif
50}
51
52#undef LOG_TAG
Dave Sparksec4dde72009-11-23 16:51:15 -080053#define LOG_TAG "IMediaMetadataRetriever"
54#include <utils/Log.h>
55#include <cutils/sched_policy.h>
56
57namespace android {
58
59static void sendSchedPolicy(Parcel& data)
60{
61 SchedPolicy policy;
Dave Sparksf311c552009-11-23 19:51:33 -080062 get_sched_policy(myTid(), &policy);
Dave Sparksec4dde72009-11-23 16:51:15 -080063 data.writeInt32(policy);
64}
65
66static void setSchedPolicy(const Parcel& data)
67{
68 SchedPolicy policy = (SchedPolicy) data.readInt32();
Dave Sparksf311c552009-11-23 19:51:33 -080069 set_sched_policy(myTid(), policy);
Dave Sparksec4dde72009-11-23 16:51:15 -080070}
71static void restoreSchedPolicy()
72{
Dave Sparksf311c552009-11-23 19:51:33 -080073 set_sched_policy(myTid(), SP_FOREGROUND);
Dave Sparksec4dde72009-11-23 16:51:15 -080074}
75}; // end namespace android
76#endif
77
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080078namespace android {
79
80enum {
81 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
82 SET_DATA_SOURCE_URL,
83 SET_DATA_SOURCE_FD,
84 SET_MODE,
James Dong16afe2f2010-12-02 17:42:08 -080085 GET_FRAME_AT_TIME,
Dave Sparksec4dde72009-11-23 16:51:15 -080086 EXTRACT_ALBUM_ART,
The Android Open Source Project89fa4ad2009-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
106 status_t setDataSource(const char* srcUrl)
107 {
108 Parcel data, reply;
109 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
110 data.writeCString(srcUrl);
111 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
112 return reply.readInt32();
113 }
114
115 status_t setDataSource(int fd, int64_t offset, int64_t length)
116 {
117 Parcel data, reply;
118 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
119 data.writeFileDescriptor(fd);
120 data.writeInt64(offset);
121 data.writeInt64(length);
122 remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
123 return reply.readInt32();
124 }
125
126 status_t setMode(int mode)
127 {
128 Parcel data, reply;
129 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
130 data.writeInt32(mode);
131 remote()->transact(SET_MODE, data, &reply);
132 return reply.readInt32();
133 }
134
James Dong16afe2f2010-12-02 17:42:08 -0800135 sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800136 {
James Dong16afe2f2010-12-02 17:42:08 -0800137 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800138 Parcel data, reply;
139 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
James Dong16afe2f2010-12-02 17:42:08 -0800140 data.writeInt64(timeUs);
141 data.writeInt32(option);
Dave Sparksec4dde72009-11-23 16:51:15 -0800142#ifndef DISABLE_GROUP_SCHEDULE_HACK
143 sendSchedPolicy(data);
144#endif
James Dong16afe2f2010-12-02 17:42:08 -0800145 remote()->transact(GET_FRAME_AT_TIME, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800146 status_t ret = reply.readInt32();
147 if (ret != NO_ERROR) {
148 return NULL;
149 }
150 return interface_cast<IMemory>(reply.readStrongBinder());
151 }
152
153 sp<IMemory> extractAlbumArt()
154 {
155 Parcel data, reply;
156 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800157#ifndef DISABLE_GROUP_SCHEDULE_HACK
158 sendSchedPolicy(data);
159#endif
160 remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800161 status_t ret = reply.readInt32();
162 if (ret != NO_ERROR) {
163 return NULL;
164 }
165 return interface_cast<IMemory>(reply.readStrongBinder());
166 }
167
168 const char* extractMetadata(int keyCode)
169 {
170 Parcel data, reply;
171 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800172#ifndef DISABLE_GROUP_SCHEDULE_HACK
173 sendSchedPolicy(data);
174#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800175 data.writeInt32(keyCode);
176 remote()->transact(EXTRACT_METADATA, data, &reply);
177 status_t ret = reply.readInt32();
178 if (ret != NO_ERROR) {
179 return NULL;
180 }
181 return reply.readCString();
182 }
183};
184
niko56f0cc52009-06-22 08:49:52 -0700185IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800186
187// ----------------------------------------------------------------------
188
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800189status_t BnMediaMetadataRetriever::onTransact(
190 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
191{
192 switch (code) {
193 case DISCONNECT: {
194 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
195 disconnect();
196 return NO_ERROR;
197 } break;
198 case SET_DATA_SOURCE_URL: {
199 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
200 const char* srcUrl = data.readCString();
201 reply->writeInt32(setDataSource(srcUrl));
202 return NO_ERROR;
203 } break;
204 case SET_DATA_SOURCE_FD: {
205 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
206 int fd = dup(data.readFileDescriptor());
207 int64_t offset = data.readInt64();
208 int64_t length = data.readInt64();
209 reply->writeInt32(setDataSource(fd, offset, length));
210 return NO_ERROR;
211 } break;
212 case SET_MODE: {
213 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
214 int mode = data.readInt32();
215 reply->writeInt32(setMode(mode));
216 return NO_ERROR;
217 } break;
James Dong16afe2f2010-12-02 17:42:08 -0800218 case GET_FRAME_AT_TIME: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800219 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
James Dong16afe2f2010-12-02 17:42:08 -0800220 int64_t timeUs = data.readInt64();
221 int option = data.readInt32();
222 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
Dave Sparksec4dde72009-11-23 16:51:15 -0800223#ifndef DISABLE_GROUP_SCHEDULE_HACK
224 setSchedPolicy(data);
225#endif
James Dong16afe2f2010-12-02 17:42:08 -0800226 sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800227 if (bitmap != 0) { // Don't send NULL across the binder interface
228 reply->writeInt32(NO_ERROR);
229 reply->writeStrongBinder(bitmap->asBinder());
230 } else {
231 reply->writeInt32(UNKNOWN_ERROR);
232 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800233#ifndef DISABLE_GROUP_SCHEDULE_HACK
234 restoreSchedPolicy();
235#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800236 return NO_ERROR;
237 } break;
Dave Sparksec4dde72009-11-23 16:51:15 -0800238 case EXTRACT_ALBUM_ART: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800239 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparksec4dde72009-11-23 16:51:15 -0800240#ifndef DISABLE_GROUP_SCHEDULE_HACK
241 setSchedPolicy(data);
242#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800243 sp<IMemory> albumArt = extractAlbumArt();
244 if (albumArt != 0) { // Don't send NULL across the binder interface
245 reply->writeInt32(NO_ERROR);
246 reply->writeStrongBinder(albumArt->asBinder());
247 } else {
248 reply->writeInt32(UNKNOWN_ERROR);
249 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800250#ifndef DISABLE_GROUP_SCHEDULE_HACK
251 restoreSchedPolicy();
252#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800253 return NO_ERROR;
254 } break;
255 case EXTRACT_METADATA: {
256 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Dave Sparksec4dde72009-11-23 16:51:15 -0800257#ifndef DISABLE_GROUP_SCHEDULE_HACK
258 setSchedPolicy(data);
259#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800260 int keyCode = data.readInt32();
261 const char* value = extractMetadata(keyCode);
262 if (value != NULL) { // Don't send NULL across the binder interface
263 reply->writeInt32(NO_ERROR);
264 reply->writeCString(value);
265 } else {
266 reply->writeInt32(UNKNOWN_ERROR);
267 }
Dave Sparksec4dde72009-11-23 16:51:15 -0800268#ifndef DISABLE_GROUP_SCHEDULE_HACK
269 restoreSchedPolicy();
270#endif
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800271 return NO_ERROR;
272 } break;
273 default:
274 return BBinder::onTransact(code, data, reply, flags);
275 }
276}
277
278// ----------------------------------------------------------------------------
279
280}; // namespace android