Switching Native MIDI API to an "opaque pointers" model.
Test: manual
Change-Id: Ic181008427e6e81106d867cc3a70deef8c591841
diff --git a/media/native/midi/midi.cpp b/media/native/midi/midi.cpp
index 1bf0bd0..17b92da3 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/midi.cpp
@@ -25,10 +25,9 @@
#include "android/media/midi/BpMidiDeviceServer.h"
#include "media/MidiDeviceInfo.h"
-#include "MidiDeviceRegistry.h"
-#include "MidiPortRegistry.h"
#include "midi.h"
+#include "midi_internal.h"
using android::IBinder;
using android::BBinder;
@@ -37,13 +36,28 @@
using android::status_t;
using android::base::unique_fd;
using android::binder::Status;
-using android::media::midi::BpMidiDeviceServer;
using android::media::midi::MidiDeviceInfo;
-using android::media::midi::MidiDeviceRegistry;
-using android::media::midi::MidiPortRegistry;
+
+struct AMIDI_Port {
+ std::atomic_int state;
+ AMIDI_Device *device;
+ sp<IBinder> binderToken;
+ unique_fd ufd;
+};
#define SIZE_MIDIRECEIVEBUFFER AMIDI_BUFFER_SIZE
+enum {
+ MIDI_PORT_STATE_CLOSED = 0,
+ MIDI_PORT_STATE_OPEN_IDLE,
+ MIDI_PORT_STATE_OPEN_ACTIVE
+};
+
+enum {
+ PORTTYPE_OUTPUT = 0,
+ PORTTYPE_INPUT = 1
+};
+
/* TRANSFER PACKET FORMAT (as defined in MidiPortImpl.java)
*
* Transfer packet format is as follows (see MidiOutputPort.mThread.run() to see decomposition):
@@ -63,20 +77,12 @@
* So 'read()' always returns a whole message.
*/
-status_t AMIDI_getDeviceById(int32_t id, AMIDI_Device *devicePtr) {
- return MidiDeviceRegistry::getInstance().obtainDeviceToken(id, devicePtr);
-}
-
-status_t AMIDI_getDeviceInfo(AMIDI_Device device, AMIDI_DeviceInfo *deviceInfoPtr) {
- sp<BpMidiDeviceServer> deviceServer;
- status_t result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
- if (result != OK) {
- ALOGE("AMIDI_getDeviceInfo bad device token %d: %d", device, result);
- return result;
- }
-
+/*
+ * Device Functions
+ */
+status_t AMIDI_getDeviceInfo(AMIDI_Device *device, AMIDI_DeviceInfo *deviceInfoPtr) {
MidiDeviceInfo deviceInfo;
- Status txResult = deviceServer->getDeviceInfo(&deviceInfo);
+ Status txResult = device->server->getDeviceInfo(&deviceInfo);
if (!txResult.isOk()) {
ALOGE("AMIDI_getDeviceInfo transaction error: %d", txResult.transactionError());
return txResult.transactionError();
@@ -87,49 +93,74 @@
deviceInfoPtr->isPrivate = deviceInfo.isPrivate();
deviceInfoPtr->inputPortCount = deviceInfo.getInputPortNames().size();
deviceInfoPtr->outputPortCount = deviceInfo.getOutputPortNames().size();
+
+ return OK;
+}
+
+/*
+ * Port Helpers
+ */
+static status_t AMIDI_openPort(AMIDI_Device *device, int portNumber, int type,
+ AMIDI_Port **portPtr) {
+ sp<BBinder> portToken(new BBinder());
+ unique_fd ufd;
+ Status txResult = type == PORTTYPE_OUTPUT
+ ? device->server->openOutputPort(portToken, portNumber, &ufd)
+ : device->server->openInputPort(portToken, portNumber, &ufd);
+ if (!txResult.isOk()) {
+ ALOGE("AMIDI_openPort transaction error: %d", txResult.transactionError());
+ return txResult.transactionError();
+ }
+
+ AMIDI_Port* port = new AMIDI_Port;
+ port->state = MIDI_PORT_STATE_OPEN_IDLE;
+ port->device = device;
+ port->binderToken = portToken;
+ port->ufd = std::move(ufd);
+
+ *portPtr = port;
+
+ return OK;
+}
+
+static status_t AMIDI_closePort(AMIDI_Port *port) {
+ int portState = MIDI_PORT_STATE_OPEN_IDLE;
+ while (!port->state.compare_exchange_weak(portState, MIDI_PORT_STATE_CLOSED)) {
+ if (portState == MIDI_PORT_STATE_CLOSED) {
+ return -EINVAL; // Already closed
+ }
+ }
+
+ Status txResult = port->device->server->closePort(port->binderToken);
+ if (!txResult.isOk()) {
+ return txResult.transactionError();
+ }
+
+ delete port;
+
return OK;
}
/*
* Output (receiving) API
*/
-status_t AMIDI_openOutputPort(AMIDI_Device device, int portNumber, AMIDI_OutputPort *outputPortPtr) {
- sp<BpMidiDeviceServer> deviceServer;
- status_t result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
- if (result != OK) {
- ALOGE("AMIDI_openOutputPort bad device token %d: %d", device, result);
- return result;
- }
-
- sp<BBinder> portToken(new BBinder());
- unique_fd ufd;
- Status txResult = deviceServer->openOutputPort(portToken, portNumber, &ufd);
- if (!txResult.isOk()) {
- ALOGE("AMIDI_openOutputPort transaction error: %d", txResult.transactionError());
- return txResult.transactionError();
- }
-
- result = MidiPortRegistry::getInstance().addOutputPort(
- device, portToken, std::move(ufd), outputPortPtr);
- if (result != OK) {
- ALOGE("AMIDI_openOutputPort port registration error: %d", result);
- // Close port
- return result;
- }
- return OK;
+status_t AMIDI_openOutputPort(AMIDI_Device *device, int portNumber,
+ AMIDI_OutputPort **outputPortPtr) {
+ return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outputPortPtr);
}
-ssize_t AMIDI_receive(AMIDI_OutputPort outputPort, AMIDI_Message *messages, ssize_t maxMessages) {
- unique_fd *ufd;
- // TODO: May return a nicer self-unlocking object
- status_t result = MidiPortRegistry::getInstance().getOutputPortFdAndLock(outputPort, &ufd);
- if (result != OK) {
- return result;
+ssize_t AMIDI_receive(AMIDI_OutputPort *outputPort, AMIDI_Message *messages, ssize_t maxMessages) {
+ AMIDI_Port *port = (AMIDI_Port*)outputPort;
+ int portState = MIDI_PORT_STATE_OPEN_IDLE;
+ if (!port->state.compare_exchange_strong(portState, MIDI_PORT_STATE_OPEN_ACTIVE)) {
+ // The port has been closed.
+ return -EPIPE;
}
+ status_t result = OK;
ssize_t messagesRead = 0;
while (messagesRead < maxMessages) {
- struct pollfd checkFds[1] = { { *ufd, POLLIN, 0 } };
+ struct pollfd checkFds[1] = { { port->ufd, POLLIN, 0 } };
int pollResult = poll(checkFds, 1, 0);
if (pollResult < 1) {
result = android::INVALID_OPERATION;
@@ -139,7 +170,7 @@
AMIDI_Message *message = &messages[messagesRead];
uint8_t readBuffer[AMIDI_PACKET_SIZE];
memset(readBuffer, 0, sizeof(readBuffer));
- ssize_t readCount = read(*ufd, readBuffer, sizeof(readBuffer));
+ ssize_t readCount = read(port->ufd, readBuffer, sizeof(readBuffer));
if (readCount == EINTR) {
continue;
}
@@ -157,100 +188,38 @@
if (dataSize) {
memcpy(message->buffer, readBuffer + 1, dataSize);
}
- message->timestamp = *(uint64_t*) (readBuffer + readCount - sizeof(uint64_t));
+ message->timestamp = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t));
}
message->len = dataSize;
++messagesRead;
}
- MidiPortRegistry::getInstance().unlockOutputPort(outputPort);
+ port->state.store(MIDI_PORT_STATE_OPEN_IDLE);
+
return result == OK ? messagesRead : result;
}
-status_t AMIDI_closeOutputPort(AMIDI_OutputPort outputPort) {
- AMIDI_Device device;
- sp<IBinder> portToken;
- status_t result =
- MidiPortRegistry::getInstance().removeOutputPort(outputPort, &device, &portToken);
- if (result != OK) {
- return result;
- }
-
- sp<BpMidiDeviceServer> deviceServer;
- result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
- if (result != OK) {
- return result;
- }
-
- Status txResult = deviceServer->closePort(portToken);
- if (!txResult.isOk()) {
- return txResult.transactionError();
- }
- return OK;
+status_t AMIDI_closeOutputPort(AMIDI_OutputPort *outputPort) {
+ return AMIDI_closePort((AMIDI_Port*)outputPort);
}
/*
* Input (sending) API
*/
-status_t AMIDI_openInputPort(AMIDI_Device device, int portNumber, AMIDI_InputPort *inputPortPtr) {
- sp<BpMidiDeviceServer> deviceServer;
- status_t result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
- if (result != OK) {
- ALOGE("AMIDI_openInputPort bad device token %d: %d", device, result);
- return result;
- }
-
- sp<BBinder> portToken(new BBinder());
- unique_fd ufd; // this is the file descriptor of the "receive" port s
- Status txResult = deviceServer->openInputPort(portToken, portNumber, &ufd);
- if (!txResult.isOk()) {
- ALOGE("AMIDI_openInputPort transaction error: %d", txResult.transactionError());
- return txResult.transactionError();
- }
-
- result = MidiPortRegistry::getInstance().addInputPort(
- device, portToken, std::move(ufd), inputPortPtr);
- if (result != OK) {
- ALOGE("AMIDI_openInputPort port registration error: %d", result);
- // Close port
- return result;
- }
-
- return OK;
+status_t AMIDI_openInputPort(AMIDI_Device *device, int portNumber, AMIDI_InputPort **inputPortPtr) {
+ return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)inputPortPtr);
}
-status_t AMIDI_closeInputPort(AMIDI_InputPort inputPort) {
- AMIDI_Device device;
- sp<IBinder> portToken;
- status_t result = MidiPortRegistry::getInstance().removeInputPort(
- inputPort, &device, &portToken);
- if (result != OK) {
- ALOGE("AMIDI_closeInputPort remove port error: %d", result);
- return result;
- }
-
- sp<BpMidiDeviceServer> deviceServer;
- result = MidiDeviceRegistry::getInstance().getDeviceByToken(device, &deviceServer);
- if (result != OK) {
- ALOGE("AMIDI_closeInputPort can't find device error: %d", result);
- return result;
- }
-
- Status txResult = deviceServer->closePort(portToken);
- if (!txResult.isOk()) {
- result = txResult.transactionError();
- ALOGE("AMIDI_closeInputPort transaction error: %d", result);
- return result;
- }
-
- return OK;
+status_t AMIDI_closeInputPort(AMIDI_InputPort *inputPort) {
+ return AMIDI_closePort((AMIDI_Port*)inputPort);
}
-ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort /*inputPort*/) {
+ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort */*inputPort*/) {
return SIZE_MIDIRECEIVEBUFFER;
}
-static ssize_t AMIDI_makeSendBuffer(uint8_t *buffer, uint8_t *data, ssize_t numBytes, uint64_t timestamp) {
+static ssize_t AMIDI_makeSendBuffer(
+ uint8_t *buffer, uint8_t *data, ssize_t numBytes,uint64_t timestamp) {
buffer[0] = AMIDI_OPCODE_DATA;
memcpy(buffer + 1, data, numBytes);
memcpy(buffer + 1 + numBytes, ×tamp, sizeof(timestamp));
@@ -264,11 +233,11 @@
// }
//}
-ssize_t AMIDI_send(AMIDI_InputPort inputPort, uint8_t *buffer, ssize_t numBytes) {
+ssize_t AMIDI_send(AMIDI_InputPort *inputPort, uint8_t *buffer, ssize_t numBytes) {
return AMIDI_sendWithTimestamp(inputPort, buffer, numBytes, 0);
}
-ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort inputPort, uint8_t *data,
+ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort *inputPort, uint8_t *data,
ssize_t numBytes, int64_t timestamp) {
if (numBytes > SIZE_MIDIRECEIVEBUFFER) {
@@ -277,15 +246,9 @@
// AMIDI_logBuffer(data, numBytes);
- unique_fd *ufd = NULL;
- status_t result = MidiPortRegistry::getInstance().getInputPortFd(inputPort, &ufd);
- if (result != OK) {
- return result;
- }
-
uint8_t writeBuffer[SIZE_MIDIRECEIVEBUFFER + AMIDI_PACKET_OVERHEAD];
ssize_t numTransferBytes = AMIDI_makeSendBuffer(writeBuffer, data, numBytes, timestamp);
- ssize_t numWritten = write(*ufd, writeBuffer, numTransferBytes);
+ ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes);
if (numWritten < numTransferBytes) {
ALOGE("AMIDI_sendWithTimestamp Couldn't write MIDI data buffer. requested:%zu, written%zu",
@@ -295,16 +258,10 @@
return numWritten - AMIDI_PACKET_OVERHEAD;
}
-status_t AMIDI_flush(AMIDI_InputPort inputPort) {
- unique_fd *ufd = NULL;
- status_t result = MidiPortRegistry::getInstance().getInputPortFd(inputPort, &ufd);
- if (result != OK) {
- return result;
- }
-
+status_t AMIDI_flush(AMIDI_InputPort *inputPort) {
uint8_t opCode = AMIDI_OPCODE_FLUSH;
ssize_t numTransferBytes = 1;
- ssize_t numWritten = write(*ufd, &opCode, numTransferBytes);
+ ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, &opCode, numTransferBytes);
if (numWritten < numTransferBytes) {
ALOGE("AMIDI_flush Couldn't write MIDI flush. requested:%zu, written%zu",