1 /* 2 ** 3 ** Copyright 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 21 #include <binder/Parcel.h> 22 23 #include <media/IMediaPlayer.h> 24 #include <media/IStreamSource.h> 25 26 #include <surfaceflinger/ISurface.h> 27 #include <surfaceflinger/Surface.h> 28 #include <gui/ISurfaceTexture.h> 29 #include <utils/String8.h> 30 31 namespace android { 32 33 enum { 34 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, 35 SET_DATA_SOURCE_URL, 36 SET_DATA_SOURCE_FD, 37 SET_DATA_SOURCE_STREAM, 38 PREPARE_ASYNC, 39 START, 40 STOP, 41 IS_PLAYING, 42 PAUSE, 43 SEEK_TO, 44 GET_CURRENT_POSITION, 45 GET_DURATION, 46 RESET, 47 SET_AUDIO_STREAM_TYPE, 48 SET_LOOPING, 49 SET_VOLUME, 50 INVOKE, 51 SET_METADATA_FILTER, 52 GET_METADATA, 53 SET_AUX_EFFECT_SEND_LEVEL, 54 ATTACH_AUX_EFFECT, 55 SET_VIDEO_SURFACETEXTURE, 56 SET_PARAMETER, 57 GET_PARAMETER, 58 }; 59 60 class BpMediaPlayer: public BpInterface<IMediaPlayer> 61 { 62 public: 63 BpMediaPlayer(const sp<IBinder>& impl) 64 : BpInterface<IMediaPlayer>(impl) 65 { 66 } 67 68 // disconnect from media player service 69 void disconnect() 70 { 71 Parcel data, reply; 72 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 73 remote()->transact(DISCONNECT, data, &reply); 74 } 75 76 status_t setDataSource(const char* url, 77 const KeyedVector<String8, String8>* headers) 78 { 79 Parcel data, reply; 80 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 81 data.writeCString(url); 82 if (headers == NULL) { 83 data.writeInt32(0); 84 } else { 85 // serialize the headers 86 data.writeInt32(headers->size()); 87 for (size_t i = 0; i < headers->size(); ++i) { 88 data.writeString8(headers->keyAt(i)); 89 data.writeString8(headers->valueAt(i)); 90 } 91 } 92 remote()->transact(SET_DATA_SOURCE_URL, data, &reply); 93 return reply.readInt32(); 94 } 95 96 status_t setDataSource(int fd, int64_t offset, int64_t length) { 97 Parcel data, reply; 98 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 99 data.writeFileDescriptor(fd); 100 data.writeInt64(offset); 101 data.writeInt64(length); 102 remote()->transact(SET_DATA_SOURCE_FD, data, &reply); 103 return reply.readInt32(); 104 } 105 106 status_t setDataSource(const sp<IStreamSource> &source) { 107 Parcel data, reply; 108 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 109 data.writeStrongBinder(source->asBinder()); 110 remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply); 111 return reply.readInt32(); 112 } 113 114 // pass the buffered ISurfaceTexture to the media player service 115 status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture) 116 { 117 Parcel data, reply; 118 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 119 sp<IBinder> b(surfaceTexture->asBinder()); 120 data.writeStrongBinder(b); 121 remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply); 122 return reply.readInt32(); 123 } 124 125 status_t prepareAsync() 126 { 127 Parcel data, reply; 128 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 129 remote()->transact(PREPARE_ASYNC, data, &reply); 130 return reply.readInt32(); 131 } 132 133 status_t start() 134 { 135 Parcel data, reply; 136 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 137 remote()->transact(START, data, &reply); 138 return reply.readInt32(); 139 } 140 141 status_t stop() 142 { 143 Parcel data, reply; 144 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 145 remote()->transact(STOP, data, &reply); 146 return reply.readInt32(); 147 } 148 149 status_t isPlaying(bool* state) 150 { 151 Parcel data, reply; 152 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 153 remote()->transact(IS_PLAYING, data, &reply); 154 *state = reply.readInt32(); 155 return reply.readInt32(); 156 } 157 158 status_t pause() 159 { 160 Parcel data, reply; 161 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 162 remote()->transact(PAUSE, data, &reply); 163 return reply.readInt32(); 164 } 165 166 status_t seekTo(int msec) 167 { 168 Parcel data, reply; 169 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 170 data.writeInt32(msec); 171 remote()->transact(SEEK_TO, data, &reply); 172 return reply.readInt32(); 173 } 174 175 status_t getCurrentPosition(int* msec) 176 { 177 Parcel data, reply; 178 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 179 remote()->transact(GET_CURRENT_POSITION, data, &reply); 180 *msec = reply.readInt32(); 181 return reply.readInt32(); 182 } 183 184 status_t getDuration(int* msec) 185 { 186 Parcel data, reply; 187 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 188 remote()->transact(GET_DURATION, data, &reply); 189 *msec = reply.readInt32(); 190 return reply.readInt32(); 191 } 192 193 status_t reset() 194 { 195 Parcel data, reply; 196 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 197 remote()->transact(RESET, data, &reply); 198 return reply.readInt32(); 199 } 200 201 status_t setAudioStreamType(int type) 202 { 203 Parcel data, reply; 204 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 205 data.writeInt32(type); 206 remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply); 207 return reply.readInt32(); 208 } 209 210 status_t setLooping(int loop) 211 { 212 Parcel data, reply; 213 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 214 data.writeInt32(loop); 215 remote()->transact(SET_LOOPING, data, &reply); 216 return reply.readInt32(); 217 } 218 219 status_t setVolume(float leftVolume, float rightVolume) 220 { 221 Parcel data, reply; 222 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 223 data.writeFloat(leftVolume); 224 data.writeFloat(rightVolume); 225 remote()->transact(SET_VOLUME, data, &reply); 226 return reply.readInt32(); 227 } 228 229 status_t invoke(const Parcel& request, Parcel *reply) 230 { 231 // Avoid doing any extra copy. The interface descriptor should 232 // have been set by MediaPlayer.java. 233 return remote()->transact(INVOKE, request, reply); 234 } 235 236 status_t setMetadataFilter(const Parcel& request) 237 { 238 Parcel reply; 239 // Avoid doing any extra copy of the request. The interface 240 // descriptor should have been set by MediaPlayer.java. 241 remote()->transact(SET_METADATA_FILTER, request, &reply); 242 return reply.readInt32(); 243 } 244 245 status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply) 246 { 247 Parcel request; 248 request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 249 // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here. 250 request.writeInt32(update_only); 251 request.writeInt32(apply_filter); 252 remote()->transact(GET_METADATA, request, reply); 253 return reply->readInt32(); 254 } 255 256 status_t setAuxEffectSendLevel(float level) 257 { 258 Parcel data, reply; 259 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 260 data.writeFloat(level); 261 remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply); 262 return reply.readInt32(); 263 } 264 265 status_t attachAuxEffect(int effectId) 266 { 267 Parcel data, reply; 268 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 269 data.writeInt32(effectId); 270 remote()->transact(ATTACH_AUX_EFFECT, data, &reply); 271 return reply.readInt32(); 272 } 273 274 status_t setParameter(int key, const Parcel& request) 275 { 276 Parcel data, reply; 277 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 278 data.writeInt32(key); 279 if (request.dataSize() > 0) { 280 data.appendFrom(const_cast<Parcel *>(&request), 0, request.dataSize()); 281 } 282 remote()->transact(SET_PARAMETER, data, &reply); 283 return reply.readInt32(); 284 } 285 286 status_t getParameter(int key, Parcel *reply) 287 { 288 Parcel data; 289 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); 290 data.writeInt32(key); 291 return remote()->transact(GET_PARAMETER, data, reply); 292 } 293 294 }; 295 296 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); 297 298 // ---------------------------------------------------------------------- 299 300 status_t BnMediaPlayer::onTransact( 301 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 302 { 303 switch(code) { 304 case DISCONNECT: { 305 CHECK_INTERFACE(IMediaPlayer, data, reply); 306 disconnect(); 307 return NO_ERROR; 308 } break; 309 case SET_DATA_SOURCE_URL: { 310 CHECK_INTERFACE(IMediaPlayer, data, reply); 311 const char* url = data.readCString(); 312 KeyedVector<String8, String8> headers; 313 int32_t numHeaders = data.readInt32(); 314 for (int i = 0; i < numHeaders; ++i) { 315 String8 key = data.readString8(); 316 String8 value = data.readString8(); 317 headers.add(key, value); 318 } 319 reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL)); 320 return NO_ERROR; 321 } break; 322 case SET_DATA_SOURCE_FD: { 323 CHECK_INTERFACE(IMediaPlayer, data, reply); 324 int fd = data.readFileDescriptor(); 325 int64_t offset = data.readInt64(); 326 int64_t length = data.readInt64(); 327 reply->writeInt32(setDataSource(fd, offset, length)); 328 return NO_ERROR; 329 } 330 case SET_DATA_SOURCE_STREAM: { 331 CHECK_INTERFACE(IMediaPlayer, data, reply); 332 sp<IStreamSource> source = 333 interface_cast<IStreamSource>(data.readStrongBinder()); 334 reply->writeInt32(setDataSource(source)); 335 return NO_ERROR; 336 } 337 case SET_VIDEO_SURFACETEXTURE: { 338 CHECK_INTERFACE(IMediaPlayer, data, reply); 339 sp<ISurfaceTexture> surfaceTexture = 340 interface_cast<ISurfaceTexture>(data.readStrongBinder()); 341 reply->writeInt32(setVideoSurfaceTexture(surfaceTexture)); 342 return NO_ERROR; 343 } break; 344 case PREPARE_ASYNC: { 345 CHECK_INTERFACE(IMediaPlayer, data, reply); 346 reply->writeInt32(prepareAsync()); 347 return NO_ERROR; 348 } break; 349 case START: { 350 CHECK_INTERFACE(IMediaPlayer, data, reply); 351 reply->writeInt32(start()); 352 return NO_ERROR; 353 } break; 354 case STOP: { 355 CHECK_INTERFACE(IMediaPlayer, data, reply); 356 reply->writeInt32(stop()); 357 return NO_ERROR; 358 } break; 359 case IS_PLAYING: { 360 CHECK_INTERFACE(IMediaPlayer, data, reply); 361 bool state; 362 status_t ret = isPlaying(&state); 363 reply->writeInt32(state); 364 reply->writeInt32(ret); 365 return NO_ERROR; 366 } break; 367 case PAUSE: { 368 CHECK_INTERFACE(IMediaPlayer, data, reply); 369 reply->writeInt32(pause()); 370 return NO_ERROR; 371 } break; 372 case SEEK_TO: { 373 CHECK_INTERFACE(IMediaPlayer, data, reply); 374 reply->writeInt32(seekTo(data.readInt32())); 375 return NO_ERROR; 376 } break; 377 case GET_CURRENT_POSITION: { 378 CHECK_INTERFACE(IMediaPlayer, data, reply); 379 int msec; 380 status_t ret = getCurrentPosition(&msec); 381 reply->writeInt32(msec); 382 reply->writeInt32(ret); 383 return NO_ERROR; 384 } break; 385 case GET_DURATION: { 386 CHECK_INTERFACE(IMediaPlayer, data, reply); 387 int msec; 388 status_t ret = getDuration(&msec); 389 reply->writeInt32(msec); 390 reply->writeInt32(ret); 391 return NO_ERROR; 392 } break; 393 case RESET: { 394 CHECK_INTERFACE(IMediaPlayer, data, reply); 395 reply->writeInt32(reset()); 396 return NO_ERROR; 397 } break; 398 case SET_AUDIO_STREAM_TYPE: { 399 CHECK_INTERFACE(IMediaPlayer, data, reply); 400 reply->writeInt32(setAudioStreamType(data.readInt32())); 401 return NO_ERROR; 402 } break; 403 case SET_LOOPING: { 404 CHECK_INTERFACE(IMediaPlayer, data, reply); 405 reply->writeInt32(setLooping(data.readInt32())); 406 return NO_ERROR; 407 } break; 408 case SET_VOLUME: { 409 CHECK_INTERFACE(IMediaPlayer, data, reply); 410 float leftVolume = data.readFloat(); 411 float rightVolume = data.readFloat(); 412 reply->writeInt32(setVolume(leftVolume, rightVolume)); 413 return NO_ERROR; 414 } break; 415 case INVOKE: { 416 CHECK_INTERFACE(IMediaPlayer, data, reply); 417 status_t result = invoke(data, reply); 418 return result; 419 } break; 420 case SET_METADATA_FILTER: { 421 CHECK_INTERFACE(IMediaPlayer, data, reply); 422 reply->writeInt32(setMetadataFilter(data)); 423 return NO_ERROR; 424 } break; 425 case GET_METADATA: { 426 CHECK_INTERFACE(IMediaPlayer, data, reply); 427 bool update_only = static_cast<bool>(data.readInt32()); 428 bool apply_filter = static_cast<bool>(data.readInt32()); 429 const status_t retcode = getMetadata(update_only, apply_filter, reply); 430 reply->setDataPosition(0); 431 reply->writeInt32(retcode); 432 reply->setDataPosition(0); 433 return NO_ERROR; 434 } break; 435 case SET_AUX_EFFECT_SEND_LEVEL: { 436 CHECK_INTERFACE(IMediaPlayer, data, reply); 437 reply->writeInt32(setAuxEffectSendLevel(data.readFloat())); 438 return NO_ERROR; 439 } break; 440 case ATTACH_AUX_EFFECT: { 441 CHECK_INTERFACE(IMediaPlayer, data, reply); 442 reply->writeInt32(attachAuxEffect(data.readInt32())); 443 return NO_ERROR; 444 } break; 445 case SET_PARAMETER: { 446 CHECK_INTERFACE(IMediaPlayer, data, reply); 447 int key = data.readInt32(); 448 449 Parcel request; 450 if (data.dataAvail() > 0) { 451 request.appendFrom( 452 const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); 453 } 454 request.setDataPosition(0); 455 reply->writeInt32(setParameter(key, request)); 456 return NO_ERROR; 457 } break; 458 case GET_PARAMETER: { 459 CHECK_INTERFACE(IMediaPlayer, data, reply); 460 return getParameter(data.readInt32(), reply); 461 } break; 462 default: 463 return BBinder::onTransact(code, data, reply, flags); 464 } 465 } 466 467 // ---------------------------------------------------------------------------- 468 469 }; // namespace android 470