/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef WEBRTC_AUDIO_DEVICE_FUNC_TEST_MANAGER_H
#define WEBRTC_AUDIO_DEVICE_FUNC_TEST_MANAGER_H

#include <list>
#include <string>

#include "webrtc/common_audio/resampler/include/resampler.h"
#include "webrtc/modules/audio_device/include/audio_device.h"
#include "webrtc/modules/audio_device/test/audio_device_test_defines.h"
#include "webrtc/system_wrappers/include/file_wrapper.h"
#include "webrtc/typedefs.h"


#define ADM_AUDIO_LAYER AudioDeviceModule::kPlatformDefaultAudio
//#define ADM_AUDIO_LAYER AudioDeviceModule::kLinuxPulseAudio

enum TestType
{
    TTInvalid = -1,
    TTAll = 0,
    TTAudioLayerSelection = 1,
    TTDeviceEnumeration = 2,
    TTDeviceSelection = 3,
    TTAudioTransport = 4,
    TTSpeakerVolume = 5,
    TTMicrophoneVolume = 6,
    TTSpeakerMute = 7,
    TTMicrophoneMute = 8,
    TTMicrophoneBoost = 9,
    TTMicrophoneAGC = 10,
    TTLoopback = 11,
    TTDeviceRemoval = 13,
    TTMobileAPI = 14,
    TTTest = 66,
};

struct AudioPacket
{
    uint8_t dataBuffer[4 * 960];
    size_t nSamples;
    size_t nBytesPerSample;
    uint8_t nChannels;
    uint32_t samplesPerSec;
};

class ProcessThread;

namespace webrtc
{

class AudioDeviceModule;
class AudioEventObserver;
class AudioTransport;

// ----------------------------------------------------------------------------
//  AudioEventObserver
// ----------------------------------------------------------------------------

class AudioEventObserver: public AudioDeviceObserver
{
public:
    virtual void OnErrorIsReported(const ErrorCode error);
    virtual void OnWarningIsReported(const WarningCode warning);
    AudioEventObserver(AudioDeviceModule* audioDevice);
    ~AudioEventObserver();
public:
    ErrorCode _error;
    WarningCode _warning;
};

// ----------------------------------------------------------------------------
//  AudioTransport
// ----------------------------------------------------------------------------

class AudioTransportImpl: public AudioTransport
{
public:
    int32_t RecordedDataIsAvailable(const void* audioSamples,
                                    const size_t nSamples,
                                    const size_t nBytesPerSample,
                                    const uint8_t nChannels,
                                    const uint32_t samplesPerSec,
                                    const uint32_t totalDelayMS,
                                    const int32_t clockDrift,
                                    const uint32_t currentMicLevel,
                                    const bool keyPressed,
                                    uint32_t& newMicLevel) override;

    int32_t NeedMorePlayData(const size_t nSamples,
                             const size_t nBytesPerSample,
                             const uint8_t nChannels,
                             const uint32_t samplesPerSec,
                             void* audioSamples,
                             size_t& nSamplesOut,
                             int64_t* elapsed_time_ms,
                             int64_t* ntp_time_ms) override;

    int OnDataAvailable(const int voe_channels[],
                        int number_of_voe_channels,
                        const int16_t* audio_data,
                        int sample_rate,
                        int number_of_channels,
                        size_t number_of_frames,
                        int audio_delay_milliseconds,
                        int current_volume,
                        bool key_pressed,
                        bool need_audio_processing) override;

    void PushCaptureData(int voe_channel, const void* audio_data,
                         int bits_per_sample, int sample_rate,
                         int number_of_channels,
                         size_t number_of_frames) override;

    void PullRenderData(int bits_per_sample, int sample_rate,
                        int number_of_channels, size_t number_of_frames,
                        void* audio_data,
                        int64_t* elapsed_time_ms,
                        int64_t* ntp_time_ms) override;

    AudioTransportImpl(AudioDeviceModule* audioDevice);
    ~AudioTransportImpl();

public:
    int32_t SetFilePlayout(bool enable, const char* fileName = NULL);
    void SetFullDuplex(bool enable);
    void SetSpeakerVolume(bool enable)
    {
        _speakerVolume = enable;
    }
    ;
    void SetSpeakerMute(bool enable)
    {
        _speakerMute = enable;
    }
    ;
    void SetMicrophoneMute(bool enable)
    {
        _microphoneMute = enable;
    }
    ;
    void SetMicrophoneVolume(bool enable)
    {
        _microphoneVolume = enable;
    }
    ;
    void SetMicrophoneBoost(bool enable)
    {
        _microphoneBoost = enable;
    }
    ;
    void SetLoopbackMeasurements(bool enable)
    {
        _loopBackMeasurements = enable;
    }
    ;
    void SetMicrophoneAGC(bool enable)
    {
        _microphoneAGC = enable;
    }
    ;

private:
    typedef std::list<AudioPacket*> AudioPacketList;
    AudioDeviceModule* _audioDevice;

    bool _playFromFile;
    bool _fullDuplex;
    bool _speakerVolume;
    bool _speakerMute;
    bool _microphoneVolume;
    bool _microphoneMute;
    bool _microphoneBoost;
    bool _microphoneAGC;
    bool _loopBackMeasurements;

    FileWrapper& _playFile;

    uint32_t _recCount;
    uint32_t _playCount;
    AudioPacketList _audioList;

    Resampler _resampler;
};

// ----------------------------------------------------------------------------
//  FuncTestManager
// ----------------------------------------------------------------------------

class FuncTestManager
{
public:
    FuncTestManager();
    ~FuncTestManager();
    int32_t Init();
    int32_t Close();
    int32_t DoTest(const TestType testType);
private:
    int32_t TestAudioLayerSelection();
    int32_t TestDeviceEnumeration();
    int32_t TestDeviceSelection();
    int32_t TestAudioTransport();
    int32_t TestSpeakerVolume();
    int32_t TestMicrophoneVolume();
    int32_t TestSpeakerMute();
    int32_t TestMicrophoneMute();
    int32_t TestMicrophoneBoost();
    int32_t TestLoopback();
    int32_t TestDeviceRemoval();
    int32_t TestExtra();
    int32_t TestMicrophoneAGC();
    int32_t SelectPlayoutDevice();
    int32_t SelectRecordingDevice();
    int32_t TestAdvancedMBAPI();
private:
    // Paths to where the resource files to be used for this test are located.
    std::string _playoutFile48;
    std::string _playoutFile44;
    std::string _playoutFile16;
    std::string _playoutFile8;

    rtc::scoped_ptr<ProcessThread> _processThread;
    AudioDeviceModule* _audioDevice;
    AudioEventObserver* _audioEventObserver;
    AudioTransportImpl* _audioTransport;
};

}  // namespace webrtc

#endif  // #ifndef WEBRTC_AUDIO_DEVICE_FUNC_TEST_MANAGER_H
