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

📄 source.c

📁 处理声源,时间,做好各类资源的调整工作,为声音的输入输出做准备.
💻 C
📖 第 1 页 / 共 5 页
字号:
                /* signal has too much energy                                */
		source_validate(src);
                return SOURCE_SKEW_NONE;
        }

        /* When we are making the adjustment we must shift playout buffers   */
        /* and timestamps that the source decode process uses.  Must be      */
        /* careful with last repair because it is not valid if no repair has */
        /* taken place.                                                      */

        if (src->skew == SOURCE_SKEW_FAST && src->skew_cnt > 3) {
                /* source is fast so we need to bring units forward.
                 * Should only move forward at most a single unit
                 * otherwise we might discard something we have not
                 * classified.  */
                
                if (ts_gt(skew_limit, src->skew_adjust)) {
                        if (recommend_skew_adjust_dur(md, TRUE, &adjustment) == FALSE) {
                                /* No suitable adjustment found, and         */
                                /* adjustment is not urgent so bail here...  */ 
				source_validate(src);
                                return src->skew;
                        }
                } else {
                        /* Things are really skewed.  We're more than        */
                        /* skew_limit off of where we ought to be.  Just     */
                        /* drop a frame and don't worry.                     */
                        debug_msg("Dropping Frame\n");
                        adjustment = ts_div(src->pdbe->frame_dur, 2);
                }

                if (ts_gt(adjustment, src->skew_adjust) || adjustment.ticks == 0) {
                        /* adjustment needed is greater than adjustment      */
                        /* period that best matches dropable by signal       */
                        /* matching.                                         */
			source_validate(src);
                        return SOURCE_SKEW_NONE;
                }
                debug_msg("dropping %d / %d samples\n", adjustment.ticks, src->skew_adjust.ticks);
                pb_shift_forward(src->media,   adjustment);
                pb_shift_forward(src->channel, adjustment);

                src->samples_added     += adjustment.ticks;
                src->pdbe->transit      = ts_sub(src->pdbe->transit, adjustment);
                src->skew_cnt           = 0;
                /* avg_transit and last_transit are fine.  Difference in     */
                /* avg_transit and transit triggered this adjustment.        */

                if (ts_valid(src->last_repair)) {
                        src->last_repair = ts_sub(src->last_repair, adjustment);
                }

                src->next_played = ts_sub(src->next_played, adjustment);

                /* Remove skew adjustment from estimate of skew outstanding */
                if (ts_gt(src->skew_adjust, adjustment)) {
                        src->skew_adjust = ts_sub(src->skew_adjust, adjustment);
                } else {
                        src->skew = SOURCE_SKEW_NONE;
                }

                conceal_dropped_samples(md, adjustment); 
                xmemchk();
                
                return SOURCE_SKEW_FAST;
        } else if (src->skew == SOURCE_SKEW_SLOW) {
                media_data *fmd;
                timestamp_t        insert_playout;

                xmemchk();
                if (recommend_skew_adjust_dur(md, FALSE, &adjustment) == FALSE) {
                        debug_msg("bad match\n");
			source_validate(src);
                        return src->skew;
                }

                debug_msg("Insert %d samples\n", adjustment.ticks);
                pb_shift_units_back_after(src->media,   playout, adjustment);
                pb_shift_units_back_after(src->channel, playout, adjustment);
                src->pdbe->transit = ts_add(src->pdbe->transit, adjustment);

                /* Insert a unit: buffer looks like current frame -> gap of adjustment -> next frame */
                media_data_dup(&fmd, md);
                insert_playout = ts_add(playout, adjustment);
                xmemchk();
                if (pb_add(src->media, (u_char*)fmd, sizeof(media_data), insert_playout) == TRUE) {
                        xmemchk();
                        conceal_inserted_samples(md, fmd, adjustment);
                        xmemchk();
                } else {
                        debug_msg("Buffer push back: insert failed\n");
                        media_data_destroy(&fmd, sizeof(media_data));
                }

                if (ts_gt(adjustment, src->skew_adjust)) {
                        src->skew_adjust = zero_ts;
                } else {
                        src->skew_adjust = ts_sub(src->skew_adjust, adjustment);
                }

                src->samples_added -= adjustment.ticks;

                debug_msg("Playout buffer shift back %d samples.\n", adjustment.ticks);
                xmemchk();

                src->skew = SOURCE_SKEW_NONE;
		source_validate(src);
                return SOURCE_SKEW_SLOW;
        }

	source_validate(src);
        return SOURCE_SKEW_NONE;
}

static int
source_repair(source		*src,
              repair_id_t	r,
              timestamp_t	fill_ts) 
{
        media_data* fill_md, *prev_md;
        timestamp_t        prev_ts;
        uint32_t     success,  prev_len;

	source_validate(src);
        /* We repair one unit at a time since it may be all we need */
        if (pb_iterator_retreat(src->media_pos) == FALSE) {
                /* New packet when source still active, but dry, e.g. new talkspurt */
		timestamp_t start, end;
                debug_msg("Repair not possible no previous unit!\n"); 
		if (pb_get_start_ts(pb_iterator_get_playout_buffer(src->media_pos), 
								   &start) &&
		    pb_get_end_ts(pb_iterator_get_playout_buffer(src->media_pos),
								 &end)) {
			debug_msg("Range available [%d - %d] want %d\n",
				  timestamp_to_ms(start),
				  timestamp_to_ms(end),
				  timestamp_to_ms(fill_ts));
		}
		    
		source_validate(src);
                return FALSE;
        }

        pb_iterator_get_at(src->media_pos,
                           (u_char**)&prev_md,
                           &prev_len,
                           &prev_ts);

        media_data_create(&fill_md, 1);
        repair(r,
               src->consec_lost,
               src->codec_states,
               prev_md,
               fill_md->rep[0]);

        success = pb_add(src->media, 
                         (u_char*)fill_md,
                         sizeof(media_data),
                         fill_ts);

        if (success) {
                src->consec_lost++;
                src->last_repair = fill_ts;
                /* Advance to unit we just added */
                pb_iterator_advance(src->media_pos);
		debug_msg("Repair added %d\n", timestamp_to_ms(fill_ts));
        } else {
                /* This should only ever fail at when source changes
                 * sample rate in less time than playout buffer
                 * timeout.  This should be a very very rare event...  
                 */
                debug_msg("Repair add data failed %d.\n", timestamp_to_ms(fill_ts));
                media_data_destroy(&fill_md, sizeof(media_data));
                src->consec_lost = 0;
		src->hold_repair += 2; 
		source_validate(src);
                return FALSE;
        }
	source_validate(src);
        return TRUE;
}

static int
source_repair_required(source *src, timestamp_t playout)
{
	timestamp_t	 gap;

	/* Repair any gap in the audio stream. Conditions for repair:  */
	/* (a) playout point of unit is further away than expected.    */
	/* (b) playout point is not too far away (repair burns cycles) */
	/* (c) playout does not correspond to new talkspurt (don't     */
	/*     fill between end of last talkspurt and start of next).  */
	/*     NB Use post_talkstart_units as talkspurts maybe longer  */
	/*     than timestamp wrap period and want to repair even if   */
	/*     timestamps wrap.                                        */
	/* (d) not start of a talkspurt.                               */
	/* (e) don't have a hold on.                                   */
	gap = ts_sub(playout, src->next_played);
	if ((ts_gt(gap, zero_ts) && ts_gt(repair_max_gap, gap)) &&
	    ((ts_gt(src->next_played, src->talkstart) && 
	      ts_gt(playout, src->talkstart)) || src->post_talkstart_units > 100) &&
	    (src->hold_repair == 0)) {
		return TRUE;
	}
	/* Repair not needed, just maintain loss related variables */
	if (src->hold_repair) {
		src->hold_repair--;
	}
	src->consec_lost = 0;
	return FALSE;
}

void
source_process(session_t 	 *sp,
               source            *src, 
               timestamp_t        start_ts,    /* Real-world time           */
               timestamp_t        end_ts)      /* Real-world time + cushion */
{
        media_data  *md;
        coded_unit  *cu;
        codec_state *cs;
        uint32_t     md_len;
        timestamp_t  playout, step;
        uint32_t     sample_rate;
	uint16_t     channels;
	int	     i;

        /* Note: src->hold_repair is used to stop repair occuring.
         * Occasionally, there is a race condition when the playout
         * point is recalculated causing overlap, and when playout
         * buffer shift occurs in middle of a loss.
         */

	session_validate(sp);

	/* The call to source_process_packets() calculates the desired playout    */
	/* point for each packet and inserts it into the channel decoder input    */
	/* buffer (src->channel) at the correct time interval.                    */

	source_process_packets(sp, src, start_ts);	
        if (src->packets_done == 0) {
                return;
        }
	source_validate(src);

        /* Split channel coder units up into media units. This takes units from     */
	/* the channel decoder input buffer (src->channel) and, after decoding,     */
	/* adds them to the media buffer (src->media). The channel decoder may keep */
	/* the units for some time in-between these two buffers e.g. if there is j  */
	/* a block interleaver, output will not start until a complete block has    */
	/* been read in. Any intermediate buffer is hidden within the channel       */
	/* decoder, and is not visible here.                                        */
        if (pb_node_count(src->channel)) {
                channel_decoder_decode(src->channel_state, src->channel, src->media, end_ts);
        }
	source_validate(src);

	/* The following loop pulls data out of the media buffer (src->media) when */
	/* it's time to play it out. It then repairs any gaps in the audio stream, */
	/* decodes anything still in encoded form, performs skew adaptation and    */
	/* mixes the data ready for playout.                                       */
        while (ts_gt(end_ts, src->next_played) && pb_iterator_advance(src->media_pos)) {
		pb_iterator_get_at(src->media_pos, (u_char**)&md, &md_len, &playout);

		if (source_repair_required(src, playout)) {
			if (source_repair(src, sp->repair, src->next_played)) {
				/* Repair moves media buffer iterator to start of repaired */
				/* frames, need to get media iterator position */
				int success;
				debug_msg("Repair succeeded (% 2d got % 6d exp % 6d talks % 6d)\n", 
					  src->consec_lost, 
					  playout.ticks, 
					  src->next_played.ticks, 
					  src->talkstart.ticks);
				success = pb_iterator_get_at(src->media_pos, 
							     (u_char**)&md, &md_len, 
							     &playout);
				assert(success);
				assert(ts_eq(playout, src->next_played));
			}
		}

		/* At this point, md is the media data at the current playout point. */
		/* There may be multiple representations of the data, for example if */
		/* we are receiving a stream using redundancy.                       */
                assert(md     != NULL);
                assert(md_len == sizeof(media_data));
		assert(md->nrep < MAX_MEDIA_UNITS && md->nrep > 0);
		for(i = 0; i < md->nrep; i++) {
			assert(md->rep[i] != NULL);
			assert(codec_is_native_coding(md->rep[i]->id) || codec_id_is_valid(md->rep[i]->id));
		}

                if (ts_gt(playout, end_ts)) {
                        /* This playout point is after now so stop */
                        pb_iterator_retreat(src->media_pos);
                        break;
                }

                assert(md != NULL);
                assert(md_len == sizeof(media_data));
		assert(md->nrep < MAX_MEDIA_UNITS && md->nrep > 0);
		for(i = 0; i < md->nrep; i++) {
			assert(md->rep[i] != NULL);
			assert(codec_is_native_coding(md->rep[i]->id) || codec_id_is_valid(md->rep[i]->id));
		}

                if (!codec_is_native_coding(md->rep[md->nrep - 1]->id)) {
			/* If we've got to here, we have no native coding for this unit */
                        /* We need to decode this unit, may not have to when repair has */
			/* been used.                                                   */
                        for(i = 0; i < md->nrep; i++) {
                                /* If there is a native coding this unit has already */
				/* been decoded and this would be a bug.             */
                                assert(code

⌨️ 快捷键说明

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