/******************************************************************************
 * This program is protected under international and U.S. copyright laws as
 * an unpublished work. This program is confidential and proprietary to the
 * copyright owners. Reproduction or disclosure, in whole or in part, or the
 * production of derivative works therefrom without the express permission of
 * the copyright owners is prohibited.
 *
 *                Copyright (C) 2020 by Dolby Laboratories.
 *                            All rights reserved.
 ******************************************************************************/

/** @file */

#ifndef TDUHT_H
#define TDUHT_H

#include "dlb_buffer.h"

/** @defgroup version Version Information
 * This is the API for discovering the version number of 
 * the time domain ubiquitous head tracking (TDUHT) library.
 * @{ */

/**
 * This macro is a string which states the version of this API. */
#define TDUHT_VERSION       "1.0.0"

/**
 * Get the version string of the API which the dap_vr library expects to be
 * used with.
 *
 * @return Version information string. */
const char *
tduht_get_version
    (void);

/**
 * TDUHT library processing latencies in samples based on whether
 * Dolby volume limiter(dvlim) is turned on or not
 */


/** 
 * Processing latency of TDUHT library in samples when dvlim is off
 */
#define TDUHT_LATENCY_DVLIM_DISABLED (0)

/** 
 * Processing latency of TDUHT library in samples when dvlim is on
 */
#define TDUHT_LATENCY_DVLIM_ENABLED (64)

/**
 * TDUHT initialization information
 *
 * This structure is used to store information required during TDUHT
 * initialization. The fields of this structure must be configured
 * properly to initialize TDUHT successfully and correctly. For the
 * usage of each field, please refer to field descriptions.
 */
typedef struct
{
    /**
     * @brief Sample rate of the input signal being (in Hertz)
     *
     * Valid values are 32000, 44100 and 48000. */
    unsigned long                   sample_rate;

    /**
    * @brief Disable dvlim processing
    *
    * dvlim processing will be disabled and no memory will be allocated for
    * it if this is a non-zero value. The latency will also be reduced to
    * TDUHT_LATENCY_DVLIM_DISABLED when this is a non-zero value. */
    int                             dvlim_process_disable;
} tduht_init_info;

/** 
 * Opaque type representing an instance of the time domain ubiquitous
 * head tracking(TDUHT) library. Use tduht_init() to obtain a valid instance handle. */
typedef struct tduht_state_s tduht_state;

/**
 * @brief Query TDUHT persistent memory requirements
 * Returns the amount of memory required for an instance of TDUHT for a
 * particular configuration. Returns 0 if the configuration is invalid.
 *
 * @returns                     Size of memory required to store TDUHT state.
 *
 * @param p_info                TDUHT initialization information.
 */
size_t
tduht_query_memory
    (const tduht_init_info *p_info
    );

/**
 * @brief Query TDUHT scratch memory requirements 
 * Returns the amount of scratch memory required for running tduht_process(). This
 * memory does not need to persist between calls to tduht_process() and you
 * can freely pass different pointers to each call (for example, you can
 * allocate this memory on the stack).
 *
 * @returns                     Size of scratch memory required to process a
 *                              block with tduht_process().
 */
size_t 
tduht_query_scratch
    (void);

/**
 * @brief Initialize TDUHT 
 * This function creates a new TDUHT instance. 
 * p_mem must point to the amount of memory as returned by tduht_query_memory() 
 * for this particular p_info.  The returned value is the TDUHT state
 * handle which should be passed to tduht_process(). 
 * The returned pointer will not necessarily be the same as p_mem.
 *
 * @returns                     Instance of TDUHT state structure.
 *
 * @param p_info                TDUHT initialization information.
 * @param p_mem                 Memory pointer with allocated size for TDUHT state.
 */
tduht_state *
tduht_init
        (const tduht_init_info *p_info
        ,void                  *p_mem
        );


/**
 * @brief This function is used to set the tracked head azimuth.
 * 
 * ### INPUT RANGE
 *   Azimuth is the head looking left degree, when looking left, this
 *   value is positive, otherwise it is negative. The valid range of this
 *   field is [TDUHT_AZIMUTH_DEGREE_MIN, TDUHT_AZIMUTH_DEGREE_MAX].
 *
 * ### DEFAULT VALUES
 *   TDUHT_AZIMUTH_DEGREE_DEFAULT.
 *
 * ### NOTE
 *   Values given outside of the specified range will be clipped.
 *
 * ### THREADING CONSIDERATIONS
 *   You may set head azimuth at any time by calling this function
 *   from a different thread of tduht_process. The new head azimuth
 *   will take effect from the next call of tduht_process().
 *
 * @param p_tduht          Instance of tduht state structure.
 * @param azimuth          Tracked head azimuth.
 */
void
tduht_azimuth_set
    (tduht_state  *p_tduht
    ,int           azimuth
    );

#define TDUHT_AZIMUTH_DEGREE_MIN     (-180)
#define TDUHT_AZIMUTH_DEGREE_MAX     (180)
#define TDUHT_AZIMUTH_DEGREE_DEFAULT (0)

/**
 * @brief This function is used to get tracked head azimuth that takes effect.
 *
 * @param p_tduht          Instance of tduht state structure.
 * @param p_azimuth        Tracked head azimuth.
 */
void
tduht_azimuth_get
    (tduht_state  *p_tduht
    ,int          *p_azimuth
    );

/**
* @brief This function is used to enable or disable time domain UHT process
*
* ### INPUT RANGE
*  - 0  - time domain UHT is disabled.
*  - !0 - time domain UHT is enabled.
*
* ### DEFAULT VALUE
*  - 1
*
* ### THREADING CONSIDERATIONS
*   You may enable or disable time domain UHT process at any time
*   by calling this function from a different thread of tduht_process.
*   The new state will take effect from the next call of tduht_process().
*
* ### NOTES
*    When TDUHT is disabled, the azimuth and elevation degree will be reset to (0,0)
*    and head tracking state will be cleared.
*    The input will be simply delayed by TDUHT_LATENCY_* according to initialization configuration
*    in order to keep the latency consistent with the case when TDUHT is enabled.
*
* @param p_tduht  Instance of tduht state structure.
* @param value    Time domain UHT enable select.
*/
void
tduht_enable_set
    (tduht_state  *p_tduht
    ,int           value
    );

/**
 * Specifies the block size for input data sampled at audio sampling
 * rates of 32kHz, 44.1kHz and 48kHz. */
#define TDUHT_BLOCK_SIZE    (256)

/**
 * Specifies the maximum number of blocks which can be passed to a single call
 * of tduht_process(). */
#define TDUHT_MAX_BLOCKS             (8)

/**
 * Output channel format identifier
 */
#define TDUHT_OUTPUT_FORMAT_LEFT          (0)
#define TDUHT_OUTPUT_FORMAT_RIGHT         (1)
#define TDUHT_OUTPUT_FORMAT_BINAURAL      (2)

/**
 * Returned error codes for tduht_process() 
 */
#define TDUHT_PROCESS_ERROR_NO_ERROR                   0
#define TDUHT_PROCESS_ERROR_INVALID_INPUT_BLOCK_NUM    1
#define TDUHT_PROCESS_ERROR_INVALID_INPUT_CHANNEL      2
#define TDUHT_PROCESS_ERROR_INVALID_OUTPUT_FORMAT      3
#define TDUHT_PROCESS_ERROR_INVALID_OUTPUT_CHANNEL     4

/** 
 * This function is used to print log messages.
 * It takes a first parameter of a pointer to a constant character 
 * and an arbitrary number of subsequent parameters of arbitrary type.
 */
typedef void (*tduht_log_fn)(const char *p_str,...);

/**
 * Log levels
 */
 /* Minimal logs will be printed out.*/
#define TDUHT_LOG_LEVEL_MINIMAL          (0)

 /* Full (detailed) logs will be printed out.*/
#define TDUHT_LOG_LEVEL_FULL             (1)

/**
 * This is a structure used for logging. 
 */
typedef struct {

    /* log function.*/
    tduht_log_fn fn_log;

    /**
     * Log level. Supported values 
     * are TDUHT_LOG_LEVEL_MINIMAL and TDUHT_LOG_LEVEL_FULL.
     */
    int          level;
} tduht_log_info;

/**
 * @brief Perform head tracking process on time domain.
 * The output sample count will always match the input sample count.
 * p_scratch must point to the amount of memory requested by tduht_query_scratch.
 *
 * ### BEHAVIORS WHEN TDUHT IS DISABLED
 *    The azimuth and elevation degree will be reset to (0,0) and head tracking state will be cleared.
 *    The input will be simply delayed by TDUHT_LATENCY_* according to initialization configuration
 *    in order to keep the latency consistent with the case when TDUHT is enabled. 
 *
 * ### INPUT FORMAT
 *   Input channel counts must be 2 channels, and the ordering of 2 channels is Left, Right.
 *
 * ### OUTPUT FORMAT
 *   Supported output formats and corresponding channel counts (nchannel)
 *   and orderings in output dlb_buffer p_output are:
 *   TDUHT_OUTPUT_FORMAT_LEFT: 1 channel (Left)
 *   TDUHT_OUTPUT_FORMAT_RIGHT: 1 channel (Right)
 *   TDUHT_OUTPUT_FORMAT_BINAURAL: 2 channels (Left, Right)
 *
 * ### INPLACE PROCESSING
 *   The buffer passed to p_input may be exactly the same buffer passed
 *   to p_output as long as the channel counts are identical. If the
 *   channel counts are different, then you will need two distinct dlb_buffer
 *   structures with different channel counts, but they may point to
 *   overlapping memory regions. 
 * 
 * ### LOG MESSAGES
 *   If both the input log structure p_tduht_log and log function p_tduht_log->fn_log 
 *   are not NULL, the log messages predefined in the function will be output. 
 *   Otherwise, the log messages will be bypassed.
 *   The log levels supported are TDUHT_LOG_LEVEL_MINIMAL and TDUHT_LOG_LEVEL_FULL. 
 *   Log messages included for different log levels are:
 *   TDUHT_LOG_LEVEL_MINIMAL
 *     - Output format when output format changes
 *     - TDUHT enabled/disabled status when TDUHT is switching between enabled and disabled.
 *     - Azimuth degree when azimuth changes more than 5 degrees compared with last call�
 *   TDUHT_LOG_LEVEL_FULL
 *     - Output format when output format changes
 *     - TDUHT enable/disable status when UHT is switching between enabled and disabled.
 *     - Azimuth degree when azimuth changes�
 *     - when tduht_reset is called
 *
 * ### ERRORS
 * If there is an error detected, then tduht_process() will return non-zero. The
 * errors that can be detected are:
 * TDUHT_PROCESS_ERROR_INVALID_INPUT_BLOCK_NUM   
 * - num_input_blocks is 0 or num_input_blocks is greater than TDUHT_MAX_BLOCKS
 * TDUHT_PROCESS_ERROR_INVALID_INPUT_CHANNEL
 * - The p_input->nchannel is not 2
 * TDUHT_PROCESS_ERROR_INVALID_OUTPUT_FORMAT
 * - output_format is greater than TDUHT_OUTPUT_FORMAT_BINAURAL
 * TDUHT_PROCESS_ERROR_INVALID_OUTPUT_CHANNEL
 * - The p_output->nchannel is 0 or greated than 2 
 *   or the p_output->nchannel does not match the amount of channels described by
 *   output_format.
 *
 * In the event of an error, the tduht_state should be considered to be in
 * an invalid state which can't be recovered from. Note that all of these
 * errors will be completely avoided in a correct program and will never be
 * triggered by parameter setting. Therefore, a correct
 * program using this function can safely ignore the error case.
 *
 * @returns                      Error codes specified by TDUHT_PROCESS_ERROR_* macros.
 *
 * @param p_tduht                Instance of tduht state structure.
 * @param num_input_blocks       Number of blocks of PCM input data. The number
 *                               of samples in each block is specified by TDUHT_BLOCK_SIZE.
 *                               Must be greater than 0 and no greater than
 *                               TDUHT_MAX_BLOCKS.
 * @param p_input                Input data buffer
 * @param p_output               Output data buffer
 * @param output_format          Output channel format identifier.
 * @param p_scratch              Scratch memory pointer with allocated size for dap_cpdp scratch.
 * @param p_tduht_log            Instance of tduht log structure
 */
int
tduht_process
    (      tduht_state            *p_tduht
    ,      unsigned                num_input_blocks
    ,const dlb_buffer             *p_input
    ,const dlb_buffer             *p_output
    ,      unsigned                output_format
    ,      void                   *p_scratch
    ,const tduht_log_info         *p_tduht_log
    );


/**
 * @brief Reset TDUHT history state
 * This function is used to clear history data of TDUHT state and 
 * reset azimuth and elevation degree to (0,0).
 * Dynamic parameters will not be cleared.
 *
 * @param p_tduht        Instance of TDUHT state structure.
 */
void
tduht_reset
    (tduht_state *p_tduht
    );

/**
 * @brief Clean up any resources owned by this TDUHT instance.
 *
 * @param p_tduht Instance of TDUHT state structure.
 */
void
tduht_close
    (tduht_state *p_tduht
    );

#endif /* TDUHT_H */
