Asterisk adding m=video line to forwarded INVITE during audio call

Hello,

We used tcpdump to capture packets on our Asterisk server (with videosupport=yes in sip.conf) while making an audio call between peer A (peera) and peer B (peerb). Both peers are on the same WIFI network behind NAT. Asterisk is on a public IP. Both peers are Android PJSIP clients with video support. As captured and shown in the wireshark logs below, peer A (who wants to make an audio-only call) is sending an m=audio line in the INVITE SDP and no m=video line. For some unknown reason, Asterisk is adding an m=video line to the INVITE SDP it resends to peer B. Why is this happening?

Peer A wants to make an audio-only call and sends an INVITE message with no m=video line in SDP. Asterisk replies to peer A with a Trying message before sending an INVITE message containing an m=video line to peer B, causing peer B to open a blank video view! Why did Asterisk add the m=video line?

Here’s the logs from tcpdump as exported from wireshark:

PEER A -> ASTERISK:

INVITE sip:peerb@XX.XX.XX.97:5060 SIP/2.0
v: SIP/2.0/UDP XX.XX.XX.130:49615;rport;branch=z9hG4bKPj3dbfb3cb-d350-4952-bee0-21ee6c7ac873
Max-Forwards: 70
f: sip:peera@XX.XX.XX.97;tag=5f59f8f7-52b6-451b-b780-90e5fa894533
t: sip:peerb@XX.XX.XX.97
m: <sip:peera@XX.XX.XX.130:49615;ob>;+sip.ice
i: 3eb4058e-4b52-47d3-9ed2-293b5331fee9
CSeq: 5422 INVITE
k: replaces, 100rel, timer, norefersub
x: 1800
Min-SE: 90
User-Agent: Pjsua2 Android 2.6
Authorization: Digest username="peera", realm="asterisk", nonce="3d698d99", uri="sip:peerb@XX.XX.XX.97:5060", response="d251a412f8d583a62d515f20fb6f1cd6", algorithm=MD5
c: application/sdp
l:   483

v=0
o=- 3709617507 3709617507 IN IP4 XX.XX.XX.30
s=pjmedia
b=AS:84
t=0 0
a=X-nat:0
m=audio 33072 RTP/AVP 98 97 99 104 18 3 0 8 9 96
c=IN IP4 XX.XX.XX.30
b=TIAS:64000
b=RS:0
b=RR:0
a=sendrecv
a=rtpmap:98 speex/16000
a=rtpmap:97 speex/8000
a=rtpmap:99 speex/32000
a=rtpmap:104 iLBC/8000
a=fmtp:104 mode=30
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-16
a=ice-ufrag:2437b648
a=ice-pwd:23d8c8bc
a=candidate:Hac100e1e 1 UDP 2130706431 XX.XX.XX.30 33072 typ host

ASTERISK -> PEER A: 100 Trying

Then, ASTERISK -> PEER B:

INVITE sip:peerb@XX.XX.XX.130:35594;ob SIP/2.0
Via: SIP/2.0/UDP XX.XX.XX.97:5060;branch=z9hG4bK1f5541ee;rport
Max-Forwards: 70
From: "peera" <sip:peera@XX.XX.XX.97>;tag=as1de3d919
To: <sip:peerb@XX.XX.XX.130:35594;ob>
Contact: <sip:peera@XX.XX.XX.97:5060>
Call-ID: 0b40165376da4a05423e108942e73ef7@XX.XX.XX.97:5060
CSeq: 102 INVITE
User-Agent: Asterisk PBX 13.1.0~dfsg-1.1ubuntu4.1
Date: Fri, 21 Jul 2017 09:18:25 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Content-Type: application/sdp
Content-Length: 446

v=0
o=root 1195287468 1195287468 IN IP4 XX.XX.XX.97
s=Asterisk PBX 13.1.0~dfsg-1.1ubuntu4.1
c=IN IP4 XX.XX.XX.97
b=CT:384
t=0 0
m=audio 11766 RTP/AVP 110 97 9 18 101
a=rtpmap:110 speex/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=0
a=rtpmap:9 G722/8000
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=maxptime:30
a=sendrecv
m=video 17896 RTP/AVP 99
a=rtpmap:99 H264/90000
a=sendrecv

Can anyone please explain why this is happening and how we may prevent the m=video line from being added to the second INVITE sent from Asterisk to peer B?

Thanks

Patrick

This is a continuation of a previous thread Video is being activated systematically in audio call

That thread indicates we are talking about chan_pjsip.

We use chan_sip not chan_pjsip on Asterisk. Teluu PJSIP is used on the client side.

So any thoughts why this m=video line is being added in Asterisk-to-peerB INVITE David?

Thanks

I’m not sure if this is the right place to report a bug but…

Looking at the source code of chan_sip.c (https://raw.githubusercontent.com/asterisk/asterisk/master/channels/chan_sip.c), the following code in function sip_result add_sdp() must be responsible for adding the m=video line when only audio is offered :

/* Check if we need video in this call */
if ((ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO)) && !p->novideo) {
	if (doing_directmedia && !ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO)) {
		ast_debug(2, "This call needs video offers, but caller probably did not offer it!\n");
	} else if (p->vrtp) {
		needvideo = TRUE;
		ast_debug(2, "This call needs video offers!\n");
	} else {
		ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
	}
}

Function ast_format_cap_has_type() is defined in include/asterisk/format_cap.h as:

int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type);

Therefore successive calls to this function using the same parameters must return the same result.

In the code above, ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO) must be true in the first if statement in order to execute the block starting with the second if,
i.e. if (doing_directmedia...

However the second if condition will always be evaluated to false in the code above because !ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO) cannot possibly be true anymore! Therefore, the execution is necessarily falling through the else if (p->vrtp) block and needvideo is being systematically set to true (since if (p->vrtp) also happens to be true). Maybe the programmer meant something like:

if (doing_directmedia && !ast_format_cap_has_type(p->caps, AST_MEDIA_TYPE_VIDEO))

i.e. p->caps was meant instead of tmpcap ???

Will investigate further and let you guys know.

Thanks

Patrick

It’s definitely a bug, so should be reported at https://issues.asterisk.org/ However I can’t see how it would produce your symptoms.

Although not likely to be relevant in this case, C functions are not mathematical functions, so can have side effects.

C functions can have side effects of course but not in this case. ast_format_cap_has_type() is a pure function in this case, its output being determined only by its input. Don’t have access to the code now from my phone.

This bug is causing my symptoms because when needvideo becomes true after execution falls through the first else if, it will cause the m=video line to be appended to the SDP later in the code.

I will report the bug in details asap and post the link here.

Thanks

Patrick

It is only affecting the SDP sent, not the SDP received.

Exactly. It is affecting the SDP sent from Asterisk to the callee, causing it to enable video due to the added m=video line. The received SDP from the caller contains only an m=audio line. In other words, this bug is causing Asterisk to append a video line to the second INVITE it sends to the callee.

It is the only place where the m=video line is being appended to the SDP in chan_sip.c

UPDATE: Looking at the code again, I realize that the m=video line is also added in function process_sdp() function, so you may be right.

I will look into it later. One thing is sure, Asterisk is adding the video line when forwarding the INVITE message.

Thanks

The buggy add_sdp() function is called from many functions in chan_sip.c including functions transmit_invite() and transmit_reinvite_with_sdp() and it is the only place where the m=video line is being added by mistake. I suspect the symptom is the result of calling transmit_reinvite_with_sdp()

Asterisk does not forward INVITEs. It generates a completely new INVITE (IAM, line seize, whatever the H.323 equivalent is, etc.) on the outgoing side.

Also, your log shows Asterisk receiving the video request. I can’t think of any good reason why Asterisk would modify the incoming request, before logging it. Even given the bug you have found, I don’t see why it would affect the incoming logged message.

Still, the functions used to create and transmit the completely new INVITE do call the buggy add_sdp() which is adding the video line even when only audio is offered in the caller’s INVITE. Please check the call hierarchy of the buggy function in chan_sip.c

Thanks

What do you mean my logs show receiving the video request? Where exactly please? The only media line is m=audio in the incoming INVITE.

Thanks

Have you raised the issue on issues.asterisk.org yet. If you want it fixed, you need to do that.

Not yet. Will do it asap. Prefer using laptop not phone. Please tell me how is video requested by caller in my log?

My guess is that the second INVITE containing the m=video line which is sent to callee is being generated by functions necessarily calling buggy add_sdp()

It’s in your original thread

<--- SIP read from UDP:xx.xx.xx.130:57559 --->
INVITE sip:peerb@xx.xx.xx.97:5060 SIP/2.0
v: SIP/2.0/UDP xx.xx.xx.130:57559;rport;branch=z9hG4bKPj8cbbe44a-b861-4e1c-bcb7-e2b88747f925
Max-Forwards: 70
f: sip:peera@xx.xx.xx.97;tag=9b6a7bb1-33ad-44e9-8bde-925fe26f0efe
t: sip:peerb@xx.xx.xx.97
m: <sip:peera@xx.xx.xx.130:57559;ob>;+sip.ice
i: bd51e42b-adaa-44ac-a0cb-bb78bf3ed53e
CSeq: 28240 INVITE
k: replaces, 100rel, timer, norefersub
x: 1800
Min-SE: 90
User-Agent: Pjsua2 Android 2.6
c: application/sdp
l: 528

v=0
o=- 3709457249 3709457249 IN IP4 xx.xx.xx.201
s=pjmedia
b=AS:84
t=0 0
a=X-nat:0
m=audio 36437 RTP/AVP 98 97 99 104 18 3 0 8 9 96
c=IN IP4 xx.xx.xx.201
b=TIAS:64000
b=RS:0
b=RR:0
a=sendrecv
a=rtpmap:98 speex/16000
a=rtpmap:97 speex/8000
a=rtpmap:99 speex/32000
a=rtpmap:104 iLBC/8000
a=fmtp:104 mode=30
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-16
a=ice-ufrag:4cbb6d80
a=ice-pwd:0b377c3e
a=candidate:Hac100bc9 1 UDP 2130706431 xx.xx.xx.201 36437 typ host
m=video 0 RTP/AVP 31
c=IN IP4 127.0.0.1

Read from and INVITE tell me this is the incoming request, the lack of a tag on t indicates that it is the initial INVITE, and it ends with the m=video, using the deprecated way of indicating hold.

Whilst it is just conceivable that Asterisk is modifying this, rather than the parsed data, I would not expect it to do it before it has logged it, and the decision to modify is a coding design one, even if the execution is complicated by the bug you found.

Your bug may be causing problems that are independent of what appears to have been received.

I’m not sure that I’m personally sufficiently interested in the video handling to make it worth my while analysing the whole of this code to work out what that function is really trying to do, but you have enough to show there is a bug, even if not what the correct code should be.

This log was captured by tcpdump and viewed in wireshark. It clearly shows that the INVITE message with the m=video line you’re referring to was an outgoing message from Asterisk’s IP as source to peer B’s IP as destination.

I’m referring to the second INVITE in this thread where the user agent is Asterisk. It is the one containing the video line and it is an outgoing message.

I’m saying the first one is sufficient cause to set up a video call. The first one, that I quoted has a video stream requested. Given that, Asterisk should respond with a video offer.