Problems with Opus, Grandstream HT802, directmedia, native_rtp

Hi,

I am working on getting our new ATAs (Grandstream HT802) to work with our system with the Opus codec. I am relatively new to Asterisk so I will do my best to describe what I see happening. If you need any more information, please let me know.

It works fine if each endpoint is configured with ‘allow=ulaw’. Calls work between endpoints with direct media enabled as well. I have issues when using ‘allow=opus,ulaw’ or ‘allow=opus’. We have a SIP trunk that only allows ulaw so I would like calls between endpoints to preferably use Opus and fallback to ulaw for outgoing calls to the trunk.

We are using Asterisk 13.13.1 but I currently have installed the latest 13 branch from the Asterisk git repo. I read this issue: https://issues.asterisk.org/jira/browse/ASTERISK-26666 and thought it may have something to do with our problem. Unfortunately, the issue persists with this version.

I have tried several softphones to compare. X-Lite, Jitsi work with Opus. A softphone called Blind does the same thing as the Grandstream HT802. Others like the Grandstream Wave app for Android, do not send the /2 in rtpmap in the SDP so Asterisk ignores the request to use Opus. This is a different issue altogether though - I just want to get the ATAs to work.

I have an ATA bridged through my computer to capture packets through Wireshark.

I am calling a test number through our SIP trunk, ATA set to use opus,ulaw, trunk set to use ulaw, directmedia is disabled. In this scenario, I get one way audio; I do not receive audio back from the trunk to my ATA. Asterisk creates a native_rtp bridge for this call.

voip*CLI> pjsip show channelstats

                                             ...........Receive......... .........Transmit..........
 BridgeId ChannelId ........ UpTime.. Codec.   Count    Lost Pct  Jitter   Count    Lost Pct  Jitter RTT....
 ===========================================================================================================

 dbbf0e61 000b8296aec2-00000 00:00:19 ulaw     1774   12970  731   0.000    895       0    0   0.000   0.000
 dbbf0e61 voipms-00000080    00:00:19 ulaw      905       0    0   0.000    887       0    0   0.000   0.000

voip*CLI> core show channel PJSIP/000b8296aec2-0000007f 
 -- General --
           Name: PJSIP/000b8296aec2-0000007f
           Type: PJSIP
       UniqueID: 1484848484.130
       LinkedID: 1484848484.130
...
  NativeFormats: (opus|ulaw)
    WriteFormat: opus
     ReadFormat: opus
 WriteTranscode: No 
  ReadTranscode: No 
 Time to Hangup: 0
   Elapsed Time: 0h2m17s
      Bridge ID: dbbf0e61-fbd5-4543-b090-c92504f5ce1f

voip*CLI> core show channel PJSIP/voipms-00000080 
 -- General --
           Name: PJSIP/voipms-00000080
           Type: PJSIP
       UniqueID: 1484848484.131
       LinkedID: 1484848484.130
...    
  NativeFormats: (ulaw)
    WriteFormat: opus
     ReadFormat: ulaw
 WriteTranscode: Yes (opus@48000)->(slin@48000)->(slin@8000)->(ulaw@8000)
  ReadTranscode: No 
 Time to Hangup: 0
   Elapsed Time: 0h3m55s
      Bridge ID: dbbf0e61-fbd5-4543-b090-c92504f5ce1f

Here is the SDP that is sent to Asterisk from the HT802 (with some sanitation):

v=0
o=000b8296aec2 8000 8000 IN IP4 {IP ADDRESS}
s=SIP Call
c=IN IP4 {IP ADDRESS}
t=0 0
m=audio 25838 RTP/AVP 123 0 101
a=sendrecv
a=rtpmap:123 opus/48000/2
a=fmtp:123 maxplaybackrate=16000
a=ptime:20
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16,32-36,54

And the debug log is getting spammed by:

[2017-01-19 13:16:14] DEBUG[24196][C-00000044] res_rtp_asterisk.c: Unsupported payload type received 
[2017-01-19 13:16:14] DEBUG[24199] translate.c: Sample size different 960 vs 160

The weird thing though, is if I check the RTP stream on Wireshark, I can listen to the incoming audio. So the incoming stream is getting to my computer (and possibly the ATA) but it is not playing it. Wireshark shows my ATA send Opus and receiving back ulaw. I have tested other codec configurations and am able to receive a different codec than I am sending (such as g723 and ulaw). Edit: further testing shows that this last part might not be true.

If I disable native_rtp bridging (using “bridge technology suspend native_rtp”) I do get audio in both directions. So the problem appears to have something to do with that. Asterisk uses a simple_bridge in this case.

If I call using two HT802’s, both using Opus, directmedia=no, it works. If I do the same with directmedia=yes, I get no audio in either direction and the debug log shows:

[2017-01-19 13:22:51] DEBUG[24379] chan_pjsip.c: Oooh, got a frame with format of opus on channel 'PJSIP/000b8296aebb-00000082' when it has not been negotiated


Another weird thing is when I make a call from one endpoint (opus,ulaw) to another (g722,ulaw), the call appears to get converted to slin8000 to ulaw then to g722.

Endpoint 1:

      NativeFormats: (opus|ulaw)
        WriteFormat: g722
         ReadFormat: opus
     WriteTranscode: Yes (g722@16000)->(slin@8000)->(ulaw@8000)
      ReadTranscode: No 

Endpoint 2:

      NativeFormats: (g722|ulaw)
    WriteFormat: g722
     ReadFormat: g722
     WriteTranscode: No 
      ReadTranscode: No 

Is there a way to keep the audio from converting to 8000 khz and keep it at a higher quality?

Thank you. Please let me know if you need any additional information.

Edit: After some more investigating, the issue might be because I am receiving a different codec than I and sending? Using native_rtp, my ATA sends Opus and receives ulaw back and refuses to play the audio. Other devices/softphones may support this though.
Does that make sense? Has anyone else experienced this?

There seems to be a few odd things going on here, one of which are missing translation paths. If you do a

core show translation paths ulaw

and note the relevant paths ulaw->opus,ulaw->g722 and then do the same for those codecs

core show translation paths opus
core show translation paths g722

and compare are all translation paths present between them? If there is no translation path then the audio won’t convert.

If it’s possible to check have you tried Asterisk 14 to see if the problem happens there?

Here is the SDP that is sent to Asterisk from the HT802 (with some sanitation): …

Can you also post the SDP from the 200 OK returned by Asterisk?

Another weird thing is when I make a call from one endpoint (opus,ulaw) to another (g722,ulaw), the call appears to get converted to slin8000 to ulaw then to g722.

Is there a way to keep the audio from converting to 8000 khz and keep it at a higher quality?

ulaw’s sample rate is always 8Khz, so if going from a 16Khz audio codec like g722 it has to first convert the samples to slin at the equivalent sample rate. It then down or up samples to match the codec being translated to.

Thanks for replying. Here’s some of the output of using core show translation paths

voip*CLI> core show translation paths ulaw
...
        ulaw:8000        To g722:16000      : (ulaw@8000)->(slin@8000)->(g722@16000)             
        ulaw:8000        To opus:48000      : (ulaw@8000)->(slin@8000)->(slin@48000)->(opus@48000)                 
        ulaw:8000        To opus:8000       : (ulaw@8000)->(slin@8000)->(opus@8000)                       
        ulaw:8000        To opus:16000      : (ulaw@8000)->(slin@8000)->(slin@16000)->(opus@16000)
...        

voip*CLI> core show translation paths opus 
...
        opus:48000       To ulaw:8000       : (opus@48000)->(slin@48000)->(slin@8000)->(ulaw@8000)        
        opus:48000       To g722:16000      : (opus@48000)->(slin@48000)->(slin@16000)->(g722@16000)  
        opus:48000       To opus:8000       : (opus@48000)->(slin@48000)->(slin@8000)->(opus@8000)        
        opus:48000       To opus:16000      : (opus@48000)->(slin@48000)->(slin@16000)->(opus@16000)    
...

voip*CLI> core show translation paths g722
...
        g722:16000       To ulaw:8000       : (g722@16000)->(slin@8000)->(ulaw@8000)                      
        g722:16000       To opus:48000      : (g722@16000)->(slin@16000)->(slin@48000)->(opus@48000)      
        g722:16000       To opus:8000       : (g722@16000)->(slin@8000)->(opus@8000)                      
        g722:16000       To opus:16000      : (g722@16000)->(slin@16000)->(opus@16000)                    
...

I should have been more specific here. I was trying to call from Opus → g722 (and vice versa) and have wide band audio. But for some reason Asterisk converts (g722@16000)->(slin@8000)->(ulaw@8000). I’m at a bit of a loss why it used ulaw at all in that case. Looking at the translation paths above, it shows that it can convert Opus to g722 and back without down converting to 8000 KHz.

I have tried Asterisk 14 and I believe that I had the same issue. I will test this again tomorrow though.
I will also post a capture of the 200 OK response from Asterisk tomorrow.

I installed Asterisk 14 and can confirm that the same thing is happening in that version.

Here is the 200 OK from Asterisk:

SIP/2.0 200 OK
Via: SIP/2.0/UDP ${IP ADDRESS}:31102;rport=1024;received=10.90.1.212;branch=z9hG4bK1984503257
Call-ID: 66305023-31102-3491@CAJ.F.CDI.FD
From: <sip:000b8296aec2@${ASTERISK SERVER}>;tag=1997129572
To: <sip:${EXTEN}@${ASTERISK SERVER}>;tag=1dc4d384-8ac5-4d2e-be07-e0a1fbbe14b6
CSeq: 12241 INVITE
Server: Asterisk
Allow: OPTIONS, SUBSCRIBE, NOTIFY, PUBLISH, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, REGISTER, REFER
Contact: <sip:${ASTERISK SERVER}:5060>
Supported: 100rel, timer, replaces, norefersub
Content-Type: application/sdp
Content-Length:   879

v=0
o=- 8000 8002 IN IP4 ${ASTERISK SERVER}
s=Asterisk
c=IN IP4 ${ASTERISK SERVER}
t=0 0
m=audio 17766 RTP/AVP 123 0 101
a=ice-ufrag:7fd448594686fd1f08ca6f9271f74edf
a=ice-pwd:610078fe4b42eecb0cdb6dae0733e89f
a=candidate:H31b6cbe2 1 UDP 2130706431 fe80::215:17ff:fe4c:a944 17766 typ host
a=candidate:Hd105ee84 1 UDP 2130706431 ${ASTERISK SERVER} 17766 typ host
a=candidate:Rd105eee3 1 UDP 16777215 ${STUN SERVER} 51869 typ relay raddr ${ASTERISK SERVER} rport 47990
a=candidate:H31b6cbe2 2 UDP 2130706430 fe80::215:17ff:fe4c:a944 17767 typ host
a=candidate:Hd105ee84 2 UDP 2130706430 ${ASTERISK SERVER} 17767 typ host
a=candidate:Rd105eee3 2 UDP 16777214 ${STUN SERVER} 61816 typ relay raddr ${ASTERISK SERVER} rport 54892
a=rtpmap:123 opus/48000/2
a=fmtp:123 maxplaybackrate=16000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:20
a=sendrecv

Here’s some interesting output from the Grandstream HT802 syslog:

...
Jan 20 08:46:30 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: New Codec '0' Rx_pt '0' iLoop '1'
Jan 20 08:46:30 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS:  #### Received the RTP Packet PT 0 which is different of what was configured 123
Jan 20 08:46:30 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS:  The function p_rtp_PacketCheck returned NULL OR NSE Pkt recv
Jan 20 08:46:30 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS:  Received codec is 0 and expected is 123
...
Jan 20 08:46:34 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS:  @@@##  #$$$  Sending RTCP  based on TS
Jan 20 08:46:34 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: Sending RTCP pkt type '200' of length '52' to user space !!!
Jan 20 08:46:34 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: Sending RTCP pkt type '202' of length '20' to user space !!!
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS:  RTCP pkt received
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: RDRD Cordless: Receiving RTCP 1
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: error2
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: RTCP packet received: 200 error!!!
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: error2
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: RTCP packet received: 202 error!!!
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: p_rtp_SeqInit 291
Jan 20 08:46:35 HT802 [00: 0B:82:96:AE:C2] [1.0.2.5] LIBGSDSP: CSS: p_rtp_SeqInit 293
...

It seems to not like receiving ulaw while it is sending Opus.

Edit:

I found this post on the Grandstream forums: http://forums.grandstream.com/forums/index.php?topic=33128.0

Does Asterisk / PJSIP allow for asymmetric codecs? I am finding some old posts on mailing lists suggesting it does not, but maybe PJSIP allows for this.

Is there a way to turn this off without completely disabling native_rtp bridges?

I have:

asymmetric_rtp_codec=false

for all endpoints.

I’m starting to think that this is a bug.

This was applied in 13.13.0:

2016-10-23 07:38 +0000 [e0bc17edff]  Joshua Colp <jcolp@digium.com>

	* pjsip: Fix a few media bugs with reinvites and asymmetric payloads.

	  When channel format changes occurred as a result of an RTP
	  re-negotiation the bridge was not informed this had happened.
	  As a result the bridge technology was not re-evaluated and the
	  channel may have been in a bridge technology that was incompatible
	  with its formats. The bridge is now unbridged and the technology
	  re-evaluated when this occurs.

	  The chan_pjsip module also allowed asymmetric codecs for sending
	  and receiving. This did not work with all devices and caused one
	  way audio problems. The default has been changed to NOT do this
	  but to match the sending codec to the receiving codec. For users
	  who want asymmetric codecs an option has been added, asymmetric_rtp_codec,
	  which will return chan_pjsip to the previous behavior.

	  The codecs returned by the chan_pjsip module when queried by
	  the bridge_native_rtp module were also not reflective of the
	  actual negotiated codecs. The nativeformats are now returned as
	  they reflect the actual negotiated codecs.

	  ASTERISK-26423 #close

	  Change-Id: I6ec88c6e3912f52c334f1a26983ccb8f267020dc

yet I am experiencing asymmetric codecs in 13.13.1.

A subsequent fix went in (which has not yet been released) that covered an additional case.

Yes, your translation paths look fine. Originally I was thinking they might be missing, but I had misread the earlier Read/Write formats and transcode fields you had posted. But it at least confirms things should be in their proper state with regards to translation paths.

This does sound very much like an asymmetric rtp problem. Originally ASTERISK-26423 fixed a problem with regards to what sounds like the problem you are having. However there was a small bug in that fix, which was subsequently fixed by ASTERISK-26603.

The latter fix has not been released yet, but has been committed, so if you are running from the source 13 branch you should have that fix. If you’d like to verify you have that fix it has the following commit id (13 branch):

cf6d13180effc92a2483dccc68f2f188689a40fa

If you don’t have that fix then try patching your system with it and see if that works. Otherwise setting “asymmetric_rtp_codec=false” as you have should work.

I just installed the latest from branch ‘13’. Latest commit is:

7f68f69732a9bb2e7fd9ce87364301fe635adfed

I can confirm that I do have the commit:

cf6d13180effc92a2483dccc68f2f188689a40fa

asymmetric_rtp_codec=no for all endpoints.

I made sure to run make uninstall and make clean before reinstalling but I am still experiencing this issue.

voip*CLI> core show version
Asterisk GIT-13-13.12.2-261-g7f68f69 built by root @ voip on a x86_64 running Linux on 2017-01-20 20:58:17 UTC

I’m thinking it is a bug as well. Please create an issue on the Asterisk issue tracker. Describe the the problem scenario and make it as easy/small as possible. For instance what you are doing sounds pretty basic already, but what if you remove one side of the call and just try playing back audio from Asterisk using the dialplan does it still occur?

If possible run the scenario and include a full debug and verbose log (debug=10, verbose=10). Also include the full SIP traffic. A packet capture would also be good, but if that data is harder to sanitize then please turn on SIP logging in Asterisk. Turn on RTP debugging (rtp set debug on) as well. See Collecting Debug Information for more help.

Snippets of your executing dialplan and sip or pjsip conf files (depending which you are using) would also be helpful. Or use something like "pjsip show endpoint " and attach the output.

Also on the issue reference ASTERISK-26603 stating that it does not fix your issue.

Thanks for your help. I will submit a bug report hopefully later today.

I set up a test extension that plays music on hold and called with an opus,ulaw endpoint. It works fine this way. Not sure if this is important but here is the debug log:

[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] res_rtp_asterisk.c: Setting RTCP address on RTP instance '0x7f253c221580'
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] pbx.c: Launching 'MusicOnHold'
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] channel.c: Scheduling timer at (50 requested / 50 actual) timer ticks per second
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] res_rtp_asterisk.c: 0x7f253c368740 -- Probation learning mode pass with source address 10.90.1.212:52662
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] channel.c: Channel PJSIP/000b8296aec2-0000016c setting write format path: ulaw -> ulaw
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] res_musiconhold.c: PJSIP/000b8296aec2-0000016c Opened file 3 '/var/lib/asterisk/moh/macroform-cold_day'
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] res_rtp_asterisk.c: Ooh, format changed from none to ulaw
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] chan_pjsip.c: Oooh, got a frame with format of opus on channel 'PJSIP/000b8296aec2-0000016c' when we're sending 'ulaw', switching to match
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] channel.c: Channel PJSIP/000b8296aec2-0000016c setting write format path: ulaw -> opus
[2017-01-23 09:43:04] DEBUG[11594][C-0000016c] res_rtp_asterisk.c: Ooh, format changed from ulaw to opus
[2017-01-23 09:43:05] DEBUG[11594][C-0000016c] res_rtp_asterisk.c: Got RTCP report of 72 bytes

I see in this log and Wireshark that it first sent a ulaw packet then switched to opus. I assume this is the way Asterisk is supposed to work in my original situation.

And the info from core show channel ...

  NativeFormats: (opus|ulaw)
    WriteFormat: ulaw
     ReadFormat: opus
 WriteTranscode: Yes (ulaw@8000)->(slin@8000)->(slin@48000)->(opus@48000)

I submitted this to the issue tracker: https://issues.asterisk.org/jira/browse/ASTERISK-26745