seanbright / asterisk-opus

Opus (transcoding) and VP8 (passthrough) support for Asterisk, needed for a better WebRTC integration
35 stars 13 forks source link

OPUS codec with custom 16khz sampling returns error. #24

Open avinvarghese opened 8 years ago

avinvarghese commented 8 years ago

Testing the Opus codec for Asterisk, working fine with default sampling 48khz. The default sampling is fixed at 48khz and is there any option to use 16khz

Asterisk : 13.11.2 | Opus : 1.1.3

Tried to customize the codec from codecs.conf

[opus8]
type = opus
samprate = 8000

Asterisk returns error: "No audio format found to offer" Sip Debug: opus16-sipDebug.txt

Thank you!

traud commented 8 years ago

codec.conf is not supported. Not because it would be handy, but simply because the source code is missing, which links that configuration file with the codec/attribute module. Nobody has written that part, yet. However since Asterisk 13.7, you should be able to achieve the same by editing the struct default_opus_attr at the beginning of res/res_format_attr_opus.c. That static struct are the Asterisk internal defaults (not the RFC defaults). That should give you the same abilities as codec.conf, except that you have to recompile rather than simply editing a configuration file. If that is not sufficient for your case, please, say so. Then, this issue can be changed to a feature request to track future development.

Nevertheless as of today, to leverage default_opus_attr, you have to go for ‘my’ fork at traud/asterisk-opus. In the long run, that fork/branch is going to merge into the one of Sean Bright, here.

Wait a minute. Looking at your SIP debug, you do not allow Opus Codec at all. Was that the correct log file? Please double-check because I am very curious: The SIP/SDP codec negotiation should succeed whatever maxplayrate was advertised.

ctrob67 commented 8 years ago

I am looking at testing Asterisk/Opus with narrow-band config for voice. Thus far I have applied your patch and have Opus transcoding in place (slin@8000<>opus@48000).

I can see default_opus_attr as you mention in Asterisk 13.7 but I can see also there is code for parsing parameters too. In any case, I am going between two instances of 13.7.

Assuming I want to drop the bit rate to 10k, then do I just have to set .maxbitrate to 10000?

Thanks.

traud commented 8 years ago

Yes, the module parses the negotiation of SDP. However, that struct contains the initial offer made by Asterisk. Consequently yes, when you change .maxbitrate to 10000 in default_opus_attr, you lower the bitrate to around 10000 – when the remote party honors that. Because you are using two Asterisk 13 = you honor SDP, you achieve your goal. Before you do that, I recommend to set .maxplaybackrate from 48000 to 8000. This changes to narrowband mode (similar to SiLK 8000) and gives a bitrate around your target value already; without changing .maxbitrate at all. If narrowband is still too much, adjust .maxbitrate as well. By the way just to avoid a possible misunderstanding, you are not limited to Asterisk 13.7. You can go for the latest Asterisk 13 as well.

However, if you need a fixed upper limit for sure, consider to go for AMR(-WB) instead, for example via my AMR module. That provides even wideband (HD Voice) at your desired bitrate. If you have a large deployment, you may consider to sponsor a EVS module.

avinvarghese commented 8 years ago

Hi Traud, I'm trying to achieve a Asterisk server to server communication and codec used is opus. It's the correct log file.

ctrob67 commented 8 years ago

Thanks Traud, I will give that a try.

I mention the version I am using as I am too well trained not to! I am building for Yocto, which is another layer of complication (meta-telephony on github) so I have to get each version of Asterisk working with that too. For now I am just interested in comparing the performance of opus versus other narrowband codecs.

traud commented 8 years ago

Avin, that log states Capabilities: us (… and does not list the Opus Codec. Actually, the list contains just the default capabilities. To enable the Opus-Codec for the SIP channel driver chan_sip, you have to add opus to your allow= parameter in your configuration file sip.conf. However, this cannot be the cause, because you stated Opus worked with the default sampling. Therefore: Is the Opus module loaded by Asterisk at all, while you created that log?

ctrob67, yes Asterisk 13.7 is fine. You need at least Asterisk 13.7 for negotiation/honoring of SDP. Looking forward to read your results, even if they are just personal experience.

ctrob67 commented 8 years ago

I made the changes and they are reflected in the SDP offering, but it didn't have the desired effect and a 48k option was still taken. I think there is still more to do, the rtp payload (type 107) was 100 bytes: v=0 o=- 1652724941 1652724941 IN IP4 10.100.0.100 s=Asterisk c=IN IP4 10.100.0.100 t=0 0 m=audio 18144 RTP/AVP 107 101 a=rtpmap:107 opus/48000/2 a=fmtp:107 maxplaybackrate=8000;sprop-maxcapturerate=8000;maxaveragebitrate=10000;useinbandfec=1;usedtx=1 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-16 a=ptime:20 a=maxptime:60 a=sendrecv

avinvarghese commented 8 years ago

Alex, I already added allow=opus in sip.conf

register => in1-q1:supersecret@192.168.3.253/in1-q1

[q1-in1]
secret=supersecret
fromuser=q-server
type=friend
disallow=all
allow=speex
context=sip-calls
canreinvite=no
dtmfmode=rfc2833
host=dynamic
qualify=yes
insecure=invite

[2000]  
        type=friend
        context=sip-calls
        ;allow=ulaw,alaw
        allow=speex
        secret=hello123
        host=dynamic
[1000]  
        type=friend
        context=sip-calls
        ;allow=ulaw,alaw
        allow=speex
        secret=hello123
        host=dynamic

asterisk-opus

Capabilities: us - in the log is at the phone end.

traud commented 8 years ago

ctrob67, how do you know, it fell back to 48000? With Opus, one cannot defer from the RTP payload size about the average Bit-Rate or Playback-Rate, because Opus is a variable bitrate codec. One cannot set an exact upper bound on it, like one is used from other audio codecs. This is explained in a paper from the conference InterSpeech 2011, chapter 4.1 (who refer to their own paper released previously at InterSpeech 2010). They claim a steady rate after about 30 seconds. These papers do not draw the full picture, because you can tweak the underlying SiLK 8000 via many compile-time settings. By the way, if you are interested in just Opus @ 8000 MHz, double-check via Digium’s or my SiLK module.

Long story short: Did you add a ast_log(LOG_NOTICE, "\n"); into codecs/codec_opus.c:opus_encoder_construct to determine which OPUS_SET_MAX_BANDWIDTH was selected? When the correct if-clause is selected, you have done everything what is possible via SIP/SDP. The next step would be to re-compile the Opus-Codec. However, when an unexpected if-clause is chosen, please, report! Then, I have to re-test that part of the code again. It worked here.

Avin, if you want to use Speex on the phone leg for sure, you have to disallow=all first (or go for allow=!all,speex). Currently, your Asterisk chooses ulaw between Asterisk and phone. Nevertheless, I do not understand why that Asterisk is not able to create a translation path with the other Asterisk server. Are you able to use opus between your Asterisk and the phone – just for testing, that would make sure the module is loaded. The next step would be debugging why ast_rtp_instance_available_formats does not return an audio codec. For this, you insert ast_log(LOG_NOTICE, "/n"); or go for an interactive session via GDB… (described in the comment section of that wiki entry).

ctrob67 commented 8 years ago

I wasn't saying it fell back to 48k more a query about why the selected 107 was described as opus/48000/2.
I think you have found the issue in the comments about the opus-codec library: I have different codec libraries at each end of the link. One is the stock install for Fedora and is generating about 10-11kbps of data but also also some frames with just one byte (08), which I presume is the DTA. The openembedded library at the other end is generating a lot more data and there is a noticeable difference between the two directions. The openembedded recipe has only processor options set so I should look about configuring that library. I would need to sort out what the licensing situation is with silk. I couldn't reach their developer site.

ctrob67 commented 8 years ago

Didn't see any pertinent configuration options for libopus but I made a call in the opposite direction and the higher data rate is coming from the call initiator and not from one particular end or the other. DTA is working in both directions though. The RTP information is different too: Call initiator: RTP 153 bytes; PT=DynamicRTP-Type-107, SSRC=0x72602EF6, Seq=11324, Time=269952 Call recipient: RTP 73 bytes; PT=opus, SSRC=0x6F9346B5, Seq=13738, Time=268800

Does this shed any light?

traud commented 8 years ago

Why is the selected 107 described as opus/48000/2.

Opus is declared this way, always. This is because each configuration has to be compatible with each other configuration. Furthermore, instead of creating several rtpmaps (which are limited in amount with some SIP/SDP implementations) fmtp declare just a preference. This was a lesson learned from AMR and SiLK…

When it comes to your different implementations, I would rather ask such questions on the Opus-Codec mailing list. If I understand you correctly, the Asterisk codec module works correctly, at least with one implementation. Anyway, three thoughts: (1) Did you double-check the version of those Opus libraries? (2) Furthermore, there is a complexity parameter which might be different for those implementations. (3) Finally, did you try without changing the Bit-Rate but just the Playback-Rate?

ctrob67 commented 8 years ago

Thanks, Traud. Yes, I figured out the naming. There is only one implementation: libopus 1.12 is used at each end. There are no significant configuration options set in Yocto - no idea about Fedora as it's an rpm. Sorry, I wasn't sufficiently clear. Both ends act the same. The end that initiates the call sets the rtp payload type to "DynamicRTP-Type-107" and sends at full bandwidth. The end that receives the call sets the rtp payload type to "PT=opus" and sends at around 10-11kbps. There's no difference in behaviour between Asterisk/opus running on Fedora and Asterisk/opus running on Yocto; it just matters which end initiated the call. I only tried setting all the parameters, as listed above ("maxplaybackrate=8000;sprop-maxcapturerate=8000;maxaveragebitrate=10000;useinbandfec=1;usedtx=1") but I will set just the playback rate and see if that is any different.

traud commented 8 years ago

Sounds like a bug somewhere. Please, add some ast_log into opus_encoder_construct and report which bandwidth is set. Could be a module-dependency/-order issue. By the way, the RTP Payload Type does not matter actually – this is a display glitch in Wireshark – I guess, you are using Wireshark.

ctrob67 commented 8 years ago

I checked the bytes in wireshark (what else) and it is just a difference in decoding the same thing. There is a difference in the debug for the codec tho: When initiating the call: [Sep 30 08:47:29] ERROR[22773][C-00000000]: codec_opus.c:106 opus_encoder_construct: attr is null. [Sep 30 08:47:29] ERROR[22773][C-00000000]: codec_opus.c:107 opus_encoder_construct: sampling rate 48000 bitrate 510000 maxplayrate 48000 channels 1 vbr 1 fec 1 dtx 0

When receiving the call: [Sep 30 08:47:34] ERROR[22781][C-00000001]: codec_opus.c:106 opus_encoder_construct: attr is not null. [Sep 30 08:47:34] ERROR[22781][C-00000001]: codec_opus.c:107 opus_encoder_construct: sampling rate 8000 bitrate 10000 maxplayrate 8000 channels 1 vbr 1 fec 1 dtx 1

So on transmit attr is null and the hardwired defaults are used. More interestingly, pvt->explicit_dst is not null and so ast_format_get_attribute_data() must be returning null, which means pvt->explcit_dst->attribute_data is null.

Hope this helps.

traud commented 8 years ago

You isolated a bug. The constants in opus_encoder_construct must be changed alongside with default_opus_attr, because a cached format does not have attribute data, because cached formats are created before the format modules are loaded. Or stated differently: Currently, you have to change both files, codecs/codec_opus.c and res/res_format_attr_opus.c. On the long run, I have to merge those constants and move them into the file asterisk/opus.h. Until then, please, change const int maxplayrate = attr ? attr->maxplayrate : 48000; to const int maxplayrate = attr ? attr->maxplayrate : 8000;. Does it work now?

ctrob67 commented 8 years ago

I've tried that already and it does work.

I thought it might be a case where it needs to use the default settings from res_format_attr_opus.c but wan't sure how that should be propagated.

Thanks for this. I can see how the codec is further configured based on these parameters.

Digressing, I see there is code for PLC in the opus plugin. I followed the README and only applied asterisk.patch. There is also enable_native_plc.patch - is this patch required as well for PLC?

traud commented 8 years ago

Yes, that patch is required to leverage Native PLC of the Opus Codec in Asterisk. For more details, please, see ASTERISK-25629…

ctrob67 commented 8 years ago

Thanks again. I am sorted now but will test further commits if able.

traud commented 8 years ago

ctrob67, thank you again for your feedback. I changed the code at traud/asterisk-opus, so you have to change only one file include/asterisk/opus.h to get 16 kHz.

Avin, do you still face your issue? If so, please, have a look at my last comment. If something was unclear, please, ask. I would like to get this issue here resolved.