From e2b1028852120bcfded33b8f06f66b780437fe92 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 23 Nov 2010 11:41:34 -0800 Subject: Support streaming data across binder boundaries. Change-Id: Ifbac61406dcb81343765f99ccba08bd90f9274cc --- media/libmedia/Android.mk | 1 + media/libmedia/IMediaPlayerService.cpp | 38 ++++++++ media/libmedia/IStreamSource.cpp | 168 +++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 media/libmedia/IStreamSource.cpp (limited to 'media/libmedia') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 2e5cbe3..731c09d 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ IMediaRecorderClient.cpp \ IMediaPlayer.cpp \ IMediaRecorder.cpp \ + IStreamSource.cpp \ Metadata.cpp \ mediarecorder.cpp \ IMediaMetadataRetriever.cpp \ diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 4abfa75..77199e1 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include // for status_t @@ -31,6 +32,7 @@ namespace android { enum { CREATE_URL = IBinder::FIRST_CALL_TRANSACTION, CREATE_FD, + CREATE_STREAM, DECODE_URL, DECODE_FD, CREATE_MEDIA_RECORDER, @@ -107,6 +109,21 @@ public: return interface_cast(reply.readStrongBinder());; } + virtual sp create( + pid_t pid, const sp &client, + const sp &source, int audioSessionId) { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(static_cast(pid)); + data.writeStrongBinder(client->asBinder()); + data.writeStrongBinder(source->asBinder()); + data.writeInt32(static_cast(audioSessionId)); + + remote()->transact(CREATE_STREAM, data, &reply); + + return interface_cast(reply.readStrongBinder());; + } + virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) { Parcel data, reply; @@ -184,6 +201,27 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; + case CREATE_STREAM: + { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + + pid_t pid = static_cast(data.readInt32()); + + sp client = + interface_cast(data.readStrongBinder()); + + sp source = + interface_cast(data.readStrongBinder()); + + int audioSessionId = static_cast(data.readInt32()); + + sp player = + create(pid, client, source, audioSessionId); + + reply->writeStrongBinder(player->asBinder()); + return OK; + break; + } case DECODE_URL: { CHECK_INTERFACE(IMediaPlayerService, data, reply); const char* url = data.readCString(); diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp new file mode 100644 index 0000000..89f2b44 --- /dev/null +++ b/media/libmedia/IStreamSource.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2010 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IStreamSource" +#include + +#include + +#include +#include + +namespace android { + +enum { + // IStreamSource + SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION, + SET_BUFFERS, + ON_BUFFER_AVAILABLE, + + // IStreamListener + QUEUE_BUFFER, + QUEUE_COMMAND, +}; + +struct BpStreamSource : public BpInterface { + BpStreamSource(const sp &impl) + : BpInterface(impl) { + } + + virtual void setListener(const sp &listener) { + Parcel data, reply; + data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor()); + data.writeStrongBinder(listener->asBinder()); + remote()->transact(SET_LISTENER, data, &reply); + } + + virtual void setBuffers(const Vector > &buffers) { + Parcel data, reply; + data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor()); + data.writeInt32(static_cast(buffers.size())); + for (size_t i = 0; i < buffers.size(); ++i) { + data.writeStrongBinder(buffers.itemAt(i)->asBinder()); + } + remote()->transact(SET_BUFFERS, data, &reply); + } + + virtual void onBufferAvailable(size_t index) { + Parcel data, reply; + data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor()); + data.writeInt32(static_cast(index)); + remote()->transact( + ON_BUFFER_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(StreamSource, "android.hardware.IStreamSource"); + +status_t BnStreamSource::onTransact( + uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { + switch (code) { + case SET_LISTENER: + { + CHECK_INTERFACE(IStreamSource, data, reply); + setListener( + interface_cast(data.readStrongBinder())); + break; + } + + case SET_BUFFERS: + { + CHECK_INTERFACE(IStreamSource, data, reply); + size_t n = static_cast(data.readInt32()); + Vector > buffers; + for (size_t i = 0; i < n; ++i) { + sp mem = + interface_cast(data.readStrongBinder()); + + buffers.push(mem); + } + setBuffers(buffers); + break; + } + + case ON_BUFFER_AVAILABLE: + { + CHECK_INTERFACE(IStreamSource, data, reply); + onBufferAvailable(static_cast(data.readInt32())); + break; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } + + return OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BpStreamListener : public BpInterface { + BpStreamListener(const sp &impl) + : BpInterface(impl) { + } + + virtual void queueBuffer(size_t index, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IStreamListener::getInterfaceDescriptor()); + data.writeInt32(static_cast(index)); + data.writeInt32(static_cast(size)); + + remote()->transact(QUEUE_BUFFER, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void queueCommand(Command cmd) { + Parcel data, reply; + data.writeInterfaceToken(IStreamListener::getInterfaceDescriptor()); + data.writeInt32(static_cast(cmd)); + + remote()->transact(QUEUE_COMMAND, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(StreamListener, "android.hardware.IStreamListener"); + +status_t BnStreamListener::onTransact( + uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { + switch (code) { + case QUEUE_BUFFER: + { + CHECK_INTERFACE(IStreamListener, data, reply); + size_t index = static_cast(data.readInt32()); + size_t size = static_cast(data.readInt32()); + + queueBuffer(index, size); + break; + } + + case QUEUE_COMMAND: + { + CHECK_INTERFACE(IStreamListener, data, reply); + Command cmd = static_cast(data.readInt32()); + + queueCommand(cmd); + break; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } + + return OK; +} + +} // namespace android -- cgit v1.1