Example #1
0
/*
 * "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;
}
Example #2
0
/*
 * "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;
}