linphone-developers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Linphone-developers] oRTP, multiple RTP streams and silence suppression


From: Mark Mickan
Subject: [Linphone-developers] oRTP, multiple RTP streams and silence suppression
Date: Wed, 01 Mar 2006 14:03:32 +1030
User-agent: Debian Thunderbird 1.0.2 (X11/20050331)

Hi all,

I'm having some problems with oRTP when handling more than one RTP stream containing silence suppression. The (attached) code works for multiple streams without silence suppression, but not with. It also works for one stream at a time with silence suppression.

Each stream is a burst of audio followed by a short silence followed by a burst of audio with the marker bit set on the first packet. Specifically, it is produced by Asterisk doing a Record() followed by a Playback().

I start the second stream about 5 seconds after the first one is started and each stream is a total of about 30 seconds. I've narrowed it down to the code blocking on the session_set_select() after the first stream has finished and when it should be receiving the second burst of audio from the second RTP stream.

Could this be a bug in oRTP, or am I doing something wrong?

Many thanks,
Mark
/**
 * This is an extract from the function which sets up a SIP call.
 * Specifically, these are the parts that relate to the setup of the
 * RTP streams we are having problems with.
 */
{
...
        if (call->local_sendrecv == SENDRECV)
                call->rtp = rtp_session_new(RTP_SESSION_SENDRECV);
        else if (call->local_sendrecv == SENDONLY)
                call->rtp = rtp_session_new(RTP_SESSION_SENDONLY);
        else if (call->local_sendrecv == RECVONLY)
                call->rtp = rtp_session_new(RTP_SESSION_RECVONLY);

        rtp_session_set_scheduling_mode(call->rtp, 1);  // enable scheduling 
mode
        rtp_session_set_blocking_mode(call->rtp, 0);    // do not enable 
blocking mode
        rtp_session_set_profile(call->rtp, &av_profile);
        rtp_session_set_payload_type(call->rtp, call->payload);
        rtp_session_enable_adaptive_jitter_compensation(call->rtp, TRUE);
        rtp_session_set_jitter_compensation(call->rtp, 40);
        rtp_session_set_local_addr(call->rtp, localip, 
call->local_sdp_audio_port);
        rtp_session_set_remote_addr(call->rtp, 
call->remote_sdp_audio_ip.c_str(), call->remote_sdp_audio_port);

        rtp_session_signal_connect(call->rtp, "telephone-event", (RtpCallback) 
recv_telephone_event, (long)call);
        rtp_session_signal_connect(call->rtp, "ssrc_changed", (RtpCallback) 
rtp_session_reset, 0);
...
}



/**
 * We use the single threaded method for reading RTP streams.  This
 * function is run in its own thread and is responsible for regularly
 * calling the RTPReadPending method.
 */
static void *mediareader(void *dummy)
{
        pthread_detach(pthread_self());

        SipControl *sipcontrol = SipControl::getInstance();

        while (1) {
                sipcontrol->RTPReadPending();
                usleep(1000);
        }
}

/**
 * The RTPReadPending method is responsible for checking for available
 * data on active RTP streams, reading that data and sending it to the
 * appropriate consumer of that data.
 */
void SipControl::RTPReadPending()
{
        SessionSet set;
        session_set_init(&set);

        // get the first of our active SIP channels
        ChannelData *trav = channels->GetChannel();

        // ...and traverse that list looking for calls that have been
        // answered.  This will give us the RTP streams to check if
        // they have pending data available
        if (trav) {
                int activechannels = 0;
                while (trav) {
                        if (trav->status == ANSWERED) {
                                session_set_set(&set, trav->rtp);
                                activechannels++;
                        }
                        trav = trav->next;
                }

                if (activechannels) {
                        // we have at least one active channel, so
                        // wait until there should be data for at
                        // least one of them
                        session_set_select(&set, NULL, NULL);

                        // ...and loop through them again to read
                        // that data and send it to the channel
                        // it is bridged to (if any)
                        mblk_t *mp;
                        trav = channels->GetChannel();
                        while (trav) {
                                if (trav->status == ANSWERED && 
session_set_is_set(&set, trav->rtp)) {
                                        int bytes_recvd = 0;
                                        if ((mp = 
rtp_session_recvm_with_ts(trav->rtp, trav->readts)) != NULL) {
                                                if ((bytes_recvd = 
mp->b_cont->b_wptr - mp->b_cont->b_rptr) > 0) {
                                                        // data is put in fifo 
and then consumed by the
                                                        // bridging code (not 
included in this code snippet)
                                                        fifo_write(trav->fifo, 
mp->b_cont->b_rptr, bytes_recvd);
                                                }
                                                freemsg(mp);
                                        }
                                        trav->readts += 160;
                                }
                                trav = trav->next;
                        }
                }
        }
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]