From 8c5e5dd5b68bc25ccd881e25f3a7280425fb5821 Mon Sep 17 00:00:00 2001
From: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
Date: Fri, 16 Jul 2010 17:19:32 -0400
Subject: [PATCH] [#3366] Handle early media received from RTP

---
 sflphone-common/src/audio/alsa/alsalayer.cpp  |   8 +-
 .../src/audio/audiortp/AudioRtpSession.h      |  13 ++-
 .../audio/audiortp/AudioSymmetricRtpSession.h |   2 +-
 .../src/audio/pulseaudio/pulselayer.cpp       |  11 +-
 sflphone-common/src/managerimpl.cpp           |  46 ++++----
 sippxml/testEarlyMedia.xml                    | 107 ++++++++++++++++++
 6 files changed, 150 insertions(+), 37 deletions(-)
 create mode 100644 sippxml/testEarlyMedia.xml

diff --git a/sflphone-common/src/audio/alsa/alsalayer.cpp b/sflphone-common/src/audio/alsa/alsalayer.cpp
index 89e6f41513..5c19f3da8c 100644
--- a/sflphone-common/src/audio/alsa/alsalayer.cpp
+++ b/sflphone-common/src/audio/alsa/alsalayer.cpp
@@ -947,7 +947,9 @@ void AlsaLayer::audioCallback(void)
 
     } else {
 
-        if (tone) {
+        normalAvailBytes = getMainBuffer()->availForGet();
+
+        if (tone && (normalAvailBytes <= 0)) {
 
             out = (SFLDataFormat *) malloc (playbackAvailBytes);
             tone->getNext (out, playbackAvailSmpl, spkrVolume);
@@ -957,7 +959,7 @@ void AlsaLayer::audioCallback(void)
             out = 0;
 	   
 	}
-	else if (file_tone && !_RingtoneHandle) {
+	else if (file_tone && !_RingtoneHandle && (normalAvailBytes <= 0)) {
 
 	    out = (SFLDataFormat *) malloc (playbackAvailBytes);
 	    file_tone->getNext (out, playbackAvailSmpl, spkrVolume);
@@ -985,8 +987,6 @@ void AlsaLayer::audioCallback(void)
 
             } 
 
-
-            normalAvailBytes = getMainBuffer()->availForGet();
             toGet = (normalAvailBytes < (int) maxNbBytesToGet) ? normalAvailBytes : maxNbBytesToGet;
 
             out = (SFLDataFormat*) malloc (maxNbBytesToGet);
diff --git a/sflphone-common/src/audio/audiortp/AudioRtpSession.h b/sflphone-common/src/audio/audiortp/AudioRtpSession.h
index 5144d37679..cd4f7edc3c 100644
--- a/sflphone-common/src/audio/audiortp/AudioRtpSession.h
+++ b/sflphone-common/src/audio/audiortp/AudioRtpSession.h
@@ -574,8 +574,10 @@ namespace sfl {
         // set available byte to maxByteToGet
         int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
 
-        if (bytesAvail == 0)
-            return 0;
+        if (bytesAvail == 0) {
+	  memset(_micDataEncoded, 0, sizeof(SFLDataFormat));
+	  return _audiocodec->getFrameSize();
+	}
 
         // Get bytes from micRingBuffer to data_from_mic
         int nbSample = _manager->getAudioDriver()->getMainBuffer()->getData(_micData , bytesAvail, 100, _ca->getCallId()) / sizeof (SFLDataFormat);
@@ -693,6 +695,7 @@ namespace sfl {
     template <typename D>
     void AudioRtpSession<D>::receiveSpeakerData ()
     {
+
         if (!_audiolayer) {
             _debug ("No audiolayer available for speaker");
             return;
@@ -707,8 +710,9 @@ namespace sfl {
 	int packetTimestamp = static_cast<D*>(this)->getFirstTimestamp();
         adu = static_cast<D*>(this)->getData(packetTimestamp);
 
-	if(!adu)
+	if(!adu) {
 	  return;
+	}
 
 	unsigned char* spkrDataIn = NULL;
 	unsigned int size = 0;
@@ -723,8 +727,6 @@ namespace sfl {
 	  spkrDataIn  = (unsigned char*) adu->getData(); // data in char
 	  size = adu->getSize(); // size in char
 
-	  
-
 	  result = jb_put(_jbuffer, spkrDataIn, JB_TYPE_VOICE, _packetLength, _ts+=20, _currentTime);
 
 	}
@@ -758,6 +760,7 @@ namespace sfl {
     template <typename D>
     void AudioRtpSession<D>::run ()
     {
+
 	// Timestamp must be initialized randomly
 	_timestamp = static_cast<D*>(this)->getCurrentTimestamp();
 
diff --git a/sflphone-common/src/audio/audiortp/AudioSymmetricRtpSession.h b/sflphone-common/src/audio/audiortp/AudioSymmetricRtpSession.h
index 0713f3db0c..c1260a6fc3 100644
--- a/sflphone-common/src/audio/audiortp/AudioSymmetricRtpSession.h
+++ b/sflphone-common/src/audio/audiortp/AudioSymmetricRtpSession.h
@@ -40,7 +40,7 @@ namespace sfl {
     {
         public:
         AudioSymmetricRtpSession(ManagerImpl * manager, SIPCall * sipcall) :
-            ost::SymmetricRTPSession(ost::InetHostAddress(sipcall->getLocalIp().c_str()), sipcall->getLocalAudioPort()),
+      ost::SymmetricRTPSession(ost::InetHostAddress(sipcall->getLocalIp().c_str()), sipcall->getLocalAudioPort()),
             AudioRtpSession<AudioSymmetricRtpSession>(manager, sipcall)
         {
             _debug("AudioSymmetricRtpSession initialized\n");
diff --git a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp
index 403ec11ad0..667f0cf272 100755
--- a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp
+++ b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp
@@ -798,7 +798,6 @@ void PulseLayer::writeToSpeaker (void)
     SFLDataFormat* out;// = (SFLDataFormat*)pa_xmalloc(framesPerBuffer);
     urgentAvailBytes = _urgentRingBuffer.AvailForGet();
 
-
     // available bytes to be written in pulseaudio internal buffer
     int writeableSize = pa_stream_writable_size (playback->pulseStream());
 
@@ -821,12 +820,16 @@ void PulseLayer::writeToSpeaker (void)
 
     } else {
 
+        // Get ringtone
         AudioLoop* tone = _manager->getTelephoneTone();
 
+	// We must test if data have been received from network in case of early media
+	normalAvailBytes = getMainBuffer()->availForGet();
+
         // flush remaining samples in _urgentRingBuffer
         flushUrgent();
 
-        if (tone != 0) {
+        if ((tone != 0) && (normalAvailBytes <= 0)) {
 
             if (playback->getStreamState() == PA_STREAM_READY) {
 
@@ -845,9 +848,7 @@ void PulseLayer::writeToSpeaker (void)
 
             int maxNbBytesToGet = 0;
 
-
             // test if audio resampling is needed
-
             if (_mainBufferSampleRate && ( (int) _audioSampleRate != _mainBufferSampleRate)) {
 
                 // upsamplefactor is used to compute the number of bytes to get in the ring buffer
@@ -862,8 +863,6 @@ void PulseLayer::writeToSpeaker (void)
 
             }
 
-            normalAvailBytes = getMainBuffer()->availForGet();
-
             byteToGet = (normalAvailBytes < (int) (maxNbBytesToGet)) ? normalAvailBytes : maxNbBytesToGet;
 
             if (byteToGet) {
diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp
index 8eafb6212d..662c7f1646 100755
--- a/sflphone-common/src/managerimpl.cpp
+++ b/sflphone-common/src/managerimpl.cpp
@@ -1355,38 +1355,42 @@ void ManagerImpl::addStream (const CallID& call_id) {
 
 	if (participToConference(call_id)) {
 
-		// bind to conference participant
-		ConferenceMap::iterator iter = _conferencemap.find(call->getConfId());
+	  _debug("Manager: Add stream to conference");
 
-		if (iter != _conferencemap.end()) {
-			Conference* conf = iter->second;
+	  // bind to conference participant
+	  ConferenceMap::iterator iter = _conferencemap.find(call->getConfId());
 
-			conf->bindParticipant(call_id);
+	  if (iter != _conferencemap.end()) {
+	    Conference* conf = iter->second;
 
-			ParticipantSet participants = conf->getParticipantList();
-			// reset ring buffer for all conference participant
-			ParticipantSet::iterator iter_p = participants.begin();
+	    conf->bindParticipant(call_id);
 
-			while (iter_p != participants.end()) {
+	    ParticipantSet participants = conf->getParticipantList();
+	    // reset ring buffer for all conference participant
+	    ParticipantSet::iterator iter_p = participants.begin();
 
-				// to avoid puting onhold the call
-				// switchCall("");
-				_audiodriver->getMainBuffer()->flush(*iter_p);
+	    while (iter_p != participants.end()) {
 
-				iter_p++;
-			}
+	      // to avoid puting onhold the call
+	      // switchCall("");
+	      _audiodriver->getMainBuffer()->flush(*iter_p);
+	      
+	      iter_p++;
+	    }
 
-			_audiodriver->getMainBuffer()->flush(default_id);
-		}
+	    _audiodriver->getMainBuffer()->flush(default_id);
+	  }
 
 	} else {
 
-		// bind to main
-		getAudioDriver()->getMainBuffer()->bindCallID(call_id);
+	  _debug("Manager: Add stream to call"); 
 
-		// _audiodriver->getMainBuffer()->flush(default_id);
-		_audiodriver->flushUrgent();
-		_audiodriver->flushMain();
+	  // bind to main
+	  getAudioDriver()->getMainBuffer()->bindCallID(call_id);
+	  
+	  // _audiodriver->getMainBuffer()->flush(default_id);
+	  _audiodriver->flushUrgent();
+	  _audiodriver->flushMain();
 
 	}
 
diff --git a/sippxml/testEarlyMedia.xml b/sippxml/testEarlyMedia.xml
new file mode 100644
index 0000000000..28f34ff4f0
--- /dev/null
+++ b/sippxml/testEarlyMedia.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- sudo sipp -sf testEarlyMedia.xml 127.0.0.1 -i 127.0.0.1 -p 5062 -l 1 -m 1 -mp 6000 -->
+
+<scenario name="Basic UAS responder">
+
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+
+ <send>
+   <![CDATA[
+
+     SIP/2.0 100 Ringing
+     [last_Via:]
+     [last_From:]
+     [last_To:];tag=[call_number]
+     [last_Call-ID:]
+     [last_CSeq:]
+     Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+     Content-Length: 0
+
+   ]]>
+ </send>
+
+ <send>
+   <![CDATA[
+
+     SIP/2.0 183 Trying
+     [last_Via:]
+     [last_From:]
+     [last_To:];tag=[call_number]
+     [last_Call-ID:]
+     [last_CSeq:]
+     Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+     Content-Type: application/sdp
+     Content-Length: [len]
+
+     v=0
+     o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+     s=-
+     c=IN IP[media_ip_type] [media_ip]
+     t=0 0
+     m=audio [media_port] RTP/AVP 0
+     a=rtpmap:0 PCMU/8000
+
+   ]]>
+ </send>
+
+ <!-- Play a pre-recorded PCAP file (RTP stream) -->
+  <nop>
+    <action>
+      <exec play_pcap_audio="g711a.pcap"/>
+    </action>
+  </nop>
+
+  <!-- Pause 8 seconds, which is approximately the duration of the -->
+  <!-- PCAP file -->
+  <pause milliseconds="8000"/>
+
+ <send retrans="500">
+   <![CDATA[
+
+     SIP/2.0 200 OK
+     [last_Via:]
+     [last_From:]
+     [last_To:];tag=[call_number]
+     [last_Call-ID:]
+     [last_CSeq:]
+     Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+     Content-Length: [len]
+
+   ]]>
+ </send>
+
+ <recv request="ACK"
+       optional="true"
+       rtd="true"
+       crlf="true">
+ </recv>
+
+ <recv request="BYE">
+ </recv>
+
+ <send>
+   <![CDATA[
+
+     SIP/2.0 200 OK
+     [last_Via:]
+     [last_From:]
+     [last_To:]
+     [last_Call-ID:]
+     [last_CSeq:]
+     Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+     Content-Length: 0
+
+   ]]>
+ </send>
+
+ <pause milliseconds="4000"/>
+
+
+ <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+ <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario> 
-- 
GitLab