/* * "Write" a multichannel frame downstream. 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, 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 < PJMEDIA_PIA_CCNT(&this_port->info); ++ch) { pjmedia_port *port = sc->port_desc[ch].port; if (!port) continue; if (!sc->port_desc[ch].reversed) { pjmedia_port_put_frame(port, frame); } else { struct reverse_port *rport = (struct reverse_port*)port; /* Update the number of NULL frames received. Once we have too * many of this, we'll stop calling op_update() to let the * media be suspended. */ if (++rport->buf[DIR_DOWNSTREAM].null_cnt > rport->max_null_frames) { /* Prevent the counter from overflowing and resetting * back to zero */ rport->buf[DIR_DOWNSTREAM].null_cnt = rport->max_null_frames + 1; continue; } /* Write zero port to delaybuf so that it doesn't underflow. * If we don't do this, get_frame() on this direction will * cause delaybuf to generate missing frame and the last * frame transmitted to delaybuf will be replayed multiple * times, which doesn't sound good. */ /* Update rport state. */ op_update(rport, DIR_DOWNSTREAM, OP_PUT); /* Discard frame if rport is paused on this direction */ if (rport->buf[DIR_DOWNSTREAM].paused) continue; /* Generate zero frame. */ pjmedia_zero_samples(sc->put_buf, PJMEDIA_PIA_SPF(&port->info)); /* Put frame to delay buffer */ pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf, sc->put_buf); } } return PJ_SUCCESS; } /* Not sure how we would handle partial frame, so better reject * it for now. */ PJ_ASSERT_RETURN(frame->size == PJMEDIA_PIA_AVG_FSZ(&this_port->info), PJ_EINVAL); /* * Write mono frame into each channels */ for (ch=0; ch < PJMEDIA_PIA_CCNT(&this_port->info); ++ch) { pjmedia_port *port = sc->port_desc[ch].port; if (!port) continue; /* Extract the mono frame to temporary buffer */ extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch, PJMEDIA_PIA_CCNT(&this_port->info), (unsigned)frame->size * 8 / PJMEDIA_PIA_BITS(&this_port->info) / PJMEDIA_PIA_CCNT(&this_port->info)); if (!sc->port_desc[ch].reversed) { /* Write to normal port */ pjmedia_frame mono_frame; mono_frame.buf = sc->put_buf; mono_frame.size = frame->size / PJMEDIA_PIA_CCNT(&this_port->info); 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; /* Reset NULL frame counter */ rport->buf[DIR_DOWNSTREAM].null_cnt = 0; /* Update rport state. */ op_update(rport, DIR_DOWNSTREAM, OP_PUT); if (!rport->buf[DIR_DOWNSTREAM].paused) { pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf, sc->put_buf); } } } return PJ_SUCCESS; }
/* * "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(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(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; }