-
Notifications
You must be signed in to change notification settings - Fork 19
Getting Unable to protect RTP: :replay_old
#186
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
Comments
Hi, appreciate the detailed description! In general, you shouldn't try to feed the same track of the player PCs with different audio streams. Because you tear create/down the publisher PC every time you start/stop, each time the publisher produces a logically new stream, in new sequence number and timestamp space/domain (as you've noticed yourself). Possible remedies:
I haven't been actively involved in the project for a few months and I'm starting to forget things - try these, check if the issue was solved, otherwise @mickel8 might offer a better assistance. |
Perfect answer @LVala! 🎉 What else I can add. Maybe just two more words about I agree that muting the track or just renegotiating the connection is the easiest way of making the solution stable. One more question, is your game one on one, or there can be more than two players in a single session? I also wonder what's the role of the timestamp in case of audio because even if you fit into the SRTP sliding window with a new RTP stream, there is a high chance you will create a gap in timestamps, which, I thought, should create some problems too 🤔 |
Hey thanks both for the quick responses!
The reason I opted against doing something like this is that it seems as though as long as the peer connection remains open, the browser indicates to the user that the microphone is enabled (red recording dot on tab and microphone icon in the URL bar): ![]()
There could be any number of players. Based on @LVala's comment:
It would seem that if e.g. there are 4 players all talking then I need to have, for each player, a player PC with 3 different tracks, one for each of the other 3 players' microphone streams? Which in turn I think means I would need 3 I think I need to go back to the drawing board and have a look at the Nexus example code, which seems like exactly what I'm doing, except I'm doing it without the video tracks. Thank you both for you patience! |
Nexus relies on a single peer connection which is a bit more complex example. In your case, when you have a separate pc for sending and a separate pc for receiving, you can do the following (I hope 🤞):
No need to exchange ice candidates. I would recommend trying this approach at first, without looking at Nexus as Nexus operates on transceivers and directions, which you might not need |
Btw, I checked your app on fly, really nice! And I was ale to talk to myself :D What about writing a short blogpost once you finish the work on audio part? |
Ok I've added code to create one track per publisher PC on each listener PC (except for the listener's own corresponding publisher, as I don't want to "echo" the user back to themself). I've also added code to handle renegotiation on all player PCs whenever a publisher starts or stops streaming. One question around this:
Am I supposed to keep state to avoid exchanging ice candidates after the initial setup of the PC? I see a handful of the following logs on the server side every time there's a renegotiation:
I tried adding code to the player on the browser side to not push ice candidates to the client after initial setup, but the logs were still appearing, so I'm not really sure what's producing the candidates. I've definitely got some bugs to iron out beyond this, though. edit: one thing in particular I'm having trouble debugging is if I open a tab and turn on the microphone (i.e. start streaming), and then open a second tab, the audio doesn't play, even though I think the problem might be that my code doesn't wait for renegotiation to complete for any new tracks before trying to send packets to them. Is that a known problem? I can't think what else might be the issue - I can't reproduce it locally, so it's slow to iterate on potential solutions because I have to redeploy every time.
I don't have a blog! I'm also painfully aware of how little of the webrtc stuff I truly have a grapple on, so I worry that anything I write will come across as poorly informed. |
Oh one other thing I'm having trouble with, if y'all have any tips: when I try to listen on an iOS mobile device, the This is a built-in iOS protection (unmuting requires user interaction, in order to prevent audio spam on a page), but I know there's some way that the OS will let me create an autoplayed, unmuted track, I'm just not sure what that is exactly. Appreciate any steer you might be able to give me, no worries if you've got no clue! :) |
It might be that ICE candidates are included in SDP offer/answer once they are gathered. I wouldn't worry about this too much. Alternatively, you can check if a similar log appears in Nexus when a new person joins.
Try to take a look at chrome://webrtc-internals. You will find there all information about incoming RTP streams, in particular whether browser receives any RTP packets and decodes them. Make also sure that you assign MediaStream to your audio element. The
No worries, we have! We can help :)
The only thing I know is that web browsers come with a similar protection and it is not applied if user somehow interacts with the website (e.g. clicks a button that joins them to a videoconferencing room). Unfortunately, I am have no experience with iOS devices so that's all I know :( |
Regarding the mobile issue I mentioned, it seems as though if microphone audio is being streamed that new
Okay, I'm game! I'll hold of on drafting anything until I get something working in my app that I'm happy with, but I'll keep you posted. Thanks for the tip about chrome://webrtc-internals, I'll give that a go :) |
I think that a simple button that just activates voice chat should be enough? Something you have right now in the right bottom corner |
Yeh I just want to make the UX a bit clearer. My original idea was that as soon as you hop into a game, you can already hear anyone who might have their microphone enabled. Given I don't think this is possible, I'm going to change the UX to match that of other conference-style apps so that you more explicitly have to "join" the voice chat to be able to hear anyone. Related to this, I realised that other conferencing apps do not fully destroy their peer connections when a user mutes their audio (or disables their video, if it's a video conferencing app). E.g. I still see the "recording" pulsing icon on my browser tab when I mute myself in a Google Meet call. So I think my fear about that UX upthread isn't as big of a problem as I thought it was - users are already probably conditioned to still seeing the recording indicator even after muting themselves. |
Tbh I think that explicit join is a better UX. Opening a web-site that can immediately play something is considered as something undesirable :)
I would leave this for the next iteration. This would be a good improvement but correct negotiation seems to be more important 😉 |
Hey there! Firstly, thank you for all your work on this, I'm totally uneducated with respect to WebRTC and yet even I was able to put together a PoC.
Context
I have an app to which I'm trying to add a voice chat feature. Specifically, it's a multiplayer game where I want it to be possible for all players to send and receive audio. I'm essentially copying the two components in live_ex_webrtc and stripping out the bits related to video to do this. That is to say, the architecture is:
pc.send_rtp(...)
live_render()
)The publisher PC isn't established until the user presses a button on the page to start streaming their microphone audio. They can press it again to stop streaming, by which I mean the PC is closed and all state is destroyed. If they press it a third time, the publisher PC is established completely fresh.
The player PC is established when the page is loaded, and never destroyed.
The problem
The problem I have is that in testing, I noticed that if I start/stop the publisher stream (by pressing the aforementioned button repeatedly) enough times, I eventually see the following message:
Unable to protect RTP: :replay_old
in the server logs, and packets stop being sent to any player PCs connected to the server. This usually happens the third time I try to start the publisher stream; not sure if that is of significance.I put a
dbg(packet)
into my code just before thepc.send_rtp()
call, and noticed that I see the:replay_old
message only when thesequence_number
field of theExRTP.Packet
s is lower than it was when the previous publisher PC was disconnected. Indeed on one occasion, I just left the publisher streaming for long enough that the sequence number caught back up to where it had been previously, and the warning ceased and I could hear audio again.I added some state to the player liveview to keep track of the last seen sequence number, and to rewrite any packets to use a sequence number one greater than the last seen, to ensure the player PC never sees a sequence number twice. This solved the problem, but it seems a bit haphazard.
So I'm wondering if I'm doing something wrong to begin with?
Appreciate any help and guidance you're able to give!
References
player.ex
publisher.ex
player.js
publisher.js
The text was updated successfully, but these errors were encountered: