📄 mix.c
字号:
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 + -