Nik Hendricks
Nik Hendricks

Reputation: 294

varying RTP stream result from custom SIP implementation

I am in the process of creating my own SIP implementation in Node.js. As well as a b2bua as a learning project.

Finding people wise in the ways of SIP has proved to be difficult elsewhere but here I have had good results

this is the GitHub of my library so far node.js-sip

this is the GitHub of my PBX so far FlowPBX

Currently, everything is working as I expect. Although I really have some questions on possible errors in my implementation.

My main issue is with RTP streams. Currently I am utilizing ffmpeg.

my function goes as follows

start_stream(call_id, sdp){
        console.log('Starting Stream')
        let port = sdp.match(/m=audio (\d+) RTP/)[1];
        let ip = sdp.match(/c=IN IP4 (\d+\.\d+\.\d+\.\d+)/)[1];
        let codec_ids = sdp.match(/m=audio \d+ RTP\/AVP (.+)/)[1].split(' ');
        let ffmpeg_codec_map = {
            'opus': 'libopus',
            'PCMU': 'pcm_mulaw',
            'PCMA': 'pcm_alaw',
            'telephone-event': 'pcm_mulaw',
            'speex': 'speex',
            'G722': 'g722',
            'G729': 'g729',
            'GSM': 'gsm',
            'AMR': 'amr',
            'AMR-WB': 'amr_wb',
            'iLBC': 'ilbc',
            'iSAC': 'isac',
        }

        let codecs = [];
        sdp.split('\n').forEach(line => {
            if(line.includes('a=rtpmap')){
                let codec = line.match(/a=rtpmap:(\d+) (.+)/)[2];
                let c_id = line.match(/a=rtpmap:(\d+) (.+)/)[1];
                codecs.push({                    
                    name: codec.split('/')[0],
                    rate: codec.split('/')[1],
                    channels: codec.split('/')[2] !== undefined ? codec.split('/')[2] : 1,
                    id: c_id
                })
            }
        })

        console.log('codecs')
        console.log(codecs)

        let selected_codec = codecs[0]
        if(selected_codec.name == 'telephone-event'){
            selected_codec = codecs[1]
            console.log(selected_codec)
        }

        //see if opus is available
        codecs.forEach(codec => {
            if(codec.name == 'opus'){
                selected_codec = codec;
            }
        })

        if(selected_codec.name != 'opus'){
            //check if g729 is available
            codecs.forEach(codec => {
                if(codec.name == 'G729'){
                    selected_codec = codec;
                }
            })
        }

        console.log('selected_codec')
        console.log(selected_codec)

        let spawn = require('child_process').spawn;
        let ffmpegArgs = [
            '-re',
            '-i', 'song.mp3',
            '-acodec', ffmpeg_codec_map[selected_codec.name],
            '-ar', selected_codec.rate,
            '-ac', selected_codec.channels,
            '-payload_type', selected_codec.id,
            '-f', 'rtp', `rtp://${ip}:${port}`
        ];

        let ffmpeg = spawn('ffmpeg', ffmpegArgs);

        ffmpeg.stdout.on('data', (data) => {
            console.log(`stdout: ${data}`);
        });
        ffmpeg.stderr.on('data', (data) => {
            console.error(`stderr: ${data}`);
        });




}

When using zoiper to test it works great. I have seen the mobile version negotiate speex and the desktop version negotiate opus mostly for the codec.

today I tried to register a grandstream phone to my pbx and the rtp stream is blank audio. opus is available and I have tried to prefer that in my stream but still even when selecting that I cannot get audio to the grandstream phone. This is the same case for a yealink phone. I can only get zoiper to work so far.

what could be causing this behavior? there is a clear path of communication between everything just like the zoiper client's I have used.

Additionally in my sip implementation, how important is the concept of a dialog? currently, I just match messages by Call-ID

and then choose what to send based on the method or response. is there any other underlying dialog functionality that I may need to implement?

It would just be awesome to get someone who really knows what they are talking about eyes on some of my code to direct this large codebase in the right direction but I realize that a big ask lol.

Upvotes: 0

Views: 30

Answers (0)

Related Questions