text: /**
   * \file ftl_private.h - Private Interfaces for the FTL SDK
   *
   * Copyright (c) 2015 Mixer Inc.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   **/
  
  #ifndef __FTL_PRIVATE_H
  #define __FTL_PRIVATE_H
  
  #define __STDC_WANT_LIB_EXT1__ 1
  
  #include <stdio.h>
  #include <stdarg.h>
  #include <stdint.h>
  #include <stdlib.h>
  #include <string.h>
  #include "gettimeofday/gettimeofday.h"
  
  #ifdef _WIN32
  #include <WS2tcpip.h>
  #include <WinSock2.h>
  #else
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <netdb.h>
  #include <unistd.h>
  #include <arpa/inet.h>
  #endif
  
  #include "threads.h"
  #include "socket.h"
  
  
  #define MAX_INGEST_COMMAND_LEN 512
  #define INGEST_PORT 8084
  #define MAX_KEY_LEN 100
  #define VIDEO_PTYPE 96
  #define AUDIO_PTYPE 97
  #define SOCKET_RECV_TIMEOUT_MS 5000
  #define SOCKET_SEND_TIMEOUT_MS 1000
  #define KEEPALIVE_FREQUENCY_MS 5000
  #define KEEPALIVE_SEND_WARN_TOLERANCE_MS 1000
  #define STATUS_THREAD_SLEEP_TIME_MS 500
  #define MAX_PACKET_BUFFER 1500  //Max length of buffer
  #define MAX_MTU 1392
  #define FTL_UDP_MEDIA_PORT 8082   //legacy port
  #define RTP_HEADER_BASE_LEN 12
  #define RTP_FUA_HEADER_LEN 2
  #define NACK_RB_SIZE (2048) //must be evenly divisible by 2^16
  #define NACK_RTT_AVG_SECONDS 5
  #define MAX_STATUS_MESSAGE_QUEUED 10
  #define MAX_FRAME_SIZE_ELEMENTS 64 //must be a minimum of 3
  #define MAX_XMIT_LEVEL_IN_MS 100 //allows a maximum burst size of 100ms at the target bitrate
  #define VIDEO_RTP_TS_CLOCK_HZ 90000
  #define AUDIO_SAMPLE_RATE 48000
  #define AUDIO_PACKET_DURATION_MS 20
  #define IPVX_ADDR_ASCII_LEN INET6_ADDRSTRLEN
  #define INGEST_LIST_URI "https://conductor.videosvc.mixer.com/api/video/v2/channels/%d/ingest"
  #define INGEST_LOAD_PORT 8079
  #define INGEST_PING_PORT 8079
  #define PEAK_BITRATE_KBPS 10000 /*if not supplied this is the peak from the perspective of the send buffer*/
  #define PING_TX_INTERVAL_MS 25
  #define SENDER_REPORT_TX_INTERVAL_MS 1000
  #define PING_PTYPE 250
  #define SENDER_REPORT_PTYPE 200
  
   // Adaptive bitrate constants
  
   // If the ratio of nacks received to packets sent is greater than the following value, we request a bitrate downgrade.
  #define MIN_NACKS_RECEIVED_TO_PACKETS_SENT_RATIO_FOR_BITRATE_DOWNGRADE 0.1
  
   // Duration at which we capture stream stats , i.e frames sent and nacks received
  #define STREAM_STATS_CAPTURE_MS 1000
  
   // Duration over which we evaluate whether we need to downgrade/upgrade bitrate. Note that we 
   // look at stats over the last c_ulBwCheckDurationMs milliseconds, every c_ulStreamStatsCaptureMs milliseconds.
  #define BW_CHECK_DURATION_MS 5000
  
   // Interval to wait for bw test after we update bitrate.
  #define BITRATE_CHANGED_COOLDOWN_INTERVAL_MS 10000
  
   // Percentage to reduce the bitrate to if bandwidth seems too constrained
  #define BW_INSUFFICIENT_BITRATE_DOWNGRADE_PERCENTAGE 50
  
   // Percentange to reduce the bitrate to if bw upgrade was too excessive
  #define REVERT_TO_STABLE_BITRATE_DOWNGRADE_PERCENTAGE 80
  
   // Percentage to increase bitrate by if conditions look ideal
  #define BW_IDEAL_BITRATE_UPGRADE_BPS 256000;
  
   // If ratio of nacks received to packets sent is below the following value bitrate update can be requested
  #define MAX_NACKS_RECEIVED_TO_PACKETS_SENT_RATIO_FORBITRATE_UPGRADE 0.01
  
   // If bandwidth is constrained within MaxBitrateUpgradeExcessiveSeconds after bitrate update, revert to last stable bitrate.
  #define MAX_MS_TO_DEEM_UPGRADE_EXCESSIVE 60000
  
  #define MAX_AVG_RTT_TO_DEEM_BW_STABLE 100
  
  #define MAX_QUEUE_FULLNESS_TO_DEEM_BW_STABLE 0.1
  
  #define MIN_QUEUE_FULLNESS_TO_DEEM_BW_CONSTRAINED 0.3
  
  #define MIN_AVG_RTT_TO_DEEM_BW_CONSTRAINED 300
   // If bitrate upgrade was excessive we freeze bitrate upgrade for the next c_bitrateUpgradeFreezeTimeMs milliseconds.
  #define BITRATE_UPGRADE_FREEZE_TIME_MS 600000 // 10*60*1000
  
  #define MAX_STAT_SIZE 5
  
  #ifndef _WIN32
  #define strncpy_s(dst, dstsz, src, cnt) strncpy(dst, src, cnt)
  #define sprintf_s(buf, bufsz, fmt, ...) sprintf(buf, fmt, __VA_ARGS__)
  #define strcpy_s(dst, dstsz, src) strcpy(dst, src)
  #define _strdup(src) strdup(src)
  #define sscanf_s sscanf
  #endif
  
  typedef enum {
    H264_NALU_TYPE_NON_IDR = 1,
    H264_NALU_TYPE_IDR = 5,
    H264_NALU_TYPE_SEI = 6,
    H264_NALU_TYPE_SPS = 7,
    H264_NALU_TYPE_PPS = 8,
    H264_NALU_TYPE_DELIM = 9,
    H264_NALU_TYPE_FILLER = 12
  }h264_nalu_type_t;
  
  typedef enum {
    FTL_CONNECTED = 0x0001,
    FTL_MEDIA_READY = 0x0002,
    FTL_STATUS_QUEUE = 0x0004,
    FTL_CXN_STATUS_THRD = 0x0008,
    FTL_KEEPALIVE_THRD = 0x0010,
    FTL_PING_THRD = 0x0020,
    FTL_RX_THRD = 0x0040,
    FTL_TX_THRD = 0x0080,
    FTL_DISABLE_TX_PING_PKTS = 0x0100,
    FTL_SPEED_TEST = 0x0200,
    FTL_BITRATE_THRD = 0x0400,
    FTL_DISCONNECT_IN_PROGRESS = 0x1000,
    FTL_DISABLE_TX_SENDER_REPORT = 0x2000
  }ftl_state_t;
  
  #ifndef _WIN32
  typedef int SOCKET;
  typedef bool BOOL;
  #define TRUE true
  #define FALSE false
  #define INVALID_SOCKET (-1)
  #define SOCKET_ERROR (-1)
  #endif
  
  /*status message queue*/
  typedef struct _status_queue_t {
    ftl_status_msg_t stats_msg;
    struct _status_queue_t *next;
  }status_queue_elmt_t;
  
  typedef struct {
    status_queue_elmt_t *head;
    int count;
    int thread_waiting;
    OS_MUTEX mutex;
    OS_SEMAPHORE sem;
  }status_queue_t;
  
  /**
   * This configuration structure handles basic information for a struct such
   * as the authetication keys and other similar information. It's members are
   * private and not to be directly manipulated
   */
  typedef struct {
    uint8_t packet[MAX_PACKET_BUFFER];
    int len;
    struct timeval insert_time;
    struct timeval xmit_time;
    int sn;
    int first;/*first packet in frame*/
    int last; /*last packet in frame*/
    OS_MUTEX mutex;
    BOOL isPartOfIframe;
  }nack_slot_t;
  
  typedef struct _ping_pkt_t {
    uint32_t header;
    struct timeval xmit_time;
  }ping_pkt_t;
  
  typedef struct _senderReport_pkt_t {
    uint32_t header;
    uint32_t ssrc;
    uint32_t ntpTimestampHigh;
    uint32_t ntpTimestampLow;
    uint32_t rtpTimestamp;
    uint32_t senderPacketCount;
    uint32_t senderOctetCount;
  }senderReport_pkt_t;
  
  typedef struct {
    struct timeval start_time;
    int64_t frames_received;
    int64_t frames_sent;
    int64_t bw_throttling_count;
    int64_t bytes_queued;
    int64_t packets_queued;
    int64_t bytes_sent;
    int64_t payload_bytes_sent;
    int64_t packets_sent;
    int64_t late_packets;
    int64_t lost_packets;
    int64_t nack_requests;
    int64_t dropped_frames;
    int pkt_xmit_delay_max;
    int pkt_xmit_delay_min;
    int total_xmit_delay;
    int xmit_delay_samples;
    int pkt_rtt_max;
    int pkt_rtt_min;
    int total_rtt;
    int rtt_samples;
    int current_frame_size;
    int max_frame_size;
  }media_stats_t;
  
  typedef struct {
    uint8_t payload_type;
    uint32_t ssrc;
    uint32_t timestamp;
    int timestamp_clock;
    uint64_t timestamp_dts_usec;
    int64_t base_dts_usec;
    int64_t randomOffset;
    uint16_t seq_num;
    uint16_t tmp_seq_num; // used for stats only
    BOOL nack_enabled;
    int64_t min_nack_rtt;
    int64_t max_nack_rtt;
    int64_t nack_rtt_avg;
    BOOL nack_slots_initalized;
    int producer;
    int consumer;
    uint16_t xmit_seq_num;
    nack_slot_t *nack_slots[NACK_RB_SIZE];
    OS_MUTEX nack_slots_lock;
    int peak_kbps;
    int kbps;
    media_stats_t stats; //cumulative since start of stream
    OS_SEMAPHORE pkt_ready;
  }ftl_media_component_common_t;
  
  typedef struct {
    ftl_audio_codec_t codec;
    int64_t dts_usec;
    ftl_media_component_common_t media_component;
    OS_MUTEX mutex;
    BOOL is_ready_to_send;
  } ftl_audio_component_t;
  
  typedef struct {
    ftl_video_codec_t codec;
    uint32_t height;
    uint32_t width;
    int fps_num;
    int fps_den;
    int64_t dts_usec;
    float dts_error;
    uint8_t fua_nalu_type;
    BOOL wait_for_idr_frame;
    ftl_media_component_common_t media_component;
    OS_MUTEX mutex;
    BOOL has_sent_first_frame;
  } ftl_video_component_t;
  
  typedef struct {
    size_t ingest_addrlen;
    struct sockaddr *ingest_addr;
    SOCKET media_socket;
    OS_MUTEX mutex;
    int assigned_port;
    OS_THREAD_HANDLE recv_thread;
    OS_THREAD_HANDLE video_send_thread;
    OS_THREAD_HANDLE audio_send_thread;
    OS_THREAD_HANDLE ping_thread;
    OS_SEMAPHORE ping_thread_shutdown;
    int max_mtu;
    struct timeval stats_tv;
    int last_rtt_delay;
    struct timeval sender_report_base_ntp;
  } ftl_media_config_t;
  
  typedef struct _ftl_ingest_t {
    char *name;
    int rtt;
    struct _ftl_ingest_t *next;
  }ftl_ingest_t;
  
  typedef struct
  {
      ftl_handle_t* handle;
      BOOL(*change_bitrate_callback)(void*, uint64_t);
      void* context;
      uint64_t initial_encoding_bitrate;
      uint64_t max_encoding_bitrate;
      uint64_t min_encoding_bitrate;
  } ftl_adaptive_bitrate_thread_params_t;
  
  typedef struct {
    SOCKET ingest_socket;
    ftl_state_t state;
    OS_MUTEX state_mutex;
    OS_MUTEX disconnect_mutex;
    char *param_ingest_hostname;
    char *ingest_hostname;
    char *ingest_ip;
    short socket_family;
    uint32_t channel_id;
    char *key;
    char hmacBuffer[512];
    int video_kbps;
    char vendor_name[50];
    char vendor_version[50];
    OS_THREAD_HANDLE connection_thread;
    OS_THREAD_HANDLE keepalive_thread;
    OS_THREAD_HANDLE bitrate_monitor_thread;
    OS_SEMAPHORE connection_thread_shutdown;
    OS_SEMAPHORE keepalive_thread_shutdown;
    OS_SEMAPHORE bitrate_thread_shutdown;
    ftl_media_config_t media;
    ftl_audio_component_t audio;
    ftl_video_component_t video;
    status_queue_t status_q;
    ftl_ingest_t *ingest_list;
    int ingest_count;
  }  ftl_stream_configuration_private_t;
  
  struct MemoryStruct {
    char *memory;
    size_t size;
  };
  
  /**
   * Charon always responses with a three digit response code after each command
   *
   * This enum holds defined number sequences
   **/
  
  typedef enum {
    FTL_INGEST_RESP_UNKNOWN = 0,
    FTL_INGEST_RESP_OK = 200,
    FTL_INGEST_RESP_PING = 201,
    FTL_INGEST_RESP_BAD_REQUEST= 400,             // The handshake was not formatted correctly
    FTL_INGEST_RESP_UNAUTHORIZED = 401,           // This channel id is not authorized to stream
    FTL_INGEST_RESP_OLD_VERSION = 402,            // This ftl api version is no longer supported
    FTL_INGEST_RESP_AUDIO_SSRC_COLLISION = 403,
    FTL_INGEST_RESP_VIDEO_SSRC_COLLISION = 404,
    FTL_INGEST_RESP_INVALID_STREAM_KEY = 405,     // The corresponding channel does not match this key
    FTL_INGEST_RESP_CHANNEL_IN_USE = 406,         // The channel ID successfully authenticated however it is already actively streaming
    FTL_INGEST_RESP_REGION_UNSUPPORTED = 407,     // Streaming from this country or region is not authorized by local governments
    FTL_INGEST_RESP_NO_MEDIA_TIMEOUT = 408,
    FTL_INGEST_RESP_GAME_BLOCKED = 409,           // The game the user account is set to can't be streamed.
    FTL_INGEST_RESP_SERVER_TERMINATE = 410,         // The sterver has terminated the stream.
    FTL_INGEST_RESP_INTERNAL_SERVER_ERROR = 500,
    FTL_INGEST_RESP_INTERNAL_MEMORY_ERROR = 900,
    FTL_INGEST_RESP_INTERNAL_COMMAND_ERROR = 901,
    FTL_INGEST_RESP_INTERNAL_SOCKET_CLOSED = 902,
    FTL_INGEST_RESP_INTERNAL_SOCKET_TIMEOUT = 903
  } ftl_response_code_t;
  
  /**
   * Logs something to the FTL logs
   */
  
  #define FTL_LOG(ftl_handle, log_level, ...) ftl_log_msg (ftl_handle, log_level, __FILE__, __LINE__, __VA_ARGS__);
  void ftl_log_msg(ftl_stream_configuration_private_t *ftl, ftl_log_severity_t log_level, const char * file, int lineno, const char * fmt, ...);
  
  /**
   * Value to string conversion functions
   */
  
  const char * ftl_audio_codec_to_string(ftl_audio_codec_t codec);
  const char * ftl_video_codec_to_string(ftl_video_codec_t codec);
  
  /**
   * Functions related to the charon prootocol itself
   **/
  
  int recv_all(SOCKET sock, char * buf, int buflen, const char line_terminator);
  
  int ftl_get_hmac(SOCKET sock, char * auth_key, char * dst);
  int ftl_read_response_code(const char * response_str);
  int ftl_read_media_port(const char *response_str);
  
  /**
   * Platform abstractions
   **/
  
  // FIXME: make this less global
  extern char error_message[1000];
  
  ftl_status_t _log_response(ftl_stream_configuration_private_t *ftl, int response_code);
  void ftl_set_state(ftl_stream_configuration_private_t *ftl, ftl_state_t state);
  void ftl_clear_state(ftl_stream_configuration_private_t *ftl, ftl_state_t state);
  BOOL ftl_get_state(ftl_stream_configuration_private_t *ftl, ftl_state_t state);
  BOOL is_legacy_ingest(ftl_stream_configuration_private_t *ftl);
  ftl_status_t dequeue_status_msg(ftl_stream_configuration_private_t *ftl, ftl_status_msg_t *stats_msg, int ms_timeout);
  ftl_status_t enqueue_status_msg(ftl_stream_configuration_private_t *ftl, ftl_status_msg_t *stats_msg);
  ftl_status_t _set_ingest_hostname(ftl_stream_configuration_private_t *ftl);
  int _get_remote_ip(struct sockaddr *addr, size_t addrlen, char *remote_ip, size_t ip_len);
  
  ftl_status_t _init_control_connection(ftl_stream_configuration_private_t *ftl);
  ftl_status_t _ingest_connect(ftl_stream_configuration_private_t *stream_config);
  ftl_status_t _ingest_disconnect(ftl_stream_configuration_private_t *stream_config);
  char * ingest_find_best(ftl_stream_configuration_private_t *ftl);
  void ingest_release(ftl_stream_configuration_private_t *ftl);
  
  ftl_status_t media_init(ftl_stream_configuration_private_t *ftl);
  ftl_status_t media_destroy(ftl_stream_configuration_private_t *ftl);
  int media_send_video(ftl_stream_configuration_private_t *ftl, int64_t dts_usec, uint8_t *data, int32_t len, int end_of_frame);
  int media_send_audio(ftl_stream_configuration_private_t *ftl, int64_t dts_usec, uint8_t *data, int32_t len);
  ftl_status_t media_speed_test(ftl_stream_configuration_private_t *ftl, int speed_kbps, int duration_ms, speed_test_t *results);
  ftl_status_t internal_ingest_disconnect(ftl_stream_configuration_private_t *ftl);
  ftl_status_t internal_ftl_ingest_destroy(ftl_stream_configuration_private_t *ftl);
  void sleep_ms(int ms);
  
  #if defined(_MSC_VER) && _MSC_VER < 1900
  #define snprintf _snprintf
  #endif
  
  #endif
  