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 mDownloadId(0)
36 {
37 mCmds[AudioProtocol::ECmdDownload - AudioProtocol::ECmdStart] = new CmdDownload(socket);
38 mCmds[AudioProtocol::ECmdStartPlayback - AudioProtocol::ECmdStart] =
39 new CmdStartPlayback(socket);
40 mCmds[AudioProtocol::ECmdStopPlayback - AudioProtocol::ECmdStart] =
41 new CmdStopPlayback(socket);
42 mCmds[AudioProtocol::ECmdStartRecording - AudioProtocol::ECmdStart] =
43 new CmdStartRecording(socket);
44 mCmds[AudioProtocol::ECmdStopRecording - AudioProtocol::ECmdStart] =
45 new CmdStopRecording(socket);
46 }
47
~RemoteAudio()48 RemoteAudio::~RemoteAudio()
49 {
50 for (int i = 0; i < (AudioProtocol::ECmdLast - AudioProtocol::ECmdStart); i++) {
51 delete mCmds[i];
52 }
53 //mBufferList.clear();
54 }
55
init(int port)56 bool RemoteAudio::init(int port)
57 {
58 mPort = port;
59 if (run() != android::NO_ERROR) {
60 LOGE("RemoteAudio cannot run");
61 // cannot run thread
62 return false;
63 }
64
65 if (!mInitWait.timedWait(CLIENT_WAIT_TIMEOUT_MSEC)) {
66 return false;
67 }
68 return mInitResult;
69 }
70
threadLoop()71 bool RemoteAudio::threadLoop()
72 {
73 // initial action until socket connection done by init
74 mLooper = new android::Looper(false);
75 if (mLooper.get() == NULL) {
76 wakeClient(false);
77 return false;
78 }
79 android::Looper::setForThread(mLooper);
80
81 if (!mSocket.init("127.0.0.1", mPort)) {
82 wakeClient(false);
83 return false;
84 }
85 LOGD("adding fd %d to polling", mSocket.getFD());
86 mLooper->addFd(mSocket.getFD(), EIdSocket, ALOOPER_EVENT_INPUT, socketRxCallback, this);
87 wakeClient(true);
88 while(!mExitRequested) {
89 mLooper->pollOnce(10000);
90 }
91 return false; // exit without requestExit()
92 }
93
wakeClient(bool result)94 void RemoteAudio::wakeClient(bool result)
95 {
96 mInitResult = result;
97 mInitWait.post();
98 }
99
handlePacket()100 bool RemoteAudio::handlePacket()
101 {
102 uint32_t data[AudioProtocol::REPLY_HEADER_SIZE/sizeof(uint32_t)];
103 AudioProtocol::CommandId id;
104 if (!AudioProtocol::handleReplyHeader(mSocket, data, id)) {
105 return false;
106 }
107 AudioParam* param = NULL;
108 CommandHandler* handler = NULL;
109 if (id == AudioProtocol::ECmdDownload) {
110 handler = reinterpret_cast<CommandHandler*>(mDownloadHandler.get());
111 } else if (id == AudioProtocol::ECmdStartPlayback) {
112 handler = reinterpret_cast<CommandHandler*>(mPlaybackHandler.get());
113 } else if (id == AudioProtocol::ECmdStartRecording) {
114 handler = reinterpret_cast<CommandHandler*>(mRecordingHandler.get());
115 param = &(handler->getParam());
116 }
117 bool result = mCmds[id - AudioProtocol::ECmdStart]->handleReply(data, param);
118 if (handler != NULL) {
119 LOGD("handler present. Notify client");
120 android::Mutex::Autolock lock(handler->mStateLock);
121 if (handler->mNotifyOnReply) {
122 handler->mNotifyOnReply = false;
123 handler->mResult = result;
124 handler->mClientWait.post();
125 }
126 handler->mActive = false;
127 }
128 return result;
129 }
130
socketRxCallback(int fd,int events,void * data)131 int RemoteAudio::socketRxCallback(int fd, int events, void* data)
132 {
133 RemoteAudio* self = reinterpret_cast<RemoteAudio*>(data);
134 if (events & ALOOPER_EVENT_INPUT) {
135 //LOGD("socketRxCallback input");
136 if (!self->handlePacket()) { //error, stop polling
137 LOGE("socketRxCallback, error in packet, stopping polling");
138 return 0;
139 }
140 }
141 return 1;
142 }
143
sendCommand(android::sp<android::MessageHandler> & command)144 void RemoteAudio::sendCommand(android::sp<android::MessageHandler>& command)
145 {
146 mLooper->sendMessage(command, toCommandHandler(command)->getMessage());
147 }
148
waitForCompletion(android::sp<android::MessageHandler> & command,int timeInMSec)149 bool RemoteAudio::waitForCompletion(android::sp<android::MessageHandler>& command, int timeInMSec)
150 {
151 return toCommandHandler(command)->timedWait(timeInMSec);
152 }
153
waitForPlaybackOrRecordingCompletion(android::sp<android::MessageHandler> & commandHandler)154 bool RemoteAudio::waitForPlaybackOrRecordingCompletion(
155 android::sp<android::MessageHandler>& commandHandler)
156 {
157 CommandHandler* handler = reinterpret_cast<CommandHandler*>(commandHandler.get());
158 handler->mStateLock.lock();
159 if(!handler->mActive) {
160 handler->mStateLock.unlock();
161 return true;
162 }
163 int runTime = handler->getParam().mBuffer->getSize() /
164 (handler->getParam().mStereo ? 4 : 2) * 1000 / handler->getParam().mSamplingF;
165 handler->mNotifyOnReply = true;
166 handler->mStateLock.unlock();
167 return waitForCompletion(commandHandler, runTime + CLIENT_WAIT_TIMEOUT_MSEC);
168 }
169
doStop(android::sp<android::MessageHandler> & commandHandler,AudioProtocol::CommandId id)170 void RemoteAudio::doStop(android::sp<android::MessageHandler>& commandHandler,
171 AudioProtocol::CommandId id)
172 {
173 CommandHandler* handler = reinterpret_cast<CommandHandler*>(commandHandler.get());
174 handler->mStateLock.lock();
175 if (!handler->mActive) {
176 handler->mStateLock.unlock();
177 return;
178 }
179 handler->mActive = false;
180 handler->mNotifyOnReply = false;
181 handler->mStateLock.unlock();
182 android::sp<android::MessageHandler> command(new CommandHandler(*this, (int)id));
183 sendCommand(command);
184 waitForCompletion(command, CLIENT_WAIT_TIMEOUT_MSEC);
185 }
186
187
downloadData(const android::String8 name,android::sp<Buffer> & buffer,int & id)188 bool RemoteAudio::downloadData(const android::String8 name, android::sp<Buffer>& buffer, int& id)
189 {
190 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mDownloadHandler.get());
191 id = mDownloadId;
192 mDownloadId++;
193 handler->getParam().mId = id;
194 handler->getParam().mBuffer = buffer;
195 sendCommand(mDownloadHandler);
196 handler->mStateLock.lock();
197 handler->mNotifyOnReply = true;
198 handler->mStateLock.unlock();
199 // assume 1Mbps ==> 1000 bits per msec ==> 125 bytes per msec
200 int maxWaitTime = CLIENT_WAIT_TIMEOUT_MSEC + buffer->getSize() / 125;
201 // client blocked until reply comes from DUT
202 if (!waitForCompletion(mDownloadHandler, maxWaitTime)) {
203 LOGE("timeout");
204 return false;
205 }
206 mBufferList[id] = buffer;
207 mIdMap[name] = id;
208 return handler->mResult;
209 }
210
getDataId(const android::String8 & name)211 int RemoteAudio::getDataId(const android::String8& name)
212 {
213 std::map<android::String8, int>::iterator it;
214 it = mIdMap.find(name);
215 if (it == mIdMap.end()) {
216 LOGE("Buffer name %s not registered", name.string());
217 return -1;
218 }
219 return it->second;
220 }
221
startPlayback(bool stereo,int samplingF,int mode,int volume,int id,int numberRepetition)222 bool RemoteAudio::startPlayback(bool stereo, int samplingF, int mode, int volume,
223 int id, int numberRepetition)
224 {
225 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mPlaybackHandler.get());
226 handler->mStateLock.lock();
227 if (handler->mActive) {
228 LOGE("busy");
229 handler->mStateLock.unlock();
230 return false;
231 }
232 std::map<int, android::sp<Buffer> >::iterator it;
233 it = mBufferList.find(id);
234 if (it == mBufferList.end()) {
235 LOGE("Buffer id %d not registered", id);
236 return false;
237 }
238 LOGD("RemoteAudio::startPlayback stereo %d mode %d", stereo, mode);
239 handler->mActive = true;
240 handler->getParam().mStereo = stereo;
241 handler->getParam().mSamplingF = samplingF;
242 handler->getParam().mMode = mode;
243 handler->getParam().mVolume = volume;
244 handler->getParam().mId = id;
245 // for internal tracking
246 handler->getParam().mBuffer = it->second;
247 handler->getParam().mNumberRepetition = numberRepetition;
248 handler->mStateLock.unlock();
249 sendCommand(mPlaybackHandler);
250 if (!waitForCompletion(mPlaybackHandler, CLIENT_WAIT_TIMEOUT_MSEC)) {
251 LOGE("timeout");
252 return false;
253 }
254 return handler->mResult;
255 }
256
stopPlayback()257 void RemoteAudio::stopPlayback()
258 {
259 doStop(mPlaybackHandler, AudioProtocol::ECmdStopPlayback);
260 }
261
waitForPlaybackCompletion()262 bool RemoteAudio::waitForPlaybackCompletion()
263 {
264 return waitForPlaybackOrRecordingCompletion(mPlaybackHandler);
265 }
266
startRecording(bool stereo,int samplingF,int mode,int volume,android::sp<Buffer> & buffer)267 bool RemoteAudio::startRecording(bool stereo, int samplingF, int mode, int volume,
268 android::sp<Buffer>& buffer)
269 {
270 CommandHandler* handler = reinterpret_cast<CommandHandler*>(mRecordingHandler.get());
271 handler->mStateLock.lock();
272 if (handler->mActive) {
273 LOGE("busy");
274 handler->mStateLock.unlock();
275 return false;
276 }
277 handler->mActive = true;
278 handler->getParam().mStereo = stereo;
279 handler->getParam().mSamplingF = samplingF;
280 handler->getParam().mMode = mode;
281 handler->getParam().mVolume = volume;
282 handler->getParam().mBuffer = buffer;
283 handler->mStateLock.unlock();
284 sendCommand(mRecordingHandler);
285 if (!waitForCompletion(mRecordingHandler, CLIENT_WAIT_TIMEOUT_MSEC)) {
286 LOGE("timeout");
287 return false;
288 }
289 return handler->mResult;
290 }
291
waitForRecordingCompletion()292 bool RemoteAudio::waitForRecordingCompletion()
293 {
294 return waitForPlaybackOrRecordingCompletion(mRecordingHandler);
295 }
296
stopRecording()297 void RemoteAudio::stopRecording()
298 {
299 doStop(mRecordingHandler, AudioProtocol::ECmdStopRecording);
300 }
301
302 /** should be called before RemoteAudio is destroyed */
release()303 void RemoteAudio::release()
304 {
305 android::sp<android::MessageHandler> command(new CommandHandler(*this, CommandHandler::EExit));
306 sendCommand(command);
307 join(); // wait for exit
308 mSocket.release();
309 }
310
handleMessage(const android::Message & message)311 void RemoteAudio::CommandHandler::handleMessage(const android::Message& message)
312 {
313 switch(message.what) {
314 case EExit:
315 LOGD("thread exit requested, will exit ");
316 mResult = true;
317 mThread.mExitRequested = true;
318 mClientWait.post(); // client will not wait, but just do it.
319 break;
320 case AudioProtocol::ECmdDownload:
321 case AudioProtocol::ECmdStartPlayback:
322 case AudioProtocol::ECmdStopPlayback:
323 case AudioProtocol::ECmdStartRecording:
324 case AudioProtocol::ECmdStopRecording:
325 {
326 mResult = (mThread.mCmds[message.what - AudioProtocol::ECmdStart]) \
327 ->sendCommand(mParam);
328 // no post for download. Client blocked until reply comes with time-out
329 if (message.what != AudioProtocol::ECmdDownload) {
330 mClientWait.post();
331 }
332
333 }
334 break;
335
336 }
337 }
338