sippy / rtpproxy

The RTPproxy is a high-performance software proxy for RTP streams that can work together with Sippy B2BUA, Kamailio, OpenSIPS and SER.
http://rtpproxy.org
BSD 2-Clause "Simplified" License
416 stars 114 forks source link

Play command fails #136

Open medeanwz opened 1 year ago

medeanwz commented 1 year ago

Hi, I am using rtpproxy and opensips. I initialize rtpproxy session with rtpproxy_offer("froc"), then run stream2uac(filename,1) to stream the file, and debug shows: INFO:3cbd19e5a7cd4c9b9b7da9dedd28cd61:rtpp_command_ul_handle:574: new session on IPv4 port 39640 created, tag c4d0edb4b0a14600adfd65b6002008c6;1 DBUG:GLOBAL:rtpp_command_split:396: received command "P1 3cbd19e5a7cd4c9b9b7da9dedd28cd61 /usr/local/etc/spp/sounds/service-inactive-ok.wav session c4d0edb4b0a14600adfd65b6002008c6;1 " INFO:3cbd19e5a7cd4c9b9b7da9dedd28cd61:rtpp_stream_handle_play:407: 1 times playing prompt /usr/local/etc/spp/sounds/service-inactive-ok.wav codec 8: SSRC=0xE46E025E, seq=56190 DBUG:GLOBAL:rtpc_doreply:192: sending reply "0\n"

An no errrors, however I see no RTP streams from the port 39640 and nothing is played. I am using rtpproxy 2.2.alpha.9201ab4d (and opensips 3.1.13). Please advise.

Thank you!

sobomax commented 1 year ago

Hi, the problem there is likely to be that playback is requested too early, before reverse stream has been established (i.e. before 183 or 200 OK is processed). In such case the caller's UA has not seen any SDP and is unlikely to be accepting media coming from some random port on internet. I am not sure if it's possible to generate some locally crafted 183 in OpenSIPS, if not then you would probably need to put play command into the corresponding onreply_route instead.

medeanwz commented 1 year ago

I have actually generated a locally crafted 183, on receiving INVITE:

append_to_reply("Content-Type: application/sdp\r\n"); $var(body) = "v=0\r\n"+$(rb{sdp.line,o})+"\r\ns=call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio "+$(var(rtpproxyrp){s.select,1,:})+" RTP/AVP 0 8 101\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-16\r\na=ptime:20\r\na=sendrecv\r\n"; $var(body) = $(var(body){re.subst,/(IP4.).*/\1172.17.111.254/g}); # replace the IP in the body t_reply_with_body(183, "Session Progress", $var(body)); rtpproxy_stream2uac("/usr/local/etc/spp/sounds/service-inactive-ok.wav", -1);

in my generated body I replace o= line, audio port to what rtpproxy returned in rtpproxy_offer (it is in IP:port format so i only select port above) and the IPs. The real problem here is that as soon as I see 183 going out, I do a tcpdump on port returned by rtpproxy and I see RTP coming in from UAC but I dont see any RTP packets from rtpproxy to UAC... Any ideas?

sobomax commented 1 year ago

Well, that is not exactly correct. The port number returned by the rtpproxy in the rtpproxy_offer() is the port to be presented to the UAS on the other side (since it's the port that replaces original port in the INVITE) and then the rtpproxy_answer() generates another port to be sent to UAC on 183/200 . You may try to use rtpproxy_stream2uas() instead and see if it works. I doubt it though, since the rtpproxy has no information about UAS IP at that point. The way to fix is properly is to somehow run rtpproxy_answer() on the "fake" 183, so that correct port filled in and then rtpproxy_stream2uac() should work. We use similar approach in our B2BUA to allow prompt playback to UAC before session has been fully setup. See here for example: https://github.com/sippy/b2bua/blob/master/sippy/Rtp_proxy_session.py#L203

sobomax commented 1 year ago

P.S. Schematically normal call setup looks like the following:

UAC: INVITE->rtpproxy_offer()->UAS port->INVITE :UAS UAC: 183/200<-UAC port<-rtpproxy_answer()<-183/200: UAS

And the RTP flows like the below: UAC: RTP<->UAC port<->rtpproxy<->UAS port<->RTP :UAS

Basically you are hijacking UAS port and present it to UAC, thus from the point of view of the RTPProxy RTP that comes to that port is coming from UAS, not from UAC.

medeanwz commented 1 year ago

Aha, now I understand what the problem is, thank you for detailed explanation. In my scenario however, there is no UAS, I want the call to terminate at opensips and play an early media to UAC. It seems like I will need to stream2uac for sure, but then how do I access "UAC port" (to put it in my generated 183 message) without having a UAS (for this part: UAC: 183/200<-UAC port<-rtpproxy_answer()<-183/200: UAS)?

medeanwz commented 1 year ago

This is everything I found about this. It is claimed to be possible, but in practice it did not work and I dont see rtpproxy streaming anything... and based on explanations above, these should not work either. https://opensips.org/pipermail/users/2016-January/033301.html http://lists.opensips.org/pipermail/users/2016-January/033323.html https://github.com/sipwise/rtpengine/issues/870 https://github.com/OpenSIPS/opensips/issues/1996 Any ideas if this is possible?

medeanwz commented 1 year ago

I had another look into this. As @sobomax explained, we need to create a local 183 message, then feed it to rtpproxy in order to generate a port for it, and then run play command. at this point rtpproxy does not have any commands to accept a SIP body, it read request body directly from a "received message". A solution can be using rtpproxy_engage, assuming that it has hooks on received INVITE, OK, and sending out 183, 200, etc... but it did not work. theoretically, with rtpproxy_engage as soon as our local 183 is ready to send, it should engage and generate outgoing port, but for some reason it did not work - looks like something for rtpproxy opensips module developers to look at... To remind, this is for a scenario that UAC sends INVITE to opensips, opensips does not forward but creates a local 183 and responds and plays a file...