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

📄 mix.c

📁 将每一个声源加到混音缓冲器,经过处理后返回
💻 C
📖 第 1 页 / 共 2 页
字号:
		mix_advance_head(ms, playout_end);
	}

        /* Check for overlap in decoded frames */
        if (!ts_eq(pdbe->next_mix, playout)) {
                if (ts_gt(pdbe->next_mix, playout)) {
                        delta = ts_sub(pdbe->next_mix, playout);
                        if (ts_gt(frame_period, delta)) {
                                uint32_t  trim;
				/* Unit overlaps with earlier data written to buffer.
				 * Jump past overlapping samples, decrease number of
				 * samples that need to be written and correct playout
				 * so they are written to the correct place.
				 */
				delta     = ts_convert(ms->info.sample_rate, delta);
				trim      = delta.ticks * ms->info.channels;
				debug_msg("Mixer trimmed %d samples (Expected playout %d got %d) ssrc (0x%08x)\n",
					  trim, pdbe->next_mix.ticks, playout.ticks, pdbe->ssrc);
                                samples  += trim;
				nsamples -= trim;
				playout   = ts_add(playout, delta);
                        } else {
                                debug_msg("Skipped unit\n");
				return TRUE; /* Nothing to do but no fmt change */
			}
                } else {
			debug_msg("Gap between units %d %d ssrc 0x%08x\n", 
				pdbe->next_mix.ticks, 
				playout.ticks,
				pdbe->ssrc);
                }
        }

        /* Work out where to write the data (head_time > playout) */
        delta = ts_sub(ms->head_time, playout);
        pos = ms->head - delta.ticks * ms->info.channels;
        pos = (pos + ms->buf_len) % ms->buf_len; /* Handle wraps */
	
        if (pos + nsamples > (uint32_t)ms->buf_len) { 
                audio_mix_fn(ms->mix_buffer + pos, 
                             samples, 
                             ms->buf_len - pos); 
                audio_mix_fn(ms->mix_buffer, 
                             samples + (ms->buf_len - pos), 
                             pos + nsamples - ms->buf_len); 
        } else { 
                audio_mix_fn(ms->mix_buffer + pos, 
                             samples, 
                             nsamples); 
        } 
        xmemchk();
        pdbe->next_mix = playout_end;

        return TRUE;
}

/*
 * The mix_get_audio function returns a pointer to "request" samples of mixed 
 * audio data, suitable for playout (ie: you can do audio_device_write() with
 * the returned data).
 *
 * This function was modified so that it returns the amount of
 * silence at the end of the buffer returned so that the cushion
 * adjustment functions can use it to decrease the cushion.
 *
 * Note: "request" is number of samples to get and not sampling intervals!
 */

int
mix_get_audio(mixer_t *ms, int request, sample **bufp)
{
        int  silence, amount;
        timestamp_t delta;

        xmemchk();
        mix_verify(ms);
        amount = request;
        assert(amount < ms->buf_len);
        if (amount > ms->dist) {
		timestamp_t new_head_time;
                /*
		 * If we dont have enough to give one of two things
                 * must have happened.
                 * a) There was silence :-)
                 * b) There wasn't enough time to decode the stuff...
                 * In either case we will have to return silence for
                 * now so zero the rest of the buffer and move the head.
                 */
#ifdef DEBUG_MIX
                if (!ts_eq(ms->head_time, ms->tail_time)) {
                        /* Only print message if not-silent */
                        debug_msg("Insufficient audio: %d < %d\n", ms->dist, amount);
                }
#endif /* DEBUG_MIX */
                silence = amount - ms->dist;
		new_head_time = ts_add(ms->head_time,
				       ts_map32(ms->info.sample_rate, silence/ms->info.channels));
		mix_advance_head(ms, new_head_time);
        } else {
                silence = 0;
        }

        if (ms->tail + amount > ms->buf_len) {
                /*
                 * We have run into the end of the buffer so we will
                 * have to copy stuff before we return it.
                 * The space after the 'end' of the buffer is used
                 * for this purpose as the space before is used to
                 * hold silence that is returned in case the cushion
                 * grows too much.
                 * Of course we could use both here (depending on which
                 * direction involves less copying) and copy actual
                 * voice data in the case a cushion grows into it.
                 * The problem is that in that case we are probably in
                 * trouble and want to avoid doing too much...
                 *
                 * Also if the device is working in similar boundaries
                 * to our chunk sizes and we are a bit careful about the
                 * possible cushion sizes this case can be avoided.
                 */
                xmemchk();
                memcpy(ms->mix_buffer + ms->buf_len, ms->mix_buffer, BYTES_PER_SAMPLE*(ms->tail + amount - ms->buf_len));
                xmemchk();
#ifdef DEBUG_MIX
                debug_msg("Copying start of mix len: %d\n", ms->tail + amount - ms->buf_len);
#endif /* DEBUG_MIX */
        }

        mix_verify(ms);

        *bufp = ms->mix_buffer + ms->tail;
        delta = ts_map32(ms->info.sample_rate, amount/ms->info.channels);
        ms->tail_time = ts_add(ms->tail_time, delta);
                               
        ms->tail      += amount;
        ms->tail      %= ms->buf_len;
        ms->dist      -= amount;
        mix_verify(ms);

        return silence;
}

/*
 * We need the amount of time we went dry so that we can make a time
 * adjustment to keep in sync with the receive buffer etc...
 */
void
mix_new_cushion(mixer_t *ms, 
                int      last_cushion_size, 
                int      new_cushion_size, 
                int      dry_time, 
                sample **bufp)
{
        int diff, elapsed_time;

        debug_msg("Getting new cushion %d old %d\n", new_cushion_size, last_cushion_size);

        mix_verify(ms);
        elapsed_time = (last_cushion_size + dry_time);
        diff = abs(new_cushion_size - elapsed_time) * ms->info.channels;

        if (new_cushion_size > elapsed_time) {
                /*
                 * New cushion is larger so move tail back to get
                 * the right amount and end up at the correct time.
                 * The effect of moving the tail is that some old
                 * audio and/or silence will be replayed. We do not
                 * care to much as we are right after an underflow.
                 */
                ms->tail -= diff;
                if (ms->tail < 0) {
                        ms->tail += ms->buf_len;
                }
                ms->dist += diff;

                ms->tail_time = ts_sub(ms->tail_time,
                                       ts_map32(ms->info.sample_rate, diff/ms->info.channels));
                mix_verify(ms);
        } else if (new_cushion_size < elapsed_time) {
                /*
                 * New cushion is smaller so we have to throw away
                 * some audio.
                 */
                ms->tail += diff;
                ms->tail %= ms->buf_len;
                ms->tail_time = ts_add(ms->tail_time,
                                       ts_map32(ms->info.sample_rate, diff/ms->info.channels));
                if (diff > ms->dist) {
                        ms->head = ms->tail;
                        ms->head_time = ms->tail_time;
                        ms->dist = 0;
                } else {
                        ms->dist -= diff;
                }
                mix_verify(ms);
        }
        mix_verify(ms);
        mix_get_audio(ms, new_cushion_size * ms->info.channels, bufp);
        mix_verify(ms);
}

uint16_t
mix_get_energy(mixer_t *ms, uint16_t samples)
{
        sample        *bp;

        if (ms->tail < samples) {
                bp = ms->mix_buffer + ms->buf_len - samples * ms->info.channels;
        } else {
                bp = ms->mix_buffer + ms->tail - samples;
        }

        return audio_avg_energy(bp, samples, 1);
}

int
mix_active(mixer_t *ms)
{
        mix_verify(ms);
        return !ts_eq(ms->head_time, ms->tail_time);
}

const mixer_info_t *
mix_query(const mixer_t *ms)
{
	mix_verify(ms);
        if (ms == NULL) {
                return FALSE;
        }
        return &ms->info;
}

⌨️ 快捷键说明

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