C++程序  |  310行  |  10.42 KB

/*
 * 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.
 */

// test RemoteAudio with fake TCP

#include <unistd.h>

#include <utils/String8.h>

#include <gtest/gtest.h>

#include <utils/StrongPointer.h>

#include <Log.h>
#include <audio/AudioHardware.h>
#include <audio/AudioProtocol.h>
#include <audio/AudioSignalFactory.h>
#include <ClientSocket.h>
#include <audio/RemoteAudio.h>



void assertTrue(bool cond) {
    ASSERT_TRUE(cond);
}
void assertData(const char* data1, const char* data2, int len) {
    for (int i = 0; i < len; i++) {
        //LOGD("0x%x vs 0x%x", data1[i], data2[i]);
        ASSERT_TRUE(data1[i] == data2[i]);
    }
}

class ClientSocketForTest: public ClientSocket {
public:
    ClientSocketForTest()
        : mToRead(NULL),
          mReadLength(0) {};

    virtual ~ClientSocketForTest() {
        close(mSocket);
        close(mPipeWrFd);
    }
    virtual bool init(const char* hostIp, int port, bool enableTimeout = false) {
        LOGD("ClientSocketForTest::init");
        // use this fd to work with poll
        int pipefd[2];
        if (pipe(pipefd)  == -1) {
            LOGE("cannot create pipe");
            return false;
        }
        LOGD("pipe %d %d", pipefd[0], pipefd[1]);
        mSocket = pipefd[0];
        mPipeWrFd = pipefd[1];
        const char ipExpectation[] = "127.0.0.1";
        assertTrue(memcmp(ipExpectation, hostIp, sizeof(ipExpectation)) == 0);
        return true;
    }
    virtual bool readData(char* data, int len, int timeoutInMs = 0) {
        read(mSocket, data, len);
        return true;
    }
    virtual bool sendData(const char* data, int len) {
        assertTrue((len + mSendPointer) <= mSendLength);
        assertData(data, mToSend + mSendPointer, len);
        mSendPointer += len;
        if ((mToRead != NULL) && (mReadLength != 0)) {
            LOGD("fake TCP copy reply %d", mReadLength);
            write(mPipeWrFd, mToRead, mReadLength);
            mToRead = NULL; // prevent writing the same data again
        }
        return true;
    }

    void setSendExpectation(const char* data, int len) {
        mToSend = data;
        mSendLength = len;
        mSendPointer = 0;
    }
    void setReadExpectation(char* data, int len) {
        mToRead = data;
        mReadLength = len;
    }
public:
    int mPipeWrFd; // for writing
    const char* mToRead;
    int mReadLength;
    const char* mToSend;
    int mSendLength;
    int mSendPointer;
};

class RemoteAudioFakeTcpTest : public testing::Test {
protected:
    android::sp<RemoteAudio> mRemoteAudio;
    ClientSocketForTest mTestSocket;

protected:
    virtual void SetUp() {
        ASSERT_TRUE(U32_ENDIAN_SWAP(0x12345678) == 0x78563412);
        mRemoteAudio = new RemoteAudio(mTestSocket);
        ASSERT_TRUE(mRemoteAudio != NULL);
        ASSERT_TRUE(mRemoteAudio->init(1234));
    }

    virtual void TearDown() {
        mRemoteAudio->release();
        mRemoteAudio.clear();
    }

    void doDownload() {
        android::sp<Buffer> buffer = AudioSignalFactory::generateZeroSound(AudioHardware::E2BPS, 2,
                false);
        uint32_t prepareSend[] = {
                U32_ENDIAN_SWAP(AudioProtocol::ECmdDownload),
                U32_ENDIAN_SWAP(8),
                U32_ENDIAN_SWAP(0), //id
                U32_ENDIAN_SWAP(0)
        };
        uint32_t prepareReply[] = {
                U32_ENDIAN_SWAP((AudioProtocol::ECmdDownload & 0xffff) | 0x43210000),
                0,
                0
        };
        LOGD("reply 0x%x", prepareReply[0]);

        mTestSocket.setSendExpectation((char*)prepareSend, sizeof(prepareSend));
        // this is reply, but set expectation for reply first as it is sent after send
        mTestSocket.setReadExpectation((char*)prepareReply, sizeof(prepareReply));

        int id = -1;
        android::String8 name("1");
        ASSERT_TRUE(mRemoteAudio->downloadData(name, buffer, id));
        ASSERT_TRUE(id >= 0);
    }
};

TEST_F(RemoteAudioFakeTcpTest, InitTest) {
    // all done in SetUp
}

TEST_F(RemoteAudioFakeTcpTest, DownloadTest) {
    doDownload();
}

TEST_F(RemoteAudioFakeTcpTest, PlayTest) {
    doDownload();

    bool stereo = false;
    int id = 0;
    int samplingF = 44100;
    int mode = AudioHardware::EModeVoice | (stereo ? 0x80000000 : 0);
    int volume = 0;
    int repeat = 1;

    uint32_t prepareSend[] = {
            U32_ENDIAN_SWAP(AudioProtocol::ECmdStartPlayback),
            U32_ENDIAN_SWAP(20),
            U32_ENDIAN_SWAP(id), //id
            U32_ENDIAN_SWAP(samplingF),
            U32_ENDIAN_SWAP(mode),
            U32_ENDIAN_SWAP(volume),
            U32_ENDIAN_SWAP(repeat)
    };
    uint32_t prepareReply[] = {
            U32_ENDIAN_SWAP((AudioProtocol::ECmdStartPlayback & 0xffff) | 0x43210000),
            0,
            0
    };

    mTestSocket.setSendExpectation((char*)prepareSend, sizeof(prepareSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)prepareReply, sizeof(prepareReply));

    ASSERT_TRUE(mRemoteAudio->startPlayback(stereo, samplingF, mode, volume, id, repeat));
    ASSERT_TRUE(mRemoteAudio->waitForPlaybackCompletion());
}

TEST_F(RemoteAudioFakeTcpTest, PlayStopTest) {
    doDownload();

    bool stereo = false;
    int id = 0;
    int samplingF = 44100;
    int mode = AudioHardware::EModeVoice | (stereo ? 0x80000000 : 0);
    int volume = 0;
    int repeat = 1;

    uint32_t startPlaybackSend[] = {
            U32_ENDIAN_SWAP(AudioProtocol::ECmdStartPlayback),
            U32_ENDIAN_SWAP(20),
            U32_ENDIAN_SWAP(id),
            U32_ENDIAN_SWAP(samplingF),
            U32_ENDIAN_SWAP(mode),
            U32_ENDIAN_SWAP(volume),
            U32_ENDIAN_SWAP(repeat)
    };
    uint32_t startReply[] = {
            U32_ENDIAN_SWAP((AudioProtocol::ECmdStartPlayback & 0xffff) | 0x43210000),
            0,
            0
    };

    uint32_t stopPlaybackSend[] = {
            U32_ENDIAN_SWAP(AudioProtocol::ECmdStopPlayback),
            U32_ENDIAN_SWAP(0)
    };

    uint32_t stopReply[] = {
            U32_ENDIAN_SWAP((AudioProtocol::ECmdStopPlayback & 0xffff) | 0x43210000),
            0,
            0
    };

    mTestSocket.setSendExpectation((char*)startPlaybackSend, sizeof(startPlaybackSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)startReply, sizeof(startReply));

    ASSERT_TRUE(mRemoteAudio->startPlayback(stereo, samplingF, mode, volume, id, repeat));
    sleep(1);
    mTestSocket.setSendExpectation((char*)stopPlaybackSend, sizeof(stopPlaybackSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)stopReply, sizeof(stopReply));
    mRemoteAudio->stopPlayback();

    mTestSocket.setSendExpectation((char*)startPlaybackSend, sizeof(startPlaybackSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)startReply, sizeof(startReply));
    ASSERT_TRUE(mRemoteAudio->startPlayback(stereo, samplingF, mode, volume, id, repeat));
    sleep(1);
    mTestSocket.setSendExpectation((char*)stopPlaybackSend, sizeof(stopPlaybackSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)stopReply, sizeof(stopReply));
    mRemoteAudio->stopPlayback();

    mTestSocket.setSendExpectation((char*)startPlaybackSend, sizeof(startPlaybackSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)startReply, sizeof(startReply));
    ASSERT_TRUE(mRemoteAudio->startPlayback(stereo, samplingF, mode, volume, id, repeat));
    ASSERT_TRUE(mRemoteAudio->waitForPlaybackCompletion());
}

TEST_F(RemoteAudioFakeTcpTest, RecordingTest) {
    bool stereo = false;
    int id = 0;
    int samplingF = 44100;
    int mode = AudioHardware::EModeVoice | (stereo ? 0x80000000 : 0);
    int volume = 0;
    int noSamples = 44; // 1ms worth

    android::sp<Buffer> buffer(new Buffer(100, noSamples*2, false));

    uint32_t startSend[] = {
            U32_ENDIAN_SWAP(AudioProtocol::ECmdStartRecording),
            U32_ENDIAN_SWAP(16),
            U32_ENDIAN_SWAP(samplingF),
            U32_ENDIAN_SWAP(mode),
            U32_ENDIAN_SWAP(volume),
            U32_ENDIAN_SWAP(noSamples)
    };

    // 2bytes per sample, +2 for last samples rounded off
    uint32_t startReply[noSamples/2 + 2 + 3];
    memset(startReply, 0, sizeof(startReply));
    startReply[0] = U32_ENDIAN_SWAP((AudioProtocol::ECmdStartRecording & 0xffff) | 0x43210000);
    startReply[1] = 0;
    startReply[2] = U32_ENDIAN_SWAP(noSamples * 2);

    uint32_t stopSend[] = {
            U32_ENDIAN_SWAP(AudioProtocol::ECmdStopRecording),
            U32_ENDIAN_SWAP(0)
    };

    uint32_t stopReply[] = {
            U32_ENDIAN_SWAP((AudioProtocol::ECmdStopRecording & 0xffff) | 0x43210000),
            0,
            0
    };


    mTestSocket.setSendExpectation((char*)startSend, sizeof(startSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)startReply, 12 + noSamples*2);

    ASSERT_TRUE(mRemoteAudio->startRecording(stereo, samplingF, mode, volume, buffer));
    ASSERT_TRUE(mRemoteAudio->waitForRecordingCompletion());
    ASSERT_TRUE(buffer->amountHandled() == (size_t)(noSamples * 2));
    mTestSocket.setSendExpectation((char*)startSend, sizeof(startSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)startReply, 12 + noSamples*2);
    ASSERT_TRUE(mRemoteAudio->startRecording(stereo, samplingF, mode, volume, buffer));
    sleep(1);
    mTestSocket.setSendExpectation((char*)stopSend, sizeof(stopSend));
    // this is reply, but set expectation for reply first as it is sent after send
    mTestSocket.setReadExpectation((char*)stopReply, sizeof(stopReply));
    mRemoteAudio->stopRecording();
}