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

📄 source.c

📁 处理声源,时间,做好各类资源的调整工作,为声音的输入输出做准备.
💻 C
📖 第 1 页 / 共 5 页
字号:
                if (psf == NULL) {
                        fprintf(stderr, "Could not open playout.log\n");
                } else {
                        atexit(source_close_log);
                        fprintf(psf, "# <SSRC> <RTP timestamp> <talkstart> <jitter> <transit> <avg transit> <last transit> <playout del> <spike_var> <arr time>\n");
                }
                t0 = ts - 1000; /* -1000 in case of out of order first packet */
        }

        fprintf(psf, "0x%08x %.6f %5u %5u %5u %5u %5u %5u %5u %5u\n",
		src->pdbe->ssrc,
                (ts - t0)/8000.0,
                timestamp_to_ms(src->talkstart),
                timestamp_to_ms(src->pdbe->jitter),
                timestamp_to_ms(src->pdbe->transit),
                timestamp_to_ms(src->pdbe->avg_transit),
                timestamp_to_ms(src->pdbe->last_transit),
                timestamp_to_ms(src->pdbe->playout),
                timestamp_to_ms(src->spike_var),
                timestamp_to_ms(now)
                );
	source_validate(src);
}

#endif /* SOURCE_LOG_PLAYOUT */

static void
source_update_toged(source *src, int toged)
{
	source_validate(src);
        src->toged_mask <<= 1;
        src->toged_mask |= toged;
        src->toged_cont = 0;
        if (toged == 1) {
                int m;
                m = src->toged_mask & 0xff; /* Last 8 packets */
                while (m) {
                        src->toged_cont += (m & 1);
                        m >>= 1;
                }
        }
	source_validate(src);
}


static void
sanity_check_playout_time(timestamp_t now, timestamp_t playout)
{
	assert(ts_valid(now));
	assert(ts_valid(playout));
	/* Check that the calculated playout time is within 10 seconds */
	/* of the current time. This is an arbitrary check, but if it  */
	/* fails something has almost certainly gone wrong...          */
	assert(timestamp_to_ms(ts_abs_diff(now, playout)) < 10000);
}

static void
source_process_packets(session_t *sp, source *src, timestamp_t now)
{
	/* This function calculates the desired playout point for each packet and */
	/* inserts it into the channel decoder input buffer (src->channel) at the */
	/* correct time interval.                                                 */
        timestamp_t    src_ts, playout, transit;
        pdb_entry_t    *e;
        rtp_packet     *p;
        cc_id_t         ccid = -1;
        uint16_t        units_per_packet = -1;
        uint32_t        delta_ts, delta_seq;
        uint8_t         codec_pt;
        uint8_t         adjust_playout;

	source_validate(src);
        e = src->pdbe;

        /* Timing of startup is such that sometimes we get huge burst of packets */
        /* between source creation and first round of packet processing.  Causes */
        /* too much audio to be buffered and skew adjustment make lots of adjust */
        /* actions unnecessarily.                                                */
        if (src->packets_done == 0) {
                int16_t discarded = 0;
                while(pktbuf_get_count(src->pktbuf) > 1) {
                        pktbuf_dequeue(src->pktbuf, &p);
                        discarded++;
                        xfree(p);
                }
                if (discarded > 0) {
                        debug_msg("Discarded %d surplus packets\n", discarded);
                }
        }

	/* Loop for each new packet we have received...  */
        while(pktbuf_dequeue(src->pktbuf, &p)) {
                adjust_playout = FALSE;
                
                ccid = channel_coder_get_by_payload((u_char)p->pt);
                if (channel_verify_and_stat(ccid, (u_char)p->pt, p->data, p->data_len, &units_per_packet, &codec_pt) == FALSE) {
                        debug_msg("Packet discarded for ssrc 0x%08lx: packet failed channel verify.\n", e->ssrc);
                        xfree(p);
                        continue;
                }

                if (e->channel_coder_id != ccid || 
                    e->enc              != codec_pt || 
                    e->units_per_packet != units_per_packet ||
                    src->packets_done == 0) {
                        /* Either the channel coder, payload type or number of units */
			/* per packet has changed (or this is the first packet from  */
			/* this source, and so these have not been initialized). We  */
			/* reconfigure the source and update the user interface...   */
			const audio_format   	*dev_fmt = audio_get_ofmt(sp->audio_device);
			channel_describe_data(ccid, codec_pt, p->data, p->data_len, src->pdbe->enc_fmt, src->pdbe->enc_fmt_len);
                        source_reconfigure(src, ccid, codec_pt, units_per_packet, sp->converter, sp->render_3d,
                                           (uint32_t)dev_fmt->sample_rate,
                                           (uint16_t)dev_fmt->channels);
			if (sp->mbus_engine) {
				ui_send_stats(sp, sp->mbus_ui_addr, src->pdbe->ssrc);
			}
                        adjust_playout = TRUE;
		}

		/* We have a heap of conditions to check before we get to the  */
		/* playout calculation.  These are primarily to detect whether */
		/* we have a new talkspurt as indicated by marker bit, or an   */
		/* implicit new talkspurt indicated by change in relationship  */
		/* between timestamps or sequence numbers, or whether the      */
		/* config has changed at the receiver or sender.               */
		/*                                                             */
		/* We also have to check for "spikes" in packet arrivals as we */
		/* do not want to consider these packets in the playout        */
		/* calculation.                                                */

		/* Marker bit set: explicit indication of new talkspurt */
                if (p->m) {
                        adjust_playout = TRUE;
                        debug_msg("Adjusting playout: marker bit set\n");
                }
                
		/* Check for change in timestamp-sequence number relationship. */
		/* This is an implicit indication of a new talkspurt (e.g. if  */
		/* the packet containing the marker bit was lost.              */
                delta_seq = p->seq - e->last_seq;
                delta_ts  = p->ts  - e->last_ts;
                if (delta_seq * e->inter_pkt_gap != delta_ts) {
                        debug_msg("Adjusting playout: sequence number/timestamp realignment\n");
                        adjust_playout = TRUE;
                }

		/* transit is difference between our clock and their  */
		/* clock. Note, we have to put through sequencer      */
		/* because our time representation is shorter than    */
		/* RTP's 32bits.  Mapping use first order differences */
		/* to update time representation                      */
                src_ts = ts_seq32_in(&e->seq, e->sample_rate, p->ts);
                transit = ts_sub(now, src_ts);

		if (src->packets_done == 0  || ts_gt(ts_abs_diff(transit, e->transit), transit_jump)) {
			/* Need a fresh transit estimate */
			debug_msg("Transit estimate reset %s\n", (src->packets_done == 0)?"(first packet)":"");
			e->transit = e->last_transit = e->last_last_transit = transit;
			e->avg_transit = transit;
			adjust_playout = TRUE;
		}

		/* Check neither we nor source has changed sampling rate */
		if (ts_get_freq(transit) != ts_get_freq(e->last_transit)) {
			debug_msg("Adjusting playout: sampling rate change (either local or remote)\n");
			adjust_playout = TRUE;
			e->received = 0;
		}

                /* Spike adaptation - Ramjee, Kurose, Towsley, and Schulzerinne.   */
                /* Adaptive Playout Mechanisms for Packetized Audio Applications   */
                /* in Wide-Area Networks, IEEE Infocom 1994, pp 680-688.           */
                if (adjust_playout) {
			/* If we're about to adjust the playout point, we ignore spike events... */
			if (src->playout_mode == PLAYOUT_MODE_SPIKE) {
				debug_msg("Leaving spike mode due to required playout adjustment\n");
			}
                        src->playout_mode = PLAYOUT_MODE_NORMAL;
                } else {
			/* ...otherwise, we track spikes in the transit delay. */
                        timestamp_t delta_transit = ts_abs_diff(transit, e->last_transit);
                        if (ts_gt(delta_transit, spike_jump)) {
				/* Transit delay increased suddenly - this is a "spike" */
                                debug_msg("Entering spike mode (%d, %dHz) > (%d, %dHz))\n", 
					  delta_transit.ticks, ts_get_freq(delta_transit),
					  spike_jump.ticks, ts_get_freq(spike_jump));
				debug_msg("transit (%d, %dHz) last_transit (%d, %dHz)\n",
					  transit.ticks, ts_get_freq(transit),
					  e->last_transit.ticks, ts_get_freq(e->last_transit));
                                src->playout_mode = PLAYOUT_MODE_SPIKE;
                                src->spike_var    = zero_ts;
                                e->spike_events++;
                        } else {
				if (src->playout_mode == PLAYOUT_MODE_SPIKE) {
					timestamp_t delta_var;
					src->spike_var = ts_div(src->spike_var, 2);
					delta_var = ts_add(ts_abs_diff(transit, e->last_transit),
							   ts_abs_diff(transit, e->last_last_transit));
					delta_var = ts_div(delta_var, 8);
					src->spike_var = ts_add(src->spike_var, delta_var);
					if (ts_gt(spike_end, src->spike_var)) {
						debug_msg("Leaving spike mode\n");
						src->playout_mode = PLAYOUT_MODE_NORMAL;
					}
				}
                        }
                }

                /* Check for continuous number of packets being discarded.   */
                /* This happens when jitter or transit estimate is no longer */
                /* consistent with the real world.                           */
                if (src->toged_cont >= NO_TOGED_CONT_FOR_PLAYOUT_RECALC) {
                        debug_msg("Adjusting playout: many consecutive discarded packets\n");
                        adjust_playout  = TRUE;
                        src->toged_cont = 0;
                        /* We've been dropping packets so take a new transit */
                        /* estimate and discard all existing transit info.   */
			e->transit = e->last_transit = e->last_last_transit = transit;
			e->avg_transit = transit;
                }
                
                if (adjust_playout && (ts_gt(ts_sub(now, e->last_arr), transit_reset) || (e->received < 20))) {
                        /* Source has been quiet for a long time.  Discard   */
                        /* old average transit estimate.                     */
			debug_msg("Average transit reset (%d -> %d)\n", timestamp_to_ms(transit), timestamp_to_ms(e->avg_transit));
			e->transit           = transit;
			e->last_transit      = transit;
			e->last_last_transit = transit;
			e->avg_transit       = transit;
                }

                /* Calculate the playout point for this packet.              */
                /* Playout calc updates avg_transit and jitter.              */
                /* Do not call if in spike mode as it distorts both.         */
                if (src->playout_mode == PLAYOUT_MODE_NORMAL) {
                        playout = playout_calc(sp, e->ssrc, transit, adjust_playout);
                } else {
                        playout = e->playout;
			debug_msg("in spike\n");
                }
                playout = ts_add(e->transit, playout);
                playout = ts_add(src_ts, playout);
		debug_msg("%d %d\n", timestamp_to_ms(playout), timestamp_to_ms(now));
		sanity_check_playout_time(now, playout);

		/* At this point we know the desired playout time for this packet, */
		/* and adjust_playout is set if this has changed from the previous */
		/* packet.                                                         */
                if (adjust_playout) {
                        if (ts_gt(playout, now) == FALSE) {
                                /* This is the first packet in this spurt and */
                                /* it would not have been played out.  Push   */
                                /* back to point where it will...             */
                                /* This usually happens because of VAD check  */
                                /* above...                                   */
                                timestamp_t shortfall = ts_sub(now, playout);
                                /* And then a little more...                  */
                                shortfall  = ts_add(shortfall, e->frame_dur);
                                e->playout = ts_add(e->playout, shortfall);
                                playout    = ts_add(playout, shortfall);
                                debug_msg("Pushed back first packet - would have missed playout time\n");
                                assert(ts_gt(playout, now));
                        }
                        if (ts_valid(src->next_played) && ts_gt(src->next_played, playout)) {
                                /* Talkspurts would have overlapped.  May     */
                                /* cause problems for redundancy decoder.     */
                                /* Don't take any chances.                    */
                                timestamp_t overlap = ts_sub(src->next_played, playout);
                                debug_msg("Overlap %d us (next_played %d (%dhz) playout %d (%dHz))\n", 
					  timestamp_to_us(overlap), 
					  src->next_played.ticks, ts_get_freq(src->next_played),
					  playout.ticks, ts_get_freq(playout));
                                e->playout   = ts_add(e->playout, overlap);
                                playout      = ts_add(playout, overlap);
                        }
                        src->talkstart = playout; /* Note start of new talkspurt  */
                        src->post_talkstart_units = 0;
                } else {
                        src->post_talkstart_units++;
                }

                if (src->packets_done == 0) {
                        /* This is first packet so expect next played to have its */
                        /* playout.                                               */
                        src->next_played = playout;
                }

		sanity_check_playout_time(now, playout);

                if (ts_gt(now, playout)) {
                        /* Packet being decoded is before start of current   */
                        /* so there is now way it's audio will be played     */
                        /* Playout recalculation gets triggered in           */
                        /* rtp_callback if toged_cont hits a critical        */
                        /* threshold.  It signifies current playout delay    */
                        /* is inappropriate.                                 */
                        if (src->playout_mode == PLAYOUT_MODE_NORMAL) {
                                debug_msg("Packet late (compared to now)\n");
                                source_update_toged(src, 1);
                                src->pdbe->jit_toged++;
                        } else {
                                /* Spike mode - don't worry about jit_toged  */
                                src->pdbe->spike_toged++;
                        }
                } else {
			/* This packet arrived in time to be played out. We  */
			/* add it to the channel decoder buffer at the point */
			/* determined by the playout delay.                  */
                        u_char  *u = (u_char*)block_alloc(p->data_len);
                        memcpy(u, p->data, p->data_len);
                        if (source_process_packet(src, u, p->data_len, codec_pt, playout) == FALSE) {
				debug_msg("Unwanted packet?\n");
                                block_free(u, (int)p->data_len);
                        }

⌨️ 快捷键说明

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