📄 splitcomb.c
字号:
out += ch;
for (i=0; i<samples_count; ++i) {
*out = *in++;
out += ch_cnt;
}
}
/*
* "Write" a multichannel frame. This would split the multichannel frame
* into individual mono channel, and write it to the appropriate port.
*/
static pj_status_t put_frame(pjmedia_port *this_port,
const pjmedia_frame *frame)
{
struct splitcomb *sc = (struct splitcomb*) this_port;
unsigned ch;
/* Handle null frame */
if (frame->type == PJMEDIA_FRAME_TYPE_NONE) {
for (ch=0; ch < this_port->info.channel_count; ++ch) {
pjmedia_port *port = sc->port_desc[ch].port;
if (!port) continue;
pjmedia_port_put_frame(port, frame);
}
return PJ_SUCCESS;
}
/* Not sure how we would handle partial frame, so better reject
* it for now.
*/
PJ_ASSERT_RETURN(frame->size == this_port->info.bytes_per_frame,
PJ_EINVAL);
/*
* Write mono frame into each channels
*/
for (ch=0; ch < this_port->info.channel_count; ++ch) {
pjmedia_port *port = sc->port_desc[ch].port;
if (!port)
continue;
if (!sc->port_desc[ch].reversed) {
/* Write to normal port */
pjmedia_frame mono_frame;
/* Extract the mono frame */
extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch,
this_port->info.channel_count,
frame->size * 8 /
this_port->info.bits_per_sample /
this_port->info.channel_count);
mono_frame.buf = sc->put_buf;
mono_frame.size = frame->size / this_port->info.channel_count;
mono_frame.type = frame->type;
mono_frame.timestamp.u64 = frame->timestamp.u64;
/* Write */
pjmedia_port_put_frame(port, &mono_frame);
} else {
/* Write to reversed phase port */
struct reverse_port *rport = (struct reverse_port*)port;
if (rport->dn_write_pos == rport->dn_read_pos) {
/* Only report overflow if the frame is constantly read
* by the 'consumer' of the reverse port.
* It is possible that nobody reads the buffer, so causing
* overflow to happen rapidly, and writing log message this
* way does not seem to be wise.
*/
if (rport->dn_read_pos != rport->dn_overflow_pos) {
rport->dn_overflow_pos = rport->dn_read_pos;
LOG_DN_((THIS_FILE, "Overflow in downstream direction"));
}
/* Adjust write position */
rport->dn_write_pos =
(rport->dn_write_pos + rport->buf_cnt/2) %
rport->buf_cnt;
}
/* Extract mono-frame and put it in downstream buffer */
extract_mono_frame((const pj_int16_t*)frame->buf,
rport->dnstream_buf[rport->dn_write_pos],
ch, this_port->info.channel_count,
frame->size * 8 /
this_port->info.bits_per_sample /
this_port->info.channel_count);
rport->dn_write_pos = (rport->dn_write_pos + 1) %
rport->buf_cnt;
}
}
return PJ_SUCCESS;
}
/*
* Get a multichannel frame.
* This will get mono channel frame from each port and put the
* mono frame into the multichannel frame.
*/
static pj_status_t get_frame(pjmedia_port *this_port,
pjmedia_frame *frame)
{
struct splitcomb *sc = (struct splitcomb*) this_port;
unsigned ch;
pj_bool_t has_frame = PJ_FALSE;
/* Clear output frame */
pjmedia_zero_samples((pj_int16_t*)frame->buf,
this_port->info.samples_per_frame);
/* Read frame from each port */
for (ch=0; ch < this_port->info.channel_count; ++ch) {
pjmedia_port *port = sc->port_desc[ch].port;
pjmedia_frame mono_frame;
pj_status_t status;
if (!port)
continue;
/* Read from the port */
if (sc->port_desc[ch].reversed == PJ_FALSE) {
/* Read from normal port */
mono_frame.buf = sc->get_buf;
mono_frame.size = port->info.bytes_per_frame;
mono_frame.timestamp.u64 = frame->timestamp.u64;
status = pjmedia_port_get_frame(port, &mono_frame);
if (status != PJ_SUCCESS ||
mono_frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
{
continue;
}
/* Combine the mono frame into multichannel frame */
store_mono_frame((const pj_int16_t*)mono_frame.buf,
(pj_int16_t*)frame->buf, ch,
this_port->info.channel_count,
mono_frame.size * 8 /
this_port->info.bits_per_sample);
frame->timestamp.u64 = mono_frame.timestamp.u64;
} else {
/* Read from temporary buffer for reverse port */
struct reverse_port *rport = (struct reverse_port*)port;
/* Check for underflows */
if (rport->up_read_pos == rport->up_write_pos) {
/* Only report underflow if the buffer is constantly filled
* up at the other side.
* It is possible that nobody writes the buffer, so causing
* underflow to happen rapidly, and writing log message this
* way does not seem to be wise.
*/
if (rport->up_write_pos != rport->up_underflow_pos) {
rport->up_underflow_pos = rport->up_write_pos;
LOG_UP_((THIS_FILE, "Underflow in upstream direction"));
}
/* Adjust read position */
rport->up_read_pos =
(rport->up_write_pos - rport->buf_cnt/2) %
rport->buf_cnt;
}
TRACE_UP_((THIS_FILE, "Upstream read at buffer pos %d",
rport->up_read_pos));
/* Combine the mono frame into multichannel frame */
store_mono_frame((const pj_int16_t*)rport->upstream_buf[rport->up_read_pos],
(pj_int16_t*)frame->buf, ch,
this_port->info.channel_count,
port->info.samples_per_frame);
rport->up_read_pos = (rport->up_read_pos + 1) %
rport->buf_cnt;
}
has_frame = PJ_TRUE;
}
/* Return NO_FRAME is we don't get any frames from downstream ports */
if (has_frame) {
frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
frame->size = this_port->info.bytes_per_frame;
} else
frame->type = PJMEDIA_FRAME_TYPE_NONE;
return PJ_SUCCESS;
}
static pj_status_t on_destroy(pjmedia_port *this_port)
{
/* Nothing to do */
PJ_UNUSED_ARG(this_port);
return PJ_SUCCESS;
}
/*
* Get a mono frame from a reversed phase channel.
*/
static pj_status_t rport_put_frame(pjmedia_port *this_port,
const pjmedia_frame *frame)
{
struct reverse_port *rport = (struct reverse_port*) this_port;
unsigned count;
pj_assert(frame->size <= rport->base.info.bytes_per_frame);
/* Check for overflows */
if (rport->up_write_pos == rport->up_read_pos) {
/* Only report overflow if the frame is constantly read
* at the other end of the buffer (the multichannel side).
* It is possible that nobody reads the buffer, so causing
* overflow to happen rapidly, and writing log message this
* way does not seem to be wise.
*/
if (rport->up_read_pos != rport->up_overflow_pos) {
rport->up_overflow_pos = rport->up_read_pos;
LOG_UP_((THIS_FILE, "Overflow in upstream direction"));
}
/* Adjust the write position */
rport->up_write_pos = (rport->up_read_pos + rport->buf_cnt/2) %
rport->buf_cnt;
}
/* Handle NULL frame */
if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) {
TRACE_UP_((THIS_FILE, "Upstream write %d null samples at buf pos %d",
this_port->info.samples_per_frame, rport->up_write_pos));
pjmedia_zero_samples(rport->upstream_buf[rport->up_write_pos],
this_port->info.samples_per_frame);
rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt;
return PJ_SUCCESS;
}
/* Not sure how to handle partial frame, so better reject for now */
PJ_ASSERT_RETURN(frame->size == this_port->info.bytes_per_frame,
PJ_EINVAL);
/* Copy normal frame to curcular buffer */
count = frame->size * 8 / this_port->info.bits_per_sample;
TRACE_UP_((THIS_FILE, "Upstream write %d samples at buf pos %d",
count, rport->up_write_pos));
pjmedia_copy_samples(rport->upstream_buf[rport->up_write_pos],
(const pj_int16_t*) frame->buf, count);
rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt;
return PJ_SUCCESS;
}
/*
* Get a mono frame from a reversed phase channel.
*/
static pj_status_t rport_get_frame(pjmedia_port *this_port,
pjmedia_frame *frame)
{
struct reverse_port *rport = (struct reverse_port*) this_port;
unsigned count;
count = rport->base.info.samples_per_frame;
frame->size = this_port->info.bytes_per_frame;
frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
/* Check for underflows */
if (rport->dn_read_pos == rport->dn_write_pos) {
/* Only report underflow if the buffer is constantly filled
* up at the other side.
* It is possible that nobody writes the buffer, so causing
* underflow to happen rapidly, and writing log message this
* way does not seem to be wise.
*/
if (rport->dn_write_pos != rport->dn_underflow_pos) {
rport->dn_underflow_pos = rport->dn_write_pos;
LOG_DN_((THIS_FILE, "Underflow in downstream direction"));
}
/* Adjust read position */
rport->dn_read_pos =
(rport->dn_write_pos - rport->buf_cnt/2) % rport->buf_cnt;
}
/* Get the samples from the circular buffer */
pjmedia_copy_samples((pj_int16_t*)frame->buf,
rport->dnstream_buf[rport->dn_read_pos],
count);
rport->dn_read_pos = (rport->dn_read_pos+1) % rport->buf_cnt;
return PJ_SUCCESS;
}
static pj_status_t rport_on_destroy(pjmedia_port *this_port)
{
/* Nothing to do */
PJ_UNUSED_ARG(this_port);
return PJ_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -