cts_audio work: initial code
- volume calibration and THD test case work tuned.
- 59 unit tests pass
- local audio playback / recording works : uses tinyalsa
- host to device ptorocol in host side implemented / tested (with loopback)
- device side recording / playback works for test cases / test_io.xml
- python processing baseline added.
- spectrum algorithm implementated: calculate Transfer Function of device
  over host and check if amplitudes are within margain. Needs parameter tuning
- spectrum test needs some improvements due to the non-flat response from
  ref microphone.

Change-Id: I5288dec42f272260f30f1ace1374d365e31d1664
diff --git a/suite/audio_quality/lib/include/audio/AudioHardware.h b/suite/audio_quality/lib/include/audio/AudioHardware.h
new file mode 100644
index 0000000..c505c31
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioHardware.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef CTSAUDIO_AUDIOHARDWARE_H
+#define CTSAUDIO_AUDIOHARDWARE_H
+
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include "Buffer.h"
+
+class TaskCase;
+/**
+ * Utility class for H/W detection
+ */
+class AudioHardware : virtual public android::RefBase {
+public:
+    /** audio length should be multiple of this */
+    static const int SAMPLES_PER_ONE_GO = 4096;
+
+    enum SamplingRate {
+        ESamplingRateInvald = 0,
+        ESampleRate_16000 = 16000,
+        ESampleRate_44100 = 44100
+    };
+    enum BytesPerSample {
+        E2BPS = 2
+    };
+    enum AudioMode {
+        EModeVoice = 0,
+        EModeMusic = 1
+    };
+
+    /**
+     * detect supported audio H/W
+     * @return card number of detected H/W. -1 if not found.
+     */
+    static int detectAudioHw();
+
+    /**
+     * Factory method
+     * options are : local or remote, playback or recording
+     * can return NULL(sp.get() == NULL) if H/W not found
+     */
+    static android::sp<AudioHardware> createAudioHw(bool local, bool playback,
+            TaskCase* testCase = NULL);
+
+    virtual ~AudioHardware();
+    /**
+     * prepare playback or recording
+     */
+    virtual bool prepare(SamplingRate samplingRate, int volume, int mode = EModeVoice) = 0;
+
+    /**
+     * Convenience API to pass buffer ID. The buffer can be either present in testCase
+     * or in remote device (when testCase is NULL)
+     */
+    virtual bool startPlaybackOrRecordById(const android::String8& id, TaskCase* testCase = NULL);
+
+    /**
+     *  Playback / Record with given buffer
+     *  @param buffer buffer to play / record
+     *  @param numberRepetition How many times to repeat playback / record for given buffer.
+     *         For record, it does not have much meaning as the last recording will always
+     *         override.
+     */
+    virtual bool startPlaybackOrRecord(android::sp<Buffer>& buffer,
+            int numberRepetition = 1) = 0;
+    /**
+     * Wait for the playback / recording to complete. return true when successfully finished.
+     * Calling waitForCompletion after calling stopPlaybackOrRecord will lead into blocking
+     * the calling thread for some time.
+     */
+    virtual bool waitForCompletion() = 0;
+    /// stops the on-going action. The active task can be canceled.
+    virtual void stopPlaybackOrRecord() = 0;
+
+protected:
+    static int mHwId;
+};
+
+
+#endif // CTSAUDIO_AUDIOHARDWARE_H
diff --git a/suite/audio_quality/lib/include/audio/AudioLocal.h b/suite/audio_quality/lib/include/audio/AudioLocal.h
new file mode 100644
index 0000000..a263528
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioLocal.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_AUDIOLOCAL_H
+#define CTSAUDIO_AUDIOLOCAL_H
+
+#include <utils/StrongPointer.h>
+#include <utils/threads.h>
+
+#include <Semaphore.h>
+
+#include "AudioHardware.h"
+
+class Buffer;
+
+/**
+ * Basic API for playback and record
+ */
+class AudioLocal: public android::Thread, public AudioHardware {
+public:
+
+    virtual bool prepare(AudioHardware::SamplingRate samplingRate, int gain,
+            int mode = AudioHardware::EModeVoice);
+    virtual bool startPlaybackOrRecord(android::sp<Buffer>& buffer, int numberRepetition = 1);
+    virtual bool waitForCompletion();
+    virtual void stopPlaybackOrRecord();
+
+    virtual ~AudioLocal();
+protected:
+    AudioLocal();
+
+    virtual bool doPrepare(AudioHardware::SamplingRate, int samplesInOneGo) = 0;
+    virtual bool doPlaybackOrRecord(android::sp<Buffer>& buffer) = 0;
+    virtual void doStop() = 0;
+    virtual void releaseHw() {};
+
+private:
+
+
+    bool threadLoop();
+
+    enum AudioCommand{
+        ECmNone = 0,
+        ECmInitialize,
+        ECmRun,
+        ECmStop,
+        ECmThreadStop // terminate the thread
+    };
+
+    bool issueCommandAndWaitForCompletion(AudioCommand command);
+
+protected:
+
+private:
+    // only one command at a time.
+    // Thus, all parameters can be stored here.
+    AudioHardware::SamplingRate mSamplingRate;
+
+    android::sp<Buffer> mBuffer;
+    int mNumberRepetition;
+    int mCurrentRepeat;
+
+    enum AudioState{
+        EStNone,
+        EStCreated,
+        EStInitialized,
+        EStRunning  // playing or recording
+    };
+    volatile AudioState mState;
+    volatile AudioCommand mCurrentCommand;
+
+
+    static const int COMMAND_WAIT_TIME_MSEC = 4000;
+
+    Semaphore mClientCommandWait;
+    Semaphore mClientCompletionWait;
+    Semaphore mAudioThreadWait;
+
+    bool mCommandResult;
+    bool mCompletionResult;
+};
+
+#endif // CTSAUDIO_AUDIOLOCAL_H
diff --git a/suite/audio_quality/lib/include/audio/AudioPlaybackLocal.h b/suite/audio_quality/lib/include/audio/AudioPlaybackLocal.h
new file mode 100644
index 0000000..94422af
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioPlaybackLocal.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_AUDIOPLAYBACKLOCAL_H
+#define CTSAUDIO_AUDIOPLAYBACKLOCAL_H
+
+#include <utils/String8.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#include "AudioLocal.h"
+
+
+class AudioPlaybackLocal: public AudioLocal {
+public:
+    AudioPlaybackLocal(int hwId);
+    virtual ~AudioPlaybackLocal();
+protected:
+    bool doPrepare(AudioHardware::SamplingRate, int samplesInOneGo);
+    bool doPlaybackOrRecord(android::sp<Buffer>& buffer);
+    void doStop();
+    void releaseHw();
+
+private:
+    int mHwId;
+    struct pcm* mPcmHandle;
+    // unit playback samples
+    int mSamples;
+    // unit playback sizes
+    int mSizes;
+};
+
+
+#endif // CTSAUDIO_AUDIOPLAYBACKLOCAL_H
diff --git a/suite/audio_quality/lib/include/audio/AudioProtocol.h b/suite/audio_quality/lib/include/audio/AudioProtocol.h
new file mode 100644
index 0000000..83ba922
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioProtocol.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_AUDIOPROTOCOL_H
+#define CTSAUDIO_AUDIOPROTOCOL_H
+
+#include <stdint.h>
+
+#include <utils/StrongPointer.h>
+#include "Log.h"
+#include "audio/Buffer.h"
+#include "ClientSocket.h"
+
+#define U32_ENDIAN_SWAP(x) ( ((x) & 0x000000ff)<<24 | ((x) & 0x0000ff00)<<8 | \
+        ((x) & 0x00ff0000)>>8 | ((x) & 0xff000000)>>24 )
+
+class AudioParam {
+public:
+    bool mStereo;
+    uint32_t mSamplingF;
+    uint32_t mMode;
+    uint32_t mNumberRepetition; // only for playback
+    uint32_t mVolume;
+    uint32_t mId;
+    android::sp<Buffer> mBuffer;
+};
+
+class AudioProtocol {
+public:
+    enum CommandId {
+        ECmdStart               = 0x12340001, //not actual command
+        ECmdDownload            = 0x12340001,
+        ECmdStartPlayback       = 0x12340002,
+        ECmdStopPlayback        = 0x12340003,
+        ECmdStartRecording      = 0x12340004,
+        ECmdStopRecording       = 0x12340005,
+        ECmdLast                = 0x12340006, // not actual command
+    };
+
+    static const uint32_t REPLY_HEADER_SIZE = 12;
+    // up to 5 parameters for command / reply
+    class ProtocolParam {
+    public:
+        void* param[5];
+    };
+
+    virtual ~AudioProtocol() {
+        //LOGD("~AudioProtocol %x", this);
+    };
+
+    /// default implementation, no param, no payload
+    virtual bool sendCommand(AudioParam& param);
+    /// default implementation, no param, no payload
+    virtual bool handleReply(const uint32_t* data, AudioParam* param);
+
+    /**
+     * read header of reply and returns CommandId of reply.
+     * @param socket socket to read
+     * @param data pointer to buffer to store header, it should be uint32_t[3]
+     * @param id types of reply
+     * @return true if everything OK
+     */
+    static bool handleReplyHeader(ClientSocket& socket, uint32_t* data, CommandId& id);
+
+protected:
+    AudioProtocol(ClientSocket& socket, uint32_t command)
+        : mCommand(command),
+          mSocket(socket) {};
+
+    bool sendData(const char* data, int len) {
+        return mSocket.sendData(data, len);
+    };
+
+    bool checkHeaderId(const uint32_t* data, uint32_t command);
+    bool readData(char* data, int len) {
+        return mSocket.readData(data, len);
+    };
+
+protected:
+    int mBuffer[8];
+private:
+    uint32_t mCommand;
+    ClientSocket& mSocket;
+
+};
+
+class CmdDownload: public AudioProtocol {
+public:
+    CmdDownload(ClientSocket& socket)
+        : AudioProtocol(socket, ECmdDownload) {};
+    virtual ~CmdDownload() {};
+    virtual bool sendCommand(AudioParam& param);
+};
+
+
+class CmdStartPlayback: public AudioProtocol {
+public:
+    CmdStartPlayback(ClientSocket& socket)
+        : AudioProtocol(socket, ECmdStartPlayback) {};
+    virtual ~CmdStartPlayback() {};
+    virtual bool sendCommand(AudioParam& param);
+};
+
+class CmdStopPlayback: public AudioProtocol {
+public:
+    CmdStopPlayback(ClientSocket& socket)
+        : AudioProtocol(socket, ECmdStopPlayback) {};
+    virtual ~CmdStopPlayback() {};
+};
+
+class CmdStartRecording: public AudioProtocol {
+public:
+    CmdStartRecording(ClientSocket& socket)
+        : AudioProtocol(socket, ECmdStartRecording) {};
+    virtual ~CmdStartRecording() {};
+
+    virtual bool sendCommand(AudioParam& param);
+
+    virtual bool handleReply(const uint32_t* data, AudioParam* param);
+};
+
+class CmdStopRecording: public AudioProtocol {
+public:
+    CmdStopRecording(ClientSocket& socket)
+        : AudioProtocol(socket, ECmdStopRecording) {};
+    virtual ~CmdStopRecording() {};
+};
+
+
+
+
+#endif // CTSAUDIO_AUDIOPROTOCOL_H
diff --git a/suite/audio_quality/lib/include/audio/AudioRecordingLocal.h b/suite/audio_quality/lib/include/audio/AudioRecordingLocal.h
new file mode 100644
index 0000000..614ed6d
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioRecordingLocal.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_AUDIORECORDINGLOCAL_H
+#define CTSAUDIO_AUDIORECORDINGLOCAL_H
+
+#include <utils/String8.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#include "AudioLocal.h"
+
+
+class AudioRecordingLocal: public AudioLocal {
+public:
+    AudioRecordingLocal(int hwId);
+    virtual ~AudioRecordingLocal();
+protected:
+    bool doPrepare(AudioHardware::SamplingRate, int samplesInOneGo);
+    bool doPlaybackOrRecord(android::sp<Buffer>& buffer);
+    void doStop();
+    void releaseHw();
+
+private:
+    int mHwId;
+    struct pcm* mPcmHandle;
+    // unit recording samples
+    int mSamples;
+    // unit recording sizes
+    int mSizes;
+    // alsa buffer size
+    int mBufferSize;
+};
+
+
+#endif // CTSAUDIO_AUDIORECORDINGLOCAL_H
diff --git a/suite/audio_quality/lib/include/audio/AudioRemote.h b/suite/audio_quality/lib/include/audio/AudioRemote.h
new file mode 100644
index 0000000..1268ee0
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioRemote.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_AUDIOREMOTE_H
+#define CTSAUDIO_AUDIOREMOTE_H
+#include <utils/StrongPointer.h>
+#include "AudioHardware.h"
+// real implementation
+#include "RemoteAudio.h"
+
+
+// wrapper in AudioHardware interface
+class AudioRemote: public AudioHardware {
+public:
+    virtual bool prepare(AudioHardware::SamplingRate samplingRate, int volume,
+            int mode = AudioHardware::EModeVoice);
+
+protected:
+    AudioRemote(android::sp<RemoteAudio>& remote);
+    virtual ~AudioRemote() {};
+
+protected:
+    android::sp<RemoteAudio> mRemote;
+    AudioHardware::SamplingRate mSamplingRate;
+    int mVolume;
+    int mMode;
+};
+
+class AudioRemotePlayback: public AudioRemote {
+public:
+    AudioRemotePlayback(android::sp<RemoteAudio>& remote);
+    virtual ~AudioRemotePlayback() {};
+    virtual bool startPlaybackOrRecord(android::sp<Buffer>& buffer, int numberRepetition = 1);
+    virtual bool waitForCompletion();
+    virtual void stopPlaybackOrRecord();
+    bool startPlaybackForRemoteData(int id, bool stereo,  int numberRepetition = 1);
+};
+
+class AudioRemoteRecording: public AudioRemote {
+public:
+    AudioRemoteRecording(android::sp<RemoteAudio>& remote);
+    virtual ~AudioRemoteRecording() {};
+    virtual bool startPlaybackOrRecord(android::sp<Buffer>& buffer, int numberRepetition = 1);
+    virtual bool waitForCompletion();
+    virtual void stopPlaybackOrRecord();
+};
+
+
+#endif // CTSAUDIO_AUDIOREMOTE_H
diff --git a/suite/audio_quality/lib/include/audio/AudioSignalFactory.h b/suite/audio_quality/lib/include/audio/AudioSignalFactory.h
new file mode 100644
index 0000000..1c985cc
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/AudioSignalFactory.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_AUDIOSIGNALFACTORY_H
+#define CTSAUDIO_AUDIOSIGNALFACTORY_H
+
+#include <utils/StrongPointer.h>
+
+#include "AudioHardware.h"
+#include "Buffer.h"
+/**
+ * factory for creating various audio signals
+ */
+class AudioSignalFactory {
+public:
+    static android::sp<Buffer> generateSineWave(AudioHardware::BytesPerSample BPS,
+            int maxPositive, AudioHardware::SamplingRate samplingRate, int signalFreq, int samples,
+            bool stereo = true);
+    static android::sp<Buffer> generateWhiteNoise(AudioHardware::BytesPerSample BPS,
+            int maxPositive, int samples, bool stereo = true);
+    static android::sp<Buffer> generateZeroSound(AudioHardware::BytesPerSample BPS,
+            int samples, bool stereo = true);
+};
+
+
+#endif // CTSAUDIO_AUDIOSIGNALFACTORY_H
diff --git a/suite/audio_quality/lib/include/audio/Buffer.h b/suite/audio_quality/lib/include/audio/Buffer.h
new file mode 100644
index 0000000..343c502
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/Buffer.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef CTSAUDIO_BUFFER_H
+#define CTSAUDIO_BUFFER_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <utils/String8.h>
+
+#include <utils/RefBase.h>
+
+#include <Log.h>
+
+/**
+ * Buffer passed for audio playback and recording
+ * The buffer is supposed to be used with sp to guarantee that audio thread can
+ * access it even if the client thread is dead.
+ */
+class Buffer: public virtual android::RefBase {
+public:
+    Buffer(size_t capacity, size_t size = 0, bool stereo = true);
+
+    virtual ~Buffer();
+
+    inline size_t getCapacity() {
+        return mCapacity;
+    };
+
+    inline size_t getSize() {
+        return mSize;
+    };
+
+    inline size_t getSamples() {
+        return (getSize() / (isStereo() ? 4 : 2));
+    };
+
+    inline void setSize(size_t size) {
+        mSize = size;
+    };
+
+    inline void increaseSize(size_t size) {
+        mSize += size;
+    }
+    inline char* getData() {
+        return mData;
+    };
+
+    inline void setData(char* data, size_t len) {
+        ASSERT(len <= mCapacity);
+        memcpy(mData, data, len);
+        mSize = len;
+    };
+
+    inline char* getUnhanledData() {
+        return mData + mHandled;
+    };
+
+    inline bool bufferHandled() {
+        return mSize <= mHandled;
+    };
+
+    inline void restart() {
+        mHandled = 0;
+    };
+    /// size was recorded
+    inline void increaseHandled(size_t size) {
+        mHandled += size;
+    };
+
+    inline void setHandled(size_t size) {
+        mHandled = size;
+    }
+    /// amount recorded
+    inline size_t amountHandled() {
+        return mHandled;
+    };
+
+    inline size_t amountToHandle() {
+        return mSize - mHandled;
+    };
+
+    inline bool isStereo() {
+        return mStereo;
+    };
+    enum ConvertOption {
+        EKeepCh0 = 0,
+        EKeepCh1 = 1,
+        EAverage = 2
+    };
+    /// change stereo buffer to mono
+    void changeToMono(ConvertOption option);
+    /// change mono buffer to stereo. This does not increase allocated memory.
+    /// So it will fail if capacity is not big enough.
+    bool changeToStereo();
+
+    /// save the buffer to file
+    /// extension appropriate for the data type will be appended to file name
+    bool saveToFile(const android::String8& filename);
+
+    bool operator ==(const Buffer& b) const;
+
+    /// load raw data from given file.
+    /// data format is decided by extension
+    /// .r2s: 16 bps, stereo
+    /// .r2m: 16bps, mono
+    static Buffer* loadFromFile(const android::String8& filename);
+private:
+    // max data that can be hold
+    size_t mCapacity;
+    // data stored for playback / to store for recording
+    size_t mSize;
+    // how much data was handled / recorded
+    size_t mHandled;
+    // stereo or mono
+    bool mStereo;
+    // payload
+    char* mData;
+};
+
+
+
+#endif // CTSAUDIO_BUFFER_H
diff --git a/suite/audio_quality/lib/include/audio/RemoteAudio.h b/suite/audio_quality/lib/include/audio/RemoteAudio.h
new file mode 100644
index 0000000..4c587e6
--- /dev/null
+++ b/suite/audio_quality/lib/include/audio/RemoteAudio.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+
+#ifndef CTSAUDIO_REMOTEAUDIO_H
+#define CTSAUDIO_REMOTEAUDIO_H
+
+#include <map>
+
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+#include <utils/threads.h>
+
+#include "audio/Buffer.h"
+#include "AudioProtocol.h"
+#include "ClientSocket.h"
+#include "Semaphore.h"
+
+class CommandHandler;
+/**
+ * Tcp communication runs in a separate thread,
+ * and client can communicate using public APIs
+ * Assumption: only one command at a time. No other command can come
+ * while a command is pending.
+ */
+class RemoteAudio: public android::Thread {
+public:
+
+    RemoteAudio(ClientSocket& socket);
+    virtual ~RemoteAudio();
+
+    /** launch a thread, and connect to host */
+    bool init(int port);
+    bool downloadData(const android::String8 name, android::sp<Buffer>& buffer, int& id);
+    // <0 : not found
+    int getDataId(const android::String8& name);
+    bool startPlayback(bool stereo, int samplingF, int mode, int volume,
+            int id, int numberRepetition);
+    void stopPlayback();
+    bool waitForPlaybackCompletion();
+    // buffer.getSize() determines number of samples
+    bool startRecording(bool stereo, int samplingF, int mode, int volume,
+            android::sp<Buffer>& buffer);
+    bool waitForRecordingCompletion();
+    void stopRecording();
+    /** should be called before RemoteAudio is destroyed */
+    void release();
+
+private:
+    RemoteAudio(const RemoteAudio&);
+
+    bool threadLoop();
+    void wakeClient(bool result);
+    void cleanup(bool notifyClient);
+
+    bool handlePacket();
+    static int socketRxCallback(int fd, int events, void* data);
+
+    class CommandHandler;
+    void sendCommand(android::sp<android::MessageHandler>& command);
+
+    // this is just semaphore wait without any addition
+    bool waitForCompletion(android::sp<android::MessageHandler>& command, int timeInMSec);
+    // common code for waitForXXXCompletion
+    bool waitForPlaybackOrRecordingCompletion(
+            android::sp<android::MessageHandler>& commandHandler);
+    // common code for stopXXX
+    void doStop(android::sp<android::MessageHandler>& commandHandler, AudioProtocol::CommandId id);
+
+    CommandHandler* toCommandHandler(android::sp<android::MessageHandler>& command) {
+        return reinterpret_cast<CommandHandler*>(command.get());
+    };
+
+private:
+    bool mExitRequested;
+    bool mInitResult;
+    // used only for notifying successful init
+    Semaphore mInitWait;
+
+
+    enum EventId {
+        EIdSocket = 1,
+    };
+    static const int CLIENT_WAIT_TIMEOUT_MSEC = 2000;
+    int mPort;
+    ClientSocket& mSocket;
+
+
+    android::sp<android::Looper> mLooper;
+
+    friend class CommandHandler;
+
+    class CommandHandler: public android::MessageHandler {
+    public:
+        enum ClientCommands {
+            EExit = 1,
+        };
+        CommandHandler(RemoteAudio& thread, int command)
+            : mThread(thread),
+              mMessage(command),
+              mNotifyOnReply(false),
+              mActive(false) {};
+        virtual ~CommandHandler() {};
+        void handleMessage(const android::Message& message);
+        bool timedWait(int timeInMSec) {
+            return mClientWait.timedWait(timeInMSec);
+        };
+        AudioParam& getParam() {
+            return mParam;
+        };
+        android::Message& getMessage() {
+            return mMessage;
+        };
+
+    private:
+        RemoteAudio& mThread;
+        AudioParam mParam;
+        Semaphore mClientWait;
+        android::Mutex mStateLock;
+        android::Message mMessage;
+        bool mResult;
+        bool mNotifyOnReply;
+        bool mActive;
+        friend class RemoteAudio;
+    };
+    android::sp<android::MessageHandler> mDownloadHandler;
+    android::sp<android::MessageHandler> mPlaybackHandler;
+    android::sp<android::MessageHandler> mRecordingHandler;
+
+    AudioProtocol* mCmds[AudioProtocol::ECmdLast - AudioProtocol::ECmdStart];
+    int mDownloadId;
+    std::map<int, android::sp<Buffer> > mBufferList;
+    std::map<android::String8, int> mIdMap;
+};
+
+
+
+#endif // CTSAUDIO_REMOTEAUDIO_H