1c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov/* 2c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * Copyright (C) 2017 The Android Open Source Project 3c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * 4c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * Licensed under the Apache License, Version 2.0 (the "License"); 5c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * you may not use this file except in compliance with the License. 6c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * You may obtain a copy of the License at 7c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * 8c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * http://www.apache.org/licenses/LICENSE-2.0 9c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * 10c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * Unless required by applicable law or agreed to in writing, software 11c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * distributed under the License is distributed on an "AS IS" BASIS, 12c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * See the License for the specific language governing permissions and 14c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * limitations under the License. 15c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov */ 16c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 17c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#define LOG_TAG "NativeMIDI" 18c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 19c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include <poll.h> 20c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include <unistd.h> 21c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 22c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include <binder/Binder.h> 23c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include <utils/Errors.h> 24c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include <utils/Log.h> 25c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 26c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include "android/media/midi/BpMidiDeviceServer.h" 27c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include "media/MidiDeviceInfo.h" 28c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 29c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#include "midi.h" 3071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean#include "midi_internal.h" 31c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 32c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::IBinder; 33c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::BBinder; 34c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::OK; 35c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::sp; 36c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::status_t; 37c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::base::unique_fd; 38c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::binder::Status; 39c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganovusing android::media::midi::MidiDeviceInfo; 4071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 4171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstruct AMIDI_Port { 4271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean std::atomic_int state; 4371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean AMIDI_Device *device; 4471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean sp<IBinder> binderToken; 4571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean unique_fd ufd; 4671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean}; 47c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 48c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov#define SIZE_MIDIRECEIVEBUFFER AMIDI_BUFFER_SIZE 49c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 5071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanenum { 5171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean MIDI_PORT_STATE_CLOSED = 0, 5271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean MIDI_PORT_STATE_OPEN_IDLE, 5371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean MIDI_PORT_STATE_OPEN_ACTIVE 5471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean}; 5571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 5671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanenum { 5771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean PORTTYPE_OUTPUT = 0, 5871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean PORTTYPE_INPUT = 1 5971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean}; 6071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 61c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov/* TRANSFER PACKET FORMAT (as defined in MidiPortImpl.java) 62c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * 63c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * Transfer packet format is as follows (see MidiOutputPort.mThread.run() to see decomposition): 64c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * |oc|md|md| ......... |md|ts|ts|ts|ts|ts|ts|ts|ts| 65c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * ^ +--------------------+-----------------------+ 66c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * | ^ ^ 67c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * | | | 68c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * | | + timestamp (8 bytes) 69c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * | | 70c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * | + MIDI data bytes (numBytes bytes) 71c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * | 72c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * + OpCode (AMIDI_OPCODE_DATA) 73c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * 74c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * NOTE: The socket pair is configured to use SOCK_SEQPACKET mode. 75c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * SOCK_SEQPACKET, for a sequenced-packet socket that is connection-oriented, preserves message 76c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * boundaries, and delivers messages in the order that they were sent. 77c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * So 'read()' always returns a whole message. 78c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov */ 79c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 8071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean/* 8171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean * Device Functions 8271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean */ 8371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatus_t AMIDI_getDeviceInfo(AMIDI_Device *device, AMIDI_DeviceInfo *deviceInfoPtr) { 84c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov MidiDeviceInfo deviceInfo; 8571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean Status txResult = device->server->getDeviceInfo(&deviceInfo); 86c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (!txResult.isOk()) { 87c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ALOGE("AMIDI_getDeviceInfo transaction error: %d", txResult.transactionError()); 88c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return txResult.transactionError(); 89c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 90c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 91c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov deviceInfoPtr->type = deviceInfo.getType(); 92c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov deviceInfoPtr->uid = deviceInfo.getUid(); 93c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov deviceInfoPtr->isPrivate = deviceInfo.isPrivate(); 94c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov deviceInfoPtr->inputPortCount = deviceInfo.getInputPortNames().size(); 95c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov deviceInfoPtr->outputPortCount = deviceInfo.getOutputPortNames().size(); 9671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 97c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return OK; 98c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 99c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 100c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov/* 10171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean * Port Helpers 102c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov */ 10371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatic status_t AMIDI_openPort(AMIDI_Device *device, int portNumber, int type, 10471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean AMIDI_Port **portPtr) { 105c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov sp<BBinder> portToken(new BBinder()); 106c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov unique_fd ufd; 10771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean Status txResult = type == PORTTYPE_OUTPUT 10871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean ? device->server->openOutputPort(portToken, portNumber, &ufd) 10971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean : device->server->openInputPort(portToken, portNumber, &ufd); 110c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (!txResult.isOk()) { 11171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean ALOGE("AMIDI_openPort transaction error: %d", txResult.transactionError()); 112c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return txResult.transactionError(); 113c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 114c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 11571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean AMIDI_Port* port = new AMIDI_Port; 11671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean port->state = MIDI_PORT_STATE_OPEN_IDLE; 11771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean port->device = device; 11871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean port->binderToken = portToken; 11971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean port->ufd = std::move(ufd); 12071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 12171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean *portPtr = port; 12271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 12371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return OK; 12471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean} 12571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 12671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatic status_t AMIDI_closePort(AMIDI_Port *port) { 12771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean int portState = MIDI_PORT_STATE_OPEN_IDLE; 12871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean while (!port->state.compare_exchange_weak(portState, MIDI_PORT_STATE_CLOSED)) { 12971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean if (portState == MIDI_PORT_STATE_CLOSED) { 13071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return -EINVAL; // Already closed 13171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean } 13271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean } 13371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 13471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean Status txResult = port->device->server->closePort(port->binderToken); 13571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean if (!txResult.isOk()) { 13671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return txResult.transactionError(); 137c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 13871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 13971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean delete port; 14071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 141c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return OK; 142c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 143c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 14471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean/* 14571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean * Output (receiving) API 14671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean */ 14771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatus_t AMIDI_openOutputPort(AMIDI_Device *device, int portNumber, 14871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean AMIDI_OutputPort **outputPortPtr) { 14971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outputPortPtr); 15071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean} 15171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 15271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanssize_t AMIDI_receive(AMIDI_OutputPort *outputPort, AMIDI_Message *messages, ssize_t maxMessages) { 15371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean AMIDI_Port *port = (AMIDI_Port*)outputPort; 15471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean int portState = MIDI_PORT_STATE_OPEN_IDLE; 15571f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean if (!port->state.compare_exchange_strong(portState, MIDI_PORT_STATE_OPEN_ACTIVE)) { 15671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean // The port has been closed. 15771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return -EPIPE; 158c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 159c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 16071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean status_t result = OK; 161c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ssize_t messagesRead = 0; 162c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov while (messagesRead < maxMessages) { 16371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean struct pollfd checkFds[1] = { { port->ufd, POLLIN, 0 } }; 164c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov int pollResult = poll(checkFds, 1, 0); 165c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (pollResult < 1) { 166c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov result = android::INVALID_OPERATION; 167c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov break; 168c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 169c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 170c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov AMIDI_Message *message = &messages[messagesRead]; 171c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov uint8_t readBuffer[AMIDI_PACKET_SIZE]; 172c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov memset(readBuffer, 0, sizeof(readBuffer)); 17371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean ssize_t readCount = read(port->ufd, readBuffer, sizeof(readBuffer)); 174c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (readCount == EINTR) { 175c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov continue; 176c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 177c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (readCount < 1) { 178c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov result = android::NOT_ENOUGH_DATA; 179c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov break; 180c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 181c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 182c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov // set Packet Format definition at the top of this file. 183c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov size_t dataSize = 0; 184c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov message->opcode = readBuffer[0]; 185c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov message->timestamp = 0; 186c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (message->opcode == AMIDI_OPCODE_DATA && readCount >= AMIDI_PACKET_OVERHEAD) { 187c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov dataSize = readCount - AMIDI_PACKET_OVERHEAD; 188c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (dataSize) { 189c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov memcpy(message->buffer, readBuffer + 1, dataSize); 190c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 19171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean message->timestamp = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t)); 192c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 193c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov message->len = dataSize; 194c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ++messagesRead; 195c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 196c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 19771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean port->state.store(MIDI_PORT_STATE_OPEN_IDLE); 19871f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean 199c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return result == OK ? messagesRead : result; 200c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 201c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 20271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatus_t AMIDI_closeOutputPort(AMIDI_OutputPort *outputPort) { 20371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return AMIDI_closePort((AMIDI_Port*)outputPort); 204c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 205c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 206c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov/* 207c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov * Input (sending) API 208c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov */ 20971f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatus_t AMIDI_openInputPort(AMIDI_Device *device, int portNumber, AMIDI_InputPort **inputPortPtr) { 21071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)inputPortPtr); 211c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 212c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 21371f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatus_t AMIDI_closeInputPort(AMIDI_InputPort *inputPort) { 21471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean return AMIDI_closePort((AMIDI_Port*)inputPort); 215c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 216c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 21771f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort */*inputPort*/) { 218c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return SIZE_MIDIRECEIVEBUFFER; 219c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 220c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 22171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatic ssize_t AMIDI_makeSendBuffer( 22271f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean uint8_t *buffer, uint8_t *data, ssize_t numBytes,uint64_t timestamp) { 223c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov buffer[0] = AMIDI_OPCODE_DATA; 224c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov memcpy(buffer + 1, data, numBytes); 225c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov memcpy(buffer + 1 + numBytes, ×tamp, sizeof(timestamp)); 226c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return numBytes + AMIDI_PACKET_OVERHEAD; 227c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 228c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 229c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov// Handy debugging function. 230c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov//static void AMIDI_logBuffer(uint8_t *data, size_t numBytes) { 231c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov// for (size_t index = 0; index < numBytes; index++) { 232c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov// ALOGI(" data @%zu [0x%X]", index, data[index]); 233c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov// } 234c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov//} 235c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 23671f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanssize_t AMIDI_send(AMIDI_InputPort *inputPort, uint8_t *buffer, ssize_t numBytes) { 237c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return AMIDI_sendWithTimestamp(inputPort, buffer, numBytes, 0); 238c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 239c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 24071f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort *inputPort, uint8_t *data, 241c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ssize_t numBytes, int64_t timestamp) { 242c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 243c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (numBytes > SIZE_MIDIRECEIVEBUFFER) { 244c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return android::BAD_VALUE; 245c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 246c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 247c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov // AMIDI_logBuffer(data, numBytes); 248c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 249c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov uint8_t writeBuffer[SIZE_MIDIRECEIVEBUFFER + AMIDI_PACKET_OVERHEAD]; 250c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ssize_t numTransferBytes = AMIDI_makeSendBuffer(writeBuffer, data, numBytes, timestamp); 25171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes); 252c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 253c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (numWritten < numTransferBytes) { 254c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ALOGE("AMIDI_sendWithTimestamp Couldn't write MIDI data buffer. requested:%zu, written%zu", 255c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov numTransferBytes, numWritten); 256c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 257c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 258c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return numWritten - AMIDI_PACKET_OVERHEAD; 259c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 260c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 26171f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLeanstatus_t AMIDI_flush(AMIDI_InputPort *inputPort) { 262c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov uint8_t opCode = AMIDI_OPCODE_FLUSH; 263c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ssize_t numTransferBytes = 1; 26471f672b98a0c31001ca28de86d9ac99fef0812b1Paul McLean ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, &opCode, numTransferBytes); 265c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 266c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov if (numWritten < numTransferBytes) { 267c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov ALOGE("AMIDI_flush Couldn't write MIDI flush. requested:%zu, written%zu", 268c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov numTransferBytes, numWritten); 269c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return android::INVALID_OPERATION; 270c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov } 271c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 272c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov return OK; 273c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov} 274c276c59eb5d0f36a1133ad718e5e1244390f4688Mikhail Naganov 275