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

📄 source.c

📁 处理声源,时间,做好各类资源的调整工作,为声音的输入输出做准备.
💻 C
📖 第 1 页 / 共 5 页
字号:
                        source_update_toged(src, 0);
                } 

		/* Signal the playout delay to the video tool, so it can lip */
		/* sync with us.                                             */
		if (adjust_playout && sp->sync_on) {
			mbus_qmsgf(sp->mbus_engine, sp->mbus_video_addr, FALSE, "rtp.source.playout", "\"%08lx\" %d", 
				   src->pdbe->ssrc, timestamp_to_ms(ts_abs_diff(playout, now)));
		}

                /* Update persistent database fields... */
                if (e->last_seq > p->seq) {
                        e->misordered++;
                }
                e->last_seq          = p->seq;
                e->last_ts           = p->ts;
                e->last_arr          = now;
                e->last_last_transit = e->last_transit;
                e->last_transit      = transit;

		/* This would be a good place to log a histogram of loss     */
		/* lengths, right? llhist[p->seq - e->last_seq]++ after a    */
		/* check that this is not the first packet in a talkspurt.   */
		/* We could then feed it back to the sender in our reception */
		/* reports, where it could be used to adapt the redundancy   */
		/* offset, for example. [csp]                                */

#ifdef SOURCE_LOG_PLAYOUT
                source_playout_log(src, p->ts, now);
#endif /* SOURCE_LOG_PLAYOUT */
                src->packets_done++;
                xfree(p);
        }
	source_validate(src);
}

int
source_add_packet (source     *src, 
                   rtp_packet *pckt)
{
	source_validate(src);
        src->byte_count += pckt->data_len;
        return pktbuf_enqueue(src->pktbuf, pckt);
}

static void
source_update_bps(source *src, timestamp_t now)
{
        timestamp_t delta;

	source_validate(src);
        if (!ts_valid(src->byte_count_start)) {
                src->byte_count_start = now;
                src->byte_count       = 0;
                src->bps              = 0.0;
		source_validate(src);
                return;
        }

        delta = ts_sub(now, src->byte_count_start);
        
        if (ts_gt(delta, bw_avg_period)) {
                double this_est;
                this_est = 8.0 * src->byte_count * 1000.0/ timestamp_to_ms(delta);
                if (src->bps == 0.0) {
                        src->bps = this_est;
                } else {
                        src->bps += (this_est - src->bps)/2.0;
                }
                src->byte_count = 0;
                src->byte_count_start = now;
        }
	source_validate(src);
}

double 
source_get_bps(source *src)
{
        return src->bps;
}

static int16_t
find_local_match(sample *buffer, uint16_t wstart, uint16_t wlen, uint16_t sstart, uint16_t send, uint16_t channels)
{
        uint16_t i,j, i_min = sstart;
        uint32_t score = 0, score_min = 0xffffffff;

        for (i = sstart; i < send; i += channels) {
                score = 0;
                for(j = 0; j < wlen; j += channels) {
                        score += abs((int32_t)buffer[wstart + j] - (int32_t)buffer[i + j]);
                }
                if (score <= score_min) {
                        score_min = score;
                        i_min     = i;
                }
        }

        if (score_min / wlen < MATCH_THRESHOLD) {
                return i_min / channels;
        }
        return -1;
}

/* recommend_skew_adjust_dur examines a frame to determine how much audio    */
/* to insert or drop.   Argument drop is boolean to indicate whether         */
/* dropping samples (TRUE) or inserting (FALSE).                             */

static int32_t
recommend_skew_adjust_dur(media_data *md, int drop, timestamp_t *adjust) 
{
        int16_t matchlen;
        uint32_t rate;
	uint16_t channels, samples;
        sample *buffer;
        int16_t i;

        i = md->nrep - 1;
        while(i >= 0) {
                if (codec_get_native_info(md->rep[i]->id, &rate, &channels)) {
                        break;
                }
                i--;
        }
        assert(i != -1);
        
        buffer  = (sample*)md->rep[i]->data;
        samples = md->rep[i]->data_len / (sizeof(sample) * channels);
        if (drop) {
                /* match with first samples of frame start just past
                 * search window and finish at end of frame 
                 */
                matchlen = find_local_match((sample*)md->rep[i]->data,                                     /* buffer            */
                                            0,                                                             /* window start      */
                                            (uint16_t)(SOURCE_COMPARE_WINDOW_SIZE * channels),             /* window len        */
                                            (uint16_t)(SOURCE_COMPARE_WINDOW_SIZE * channels),             /* search area start */
                                            (uint16_t)((samples - SOURCE_COMPARE_WINDOW_SIZE) * channels), /* search area len   */
                                            channels);
                if (matchlen == -1) {
                        return FALSE;
                }
        } else {
                /* match with last samples of frame.  Start at the
                 * start of frame and finish just before search window.
                 */
                matchlen = find_local_match((sample*)md->rep[i]->data,                                         /* buffer */
                                            (uint16_t)((samples - SOURCE_COMPARE_WINDOW_SIZE) * channels),     /* wstart */
                                            (uint16_t)(SOURCE_COMPARE_WINDOW_SIZE * channels),                 /* wlen   */
                                            0,                                                                 /* sstart */
                                            (uint16_t)((samples - 2 * SOURCE_COMPARE_WINDOW_SIZE) * channels), /* slen   */
                                            channels);
                /* Want to measure from where frames will overlap. */
                if (matchlen == -1) {
                        return FALSE;
                }
                matchlen += SOURCE_COMPARE_WINDOW_SIZE;
        }
        assert(matchlen >= 0);
        assert(matchlen <= samples);
        *adjust = ts_map32(rate, matchlen);
        return TRUE;
}

static void
conceal_dropped_samples(media_data *md, timestamp_t drop_dur)
{
        /* We are dropping drop_dur samples and want signal to be            */
        /* continuous.  So we blend samples that would have been played if   */
        /* they weren't dropped with where signal continues after the drop.  */
        uint32_t drop_samples;
        uint32_t rate;
	uint16_t channels;
        int32_t i;
        sample *new_start, *buf;

        for (i = md->nrep - 1; i >= 0; i--) {
                if (codec_get_native_info(md->rep[i]->id, &rate, &channels)) {
                        break;
                }
        }

        assert(i != -1);

        buf          = (sample*)md->rep[i]->data;
        drop_dur     = ts_convert(rate, drop_dur);
        drop_samples = channels * drop_dur.ticks;
        new_start    = buf + drop_samples;
        
        audio_blend(buf, new_start, new_start, SOURCE_MERGE_LEN_SAMPLES, channels);
        xmemchk();
}

/* Source conceal_inserted_samples blends end of omd with overlap in imd    */
/* just before insert takes over.  Aims to provide transparent transitition */
/* between added block and old block.                                       */

static void
conceal_inserted_samples(media_data *omd, media_data *imd, timestamp_t insert_dur)
{
        uint32_t rate;
	uint16_t channels;
        uint32_t dst_samples, src_samples, skip;
        int32_t  i;
        sample *dst, *src;
        
        assert(omd != NULL);
        assert(imd != NULL);
        
        for (i = omd->nrep - 1; i >= 0; i--) {
                if (codec_get_native_info(omd->rep[i]->id, &rate, &channels)) {
                        break;
                }
        }
        assert(i >= 0);

        for (i = imd->nrep - 1; i >= 0; i--) {
                if (codec_get_native_info(imd->rep[i]->id, &rate, &channels)) {
                        break;
                }
        }
        assert(i >= 0);

        dst_samples = omd->rep[i]->data_len / sizeof(sample);
        dst         = ((sample*)omd->rep[i]->data) + dst_samples - SOURCE_MERGE_LEN_SAMPLES * channels;


        src_samples = imd->rep[i]->data_len / sizeof(sample);
        skip        = insert_dur.ticks * channels - SOURCE_MERGE_LEN_SAMPLES;
        if (skip > src_samples - SOURCE_MERGE_LEN_SAMPLES * channels) {
                debug_msg("Clipping insert length\n");
                skip = src_samples - SOURCE_MERGE_LEN_SAMPLES * channels;
        }
        src = ((sample*)imd->rep[i]->data) + skip;

        xmemchk();
        audio_blend(dst, src, dst, channels * SOURCE_MERGE_LEN_SAMPLES, channels);
        xmemchk();
}

/* source_check_buffering is supposed to check amount of audio buffered      */
/* corresponds to what we expect from playout so we can think about skew     */
/* adjustment.                                                               */

int
source_check_buffering(source *src)
{
        timestamp_t actual, desired, diff;

	source_validate(src);
        if (src->post_talkstart_units < 20) {
                /* If the source is new(ish) then not enough audio will be   */
                /* in the playout buffer because it hasn't arrived yet.      */
                return FALSE;
        }

        actual  = source_get_audio_buffered(src);
        desired = source_get_playout_delay(src);
        diff    = ts_abs_diff(actual, desired);

        if (ts_gt(actual, desired) && ts_gt(diff, skew_thresh)) {
                src->skew_adjust = diff;
                /* We're accumulating audio, their clock faster   */
                src->skew = SOURCE_SKEW_FAST; 
                src->skew_cnt++;
		source_validate(src);
                return TRUE;
        } else if (ts_gt(desired, actual)) {
                /* We're short of audio, so their clock is slower */
                /* Lower bound is much harder than upper bound    */
                /* since mixer will dry up / repair will start to */
                /* be invoked as we decode units late.            */
                src->skew_adjust = diff;
                src->skew = SOURCE_SKEW_SLOW;
		source_validate(src);
                return TRUE;
        }
        src->skew = SOURCE_SKEW_NONE;
        src->skew_adjust = zero_ts;
	source_validate(src);
        return FALSE;
}

/* source_skew_adapt exists to shift playout units if source clock appears   */
/* to be fast or slow.  The media_data unit is here so that it can be        */
/* examined to see if it is low energy and adjustment would be okay.  Might  */
/* want to be more sophisticated and put a silence detector in rather than   */
/* static threshold.                                                         */
/*                                                                           */
/* Returns what adaption type occurred.                                      */

static skew_t
source_skew_adapt(source *src, media_data *md, timestamp_t playout)
{
        uint32_t i = 0, e = 0, samples = 0;
        uint32_t rate;
	uint16_t channels;
        timestamp_t adjustment, frame_dur;
        
	source_validate(src);
        assert(src);
        assert(md);
        assert(src->skew != SOURCE_SKEW_NONE);

        for(i = 0; i < md->nrep; i++) {
                if (codec_get_native_info(md->rep[i]->id, &rate, &channels)) {
                        samples = md->rep[i]->data_len / (channels * sizeof(sample));
                        e = audio_avg_energy((sample*)md->rep[i]->data, samples * channels, channels);
                        src->mean_energy = (15 * src->mean_energy + e)/16;
                        frame_dur = ts_map32(rate, samples);
                        break;
                }
        }

        if (i == md->nrep) {
                /* don't adapt if unit has not been decoded (error) or       */

⌨️ 快捷键说明

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