• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
20 #include <binder/Parcel.h>
21 #include <media/IMediaMetadataRetriever.h>
22 #include <utils/String8.h>
23 
24 // 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 #undef LOG_TAG
33 #define LOG_TAG "IMediaMetadataRetriever"
34 #include <utils/Log.h>
35 #include <cutils/sched_policy.h>
36 
37 namespace android {
38 
sendSchedPolicy(Parcel & data)39 static void sendSchedPolicy(Parcel& data)
40 {
41     SchedPolicy policy;
42     get_sched_policy(gettid(), &policy);
43     data.writeInt32(policy);
44 }
45 
setSchedPolicy(const Parcel & data)46 static void setSchedPolicy(const Parcel& data)
47 {
48     SchedPolicy policy = (SchedPolicy) data.readInt32();
49     set_sched_policy(gettid(), policy);
50 }
restoreSchedPolicy()51 static void restoreSchedPolicy()
52 {
53     set_sched_policy(gettid(), SP_FOREGROUND);
54 }
55 }; // end namespace android
56 #endif
57 
58 namespace android {
59 
60 enum {
61     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
62     SET_DATA_SOURCE_URL,
63     SET_DATA_SOURCE_FD,
64     GET_FRAME_AT_TIME,
65     EXTRACT_ALBUM_ART,
66     EXTRACT_METADATA,
67 };
68 
69 class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
70 {
71 public:
BpMediaMetadataRetriever(const sp<IBinder> & impl)72     BpMediaMetadataRetriever(const sp<IBinder>& impl)
73         : BpInterface<IMediaMetadataRetriever>(impl)
74     {
75     }
76 
77     // disconnect from media metadata retriever service
disconnect()78     void disconnect()
79     {
80         Parcel data, reply;
81         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
82         remote()->transact(DISCONNECT, data, &reply);
83     }
84 
setDataSource(const char * srcUrl,const KeyedVector<String8,String8> * headers)85     status_t setDataSource(
86             const char *srcUrl, const KeyedVector<String8, String8> *headers)
87     {
88         Parcel data, reply;
89         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
90         data.writeCString(srcUrl);
91 
92         if (headers == NULL) {
93             data.writeInt32(0);
94         } else {
95             // serialize the headers
96             data.writeInt32(headers->size());
97             for (size_t i = 0; i < headers->size(); ++i) {
98                 data.writeString8(headers->keyAt(i));
99                 data.writeString8(headers->valueAt(i));
100             }
101         }
102 
103         remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
104         return reply.readInt32();
105     }
106 
setDataSource(int fd,int64_t offset,int64_t length)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 
getFrameAtTime(int64_t timeUs,int option)118     sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
119     {
120         ALOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
121         Parcel data, reply;
122         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
123         data.writeInt64(timeUs);
124         data.writeInt32(option);
125 #ifndef DISABLE_GROUP_SCHEDULE_HACK
126         sendSchedPolicy(data);
127 #endif
128         remote()->transact(GET_FRAME_AT_TIME, data, &reply);
129         status_t ret = reply.readInt32();
130         if (ret != NO_ERROR) {
131             return NULL;
132         }
133         return interface_cast<IMemory>(reply.readStrongBinder());
134     }
135 
extractAlbumArt()136     sp<IMemory> extractAlbumArt()
137     {
138         Parcel data, reply;
139         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
140 #ifndef DISABLE_GROUP_SCHEDULE_HACK
141         sendSchedPolicy(data);
142 #endif
143         remote()->transact(EXTRACT_ALBUM_ART, 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 
extractMetadata(int keyCode)151     const char* extractMetadata(int keyCode)
152     {
153         Parcel data, reply;
154         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
155 #ifndef DISABLE_GROUP_SCHEDULE_HACK
156         sendSchedPolicy(data);
157 #endif
158         data.writeInt32(keyCode);
159         remote()->transact(EXTRACT_METADATA, data, &reply);
160         status_t ret = reply.readInt32();
161         if (ret != NO_ERROR) {
162             return NULL;
163         }
164         return reply.readCString();
165     }
166 };
167 
168 IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
169 
170 // ----------------------------------------------------------------------
171 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)172 status_t BnMediaMetadataRetriever::onTransact(
173     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
174 {
175     switch (code) {
176         case DISCONNECT: {
177             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
178             disconnect();
179             return NO_ERROR;
180         } break;
181         case SET_DATA_SOURCE_URL: {
182             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
183             const char* srcUrl = data.readCString();
184 
185             KeyedVector<String8, String8> headers;
186             int32_t numHeaders = data.readInt32();
187             for (int i = 0; i < numHeaders; ++i) {
188                 String8 key = data.readString8();
189                 String8 value = data.readString8();
190                 headers.add(key, value);
191             }
192 
193             reply->writeInt32(
194                     setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL));
195 
196             return NO_ERROR;
197         } break;
198         case SET_DATA_SOURCE_FD: {
199             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
200             int fd = dup(data.readFileDescriptor());
201             int64_t offset = data.readInt64();
202             int64_t length = data.readInt64();
203             reply->writeInt32(setDataSource(fd, offset, length));
204             return NO_ERROR;
205         } break;
206         case GET_FRAME_AT_TIME: {
207             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
208             int64_t timeUs = data.readInt64();
209             int option = data.readInt32();
210             ALOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
211 #ifndef DISABLE_GROUP_SCHEDULE_HACK
212             setSchedPolicy(data);
213 #endif
214             sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
215             if (bitmap != 0) {  // Don't send NULL across the binder interface
216                 reply->writeInt32(NO_ERROR);
217                 reply->writeStrongBinder(bitmap->asBinder());
218             } else {
219                 reply->writeInt32(UNKNOWN_ERROR);
220             }
221 #ifndef DISABLE_GROUP_SCHEDULE_HACK
222             restoreSchedPolicy();
223 #endif
224             return NO_ERROR;
225         } break;
226         case EXTRACT_ALBUM_ART: {
227             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
228 #ifndef DISABLE_GROUP_SCHEDULE_HACK
229             setSchedPolicy(data);
230 #endif
231             sp<IMemory> albumArt = extractAlbumArt();
232             if (albumArt != 0) {  // Don't send NULL across the binder interface
233                 reply->writeInt32(NO_ERROR);
234                 reply->writeStrongBinder(albumArt->asBinder());
235             } else {
236                 reply->writeInt32(UNKNOWN_ERROR);
237             }
238 #ifndef DISABLE_GROUP_SCHEDULE_HACK
239             restoreSchedPolicy();
240 #endif
241             return NO_ERROR;
242         } break;
243         case EXTRACT_METADATA: {
244             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
245 #ifndef DISABLE_GROUP_SCHEDULE_HACK
246             setSchedPolicy(data);
247 #endif
248             int keyCode = data.readInt32();
249             const char* value = extractMetadata(keyCode);
250             if (value != NULL) {  // Don't send NULL across the binder interface
251                 reply->writeInt32(NO_ERROR);
252                 reply->writeCString(value);
253             } else {
254                 reply->writeInt32(UNKNOWN_ERROR);
255             }
256 #ifndef DISABLE_GROUP_SCHEDULE_HACK
257             restoreSchedPolicy();
258 #endif
259             return NO_ERROR;
260         } break;
261         default:
262             return BBinder::onTransact(code, data, reply, flags);
263     }
264 }
265 
266 // ----------------------------------------------------------------------------
267 
268 }; // namespace android
269