How to stream back audio using External Media Channel using ARI in asterisk

1k views Asked by At

Working with AsterNET.ARI I am able to expose audio stream from asterisk, using ExternalMedia.

Scenario:

  1. Call is started and Stasis App is invoked
  2. Create ExternalMediaChannel that sends stream to a RTP server I created listening from all IPs in Port: 7777.
  3. Create bridge type mixing and add both channels in it

The goal is to send back this stream to this channel that normally should be heared in the originator channel since both channels are in the same bridge.

It looks like the RTP is sent back and received by asterisk but however I'm not able to hear it.

ARI ExternMediaChannel: {"UNICASTRTP_LOCAL_PORT":"15672","UNICASTRTP_LOCAL_ADDRESS":"172.18.33.220"}

Asterisk

Got  RTP packet from    10.114.0.234:55874 (type 111, seq 031742, ts 3934092822, len 000069)

Sent RTP packet to      172.18.33.220:7777 (type 118, seq 029097, ts 1090576, len 000640)

Got  RTP packet from    10.114.0.234:55874 (type 111, seq 031743, ts 3934093782, len 000071)

Sent RTP packet to      172.18.33.220:7777 (type 118, seq 029098, ts 1090896, len 000640)

RTP Server

Sending To: 172.18.33.220:15672

Received From: 172.18.33.220:15672

Sending To: 172.18.33.220:15672

Received From: 172.18.33.220:15672

I can actually print the byte codes received and I know it's the audio because I have saved the byte codes to file and played the file successfully.

How I am receiving and trying to send the stream back (RTP Server):

public class UDPListener
{
    private const int ListenPort = 7777;

    public static void StartListener()
    {
        UdpClient server = new UdpClient(ListenPort);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, ListenPort);

        Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        try
        {
            Console.WriteLine("Listening to: " + ListenPort);

            while (true)
            {
                byte[] bytes = server.Receive(ref groupEP);
                // PRINTS THE BYTE CODES
                // Console.WriteLine($" {Encoding.ASCII.GetString(bytes, 0, bytes.Length)}");

                RtpPacket rcvpacket;
                bool parsedRCV = RtpPacket.TryParse(bytes, out rcvpacket);
                if(parsedRCV){
                    Console.WriteLine($"Received From: {groupEP.Address}:{groupEP.Port}");
                }                   

                RtpPacket packet;
                bool parsed = RtpPacket.TryParse(bytes, out packet);
                if(parsed){
                    Console.WriteLine($"Sending To: {groupEP.Address}:{groupEP.Port}");
                    client.SendTo(packet.PayloadSegment, groupEP);
                }
            }
        }            
    }
}

RtpPacket is a C# class that represents the definition of a RTP packet.

struct RtpPacket
{
    public const int RtpHeaderSize = 12;
    public const int RtpProtocolVersion = 2;

    public int ProtocolVersion { get; private set; }
    public bool PaddingFlag { get; private set; }
    public bool ExtensionFlag { get; private set; }
    public int CsrcCount { get; private set; }
    public bool MarkerBit { get; private set; }
    public int PayloadType { get; private set; }
    public ushort SeqNumber { get; private set; }
    public uint Timestamp { get; private set; }
    public uint SyncSourceId { get; private set; }
    public int ExtensionHeaderId { get; private set; }

    public ArraySegment<byte> PayloadSegment { get; set; }

    internal RtpPacket(ushort seqNumber, ArraySegment<byte> payloadSegment)
    {
        ProtocolVersion = 1;
        PaddingFlag = false;
        ExtensionFlag = false;
        CsrcCount = 0;
        MarkerBit = false;
        PayloadType = 0;
        SeqNumber = 0;
        Timestamp = 0;
        SyncSourceId = 0;
        ExtensionHeaderId = 0;
        SeqNumber = seqNumber;
        PayloadSegment = payloadSegment;
    }

    public static bool TryParse(ArraySegment<byte> byteSegment, out RtpPacket rtpPacket)
    {
        rtpPacket = new RtpPacket();

        Debug.Assert(byteSegment.Array != null, "byteSegment.Array != null");

        if (byteSegment.Count < RtpHeaderSize)
            return false;

        int offset = byteSegment.Offset;
        rtpPacket.ProtocolVersion = byteSegment.Array[offset] >> 6;

        if (rtpPacket.ProtocolVersion != RtpProtocolVersion)
            return false;

        rtpPacket.PaddingFlag = (byteSegment.Array[offset] >> 5 & 1) != 0;
        rtpPacket.ExtensionFlag = (byteSegment.Array[offset] >> 4 & 1) != 0;
        rtpPacket.CsrcCount = byteSegment.Array[offset++] & 0xF;

        rtpPacket.MarkerBit = byteSegment.Array[offset] >> 7 != 0;
        rtpPacket.PayloadType = byteSegment.Array[offset++] & 0x7F;

        rtpPacket.SeqNumber = (ushort)BigEndianConverter.ReadUInt16(byteSegment.Array, offset);
        offset += 2;

        rtpPacket.Timestamp = BigEndianConverter.ReadUInt32(byteSegment.Array, offset);
        offset += 4;

        rtpPacket.SyncSourceId = BigEndianConverter.ReadUInt32(byteSegment.Array, offset);
        offset += 4 + 4 * rtpPacket.CsrcCount;

        if (rtpPacket.ExtensionFlag)
        {
            rtpPacket.ExtensionHeaderId = BigEndianConverter.ReadUInt16(byteSegment.Array, offset);
            offset += 2;

            int extensionHeaderLength = BigEndianConverter.ReadUInt16(byteSegment.Array, offset) * 4;
            offset += 2 + extensionHeaderLength;
        }

        int payloadSize = byteSegment.Offset + byteSegment.Count - offset;

        if (rtpPacket.PaddingFlag)
        {
            int paddingBytes = byteSegment.Array[byteSegment.Offset + byteSegment.Count - 1];
            payloadSize -= paddingBytes;
        }

        rtpPacket.PayloadSegment = new ArraySegment<byte>(byteSegment.Array, offset, payloadSize);
        return true;
    }
}

public static class BigEndianConverter
{
    public static uint ReadUInt32(byte[] buffer, int offset)
    {
        return (uint)(buffer[offset] << 24 |
                       buffer[offset + 1] << 16 |
                       buffer[offset + 2] << 8 |
                       buffer[offset + 3]);
    }

    public static int ReadUInt24(byte[] buffer, int offset)
    {
        return buffer[offset] << 16 |
               buffer[offset + 1] << 8 |
               buffer[offset + 2];
    }

    public static int ReadUInt16(byte[] buffer, int offset)
    {
        return (buffer[offset] << 8) | buffer[offset + 1];
    }
}

Any idea why I am not able to hear the stream back ?

0

There are 0 answers