Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PeerConnection OnTrack callback never invoked #880

Closed
tylerlong opened this issue Oct 17, 2019 · 23 comments · Fixed by #883
Closed

PeerConnection OnTrack callback never invoked #880

tylerlong opened this issue Oct 17, 2019 · 23 comments · Fixed by #883

Comments

@tylerlong
Copy link

tylerlong commented Oct 17, 2019

Your environment.

  • Version: v2.1.8
  • Browser: None
  • Other Information - I am trying to create a softphone using SIP and this library. The remote SIP & RTC service have no problem, because I have done a softphone using Node.js: https://github.com/ringcentral/ringcentral-softphone-js . I am trying to make a GoLang version, but I am stuck.

What did you do?

I have written the following code: https://github.com/ringcentral/ringcentral-softphone-go/blob/master/softphone.go#L137-L220

Just for your reference, here is the Node.js version of the GoLang code: https://github.com/ringcentral/ringcentral-softphone-js/blob/ce833c613d5e4bb959235e37addefd10cc9cb81e/index.js#L140-L177 . The Node.js code works like a charm.

What did you expect?

I expect that the peerConnection.OnTrack callback function will be invoked so that I can get the input audio

What happened?

peerConnection.OnTrack never invoked and I am stuck.

Some questions:

Could it because I specify the wrong codec? If so, I expect some error message like: no codec to handle the remote track. remote SDP sample:

v=0
o=- 5305405169010475891 908790132696250821 IN IP4 104.245.57.182
s=SmcSip
c=IN IP4 104.245.57.182
t=0 0
m=audio 20040 RTP/SAVPF 109 111 18 0 8 9 96 101
a=rtpmap:109 OPUS/16000
a=fmtp:109 useinbandfec=1
a=rtcp-fb:109 ccm tmmbr
a=rtpmap:111 OPUS/48000/2
a=fmtp:111 useinbandfec=1
a=rtcp-fb:111 ccm tmmbr
a=rtpmap:18 g729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:9 g722/8000
a=rtpmap:96 ilbc/8000
a=fmtp:96 mode=20
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:20041
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-1 E2:F8:90:C6:37:7E:82:17:3C:63:CF:55:68:4E:1D:16:17:2C:D9:4D
a=ice-ufrag:atwbXWRm
a=ice-pwd:32SCWdSoU7BgkXxet5g5mlId5E
a=candidate:muEZ8Bb5Zhy8XFSL 1 UDP 2130706431 104.245.57.182 20040 typ host
a=candidate:muEZ8Bb5Zhy8XFSL 2 UDP 2130706430 104.245.57.182 20041 typ host

How can I port the Node.JS code to GoLang? Because I know Node.js version works like charm. And the code even works in browser (with browser WebRTC). So if pion/webrtc is compatible with browser WebRTC, I should be able to get this GoLang version work.

Could it becuase of this #879? I temporarily worked around the issue: https://github.com/ringcentral/ringcentral-softphone-go/blob/master/softphone.go#L133

@Sean-Der
Copy link
Member

Hey @tylerlong I think it could be a few different things

  • sha-1 instead of sha-256. We don't support older ciphers, I can add support though to unblock you!
  • This SDP doesn't contain any SSRCes. Pion isn't expecting to receive any incoming audio without it.

@tylerlong
Copy link
Author

tylerlong commented Oct 18, 2019

sha-1 instead of sha-256. We don't support older ciphers, I can add support though to unblock you!

Please do, thanks. There are lots of legacy things in the world that we have to support. I cannot control the remote side so I cannot change its cipher but accept it. Thanks again.

Before Pion support legacy ciphers, it should panic with error message: "unsupported cipher in remote SDP: 'sha-1'", otherwise as a developer I have no idea what happened. Just my two cents. Thanks.

@Sean-Der
Copy link
Member

@tylerlong My guess is that if you turned on verbose debugging it probably threw an error message on fingerprint mismatch.

Unfortunately we can't panic because we are a library :/ don't want to hurt other code is running. OnConnectionState should be returning Failed though!

Would it be possible to get an account for ringcentral? Happy to debug, would love to get everything working this weekend!

@tylerlong
Copy link
Author

tylerlong commented Oct 18, 2019

This SDP doesn't contain any SSRCes. Pion isn't expecting to receive any incoming audio without it.

As my understanding, SSRC is optional. https://tools.ietf.org/id/draft-westerlund-mmusic-max-ssrc-00.html#rfc.section.1

This document describes use-cases where endpoints, for a given media type, use multiple media sources.

It is not the use case for me. I don't need multiple media sources.

Many applications and systems have been designed to ensure that any given endpoint only needs to, for a given SDP media description, send or receive a single media stream, associated with a single source.

Above is my use case.

Sean-Der added a commit that referenced this issue Oct 19, 2019
If we receive an unknown SSRC and we have a single
media section with no SSRCes declared fire an OnTrack
with that stream

Resolves #880
Sean-Der added a commit that referenced this issue Oct 19, 2019
If we receive an unknown SSRC and we have a single
media section with no SSRCes declared fire an OnTrack
with that stream

Resolves #880
Sean-Der added a commit that referenced this issue Oct 20, 2019
Sean-Der added a commit that referenced this issue Oct 20, 2019
If we receive an unknown SSRC and we have a single
media section with no SSRCes declared fire an OnTrack
with that stream

Resolves #880
Sean-Der added a commit that referenced this issue Oct 20, 2019
Sean-Der added a commit that referenced this issue Oct 20, 2019
If we receive an unknown SSRC and we have a single
media section with no SSRCes declared fire an OnTrack
with that stream

Resolves #880
Sean-Der added a commit that referenced this issue Oct 20, 2019
@Sean-Der
Copy link
Member

Hey @tylerlong

This is fixed! I am able to use the ringcentral softphone and save the PCM to disk! Unfortunately the oggwriter is hardcoded to support Opus only, if you are interested we could expand it to support PCM if that is helpful!

@tylerlong
Copy link
Author

@Sean-Der Thank you so much! That is fast!

I don't know much about audio formats. But overall support more is a good idea.

Let me have a try and get back to you.

@tylerlong
Copy link
Author

I tried the latest version github.com/pion/webrtc/v2 v2.1.9 and it still doesn't work for me

PeerConnection OnTrack callback never invoked.

But yesterday I tried it at home it worked. The different is yesterday I was trying it on Windows and today I am trying it on macOS.

@Sean-Der
Copy link
Member

Sean-Der commented Oct 21, 2019

@tylerlong

I added a test to assert it was working (and everything seems fine!) my guess would be there is another issue. Probably networking if you are in different environments, many office networks only work with TURN enabled etc..

  • Is ICE+ConnectionState going to connected?
  • If you do a tcpdump do you see audio packets flowing from the remote peer?
  • Is the SDP different in the cases it isn't working?

@tylerlong
Copy link
Author

I do see "OnICEConnectionStateChange connected"

SDP:

v=0
o=- 8992091129720114931 3299709293645669172 IN IP4 104.245.57.182
s=SmcSip
c=IN IP4 104.245.57.182
t=0 0
m=audio 39908 RTP/SAVPF 109 111 18 0 8 9 96 101
a=rtpmap:109 OPUS/16000
a=fmtp:109 useinbandfec=1
a=rtcp-fb:109 ccm tmmbr
a=rtpmap:111 OPUS/48000/2
a=fmtp:111 useinbandfec=1
a=rtcp-fb:111 ccm tmmbr
a=rtpmap:18 g729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:9 g722/8000
a=rtpmap:96 ilbc/8000
a=fmtp:96 mode=20
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:39909
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-1 27:EF:98:E2:3D:12:18:B6:D7:A9:BA:33:4A:68:F7:3E:B1:63:7C:AC
a=ice-ufrag:57CmAD1c
a=ice-pwd:Yd1CvwSTnTZLRTMBGKUQk1chbK
a=candidate:2uEo5H7EOY3ditac 1 UDP 2130706431 104.245.57.182 39908 typ host
a=candidate:2uEo5H7EOY3ditac 2 UDP 2130706430 104.245.57.182 39909 typ host

@tylerlong
Copy link
Author

I am going home to try it on my windows machine. Update you later.

@tylerlong
Copy link
Author

tylerlong commented Oct 21, 2019

Windows

I tried it on my Windows a couple of times. And the conclusion is : sometimes it works while sometimes it doesn't.

The same code, I run it multiple times and I got different result. weird.

When it worked

OnSignalingStateChange have-remote-offer
OnICEConnectionStateChange checking 
OnSignalingStateChange stable

OnICECandidate host 192.168.0.15:61213
OnICECandidate nil

OnICEConnectionStateChange connected 
OnConnectionStateChange connected
OnTrack

Sample SDP when it worked

v=0
o=- 5963121565783506081 4058657120322569797 IN IP4 104.245.57.249
s=SmcSip
c=IN IP4 104.245.57.249
t=0 0
m=audio 36200 RTP/SAVPF 109 111 18 0 8 9 96 101
a=rtpmap:109 OPUS/16000
a=fmtp:109 useinbandfec=1
a=rtcp-fb:109 ccm tmmbr
a=rtpmap:111 OPUS/48000/2
a=fmtp:111 useinbandfec=1
a=rtcp-fb:111 ccm tmmbr
a=rtpmap:18 g729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:9 g722/8000
a=rtpmap:96 ilbc/8000
a=fmtp:96 mode=20
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:36201
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-1 40:98:E4:34:C3:11:5B:71:B1:66:B2:C9:D6:BD:9E:52:81:92:1B:6E
a=ice-ufrag:AR9yOAXG
a=ice-pwd:dDvnPaaTk74az3hd1Ai7wSd1cj
a=candidate:rjRIpigWfTeIbojw 1 UDP 2130706431 104.245.57.249 36200 typ host
a=candidate:rjRIpigWfTeIbojw 2 UDP 2130706430 104.245.57.249 36201 typ host

When it didn't work

OnSignalingStateChange have-remote-offer
OnICEConnectionStateChange checking 
OnSignalingStateChange stable

OnICECandidate host 192.168.0.15:56850
OnICECandidate nil

OnICEConnectionStateChange connected

then after around 30 seconds, I got:

OnConnectionStateChange failed
OnICEConnectionStateChange disconnected 
OnICEConnectionStateChange failed 

Sample SDP when it didn't work

v=0
o=- 7452111111381642799 6657573025900769579 IN IP4 104.245.57.249
s=SmcSip
c=IN IP4 104.245.57.249
t=0 0
m=audio 47600 RTP/SAVPF 109 111 18 0 8 9 96 101
a=rtpmap:109 OPUS/16000
a=fmtp:109 useinbandfec=1
a=rtcp-fb:109 ccm tmmbr
a=rtpmap:111 OPUS/48000/2
a=fmtp:111 useinbandfec=1
a=rtcp-fb:111 ccm tmmbr
a=rtpmap:18 g729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:9 g722/8000
a=rtpmap:96 ilbc/8000
a=fmtp:96 mode=20
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:47601
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-1 37:6C:DC:44:00:BE:BA:07:0A:86:AF:16:1F:43:49:41:BB:22:41:84
a=ice-ufrag:VwlBdEws
a=ice-pwd:APbbNITDFAVfKGHN1DxM8Zhjt7
a=candidate:7QZebzHBbQModeJU 1 UDP 2130706431 104.245.57.249 47600 typ host
a=candidate:7QZebzHBbQModeJU 2 UDP 2130706430 104.245.57.249 47601 typ host

macOS

Most of the time it fails.

v=0
o=- 3003893328699748873 1358899279031815794 IN IP4 104.245.57.182
s=SmcSip
c=IN IP4 104.245.57.182
t=0 0
m=audio 29424 RTP/SAVPF 109 111 18 0 8 9 96 101
a=rtpmap:109 OPUS/16000
a=fmtp:109 useinbandfec=1
a=rtcp-fb:109 ccm tmmbr
a=rtpmap:111 OPUS/48000/2
a=fmtp:111 useinbandfec=1
a=rtcp-fb:111 ccm tmmbr
a=rtpmap:18 g729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:9 g722/8000
a=rtpmap:96 ilbc/8000
a=fmtp:96 mode=20
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:29425
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-1 5D:93:65:C6:1F:93:F7:37:19:3C:C8:76:44:98:BD:B0:9A:E9:90:0B
a=ice-ufrag:4Cv3oxDG
a=ice-pwd:VDAHykTXrVTPzdUtlTDPn9lcQb
a=candidate:bI2GF67wa6ppc8oE 1 UDP 2130706431 104.245.57.182 29424 typ host
a=candidate:bI2GF67wa6ppc8oE 2 UDP 2130706430 104.245.57.182 29425 typ host
OnSignalingStateChange have-remote-offer
OnICEConnectionStateChange checking 

OnSignalingStateChange stable

OnICECandidate host 10.32.21.94:50517
OnICECandidate nil

OnICEConnectionStateChange connected 
OnConnectionStateChange failed
OnICEConnectionStateChange disconnected 
OnICEConnectionStateChange failed 

In rare cases it succeeds:

v=0
o=- 8191891114657166899 1133201147605880630 IN IP4 104.245.57.249
s=SmcSip
c=IN IP4 104.245.57.249
t=0 0
m=audio 23212 RTP/SAVPF 109 111 18 0 8 9 96 101
a=rtpmap:109 OPUS/16000
a=fmtp:109 useinbandfec=1
a=rtcp-fb:109 ccm tmmbr
a=rtpmap:111 OPUS/48000/2
a=fmtp:111 useinbandfec=1
a=rtcp-fb:111 ccm tmmbr
a=rtpmap:18 g729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 pcmu/8000
a=rtpmap:8 pcma/8000
a=rtpmap:9 g722/8000
a=rtpmap:96 ilbc/8000
a=fmtp:96 mode=20
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:23213
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-1 97:E3:8A:5B:94:87:0F:C0:42:57:6C:29:5E:EE:EF:18:79:0B:BF:4F
a=ice-ufrag:wchffjDE
a=ice-pwd:Ze2XnqcMIx97EvFNA76NudFjb1
a=candidate:pB33NG4AflUhYaUy 1 UDP 2130706431 104.245.57.249 23212 typ host
a=candidate:pB33NG4AflUhYaUy 2 UDP 2130706430 104.245.57.249 23213 typ host
OnSignalingStateChange have-remote-offer
OnICEConnectionStateChange checking 

OnICECandidate host 10.32.21.94:58878
OnICECandidate nil

OnICEConnectionStateChange connected 
OnConnectionStateChange connected
OnTrack

@Sean-Der
Copy link
Member

Let me try on my end tonight!

If you try on MacOS multiple times do you get similar results?

If you can get a pcap comparing good/bad results that would be really helpful! Hopefully I can replace tonight and just fix the issue :)

thanks @tylerlong

@tylerlong
Copy link
Author

No hurry. I will post more detail in my comment above.

@tylerlong
Copy link
Author

tylerlong commented Oct 21, 2019

I did some debugging.

// line 1893 - 1902 peerConnection.go
	// Start the dtls transport
	err = pc.dtlsTransport.Start(DTLSParameters{
		Role:         dtlsRole,
		Fingerprints: []DTLSFingerprint{{Algorithm: fingerprintHash, Value: fingerprint}},
	})
	pc.updateConnectionState(pc.ICEConnectionState(), pc.dtlsTransport.State())
	if err != nil {
		pc.log.Warnf("Failed to start manager: %s", err)
		return
	}
dtls: The connection timed out during the handshake

So the root cause is

	err = pc.dtlsTransport.Start(DTLSParameters{
		Role:         dtlsRole,
		Fingerprints: []DTLSFingerprint{{Algorithm: fingerprintHash, Value: fingerprint}},
	})

timeout

@tylerlong
Copy link
Author

tylerlong commented Oct 21, 2019

If I debug into pc.dtlsTransport.Start, then it always succeeds.

So it might has something to do with timing. If we delay the execution of pc.dtlsTransport.Start for 1 second, it always succeed. Not 100% sure though.

@Sean-Der
Copy link
Member

I will work on reproducing! I am not sure why DTLS is timing out. Hopefully I can reproduce it on my home network.

If you can use wireshark/tcpdump and get all UDP traffic it would help a lot to figure out what went wrong. If you send it to my pion.ly email I can check it out right away!

@Sean-Der
Copy link
Member

@tylerlong do you see any errors server side? It sounds like we are causing an error by sending DTLS traffic too soon maybe?

I will look at what happens when we delay DTLS vs when we don't

@tylerlong
Copy link
Author

tylerlong commented Oct 22, 2019

Unfortunately I cannot see server side log. I don't maintain our server side code and I treat it as a black box when I created the Node.js softphone SDK.

I've sent tcpdump file to you via email.

@tylerlong
Copy link
Author

tylerlong commented Oct 22, 2019

https://github.com/pion/webrtc/blob/master/dtlstransport.go#L256:

dtlsConn, err := dtls.Client(dtlsEndpoint, dtlsConfig)

If I add breakpoint to this line and its next line and "Step Over" to next line, it always work

If I add breakpoint to this line and its next line and "Resume Program" (no matter how long I wait before resume), it often doesn't work.

So I think this might be a concurrency deadlock issue.

"Step Over" is like single threaded, so it never deadlock.
"Resume Program" is multiple threaded so it often deadlock and timeout.

@Sean-Der
Copy link
Member

@tylerlong

Looking at the pcap we keep DTLS traffic, but the other side never responds. We are running as the DTLS client (and we also are able to choose if we want to run as Client or Server).

Let me get a PR that switches roles and we can see if that helps! Will be done tonight

Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client takes when answering via
the SettingEngine.

Relates to #880
Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client takes when answering via
the SettingEngine.

Relates to #880
Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client
takes when answering via the SettingEngine.

Relates to #880
Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client
takes when answering via the SettingEngine.

Relates to #880
Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client
takes when answering via the SettingEngine.

Relates to #880
Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client
takes when answering via the SettingEngine.

Relates to #880
Sean-Der added a commit that referenced this issue Oct 22, 2019
User can now control what DTLSRole the local client
takes when answering via the SettingEngine.

Relates to #880
@pascal-pro
Copy link
Contributor

pascal-pro commented Nov 19, 2020

@Sean-Der / @tylerlong
One year later... I try to make the soft-phone work, without success.
I used the pawn library several times, so I was happy to find it here.
I have the same symptom, no OnTrack, and the connectionState is always checking or failed, but never goes connected.

I also noticed that without the stun, the Sip connection was a failure.

I put the DTLS on the server (as suggested in the PR).
I also had to put in a GatheringCompletePromise event, to be able to return an entire SDP.
I am trying with the v3 of pion/webrtc

@jongwow jongwow mentioned this issue Feb 15, 2021
7 tasks
@flamurhbreznica
Copy link

I have VideoCall System developed through Ionic Cordova with PeerJS, it works properly on Android.
Now that I deployed to iOS from cordova, whenever I make second call, it always set an error: The PluginMediaStream with this id "any id" already exists, and cannot join to calls anymore, also the events from peerjs does not trigger

for example:

peer.on('stream') does not trigger at all, I used this plugin to handle the MediaStreams, but for some reasons, after the first video call it says MediaStream already exists,

How i can I trigger some events if I get a call from peer, onstream, onremove,

I tried to remove streams, tracks, and other stuff after ending video call, but it did not work.

@Sean-Der
Copy link
Member

Hi @flamurhbreznica

can you please either

  • Create a new issue
  • Create a stackoverflow issue
  • Join and ask on Slack

thanks!

Sean-Der pushed a commit to streamer45/webrtc that referenced this issue Apr 23, 2023
Everytime we receieve a new SSRC we probe it and try to determine the proper way to
handle it. In most cases a Track explicitly declares a SSRC and a OnTrack is fired.
In two cases we don't know the SSRC ahead of time
* Undeclared SSRC in a single media section (pion#880)
* Simulcast

The Undeclared SSRC processing code would run before Simulcast. If a Simulcast
Offer/Answer only contained one Media Section we would never fire the OnTrack. We
would assume it was a failed Undeclared SSRC processing. This commit fixes the behavior.
Sean-Der pushed a commit to streamer45/webrtc that referenced this issue Apr 23, 2023
Everytime we receieve a new SSRC we probe it and try to determine the
proper way to handle it. In most cases a Track explicitly declares a
SSRC and a OnTrack is fired. In two cases we don't know the SSRC
ahead of time
* Undeclared SSRC in a single media section (pion#880)
* Simulcast

The Undeclared SSRC processing code would run before Simulcast.
If a Simulcast Offer/Answer only contained one Media Section we
would never fire the OnTrack. We would assume it was a failed
Undeclared SSRC processing. This commit fixes the behavior.
Sean-Der pushed a commit that referenced this issue Apr 23, 2023
Everytime we receieve a new SSRC we probe it and try to determine the
proper way to handle it. In most cases a Track explicitly declares a
SSRC and a OnTrack is fired. In two cases we don't know the SSRC
ahead of time
* Undeclared SSRC in a single media section (#880)
* Simulcast

The Undeclared SSRC processing code would run before Simulcast.
If a Simulcast Offer/Answer only contained one Media Section we
would never fire the OnTrack. We would assume it was a failed
Undeclared SSRC processing. This commit fixes the behavior.
ourwarmhouse added a commit to ourwarmhouse/Smart-Contract---Go that referenced this issue May 1, 2024
Everytime we receieve a new SSRC we probe it and try to determine the
proper way to handle it. In most cases a Track explicitly declares a
SSRC and a OnTrack is fired. In two cases we don't know the SSRC
ahead of time
* Undeclared SSRC in a single media section (pion/webrtc#880)
* Simulcast

The Undeclared SSRC processing code would run before Simulcast.
If a Simulcast Offer/Answer only contained one Media Section we
would never fire the OnTrack. We would assume it was a failed
Undeclared SSRC processing. This commit fixes the behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

4 participants