Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VoIP RTP Streaming from/to server (in Java) to/from android

My target is to have a push-to-talk chat app in GSM/UMTS/LTE networks; initially I wanted use multicast addresses and peer-to-peer without overload the server; unfortunatly, after deep investigation, I discovered that multicast is not allowed in GSM/UMTS/LTE networks, therefore I have to use the server in order to bounce the VoIP packets. I' don't like very much this solution because I have to overload the server, but I didn't find any better solution. If you have an alternative solution is very much apprieciated...

Therefore I have to send VoIP from an android client to a server (PC), and viceversa. The server is in Java, it has to receive the VoIP packets and then to send the VoIP packets to other N clients; the server is a bouncer of VoIP packets.

I developped the code, but it doesn't work; I don't have any error, simply I had very bad VoIP service: I loose a lot of pieces and what I hear is very much noised... Where is the error? I suppose It should be in the server code; the server simply get the packet and resend them, without know that they are VoIP on RTP.

Please find below

  • the code I use to send the VoIP packets to server. It works because I don't have problems when I use it for individual call sending the VoIP packets directly from Android to Android; the code to receive in android the packets from server is very similar, so I don't recopy it. As you can see I use android.net.rtp .
  • the code I use on the Java server to bounce the VoIP packets

Thank you in advance, Fausto

// ANDROID CODE USED TO SEND VOIP TO SERVER

//Attribute definition
private static final AudioCodec myAudioCodec_COSTANTE = AudioCodec.PCMU ; 
private static final int myAudioGroupTX_COSTANTE = AudioGroup.MODE_NORMAL ; 
private static final int myAudioGroupRX_COSTANTE = AudioGroup.MODE_NORMAL ;
private static final int myRtpStreamTX_COSTANTE = RtpStream.MODE_SEND_ONLY ;
private static final int myRtpStreamRX_COSTANTE = RtpStream.MODE_RECEIVE_ONLY ; 
private static final int myAudioManagerTX_COSTANTE = AudioManager.MODE_IN_COMMUNICATION;
private static final int myAudioManagerRX_COSTANTE = AudioManager.MODE_IN_COMMUNICATION; 

//Method called for VoIP trasmission
myAudioStream = new AudioStream(localClientIP);
myAudioGroup = new AudioGroup();
myAudioManager =  (AudioManager) myContext.getSystemService(Context.AUDIO_SERVICE);

myAudioGroup.setMode(myAudioGroupTX_COSTANTE);
myAudioStream.join(null); 
myAudioStream.setCodec(myAudioCodec_COSTANTE);
myAudioStream.setMode(myRtpStreamTX_COSTANTE);
myAudioStream.associate(ipaddress_Server, port_Server)    
myAudioStream.join(myAudioGroup); 
myAudioManager.setMode(myAudioManagerTX_COSTANTE);
myAudioManager.setSpeakerphoneOn(false);
myAudioManager.setMicrophoneMute(false);

//JAVA SERVER CODE USED TO RECEIVE VOIP FROM ANDROID AND TO RESEND IT TO SERVER

DatagramSocket datagramSocket_RX_VoIP= new DatagramSocket();
DatagramSocket datagramSocket_TX_VoIP= new DatagramSocket();
int unicast_port_TX_VoIP = 5000 ;
String unicast_ip_TX_VoIP = "192.168.0.3";

    Thread t = new Thread(new Runnable() {
    public void run() {
    try {
        DatagramPacket myPacket;
        while (true) {
            myPacket = ManagePacket.initializePacket(); //Function to prepare the packe ; the problem is not here!!!
            datagramSocket_RX_VoIP.receive(myPacket);

            InetAddress ppp =  InetAddress.getByName(unicast_ip_TX_VoIP);
            myPacket.setAddress(ppp);
            myPacket.setPort( unicast_port_TX_VoIP ) ;
            datagramSocket_TX_VoIP.send(myPacket);
        }

    }  catch (Exception ex) {
        log.debug("Exception: " + ex.getMessage(), ex);
    }
    }
    });
    t.start();                                        
like image 550
Fausto70 Avatar asked Jun 19 '15 22:06

Fausto70


1 Answers

You don't give enough detail about your application. With any UDP streaming application you need to address the following issues:

  • Network Jitter and Buffering: When a packet arrives, you cannot play the audio immediately after you receive it because the next packet might be later than expected and you will have a gap in your audio playback. The variance in the arrival rate is called network jitter. You need to buffer some amount of data before you try to play back. Usually you use some sort of ring buffer.

  • Packet loss: There will be packet losses with UDP. You need to "deal" with this. If you send 10 packets and packet #4 is missing, you can't play packet #3 then packet #5. It will sound bad. Ways to deal with this:

    • Loss Concealment: Try to minimize the bad effect off a packet lost. You can play silence (although this doesn't sound the best unless you fade it to silence). You can "estimate" the lost audio by generating a missing audio by examining the surrounding packets.
    • Forward Error Correction: Send packets more than once. There are numerous ways and schemes. The tradeoff is higher latency and more network utilization
  • Out of order arrivals: Packets may arrive out of order. Use the RTP sequence numbers to deal with this.

Audio streaming is not a trivial task. You can't just open a socket, send data, and play it on the other end and expect it to work. Your biggest concern with UDP streaming is network jitter and packet loss. If you don't want to deal with losses and you can have some extra latency, use TCP but be sure to buffer up enough audio before you start playing.

like image 147
jaybers Avatar answered Nov 17 '22 23:11

jaybers