Example #1
0
 /// <summary>
 /// Allows an arbitrary block of bytes to be sent on the RTP channel. This is mainly used for the Gingle
 /// client which needs to send a STUN binding request to the Google Voice gateway.
 /// </summary>
 public void SendRTPRaw(byte[] buffer, int length)
 {
     if (_rtpAudioChannel != null)
     {
         _rtpAudioChannel.SendRTPRaw(buffer);
     }
 }
Example #2
0
        /// <summary>
        /// Event handler for receiving an audio sample that is ready for encoding, packaging into RTP and sending to the remote end
        /// of the VoIP call.
        /// </summary>
        private void RTPChannelSampleAvailable(object sender, WaveInEventArgs e)
        {
            TimeSpan samplePeriod = DateTime.Now.Subtract(_lastInputSampleReceivedAt);

            _lastInputSampleReceivedAt = DateTime.Now;
            _inputSampleCount++;

            _audioLogger.Debug(_inputSampleCount + " sample period " + samplePeriod.TotalMilliseconds + "ms,  sample bytes " + e.BytesRecorded + ".");

            byte[] sample      = new byte[e.Buffer.Length / 2];
            int    sampleIndex = 0;

            for (int index = 0; index < e.Buffer.Length; index += 2)
            {
                var ulawByte = MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(e.Buffer, index));
                sample[sampleIndex++] = ulawByte;
            }

            m_rtpChannel.SendRTPRaw(sample);
        }
Example #3
0
        private void Uac_CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse)
        {
            logger.Debug($"{ prefix } Call answered; { sipResponse.StatusCode } { sipResponse.Status }");

            switch (sipResponse.StatusCode)
            {
            case 404:
                logger.Error($"{ prefix } Received 404 Not Found from remote endpoint");
                break;

            case 486:
                // Busy
                logger.Error($"{ prefix } Received 486 Remote endpoint is busy; try again later");
                break;

            case 488:
                // Possible audio format issue
                logger.Error($"{ prefix } Received 488 Not Acceptable from remote endpoint; check audio format");
                break;

            case 503:
                // Check Twilio service and geo-permissions
                logger.Error($"{ prefix } Received 503 Service Unavailable from remote endpoint; check service permissions");
                break;

            case 200:
                if (sipResponse.Header.ContentType != SDP.SDP_MIME_CONTENTTYPE)
                {
                    logger.Error($"{ prefix } Received incorrect content type");

                    Stop();
                    return;
                }

                if (sipResponse.Body.IsNullOrBlank())
                {
                    logger.Error($"{ prefix } Received an empty SDP payload");

                    Stop();
                    return;
                }

                var sdp          = SDP.ParseSDPDescription(sipResponse.Body);
                var ip           = IPAddress.Parse(sdp.Connection.ConnectionAddress);
                var announcement = sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault();

                if (announcement != null)
                {
                    if (announcement.Port != 0)
                    {
                        rtpChannel.OnControlDataReceived       += (b) => { logger.Debug($"{prefix} Control Data Received; {b.Length} bytes"); };
                        rtpChannel.OnControlSocketDisconnected += () => { logger.Debug($"{prefix} Control Socket Disconnected"); };

                        rtpChannel.RemoteEndPoint = new IPEndPoint(ip, announcement.Port);
                        rtpChannel.Start();

                        // Send some setup parameters to punch a hole in the firewall/router
                        rtpChannel.SendRTPRaw(new byte[] { 80, 95, 198, 88, 55, 96, 225, 141, 215, 205, 185, 242, 00 });
                    }
                    else
                    {
                        logger.Error($"{ prefix } Remote endpoint did not specify a port number");
                        return;
                    }
                }
                else
                {
                    logger.Error($"{ prefix } Remote endpoint has not valid audio announcement");
                    return;
                }
                break;
            }
        }
        private void Transport_SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            var endpoint = new SIPEndPoint(SIPProtocolsEnum.udp, publicIPAddress, localSIPEndPoint.Port);

            if (sipRequest.Method == SIPMethodsEnum.INVITE)
            {
                if (transaction != null)
                {
                    return;
                }

                logger.DebugFormat("{0} Incoming call from {1}", prefix, sipRequest.Header.From.FromURI.User);

                transaction = transport.CreateUASTransaction(sipRequest, remoteEndPoint, endpoint, null);
                agent       = new SIPServerUserAgent(
                    transport,
                    null,
                    sipRequest.Header.From.FromURI.User,
                    null,
                    SIPCallDirection.In,
                    null,
                    null,
                    null,
                    transaction);

                agent.CallCancelled       += Agent_CallCancelled;
                agent.TransactionComplete += Agent_TransactionComplete;

                agent.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                agent.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);

                var answer  = SDP.ParseSDPDescription(agent.CallRequest.Body);
                var address = IPAddress.Parse(answer.Connection.ConnectionAddress);
                var port    = answer.Media.FirstOrDefault(m => m.Media == SDPMediaTypesEnum.audio).Port;
                var random  = Crypto.GetRandomInt(5).ToString();
                var sdp     = new SDP
                {
                    Version     = 2,
                    Username    = "******",
                    SessionId   = random,
                    Address     = localIPEndPoint.Address.ToString(),
                    SessionName = "redfox_" + random,
                    Timing      = "0 0",
                    Connection  = new SDPConnectionInformation(publicIPAddress.ToString())
                };

                rtpChannel = new RTPChannel
                {
                    DontTimeout    = true,
                    RemoteEndPoint = new IPEndPoint(address, port)
                };

                rtpChannel.SetFrameType(FrameTypesEnum.Audio);
                // TODO Fix hardcoded ports
                rtpChannel.ReservePorts(15000, 15090);
                rtpChannel.OnFrameReady += Channel_OnFrameReady;
                rtpChannel.Start();

                // Send some setup parameters to punch a hole in the firewall/router
                rtpChannel.SendRTPRaw(new byte[] { 80, 95, 198, 88, 55, 96, 225, 141, 215, 205, 185, 242, 00 });

                rtpChannel.OnControlDataReceived       += (b) => { logger.Debug($"{prefix} Control Data Received; {b.Length} bytes"); };
                rtpChannel.OnControlSocketDisconnected += () => { logger.Debug($"{prefix} Control Socket Disconnected"); };

                var announcement = new SDPMediaAnnouncement
                {
                    Media        = SDPMediaTypesEnum.audio,
                    MediaFormats = new List <SDPMediaFormat>()
                    {
                        new SDPMediaFormat((int)SDPMediaFormatsEnum.PCMU, "PCMU", 8000)
                    },
                    Port = rtpChannel.RTPPort
                };

                sdp.Media.Add(announcement);

                SetState(State.Listening, sipRequest.Header.From.FromURI.User);

                agent.Progress(SIPResponseStatusCodesEnum.Accepted, null, null, null, null);
                agent.Answer(SDP.SDP_MIME_CONTENTTYPE, sdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);

                SetState(State.Busy, "");
                return;
            }
            if (sipRequest.Method == SIPMethodsEnum.BYE)
            {
                if (State != State.Busy)
                {
                    return;
                }

                logger.DebugFormat("{0} Hangup from {1}", prefix, sipRequest.Header.From.FromURI.User);

                var noninvite = transport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, endpoint, null);
                var response  = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);

                noninvite.SendFinalResponse(response);

                SetState(State.Finished, Endpoint);

                rtpChannel.OnFrameReady -= Channel_OnFrameReady;
                rtpChannel.Close();

                agent.TransactionComplete -= Agent_TransactionComplete;
                agent.CallCancelled       -= Agent_CallCancelled;
                agent       = null;
                transaction = null;

                SetState(State.Ready, Endpoint);

                return;
            }
            if (sipRequest.Method == SIPMethodsEnum.ACK)
            {
            }
            if (sipRequest.Method == SIPMethodsEnum.CANCEL)
            {
            }
        }