#ifndef IOS_PHONE_H_
#define IOS_PHONE_H_
/*---------------------------------------------------------------------------*/
/* ios_phone.h                                                               */
/* copyright (c) innovaphone 2012                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

NAMESPACE_BEGIN

#define MAX_EXEC_INTERVAL_8KHZ          160
#define SAMPLE_OVERRUN_THRESHOLD_8KHZ   960 /* 8 kHz samples */
#define AUDIO_PLAY_WRITE_SAMPLES        320
#define RECV_FRAGMENTATION_SAMPLES      160
#define RECV_STUFFING_FRAGMENTS_8KHZ    (2 + (2 * SAMPLE_OVERRUN_THRESHOLD_8KHZ) / RECV_FRAGMENTATION_SAMPLES)
#define RECV_STUFFING_LIMIT_8KHZ        (RECV_STUFFING_FRAGMENTS_8KHZ * RECV_FRAGMENTATION_SAMPLES)

#define MAX_SAMPLE_RATE                 16000
#if TARGET_OS_IPHONE
#define MAX_RESAMPLE_RATE               MAX_SAMPLE_RATE
#else
#define MAX_RESAMPLE_RATE               48000
#endif
#define MAX_CODEC_SAMPLE_RATE           16000
#define AUDIO_PLAY_BUFFER_SAMPLES       (RECV_STUFFING_LIMIT_8KHZ * (MAX_SAMPLE_RATE / 8000))
#define AUDIO_RECORD_BUFFER_SAMPLES     (SAMPLE_OVERRUN_THRESHOLD_8KHZ * (MAX_RESAMPLE_RATE / 8000))

struct rtp_hdr
{   byte    r_flag_cc;      /* flags + CSRC count                   */
    byte    r_payload;      /* marker + payload type                */
    word    r_sequence;     /* sequence number                      */
    dword   r_timestamp;    /* timestamp                            */
    dword   r_ssrc;         /* synchronization source               */
};

/*---------------------------------------------------------------------------*/
/* ios_dsp                                                                   */
/*---------------------------------------------------------------------------*/

class ios_dsp_query_devices {};
class ios_dsp_close {};

class ios_dsp_delayed_off_timer : public ITimer {
public:
    ios_dsp_delayed_off_timer(IIoMux * ioMux, UTimerSubclass<ios_dsp_delayed_off_timer> * owner) : ITimer(ioMux, owner) {};
};

class ios_dsp_process_timer : public ITimer {
public:
    ios_dsp_process_timer(IIoMux * ioMux, UTimerSubclass<ios_dsp_process_timer> * owner) : ITimer(ioMux, owner) {};
};

class ios_dsp_polling_timer : public ITimer {
public:
    ios_dsp_polling_timer(IIoMux * ioMux, UTimerSubclass<ios_dsp_polling_timer> * owner) : ITimer(ioMux, owner) {};
};

class ios_dsp_reconnect_timer : public ITimer {
public:
    ios_dsp_reconnect_timer(IIoMux * ioMux, UTimerSubclass<ios_dsp_reconnect_timer> * owner) : ITimer(ioMux, owner) {};
};

class ios_dsp : public UIoContext, public IAudioPhone, public USocket,
#if TARGET_OS_IPHONE
#else
    public UHeadsetProvider,
#endif
    public UIoExecSubclass<ios_dsp_query_devices>,
    public UIoExecSubclass<ios_dsp_close>,
    public UTimerSubclass<ios_dsp_delayed_off_timer>,
    public UTimerSubclass<ios_dsp_process_timer>,
    public UTimerSubclass<ios_dsp_polling_timer>,
    public UTimerSubclass<ios_dsp_reconnect_timer>
{
    void IoExec(ios_dsp_query_devices * context);
    void SetExec(IIoMux * iomux, UIoExecSubclass<ios_dsp_close> * ioContext, ios_dsp_close * execContext) { iomux->SetExec(ioContext, execContext); };
    void IoExec(ios_dsp_close * context);

    class UAudioPhone * user;
    class IInstanceLog * log;
    unsigned execInterval8khz;
    class ISocketProvider * tcpSocketProvider;

    unsigned int new_record_sample_rate_id;
    unsigned int new_playback_sample_rate_id;
    char *new_device_id;
    bool new_handset;
    bool new_speaker;
    bool new_headset;
    bool new_earpiece_nearby;
    dword start_watchdog;

    ios_dsp_delayed_off_timer delayed_off_timer;
    ios_dsp_process_timer process_timer;
    ios_dsp_polling_timer polling_timer;
    ios_dsp_reconnect_timer reconnect_timer;

    short *mic_sample_ptr;
    short *spk_sample_ptr;

    void init();
    void finit();

    void AudioExec(unsigned int mic_samples, unsigned int spk_samples);
    void TimerOnTimeout(ios_dsp_delayed_off_timer * timer);
    void TimerOnTimeout(ios_dsp_process_timer * timer);
    void TimerOnTimeout(ios_dsp_polling_timer * timer);
    void TimerOnTimeout(ios_dsp_reconnect_timer * timer);

public:
    void SetExec(IIoMux * iomux, UIoExecSubclass<ios_dsp_query_devices> * ioContext, ios_dsp_query_devices * execContext) { iomux->SetExec(ioContext, execContext); };

    class IIoMux * iomux;

    int execCnt;
    bool shutDown;

    dword audio_io_in_doorbell;
    dword audio_io_in_doorbell_ack;
    dword audio_io_out_doorbell;
    dword audio_io_out_doorbell_ack;

	char tag[16]; // AC_DSP:

    bool headset_plugged;
    bool channel_attached;

    void headset_plugged_changed(bool plugged);
    void headset_hook();
    void earpiece_proximity(bool nearby);
    void codec_mode_changed(bool new_ringing);
    void audio_devices_updated();

    unsigned int record_sample_rate_id;
    unsigned int playback_sample_rate_id;
    bool mute;
    char *device_id;
    bool handset;
    bool speaker;
    bool headset;
    bool ringing;
    bool earpiece_nearby;

    struct SAudioDevices *AudioDevices;
    unsigned AudioDevicesAllocated;
    unsigned AudioDeviceCount;
    void UpdateDeviceList();
    void StartListenDeviceList();
    void StopListenDeviceList();
    int device_change_pipefd[2];
    bool device_change_pipe_created;
    void IoContextNotify(bool indRX, bool indTX);
    class IHeadsetProvider *headsetProvider;
    unsigned FindHeadsetDevice(const char *deviceId);
    void HookKeyReceived(const char *deviceId, byte key);
    void HeadsetCloseComplete(class IHeadsetProvider *provider);
    void HeadsetDispatch(class IHeadsetProvider *provider, bool polling);
    class IHeadsetProvider *headsetSocketUser;
    class ISocket *headsetSocket;
    byte headsetSocketBuf[4096];
    void TcpSocketConnect(class IHeadsetProvider *provider, IPaddr addr, word port);
    void TcpSocketSend(class IHeadsetProvider *provider, const void * buf, size_t len);
    void TcpSocketShutdown(class IHeadsetProvider *provider);
    void SocketRecvResult(ISocket * const socket, void * buf, size_t len);
    void SocketRecvCanceled(ISocket * const socket, void * buf) {}
    void SocketShutdown(ISocket * const socket, shutdownreason_t reason);

    void start_thread();
    pthread_t start_thread_id;
    bool start_thread_running;
    dword audio_activated;
    static bool audio_session_preconfigured;
    bool audio_session;
    OSType componentSubType;
    AudioUnit audio_unit;
    unsigned int input_sample_rate;
    unsigned int output_sample_rate;
    AudioUnitSampleType recordSampleBuffer[AUDIO_RECORD_BUFFER_SAMPLES / 2];
    AudioBufferList recordIoDataList;
#if TARGET_OS_IPHONE
#else
    AudioUnit record_audio_unit;
    AudioConverterRef input_audio_converter;
    AudioConverterRef output_audio_converter;
#endif

    AudioUnitSampleType audio_play_buffer[AUDIO_PLAY_BUFFER_SAMPLES];
    unsigned int audio_play_pos;
    unsigned int audio_play_pos_ack;
    unsigned int audio_play_fill;

    AudioUnitSampleType audio_record_buffer[AUDIO_RECORD_BUFFER_SAMPLES];
    unsigned int audio_record_pos;
    unsigned int audio_record_pos_ack;
    unsigned int audio_record_buffer_fulls;

    ios_dsp(class IIoMux * const iomux, class IInstanceLog * log, unsigned execInterval8khz, class ISocketProvider * tcpSocketProvider);
    ~ios_dsp();

    void update_dsp(bool media_config_changed);

    void Initialize(class UAudioPhone * const user);
    unsigned ExecJitter8khz();
    void QueryDevices(void * context);
    unsigned DeviceCount();
    const char * DeviceId(unsigned deviceNumber);
    enum AudioDeviceType DeviceType(unsigned deviceNumber);
    unsigned DeviceCapabilities(unsigned deviceNumber);
    const char * DeviceName(unsigned deviceNumber);

    void StartDevice(const char *deviceId, enum AudioDeviceMode deviceMode, unsigned micSampleRate, unsigned spkSampleRate);
    void StopDevice(const char *deviceId);
    unsigned AudioDelay8khz();
    const short * MicrophoneSamplePtr() { return mic_sample_ptr; };
    short * SpeakerSamplePtr() { return spk_sample_ptr; };
    void StartMonitoring(const char *deviceId, enum AudioDeviceMode deviceMode) {};
    void StopMonitoring(const char *deviceId) {};
    void StartHookDevice(const char *deviceId);
    void StopHookDevice(const char *deviceId);
    void SendHookKey(const char *deviceId, byte key, byte callId, const char * number, const char * name);
    void SetMicrophoneMute(bool mute);
    void Close();
};


NAMESPACE_END

/*---------------------------------------------------------------------------*/
#endif /* IOS_PHONE_H_ */
