John Grossman 881186c322 Enhance Visualizer behavior in the case of mediaserver death.
Bring the Visualizer class into line with the SDK documentation by
returning ERROR_DEAD_OBJECT instead of ERROR_INVALID_OPERATION when
the Visualizer loses its binder connection to the mediaserver because
of a mediaserver restart.

Also add a new callback interface to allow clients to be
asynchronously notified in the case of server death.  Right now, the
interface definition and the registration method are flagged as hidden
pending API council review/approval.

See http://b/issue?id=5717519 for details.

Change-Id: Id428fb946d6d7676bffd2a597366e8444ebe24f2
Signed-off-by: John Grossman <johngro@google.com>
2012-01-12 14:36:16 -08:00

203 lines
5.5 KiB
C++

/*
**
** Copyright 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 "IEffect"
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include <media/IEffect.h>
namespace android {
enum {
ENABLE = IBinder::FIRST_CALL_TRANSACTION,
DISABLE,
COMMAND,
DISCONNECT,
GET_CBLK
};
class BpEffect: public BpInterface<IEffect>
{
public:
BpEffect(const sp<IBinder>& impl)
: BpInterface<IEffect>(impl)
{
}
status_t enable()
{
LOGV("enable");
Parcel data, reply;
data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
remote()->transact(ENABLE, data, &reply);
return reply.readInt32();
}
status_t disable()
{
LOGV("disable");
Parcel data, reply;
data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
remote()->transact(DISABLE, data, &reply);
return reply.readInt32();
}
status_t command(uint32_t cmdCode,
uint32_t cmdSize,
void *pCmdData,
uint32_t *pReplySize,
void *pReplyData)
{
LOGV("command");
Parcel data, reply;
data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
data.writeInt32(cmdCode);
int size = cmdSize;
if (pCmdData == NULL) {
size = 0;
}
data.writeInt32(size);
if (size) {
data.write(pCmdData, size);
}
if (pReplySize == NULL) {
size = 0;
} else {
size = *pReplySize;
}
data.writeInt32(size);
status_t status = remote()->transact(COMMAND, data, &reply);
if (status != NO_ERROR) {
if (pReplySize != NULL)
*pReplySize = 0;
return status;
}
status = reply.readInt32();
size = reply.readInt32();
if (size != 0 && pReplyData != NULL && pReplySize != NULL) {
reply.read(pReplyData, size);
*pReplySize = size;
}
return status;
}
void disconnect()
{
LOGV("disconnect");
Parcel data, reply;
data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
remote()->transact(DISCONNECT, data, &reply);
return;
}
virtual sp<IMemory> getCblk() const
{
Parcel data, reply;
sp<IMemory> cblk;
data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
}
return cblk;
}
};
IMPLEMENT_META_INTERFACE(Effect, "android.media.IEffect");
// ----------------------------------------------------------------------
status_t BnEffect::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case ENABLE: {
LOGV("ENABLE");
CHECK_INTERFACE(IEffect, data, reply);
reply->writeInt32(enable());
return NO_ERROR;
} break;
case DISABLE: {
LOGV("DISABLE");
CHECK_INTERFACE(IEffect, data, reply);
reply->writeInt32(disable());
return NO_ERROR;
} break;
case COMMAND: {
LOGV("COMMAND");
CHECK_INTERFACE(IEffect, data, reply);
uint32_t cmdCode = data.readInt32();
uint32_t cmdSize = data.readInt32();
char *cmd = NULL;
if (cmdSize) {
cmd = (char *)malloc(cmdSize);
data.read(cmd, cmdSize);
}
uint32_t replySize = data.readInt32();
uint32_t replySz = replySize;
char *resp = NULL;
if (replySize) {
resp = (char *)malloc(replySize);
}
status_t status = command(cmdCode, cmdSize, cmd, &replySz, resp);
reply->writeInt32(status);
if (replySz < replySize) {
replySize = replySz;
}
reply->writeInt32(replySize);
if (replySize) {
reply->write(resp, replySize);
}
if (cmd) {
free(cmd);
}
if (resp) {
free(resp);
}
return NO_ERROR;
} break;
case DISCONNECT: {
LOGV("DISCONNECT");
CHECK_INTERFACE(IEffect, data, reply);
disconnect();
return NO_ERROR;
} break;
case GET_CBLK: {
CHECK_INTERFACE(IEffect, data, reply);
reply->writeStrongBinder(getCblk()->asBinder());
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// ----------------------------------------------------------------------------
}; // namespace android