VoIP RTP 流媒体 from/to 服务器(在 Java 中)to/from android
VoIP RTP Streaming from/to server (in Java) to/from android
我的目标是在 GSM/UMTS/LTE 网络中拥有一个即按即说的聊天应用程序;最初我想使用多播地址和点对点而不会使服务器过载;不幸的是,经过深入调查,我发现 GSM/UMTS/LTE 网络不允许多播,因此我必须使用服务器来反弹 VoIP 数据包。我不太喜欢这个解决方案,因为我不得不让服务器过载,但我没有找到更好的解决方案。如果您有替代解决方案,非常感谢...
因此我必须将 VoIP 从 android 客户端发送到服务器 (PC),反之亦然。服务器在Java,它必须接收VoIP数据包,然后将VoIP数据包发送给其他N个客户端;服务器是 VoIP 数据包的保镖。
我开发了代码,但是没有用;我没有任何错误,只是我的 VoIP 服务非常糟糕:我丢失了很多部件,而且我听到的声音非常嘈杂……错误在哪里?我想它应该在服务器代码中;服务器只是获取数据包并重新发送它们,而不知道它们是 RTP 上的 VoIP。
请在下面找到
- 我用来将 VoIP 数据包发送到服务器的代码。它之所以有效,是因为当我将它用于直接从 Android 向 Android 发送 VoIP 数据包的个人呼叫时,我没有遇到任何问题; android 从服务器接收数据包的代码非常相似,所以我不再复制它。如您所见,我使用 android.net.rtp .
- 我在 Java 服务器上用来反弹 VoIP 数据包的代码
提前谢谢你,福斯托
// ANDROID 用于向服务器发送 VOIP 的代码
//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 用于从 ANDROID 接收 VOIP 并将其重新发送到服务器的服务器代码
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();
您没有提供有关申请的足够详细信息。对于任何 UDP 流应用程序,您都需要解决以下问题:
网络抖动和缓冲:当数据包到达时,您无法在收到后立即播放音频,因为下一个数据包可能会比预期晚,并且您的音频播放会出现间隙。到达率的变化称为网络抖动。在尝试播放之前,您需要缓冲一些数据。通常你使用某种环形缓冲区。
丢包:使用UDP会有丢包。你需要 "deal" 这个。如果您发送 10 个数据包而数据包 #4 丢失,则您无法播放数据包 #3 然后数据包 #5。听起来会很糟糕。处理方法:
- 丢失隐藏:尽量减少丢失数据包的不良影响。您可以播放静音(尽管这听起来不是最好的,除非您将其淡化为静音)。您可以通过检查周围的数据包生成丢失的音频来 "estimate" 丢失的音频。
- 前向纠错:多次发送数据包。有很多方法和方案。权衡是更高的延迟和更高的网络利用率
- 无序到达:数据包可能无序到达。使用RTP序列号来处理这个问题。
音频流不是一项微不足道的任务。您不能只打开一个套接字、发送数据并在另一端播放它并期望它能正常工作。您对 UDP 流式传输最关心的是网络抖动和数据包丢失。如果您不想处理丢失并且可能会有一些额外的延迟,请使用 TCP,但请务必在开始播放之前缓冲足够的音频。
我的目标是在 GSM/UMTS/LTE 网络中拥有一个即按即说的聊天应用程序;最初我想使用多播地址和点对点而不会使服务器过载;不幸的是,经过深入调查,我发现 GSM/UMTS/LTE 网络不允许多播,因此我必须使用服务器来反弹 VoIP 数据包。我不太喜欢这个解决方案,因为我不得不让服务器过载,但我没有找到更好的解决方案。如果您有替代解决方案,非常感谢...
因此我必须将 VoIP 从 android 客户端发送到服务器 (PC),反之亦然。服务器在Java,它必须接收VoIP数据包,然后将VoIP数据包发送给其他N个客户端;服务器是 VoIP 数据包的保镖。
我开发了代码,但是没有用;我没有任何错误,只是我的 VoIP 服务非常糟糕:我丢失了很多部件,而且我听到的声音非常嘈杂……错误在哪里?我想它应该在服务器代码中;服务器只是获取数据包并重新发送它们,而不知道它们是 RTP 上的 VoIP。
请在下面找到
- 我用来将 VoIP 数据包发送到服务器的代码。它之所以有效,是因为当我将它用于直接从 Android 向 Android 发送 VoIP 数据包的个人呼叫时,我没有遇到任何问题; android 从服务器接收数据包的代码非常相似,所以我不再复制它。如您所见,我使用 android.net.rtp .
- 我在 Java 服务器上用来反弹 VoIP 数据包的代码
提前谢谢你,福斯托
// ANDROID 用于向服务器发送 VOIP 的代码
//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 用于从 ANDROID 接收 VOIP 并将其重新发送到服务器的服务器代码
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();
您没有提供有关申请的足够详细信息。对于任何 UDP 流应用程序,您都需要解决以下问题:
网络抖动和缓冲:当数据包到达时,您无法在收到后立即播放音频,因为下一个数据包可能会比预期晚,并且您的音频播放会出现间隙。到达率的变化称为网络抖动。在尝试播放之前,您需要缓冲一些数据。通常你使用某种环形缓冲区。
丢包:使用UDP会有丢包。你需要 "deal" 这个。如果您发送 10 个数据包而数据包 #4 丢失,则您无法播放数据包 #3 然后数据包 #5。听起来会很糟糕。处理方法:
- 丢失隐藏:尽量减少丢失数据包的不良影响。您可以播放静音(尽管这听起来不是最好的,除非您将其淡化为静音)。您可以通过检查周围的数据包生成丢失的音频来 "estimate" 丢失的音频。
- 前向纠错:多次发送数据包。有很多方法和方案。权衡是更高的延迟和更高的网络利用率
- 无序到达:数据包可能无序到达。使用RTP序列号来处理这个问题。
音频流不是一项微不足道的任务。您不能只打开一个套接字、发送数据并在另一端播放它并期望它能正常工作。您对 UDP 流式传输最关心的是网络抖动和数据包丢失。如果您不想处理丢失并且可能会有一些额外的延迟,请使用 TCP,但请务必在开始播放之前缓冲足够的音频。