1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 #include <arpa/inet.h> 18 #include <strings.h> 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 22 #include <utils/Looper.h> 23 24 #include "Log.h" 25 #include "audio/AudioProtocol.h" 26 #include "audio/RemoteAudio.h" 27 28 29 RemoteAudio::RemoteAudio(ClientSocket& socket) 30 : mExitRequested(false), 31 mSocket(socket), 32 mDownloadHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdDownload)), 33 mPlaybackHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdStartPlayback)), 34 mRecordingHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdStartRecording)), 35 mDeviceInfoHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdGetDeviceInfo)), 36 mDownloadId(0) 37 { 38 mCmds[AudioProtocol::ECmdDownload - AudioProtocol::ECmdStart] = new CmdDownload(socket); 39 mCmds[AudioProtocol::ECmdStartPlayback - AudioProtocol::ECmdStart] = 40 new CmdStartPlayback(socket); 41 mCmds[AudioProtocol::ECmdStopPlayback - AudioProtocol::ECmdStart] = 42 new CmdStopPlayback(socket); 43 mCmds[AudioProtocol::ECmdStartRecording - AudioProtocol::ECmdStart] = 44 new CmdStartRecording(socket); 45 mCmds[AudioProtocol::ECmdStopRecording - AudioProtocol::ECmdStart] = 46 new CmdStopRecording(socket); 47 mCmds[AudioProtocol::ECmdGetDeviceInfo - AudioProtocol::ECmdStart] = 48 new CmdGetDeviceInfo(socket); 49 } 50 51 RemoteAudio::~RemoteAudio() 52 { 53 for (int i = 0; i < (AudioProtocol::ECmdLast - AudioProtocol::ECmdStart); i++) { 54 delete mCmds[i]; 55 } 56 //mBufferList.clear(); 57 } 58 59 bool RemoteAudio::init(int port) 60 { 61 mPort = port; 62 if (run() != android::NO_ERROR) { 63 LOGE("RemoteAudio cannot run"); 64 // cannot run thread 65 return false; 66 } 67 68 if (!mInitWait.timedWait(CLIENT_WAIT_TIMEOUT_MSEC)) { 69 return false; 70 } 71 return mInitResult; 72 } 73 74 bool RemoteAudio::threadLoop() 75 { 76 // initial action until socket connection done by init 77 mLooper = new android::Looper(false); 78 if (mLooper.get() == NULL) { 79 wakeClient(false); 80 return false; 81 } 82 android::Looper::setForThread(mLooper); 83 84 if (!mSocket.init("127.0.0.1", mPort)) { 85 wakeClient(false); 86 return false; 87 } 88 LOGD("adding fd %d to polling", mSocket.getFD()); 89 mLooper->addFd(mSocket.getFD(), EIdSocket, android::Looper::EVENT_INPUT, socketRxCallback, this); 90 wakeClient(true); 91 while(!mExitRequested) { 92 mLooper->pollOnce(10000); 93 } 94 return false; // exit without requestExit() 95 } 96 97 void RemoteAudio::wakeClient(bool result) 98 { 99 mInitResult = result; 100 mInitWait.post(); 101 } 102 103 bool RemoteAudio::handlePacket() 104 { 105 uint32_t data[AudioProtocol::REPLY_HEADER_SIZE/sizeof(uint32_t)]; 106 AudioProtocol::CommandId id; 107 if (!AudioProtocol::handleReplyHeader(mSocket, data, id)) { 108 return false; 109 } 110 CommandHandler* handler = NULL; 111 if (id == AudioProtocol::ECmdDownload) { 112 handler = reinterpret_cast<CommandHandler*>(mDownloadHandler.get()); 113 } else if (id == AudioProtocol::ECmdStartPlayback) { 114 handler = reinterpret_cast<CommandHandler*>(mPlaybackHandler.get()); 115 } else if (id == AudioProtocol::ECmdStartRecording) { 116 handler = reinterpret_cast<CommandHandler*>(mRecordingHandler.get()); 117 } else if (id == AudioProtocol::ECmdGetDeviceInfo) { 118 handler = reinterpret_cast<CommandHandler*>(mDeviceInfoHandler.get()); 119 } 120 AudioParam* param = NULL; 121 if (handler != NULL) { 122 param = &(handler->getParam()); 123 } 124 bool result = mCmds[id - AudioProtocol::ECmdStart]->handleReply(data, param); 125 if (handler != NULL) { 126 LOGD("handler present. Notify client"); 127 android::Mutex::Autolock lock(handler->mStateLock); 128 if (handler->mNotifyOnReply) { 129 handler->mNotifyOnReply = false; 130 handler->mResult = result; 131 handler->mClientWait.post(); 132 } 133 handler->mActive = false; 134 } 135 return result; 136 } 137 138 int RemoteAudio::socketRxCallback(int fd, int events, void* data) 139 { 140 RemoteAudio* self = reinterpret_cast<RemoteAudio*>(data); 141 if (events & android::Looper::EVENT_INPUT) { 142 //LOGD("socketRxCallback input"); 143 if (!self->handlePacket()) { //error, stop polling 144 LOGE("socketRxCallback, error in packet, stopping polling"); 145 return 0; 146 } 147 } 148 return 1; 149 } 150 151 void RemoteAudio::sendCommand(android::sp<android::MessageHandler>& command) 152 { 153 mLooper->sendMessage(command, toCommandHandler(command)->getMessage()); 154 } 155 156 bool RemoteAudio::waitForCompletion(android::sp<android::MessageHandler>& command, int timeInMSec) 157 { 158 LOGV("waitForCompletion %d", timeInMSec); 159 return toCommandHandler(command)->timedWait(timeInMSec); 160 } 161 162 bool RemoteAudio::waitForPlaybackOrRecordingCompletion( 163 android::sp<android::MessageHandler>& commandHandler) 164 { 165 CommandHandler* handler = reinterpret_cast<CommandHandler*>(commandHandler.get()); 166 handler->mStateLock.lock(); 167 if(!handler->mActive) { 168 handler->mStateLock.unlock(); 169 return true; 170 } 171 int runTime = handler->getParam().mBuffer->getSize() / 172 (handler->getParam().mStereo ? 4 : 2) * 1000 / handler->getParam().mSamplingF; 173 handler->mNotifyOnReply = true; 174 handler->mStateLock.unlock(); 175 return waitForCompletion(commandHandler, runTime + CLIENT_WAIT_TIMEOUT_MSEC); 176 } 177 178 void RemoteAudio::doStop(android::sp<android::MessageHandler>& commandHandler, 179 AudioProtocol::CommandId id) 180 { 181 CommandHandler* handler = reinterpret_cast<CommandHandler*>(commandHandler.get()); 182 handler->mStateLock.lock(); 183 if (!handler->mActive) { 184 handler->mStateLock.unlock(); 185 return; 186 } 187 handler->mActive = false; 188 handler->mNotifyOnReply = false; 189 handler->mStateLock.unlock(); 190 android::sp<android::MessageHandler> command(new CommandHandler(*this, (int)id)); 191 sendCommand(command); 192 waitForCompletion(command, CLIENT_WAIT_TIMEOUT_MSEC); 193 } 194 195 196 bool RemoteAudio::downloadData(const android::String8 name, android::sp<Buffer>& buffer, int& id) 197 { 198 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mDownloadHandler.get()); 199 id = mDownloadId; 200 mDownloadId++; 201 handler->mStateLock.lock(); 202 handler->getParam().mId = id; 203 handler->getParam().mBuffer = buffer; 204 handler->mNotifyOnReply = true; 205 handler->mStateLock.unlock(); 206 sendCommand(mDownloadHandler); 207 208 // assume 1Mbps ==> 1000 bits per msec ==> 125 bytes per msec 209 int maxWaitTime = CLIENT_WAIT_TIMEOUT_MSEC + buffer->getSize() / 125; 210 // client blocked until reply comes from DUT 211 if (!waitForCompletion(mDownloadHandler, maxWaitTime)) { 212 LOGE("timeout"); 213 return false; 214 } 215 mBufferList[id] = buffer; 216 mIdMap[name] = id; 217 return handler->mResult; 218 } 219 220 int RemoteAudio::getDataId(const android::String8& name) 221 { 222 std::map<android::String8, int>::iterator it; 223 it = mIdMap.find(name); 224 if (it == mIdMap.end()) { 225 LOGE("Buffer name %s not registered", name.string()); 226 return -1; 227 } 228 return it->second; 229 } 230 231 bool RemoteAudio::startPlayback(bool stereo, int samplingF, int mode, int volume, 232 int id, int numberRepetition) 233 { 234 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mPlaybackHandler.get()); 235 handler->mStateLock.lock(); 236 if (handler->mActive) { 237 LOGE("busy"); 238 handler->mStateLock.unlock(); 239 return false; 240 } 241 std::map<int, android::sp<Buffer> >::iterator it; 242 it = mBufferList.find(id); 243 if (it == mBufferList.end()) { 244 LOGE("Buffer id %d not registered", id); 245 return false; 246 } 247 LOGD("RemoteAudio::startPlayback stereo %d mode %d", stereo, mode); 248 handler->mActive = true; 249 handler->getParam().mStereo = stereo; 250 handler->getParam().mSamplingF = samplingF; 251 handler->getParam().mMode = mode; 252 handler->getParam().mVolume = volume; 253 handler->getParam().mId = id; 254 // for internal tracking 255 handler->getParam().mBuffer = it->second; 256 handler->getParam().mNumberRepetition = numberRepetition; 257 handler->mStateLock.unlock(); 258 sendCommand(mPlaybackHandler); 259 if (!waitForCompletion(mPlaybackHandler, CLIENT_WAIT_TIMEOUT_MSEC)) { 260 LOGE("timeout"); 261 return false; 262 } 263 return handler->mResult; 264 } 265 266 void RemoteAudio::stopPlayback() 267 { 268 doStop(mPlaybackHandler, AudioProtocol::ECmdStopPlayback); 269 } 270 271 bool RemoteAudio::waitForPlaybackCompletion() 272 { 273 return waitForPlaybackOrRecordingCompletion(mPlaybackHandler); 274 } 275 276 bool RemoteAudio::startRecording(bool stereo, int samplingF, int mode, int volume, 277 android::sp<Buffer>& buffer) 278 { 279 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mRecordingHandler.get()); 280 handler->mStateLock.lock(); 281 if (handler->mActive) { 282 LOGE("busy"); 283 handler->mStateLock.unlock(); 284 return false; 285 } 286 handler->mActive = true; 287 handler->getParam().mStereo = stereo; 288 handler->getParam().mSamplingF = samplingF; 289 handler->getParam().mMode = mode; 290 handler->getParam().mVolume = volume; 291 handler->getParam().mBuffer = buffer; 292 handler->mStateLock.unlock(); 293 sendCommand(mRecordingHandler); 294 if (!waitForCompletion(mRecordingHandler, CLIENT_WAIT_TIMEOUT_MSEC)) { 295 LOGE("timeout"); 296 return false; 297 } 298 return handler->mResult; 299 } 300 301 bool RemoteAudio::waitForRecordingCompletion() 302 { 303 return waitForPlaybackOrRecordingCompletion(mRecordingHandler); 304 } 305 306 void RemoteAudio::stopRecording() 307 { 308 doStop(mRecordingHandler, AudioProtocol::ECmdStopRecording); 309 } 310 311 bool RemoteAudio::getDeviceInfo(android::String8& data) 312 { 313 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mDeviceInfoHandler.get()); 314 handler->mStateLock.lock(); 315 handler->mNotifyOnReply = true; 316 handler->getParam().mExtra = &data; 317 handler->mStateLock.unlock(); 318 sendCommand(mDeviceInfoHandler); 319 320 // client blocked until reply comes from DUT 321 if (!waitForCompletion(mDeviceInfoHandler, CLIENT_WAIT_TIMEOUT_MSEC)) { 322 LOGE("timeout"); 323 return false; 324 } 325 return handler->mResult; 326 } 327 328 /** should be called before RemoteAudio is destroyed */ 329 void RemoteAudio::release() 330 { 331 android::sp<android::MessageHandler> command(new CommandHandler(*this, CommandHandler::EExit)); 332 sendCommand(command); 333 join(); // wait for exit 334 mSocket.release(); 335 } 336 337 void RemoteAudio::CommandHandler::handleMessage(const android::Message& message) 338 { 339 switch(message.what) { 340 case EExit: 341 LOGD("thread exit requested, will exit "); 342 mResult = true; 343 mThread.mExitRequested = true; 344 mClientWait.post(); // client will not wait, but just do it. 345 break; 346 case AudioProtocol::ECmdDownload: 347 case AudioProtocol::ECmdStartPlayback: 348 case AudioProtocol::ECmdStopPlayback: 349 case AudioProtocol::ECmdStartRecording: 350 case AudioProtocol::ECmdStopRecording: 351 case AudioProtocol::ECmdGetDeviceInfo: 352 { 353 mResult = (mThread.mCmds[message.what - AudioProtocol::ECmdStart]) \ 354 ->sendCommand(mParam); 355 // no post for download and getdeviceinfo. Client blocked until reply comes with time-out 356 if ((message.what != AudioProtocol::ECmdDownload) && 357 (message.what != AudioProtocol::ECmdGetDeviceInfo) ) { 358 mClientWait.post(); 359 } 360 361 } 362 break; 363 364 } 365 } 366