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
RemoteAudio(ClientSocket & socket)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
~RemoteAudio()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
init(int port)59 bool RemoteAudio::init(int port)
60 {
61 mPort = port;
62 if (run("RemoteAudio") != 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
threadLoop()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
wakeClient(bool result)97 void RemoteAudio::wakeClient(bool result)
98 {
99 mInitResult = result;
100 mInitWait.post();
101 }
102
handlePacket()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
socketRxCallback(int fd,int events,void * data)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
sendCommand(android::sp<android::MessageHandler> & command)151 void RemoteAudio::sendCommand(android::sp<android::MessageHandler>& command)
152 {
153 mLooper->sendMessage(command, toCommandHandler(command)->getMessage());
154 }
155
waitForCompletion(android::sp<android::MessageHandler> & command,int timeInMSec)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
waitForPlaybackOrRecordingCompletion(android::sp<android::MessageHandler> & commandHandler)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
doStop(android::sp<android::MessageHandler> & commandHandler,AudioProtocol::CommandId id)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
downloadData(const android::String8 name,android::sp<Buffer> & buffer,int & id)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
getDataId(const android::String8 & name)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
startPlayback(bool stereo,int samplingF,int mode,int volume,int id,int numberRepetition)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
stopPlayback()266 void RemoteAudio::stopPlayback()
267 {
268 doStop(mPlaybackHandler, AudioProtocol::ECmdStopPlayback);
269 }
270
waitForPlaybackCompletion()271 bool RemoteAudio::waitForPlaybackCompletion()
272 {
273 return waitForPlaybackOrRecordingCompletion(mPlaybackHandler);
274 }
275
startRecording(bool stereo,int samplingF,int mode,int volume,android::sp<Buffer> & buffer)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
waitForRecordingCompletion()301 bool RemoteAudio::waitForRecordingCompletion()
302 {
303 return waitForPlaybackOrRecordingCompletion(mRecordingHandler);
304 }
305
stopRecording()306 void RemoteAudio::stopRecording()
307 {
308 doStop(mRecordingHandler, AudioProtocol::ECmdStopRecording);
309 }
310
getDeviceInfo(android::String8 & data)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 */
release()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
handleMessage(const android::Message & message)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