⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 source.c

📁 处理声源,时间,做好各类资源的调整工作,为声音的输入输出做准备.
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * FILE:      source.c
 * AUTHOR(S): Orion Hodson 
 *
 * Layering support added by Tristan Henderson.
 *	
 * Copyright (c) 1999-2001 University College London
 * All rights reserved.
 */
 
#ifndef HIDE_SOURCE_STRINGS
static const char cvsid[] = 
	"$Id: source.c,v 1.163 2002/03/15 17:57:19 ucacoxh Exp $";
#endif /* HIDE_SOURCE_STRINGS */

#include "config_unix.h"
#include "config_win32.h"
#include "audio_types.h"
#include "codec_types.h"
#include "ts.h"
#include "playout.h"
#include "channel.h"
#include "channel_types.h"
#include "codec.h"
#include "codec_state.h"
#include "converter.h"
#include "audio_util.h"
#include "render_3D.h"
#include "repair.h"
#include "ts.h"
#include "channel_types.h"
#include "pdb.h"
#include "pktbuf.h"
#include "source.h"
#include "debug.h"
#include "util.h"
#include "net_udp.h"
#include "mix.h"
#include "rtp.h"
#include "playout_calc.h"
#include "session.h"
#include "ui_send_stats.h"
#include "auddev.h"
#include "mbus.h"

#define SKEW_ADAPT_THRESHOLD       5000
#define SOURCE_YOUNG_AGE             20
#define NO_TOGED_CONT_FOR_PLAYOUT_RECALC 3

#define SOURCE_COMPARE_WINDOW_SIZE 8
#define SOURCE_MERGE_LEN_SAMPLES SOURCE_COMPARE_WINDOW_SIZE

/* Match threshold is mean abs diff. lower score gives less noise, but less  */
/* adaption..., might be better if threshold adapted with how much extra     */
/* data we have buffered...                                                  */
#define MATCH_THRESHOLD 1200

/* constants for skew adjustment:
 SOURCE_SKEW_SLOW - denotes source clock appears slower than ours.
 SOURCE_SKEW_FAST - denotes source clock appears faster than ours.
*/
typedef enum { SOURCE_SKEW_SLOW, SOURCE_SKEW_FAST, SOURCE_SKEW_NONE } skew_t;

typedef enum { PLAYOUT_MODE_NORMAL, PLAYOUT_MODE_SPIKE } pmode_t;

typedef struct s_source {
        struct s_source            *next;
        struct s_source            *prev;
        pdb_entry_t                *pdbe;       /* persistent database entry */
        uint32_t                    age;
        timestamp_t                 next_played; /* anticipated next unit    */
        timestamp_t                 talkstart;  /* start of latest talkspurt */
        timestamp_t                 last_repair;
	int			    hold_repair;
        uint32_t                    post_talkstart_units;
        uint16_t                    consec_lost;
        uint32_t                    mean_energy;
        struct s_pktbuf            *pktbuf;
        uint32_t                    packets_done;
        struct s_channel_state     *channel_state;
        struct s_codec_state_store *codec_states;
        struct s_pb                *channel;
        struct s_pb                *media;
        struct s_pb_iterator       *media_pos;
        struct s_converter         *converter;
        pmode_t                     playout_mode; /* SPIKE, NORMAL */
        timestamp_t                 spike_var;
        /* Fine grained playout buffer adjustment variables.  Used in        */
        /* attempts to correct for clock skew between source and local host. */
        skew_t 			    skew;
        timestamp_t   		    skew_adjust;
        int16_t                     skew_cnt;
        /* Skew stats                                                        */
        int32_t                     samples_played;
        int32_t                     samples_added;
        /* b/w estimation variables                                          */
        uint32_t                    byte_count;
        timestamp_t                 byte_count_start;
        double                      bps;
        /* Playout stats (most in pdb_entry_t)                               */
	u_char                      toged_cont;	     /* Toged in a row       */
        uint16_t                    toged_mask;      /* bitmap hist. of tog  */
	uint32_t		    magic;	     /* For debugging        */
} source;

/* A linked list is used for sources and this is fine since we mostly expect */
/* 1 or 2 sources to be simultaneously active and so efficiency is not a     */
/* killer.                                                                   */

typedef struct s_source_list {
        source  sentinel;
        uint16_t nsrcs;
} source_list;

/*****************************************************************************/
/* Source List functions.  Source List is used as a container for sources    */
/*****************************************************************************/

int
source_list_create(source_list **pplist)
{
        source_list *plist = (source_list*)xmalloc(sizeof(source_list));
        if (plist != NULL) {
                *pplist = plist;
                plist->sentinel.next = &plist->sentinel;
                plist->sentinel.prev = &plist->sentinel;
                plist->nsrcs = 0;
                return TRUE;
        }
        return FALSE;
}

void
source_list_clear(source_list *plist)
{
       assert(plist != NULL);
        
       while(plist->sentinel.next != &plist->sentinel) {
               source_remove(plist, plist->sentinel.next);
       }
}

void
source_list_destroy(source_list **pplist)
{
        source_list *plist = *pplist;
        source_list_clear(plist);
        assert(plist->nsrcs == 0);
        xfree(plist);
        *pplist = NULL;
}

uint32_t
source_list_source_count(source_list *plist)
{
        return plist->nsrcs;
}

source*
source_list_get_source_no(source_list *plist, uint32_t n)
{
        source *curr = NULL;

        assert(plist != NULL);

        if (n < plist->nsrcs) {
                curr = plist->sentinel.next;
                while(n != 0) {
                        curr = curr->next;
                        n--;
                }
                return curr;
        }
        return NULL;
}

source*
source_get_by_ssrc(source_list *plist, uint32_t ssrc)
{
        source *curr = NULL, *stop = NULL;
        
        curr = plist->sentinel.next; 
        stop = &plist->sentinel;
        while(curr != stop) {
                if (curr->pdbe->ssrc == ssrc) {
                        return curr;
                }
                curr = curr->next;
        }
 
        return NULL;
}

/*****************************************************************************/
/* Timestamp constants and initialization                                    */
/*****************************************************************************/

static timestamp_t zero_ts;        /* No time at all :-)                            */
static timestamp_t keep_source_ts; /* How long source kept after source goes quiet  */
static timestamp_t history_ts;     /* How much old audio hang onto for repair usage */
static timestamp_t bw_avg_period;  /* Average period for bandwidth estimate         */
static timestamp_t skew_thresh;    /* Significant size b4 consider playout adapt    */
static timestamp_t skew_limit;     /* Upper bound, otherwise clock reset.           */
static timestamp_t transit_reset;  /* Period after which new transit time taken     */
        	                   /* if source has been quiet.                     */
static timestamp_t transit_jump;   /* If transit delta is bigger than this reset    */
static timestamp_t spike_jump;     /* Packet spike delay threshold (trigger).       */
static timestamp_t spike_end;      /* Value of var when spike over                  */
static timestamp_t repair_max_gap; /* Maximum stream gap repair is attempted for.   */
static int  time_constants_inited = FALSE;

static void
time_constants_init()
{
        /* We use these time constants *all* the time.   Initialize once     */
        zero_ts        = ts_map32(8000, 0);
        keep_source_ts = ts_map32(8000, 24000);
        history_ts     = ts_map32(8000, 2000); 
        bw_avg_period  = ts_map32(8000, 8000);
        skew_thresh    = ts_map32(8000, 320);
        skew_limit     = ts_map32(8000, 4000);
        transit_reset  = ts_map32(8000, 80000);
	transit_jump   = ts_map32(8000, 12000);
        spike_jump     = ts_map32(8000, 3000); 
        spike_end      = ts_map32(8000, 64);
        repair_max_gap = ts_map32(8000, 1600); /* 200ms */
        time_constants_inited = TRUE;
}

/*****************************************************************************/
/* Source functions.  A source is an active audio source.                    */
/*****************************************************************************/

static void 
source_validate(source *s)
{
	/* More debugging code... check the invarients of the soure. */
	/* This is called from all the routines here... if anything  */
	/* is trashing the source, this is supposed to detect it.    */
	assert(s != NULL);
	assert(s->magic == 0xface0ff);
#ifdef DEBUG
	assert(s->next != NULL);
	assert(s->prev != NULL);
        assert(s->pdbe != NULL);
        assert(s->bps  >= 0);
	assert((s->skew == SOURCE_SKEW_SLOW) || (s->skew == SOURCE_SKEW_FAST) ||( s->skew == SOURCE_SKEW_NONE));
	assert((s->playout_mode == PLAYOUT_MODE_NORMAL) || (s->playout_mode == PLAYOUT_MODE_SPIKE));
	assert(ts_valid(s->pdbe->playout));
#endif
}

source*
source_create(source_list    *plist, 
              uint32_t        ssrc,
	      pdb_t	     *pdb)
{
        source *psrc;
        int     success;

        assert(plist != NULL);
        assert(source_get_by_ssrc(plist, ssrc) == NULL);

        /* Time constant initialization. Nothing to do with source creation  */
        /* just has to go somewhere before sources might be active, here it  */
        /* definitely is!                                                    */
        if (time_constants_inited == FALSE) {
                time_constants_init();
        }

        /* On with the show...                                               */
        psrc = (source*)block_alloc(sizeof(source));
        if (psrc == NULL) {
                return NULL;
        }
        memset(psrc, 0, sizeof(source));
	psrc->magic = 0xface0ff;

        if (pdb_item_get(pdb, ssrc, &psrc->pdbe) == FALSE) {
                debug_msg("Persistent database item not found\n");
                abort();
        }

        psrc->pdbe->first_mix  = 1; /* Used to note nothing mixed anything   */
        psrc->toged_cont       = 0; /* Reset continuous thrown on ground cnt */
        psrc->toged_mask       = 0;
        psrc->channel_state    = NULL;        
        psrc->skew             = SOURCE_SKEW_NONE;
        psrc->samples_played   = 0;
        psrc->samples_added    = 0;
        psrc->spike_var        = zero_ts;
	psrc->last_repair      = zero_ts;
	psrc->hold_repair      = 0;

        /* Allocate channel and media buffers                                */
        success = pb_create(&psrc->channel, 
                            (playoutfreeproc)channel_data_destroy);
        if (!success) {
                debug_msg("Failed to allocate channel buffer\n");
                goto fail_create_channel;
        }

        success = pb_create(&psrc->media, (playoutfreeproc)media_data_destroy);
        if (!success) {
                debug_msg("Failed to allocate media buffer\n");
                goto fail_create_media;
        }

        success = pb_iterator_create(psrc->media, &psrc->media_pos);
        if (!success) {
                debug_msg("Failed to attach iterator to media buffer\n");
                goto fail_create_iterator;
        }

        success = codec_state_store_create(&psrc->codec_states, DECODER);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -