/* ** ** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include namespace android { enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, SET_DATA_SOURCE_URL, SET_DATA_SOURCE_FD, SET_DATA_SOURCE_STREAM, SET_DATA_SOURCE_CALLBACK, PREPARE_ASYNC, START, STOP, IS_PLAYING, SET_PLAYBACK_SETTINGS, GET_PLAYBACK_SETTINGS, SET_SYNC_SETTINGS, GET_SYNC_SETTINGS, PAUSE, SEEK_TO, GET_CURRENT_POSITION, GET_DURATION, RESET, SET_AUDIO_STREAM_TYPE, SET_LOOPING, SET_VOLUME, INVOKE, SET_METADATA_FILTER, GET_METADATA, SET_AUX_EFFECT_SEND_LEVEL, ATTACH_AUX_EFFECT, SET_VIDEO_SURFACETEXTURE, SET_PARAMETER, GET_PARAMETER, SET_RETRANSMIT_ENDPOINT, GET_RETRANSMIT_ENDPOINT, SET_NEXT_PLAYER, SUSPEND, RESUME, }; class BpMediaPlayer: public BpInterface { public: BpMediaPlayer(const sp& impl) : BpInterface(impl) { } // disconnect from media player service void disconnect() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(DISCONNECT, data, &reply); } status_t setDataSource( const sp &httpService, const char* url, const KeyedVector* headers) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32(httpService != NULL); if (httpService != NULL) { data.writeStrongBinder(IInterface::asBinder(httpService)); } data.writeCString(url); if (headers == NULL) { data.writeInt32(0); } else { // serialize the headers data.writeInt32(headers->size()); for (size_t i = 0; i < headers->size(); ++i) { data.writeString8(headers->keyAt(i)); data.writeString8(headers->valueAt(i)); } } remote()->transact(SET_DATA_SOURCE_URL, data, &reply); return reply.readInt32(); } status_t setDataSource(int fd, int64_t offset, int64_t length) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeFileDescriptor(fd); data.writeInt64(offset); data.writeInt64(length); remote()->transact(SET_DATA_SOURCE_FD, data, &reply); return reply.readInt32(); } status_t setDataSource(const sp &source) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(source)); remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply); return reply.readInt32(); } status_t setDataSource(const sp &source) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(source)); remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply); return reply.readInt32(); } // pass the buffered IGraphicBufferProducer to the media player service status_t setVideoSurfaceTexture(const sp& bufferProducer) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); sp b(IInterface::asBinder(bufferProducer)); data.writeStrongBinder(b); remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply); return reply.readInt32(); } status_t prepareAsync() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(PREPARE_ASYNC, data, &reply); return reply.readInt32(); } status_t start() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(START, data, &reply); return reply.readInt32(); } status_t stop() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(STOP, data, &reply); return reply.readInt32(); } status_t isPlaying(bool* state) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(IS_PLAYING, data, &reply); *state = reply.readInt32(); return reply.readInt32(); } status_t setPlaybackSettings(const AudioPlaybackRate& rate) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeFloat(rate.mSpeed); data.writeFloat(rate.mPitch); data.writeInt32((int32_t)rate.mFallbackMode); data.writeInt32((int32_t)rate.mStretchMode); remote()->transact(SET_PLAYBACK_SETTINGS, data, &reply); return reply.readInt32(); } status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(GET_PLAYBACK_SETTINGS, data, &reply); status_t err = reply.readInt32(); if (err == OK) { *rate = AUDIO_PLAYBACK_RATE_DEFAULT; rate->mSpeed = reply.readFloat(); rate->mPitch = reply.readFloat(); rate->mFallbackMode = (AudioTimestretchFallbackMode)reply.readInt32(); rate->mStretchMode = (AudioTimestretchStretchMode)reply.readInt32(); } return err; } status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32((int32_t)sync.mSource); data.writeInt32((int32_t)sync.mAudioAdjustMode); data.writeFloat(sync.mTolerance); data.writeFloat(videoFpsHint); remote()->transact(SET_SYNC_SETTINGS, data, &reply); return reply.readInt32(); } status_t getSyncSettings(AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(GET_SYNC_SETTINGS, data, &reply); status_t err = reply.readInt32(); if (err == OK) { AVSyncSettings settings; settings.mSource = (AVSyncSource)reply.readInt32(); settings.mAudioAdjustMode = (AVSyncAudioAdjustMode)reply.readInt32(); settings.mTolerance = reply.readFloat(); *sync = settings; *videoFps = reply.readFloat(); } return err; } status_t pause() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(PAUSE, data, &reply); return reply.readInt32(); } status_t seekTo(int msec) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32(msec); remote()->transact(SEEK_TO, data, &reply); return reply.readInt32(); } status_t getCurrentPosition(int* msec) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(GET_CURRENT_POSITION, data, &reply); *msec = reply.readInt32(); return reply.readInt32(); } status_t getDuration(int* msec) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(GET_DURATION, data, &reply); *msec = reply.readInt32(); return reply.readInt32(); } status_t reset() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(RESET, data, &reply); return reply.readInt32(); } status_t setAudioStreamType(audio_stream_type_t stream) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32((int32_t) stream); remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply); return reply.readInt32(); } status_t setLooping(int loop) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32(loop); remote()->transact(SET_LOOPING, data, &reply); return reply.readInt32(); } status_t setVolume(float leftVolume, float rightVolume) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeFloat(leftVolume); data.writeFloat(rightVolume); remote()->transact(SET_VOLUME, data, &reply); return reply.readInt32(); } status_t invoke(const Parcel& request, Parcel *reply) { // Avoid doing any extra copy. The interface descriptor should // have been set by MediaPlayer.java. return remote()->transact(INVOKE, request, reply); } status_t setMetadataFilter(const Parcel& request) { Parcel reply; // Avoid doing any extra copy of the request. The interface // descriptor should have been set by MediaPlayer.java. remote()->transact(SET_METADATA_FILTER, request, &reply); return reply.readInt32(); } status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply) { Parcel request; request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here. request.writeInt32(update_only); request.writeInt32(apply_filter); remote()->transact(GET_METADATA, request, reply); return reply->readInt32(); } status_t setAuxEffectSendLevel(float level) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeFloat(level); remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply); return reply.readInt32(); } status_t attachAuxEffect(int effectId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32(effectId); remote()->transact(ATTACH_AUX_EFFECT, data, &reply); return reply.readInt32(); } status_t setParameter(int key, const Parcel& request) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32(key); if (request.dataSize() > 0) { data.appendFrom(const_cast(&request), 0, request.dataSize()); } remote()->transact(SET_PARAMETER, data, &reply); return reply.readInt32(); } status_t getParameter(int key, Parcel *reply) { Parcel data; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); data.writeInt32(key); return remote()->transact(GET_PARAMETER, data, reply); } status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) { Parcel data, reply; status_t err; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); if (NULL != endpoint) { data.writeInt32(sizeof(*endpoint)); data.write(endpoint, sizeof(*endpoint)); } else { data.writeInt32(0); } err = remote()->transact(SET_RETRANSMIT_ENDPOINT, data, &reply); if (OK != err) { return err; } return reply.readInt32(); } status_t setNextPlayer(const sp& player) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); sp b(IInterface::asBinder(player)); data.writeStrongBinder(b); remote()->transact(SET_NEXT_PLAYER, data, &reply); return reply.readInt32(); } status_t getRetransmitEndpoint(struct sockaddr_in* endpoint) { Parcel data, reply; status_t err; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); err = remote()->transact(GET_RETRANSMIT_ENDPOINT, data, &reply); if ((OK != err) || (OK != (err = reply.readInt32()))) { return err; } data.read(endpoint, sizeof(*endpoint)); return err; } status_t suspend() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(SUSPEND, data, &reply); return reply.readInt32(); } status_t resume() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); remote()->transact(RESUME, data, &reply); return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); // ---------------------------------------------------------------------- status_t BnMediaPlayer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case DISCONNECT: { CHECK_INTERFACE(IMediaPlayer, data, reply); disconnect(); return NO_ERROR; } break; case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp httpService; if (data.readInt32()) { httpService = interface_cast(data.readStrongBinder()); } const char* url = data.readCString(); KeyedVector headers; int32_t numHeaders = data.readInt32(); for (int i = 0; i < numHeaders; ++i) { String8 key = data.readString8(); String8 value = data.readString8(); headers.add(key, value); } reply->writeInt32(setDataSource( httpService, url, numHeaders > 0 ? &headers : NULL)); return NO_ERROR; } break; case SET_DATA_SOURCE_FD: { CHECK_INTERFACE(IMediaPlayer, data, reply); int fd = data.readFileDescriptor(); int64_t offset = data.readInt64(); int64_t length = data.readInt64(); reply->writeInt32(setDataSource(fd, offset, length)); return NO_ERROR; } case SET_DATA_SOURCE_STREAM: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp source = interface_cast(data.readStrongBinder()); reply->writeInt32(setDataSource(source)); return NO_ERROR; } case SET_DATA_SOURCE_CALLBACK: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp source = interface_cast(data.readStrongBinder()); reply->writeInt32(setDataSource(source)); return NO_ERROR; } case SET_VIDEO_SURFACETEXTURE: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp bufferProducer = interface_cast(data.readStrongBinder()); reply->writeInt32(setVideoSurfaceTexture(bufferProducer)); return NO_ERROR; } break; case PREPARE_ASYNC: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(prepareAsync()); return NO_ERROR; } break; case START: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(start()); return NO_ERROR; } break; case STOP: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(stop()); return NO_ERROR; } break; case IS_PLAYING: { CHECK_INTERFACE(IMediaPlayer, data, reply); bool state; status_t ret = isPlaying(&state); reply->writeInt32(state); reply->writeInt32(ret); return NO_ERROR; } break; case SET_PLAYBACK_SETTINGS: { CHECK_INTERFACE(IMediaPlayer, data, reply); AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; rate.mSpeed = data.readFloat(); rate.mPitch = data.readFloat(); rate.mFallbackMode = (AudioTimestretchFallbackMode)data.readInt32(); rate.mStretchMode = (AudioTimestretchStretchMode)data.readInt32(); reply->writeInt32(setPlaybackSettings(rate)); return NO_ERROR; } break; case GET_PLAYBACK_SETTINGS: { CHECK_INTERFACE(IMediaPlayer, data, reply); AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; status_t err = getPlaybackSettings(&rate); reply->writeInt32(err); if (err == OK) { reply->writeFloat(rate.mSpeed); reply->writeFloat(rate.mPitch); reply->writeInt32((int32_t)rate.mFallbackMode); reply->writeInt32((int32_t)rate.mStretchMode); } return NO_ERROR; } break; case SET_SYNC_SETTINGS: { CHECK_INTERFACE(IMediaPlayer, data, reply); AVSyncSettings sync; sync.mSource = (AVSyncSource)data.readInt32(); sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)data.readInt32(); sync.mTolerance = data.readFloat(); float videoFpsHint = data.readFloat(); reply->writeInt32(setSyncSettings(sync, videoFpsHint)); return NO_ERROR; } break; case GET_SYNC_SETTINGS: { CHECK_INTERFACE(IMediaPlayer, data, reply); AVSyncSettings sync; float videoFps; status_t err = getSyncSettings(&sync, &videoFps); reply->writeInt32(err); if (err == OK) { reply->writeInt32((int32_t)sync.mSource); reply->writeInt32((int32_t)sync.mAudioAdjustMode); reply->writeFloat(sync.mTolerance); reply->writeFloat(videoFps); } return NO_ERROR; } break; case PAUSE: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(pause()); return NO_ERROR; } break; case SEEK_TO: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(seekTo(data.readInt32())); return NO_ERROR; } break; case GET_CURRENT_POSITION: { CHECK_INTERFACE(IMediaPlayer, data, reply); int msec = 0; status_t ret = getCurrentPosition(&msec); reply->writeInt32(msec); reply->writeInt32(ret); return NO_ERROR; } break; case GET_DURATION: { CHECK_INTERFACE(IMediaPlayer, data, reply); int msec = 0; status_t ret = getDuration(&msec); reply->writeInt32(msec); reply->writeInt32(ret); return NO_ERROR; } break; case RESET: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(reset()); return NO_ERROR; } break; case SET_AUDIO_STREAM_TYPE: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setAudioStreamType((audio_stream_type_t) data.readInt32())); return NO_ERROR; } break; case SET_LOOPING: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setLooping(data.readInt32())); return NO_ERROR; } break; case SET_VOLUME: { CHECK_INTERFACE(IMediaPlayer, data, reply); float leftVolume = data.readFloat(); float rightVolume = data.readFloat(); reply->writeInt32(setVolume(leftVolume, rightVolume)); return NO_ERROR; } break; case INVOKE: { CHECK_INTERFACE(IMediaPlayer, data, reply); status_t result = invoke(data, reply); return result; } break; case SET_METADATA_FILTER: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setMetadataFilter(data)); return NO_ERROR; } break; case GET_METADATA: { CHECK_INTERFACE(IMediaPlayer, data, reply); bool update_only = static_cast(data.readInt32()); bool apply_filter = static_cast(data.readInt32()); const status_t retcode = getMetadata(update_only, apply_filter, reply); reply->setDataPosition(0); reply->writeInt32(retcode); reply->setDataPosition(0); return NO_ERROR; } break; case SET_AUX_EFFECT_SEND_LEVEL: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setAuxEffectSendLevel(data.readFloat())); return NO_ERROR; } break; case ATTACH_AUX_EFFECT: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(attachAuxEffect(data.readInt32())); return NO_ERROR; } break; case SET_PARAMETER: { CHECK_INTERFACE(IMediaPlayer, data, reply); int key = data.readInt32(); Parcel request; if (data.dataAvail() > 0) { request.appendFrom( const_cast(&data), data.dataPosition(), data.dataAvail()); } request.setDataPosition(0); reply->writeInt32(setParameter(key, request)); return NO_ERROR; } break; case GET_PARAMETER: { CHECK_INTERFACE(IMediaPlayer, data, reply); return getParameter(data.readInt32(), reply); } break; case SET_RETRANSMIT_ENDPOINT: { CHECK_INTERFACE(IMediaPlayer, data, reply); struct sockaddr_in endpoint; memset(&endpoint, 0, sizeof(endpoint)); int amt = data.readInt32(); if (amt == sizeof(endpoint)) { data.read(&endpoint, sizeof(struct sockaddr_in)); reply->writeInt32(setRetransmitEndpoint(&endpoint)); } else { reply->writeInt32(setRetransmitEndpoint(NULL)); } return NO_ERROR; } break; case GET_RETRANSMIT_ENDPOINT: { CHECK_INTERFACE(IMediaPlayer, data, reply); struct sockaddr_in endpoint; memset(&endpoint, 0, sizeof(endpoint)); status_t res = getRetransmitEndpoint(&endpoint); reply->writeInt32(res); reply->write(&endpoint, sizeof(endpoint)); return NO_ERROR; } break; case SET_NEXT_PLAYER: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setNextPlayer(interface_cast(data.readStrongBinder()))); return NO_ERROR; } break; case SUSPEND: { CHECK_INTERFACE(IMediaPlayer, data, reply); status_t ret = suspend(); reply->writeInt32(ret); return NO_ERROR; } break; case RESUME: { CHECK_INTERFACE(IMediaPlayer, data, reply); status_t ret = resume(); reply->writeInt32(ret); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } // ---------------------------------------------------------------------------- } // namespace android