Home | History | Annotate | Download | only in audio
      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