• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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