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