| /* |
| * Copyright (C) 2012 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 <stdint.h> |
| #include <arpa/inet.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| #include <UniquePtr.h> |
| #include <utils/StrongPointer.h> |
| |
| #include "audio/Buffer.h" |
| #include "Log.h" |
| #include "audio/AudioProtocol.h" |
| |
| |
| bool AudioProtocol::sendCommand(AudioParam& param) |
| { |
| mBuffer[0] = htonl(mCommand); |
| mBuffer[1] = 0; |
| return sendData((char*)mBuffer, 8); |
| } |
| |
| bool AudioProtocol::handleReply(const uint32_t* data, AudioParam* param) |
| { |
| if (!checkHeaderId(data, mCommand)) { |
| return false; |
| } |
| if (data[1] != 0) { // no endian change for 0 |
| LOGE("error in reply %d", ntohl(data[1])); |
| return false; |
| } |
| if (data[2] != 0) { |
| LOGE("payload length %d not zero", ntohl(data[2])); |
| return false; |
| } |
| return true; |
| } |
| |
| bool AudioProtocol::handleReplyHeader(ClientSocket& socket, uint32_t* data, CommandId& id) |
| { |
| if (!socket.readData((char*)data, REPLY_HEADER_SIZE)) { |
| LOGE("handleReplyHeader cannot read"); |
| return false; |
| } |
| uint32_t command = ntohl(data[0]); |
| if ((command & 0xffff0000) != 0x43210000) { |
| LOGE("Wrong header %x %x", command, data[0]); |
| return false; |
| } |
| command = (command & 0xffff) | 0x12340000; // convert to id |
| if (command < ECmdStart) { |
| LOGE("Wrong header %x %x", command, data[0]); |
| return false; |
| } |
| if (command > (ECmdLast - 1)) { |
| LOGE("Wrong header %x %x", command, data[0]); |
| return false; |
| } |
| id = (CommandId)command; |
| LOGD("received reply with command %x", command); |
| return true; |
| } |
| |
| bool AudioProtocol::checkHeaderId(const uint32_t* data, uint32_t command) |
| { |
| if (ntohl(data[0]) != ((command & 0xffff) | 0x43210000)) { |
| LOGE("wrong reply ID 0x%x", ntohl(data[0])); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| /** |
| * param0 u32 data id |
| * param1 sp<Buffer> |
| */ |
| bool CmdDownload::sendCommand(AudioParam& param) |
| { |
| mBuffer[0] = htonl(ECmdDownload); |
| mBuffer[1] = htonl(4 + param.mBuffer->getSize()); |
| mBuffer[2] = htonl(param.mId); |
| if(!sendData((char*)mBuffer, 12)) { |
| return false; |
| } |
| return sendData(param.mBuffer->getData(), param.mBuffer->getSize()); |
| } |
| |
| /** |
| * param0 u32 data id |
| * param1 u32 sampling rate |
| * param2 u32 mono / stereo(MSB) | mode |
| * param3 u32 volume |
| * param4 u32 repeat |
| */ |
| bool CmdStartPlayback::sendCommand(AudioParam& param) |
| { |
| mBuffer[0] = htonl(ECmdStartPlayback); |
| mBuffer[1] = htonl(20); |
| mBuffer[2] = htonl(param.mId); |
| mBuffer[3] = htonl(param.mSamplingF); |
| uint32_t mode = param.mStereo ? 0x80000000 : 0; |
| mode |= param.mMode; |
| mBuffer[4] = htonl(mode); |
| mBuffer[5] = htonl(param.mVolume); |
| mBuffer[6] = htonl(param.mNumberRepetition); |
| |
| return sendData((char*)mBuffer, 28); |
| } |
| |
| |
| /** |
| * param0 u32 sampling rate |
| * param1 u32 mono / stereo(MSB) | mode |
| * param2 u32 volume |
| * param3 u32 samples |
| */ |
| bool CmdStartRecording::sendCommand(AudioParam& param) |
| { |
| mBuffer[0] = htonl(ECmdStartRecording); |
| mBuffer[1] = htonl(16); |
| mBuffer[2] = htonl(param.mSamplingF); |
| uint32_t mode = param.mStereo ? 0x80000000 : 0; |
| mode |= param.mMode; |
| mBuffer[3] = htonl(mode); |
| mBuffer[4] = htonl(param.mVolume); |
| uint32_t samples = param.mBuffer->getSize() / (param.mStereo ? 4 : 2); |
| mBuffer[5] = htonl(samples); |
| |
| return sendData((char*)mBuffer, 24); |
| } |
| |
| /** |
| * param0 sp<Buffer> |
| */ |
| bool CmdStartRecording::handleReply(const uint32_t* data, AudioParam* param) |
| { |
| if (!checkHeaderId(data, ECmdStartRecording)) { |
| return false; |
| } |
| if (data[1] != 0) { // no endian change for 0 |
| LOGE("error in reply %d", ntohl(data[1])); |
| return false; |
| } |
| int len = ntohl(data[2]); |
| if (len > (int)param->mBuffer->getCapacity()) { |
| LOGE("received data %d exceeding buffer capacity %d", len, param->mBuffer->getCapacity()); |
| // read and throw away |
| //Buffer tempBuffer(len); |
| //readData(tempBuffer.getData(), len); |
| return false; |
| } |
| if (!readData(param->mBuffer->getData(), len)) { |
| return false; |
| } |
| LOGI("received data %d from device", len); |
| param->mBuffer->setHandled(len); |
| param->mBuffer->setSize(len); |
| return true; |
| } |
| |
| bool CmdGetDeviceInfo::handleReply(const uint32_t* data, AudioParam* param) |
| { |
| if (!checkHeaderId(data, ECmdGetDeviceInfo)) { |
| return false; |
| } |
| if (data[1] != 0) { // no endian change for 0 |
| LOGE("error in reply %d", ntohl(data[1])); |
| return false; |
| } |
| int len = ntohl(data[2]); |
| |
| UniquePtr<char, DefaultDelete<char[]> > infoString(new char[len + 1]); |
| if (!readData(infoString.get(), len)) { |
| return false; |
| } |
| (infoString.get())[len] = 0; |
| LOGI("received data %s from device", infoString.get()); |
| android::String8* string = reinterpret_cast<android::String8*>(param->mExtra); |
| string->setTo(infoString.get(), len); |
| return true; |
| } |
| |
| |