Java客户端将音频发送到UDP服务器

时间:2014-05-04 15:58:07

标签: java android tcp udp streaming

我正在寻找一些链接/源代码/教程,介绍如何实现能够将音频发送到服务器的Java客户端(下图)。它将能够发送一个音频文件,然后由服务器接收并通过计算机扬声器播放。

我还想问一下,使用UDP或TCP服务器会更好地适应这种情况吗?因为我将开发一个记录声音的Android应用程序,然后将其发送到服务器,以便通过计算机扬声器实时播放。

package com.datagram;

import java.io.ByteArrayInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;

class Server {

AudioInputStream audioInputStream;
static AudioInputStream ais;
static AudioFormat format;
static boolean status = true;
static int port = 50005;
static int sampleRate = 44100;

public static void main(String args[]) throws Exception {

    DatagramSocket serverSocket = new DatagramSocket(50005);
    byte[] receiveData = new byte[4000];

    format = new AudioFormat(sampleRate, 16, 1, true, false);

    while (status == true) {    

        DatagramPacket receivePacket = new DatagramPacket(receiveData,
                receiveData.length);

        serverSocket.receive(receivePacket);
        System.out.println("It works");

        ByteArrayInputStream baiss = new ByteArrayInputStream(
                receivePacket.getData());

        ais = new AudioInputStream(baiss, format, receivePacket.getLength());

        toSpeaker(receivePacket.getData());


    }
}

public static void toSpeaker(byte soundbytes[]) {
    try {

        DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
        SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);

        sourceDataLine.open(format);

        FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
        volumeControl.setValue(100.0f);

        sourceDataLine.start();
        sourceDataLine.open(format);

        sourceDataLine.start();

        System.out.println("format? :" + sourceDataLine.getFormat());

        sourceDataLine.write(soundbytes, 0, soundbytes.length);
        System.out.println(soundbytes.toString());
        sourceDataLine.drain();
        sourceDataLine.close();
    } catch (Exception e) {
        System.out.println("Not working in speakers...");
        e.printStackTrace();
    }
}
}

1 个答案:

答案 0 :(得分:3)

首先是一个小小的澄清:你要做的事情是音频流(只是你知道 - 它将帮助你进行任何未来的谷歌搜索)。

好的,一次一个答案:

  1. "使用UDP或TCP服务器更好吗?"

    • TCP协议的细节使它不是流媒体的好选择(除非你知道如何正确使用它,这不容易但可能)。 TCP不好的原因是存在重传机制。当数据包在网络中损坏或丢失时,TCP协议请求此数据包重新传输(这是模型的简化,但它足以用于解释目的)。当传输需要实时播放的音频数据时,重传不能很好地工作。想象一下,你正在倾听某人的声音并突然停止声音,然后再次开始(延迟)。

    • 基本上UDP更好,但您必须意识到UDP协议无法确保数据报(UDP协议的消息)将以与它们从发送方出来的顺序来到接收方。因此,您必须确保丢弃任何错误顺序的数据报或缓冲传入的数据报并重新建立正确的顺序。此外,您必须记住,UDP协议不提供任何保护传输的机制 - 我的意思是您无法确定数据报是否能够安全地通过网络(它们可能会丢失并且UDP协议无法控制它)。 / p>

    • 最好的想法是不使用它们。您应该尝试实施RTP协议。

  2. "如何创建能够向所述服务器发送音频的Android客户端?"

    • 我可以看到你正在使用AudioFormat来处理音频。

    • 您需要做的是找到能够以与您服务器应用中的AudioFormat相同的格式从Android麦克风获取音频的内容。

    • 从AudioFormat文档中我可以看到您使用特定的采样率(变量 sampleRate ),您使用默认编码,即PCM,16位样本大小,带符号值和Little Endian位约定。

    • 你应该在Android中看到的是AudioRecord,它可以从麦克风中获取原始音频帧。有很多关于如何使用AudioRecord的例子,其中大多数都使用PCM 16编码。他们中的大多数都会将音频写入文件,但没有什么可以阻止你将其推送到某种网络套接字。只是谷歌吧。

    • 请记住使用与您在服务器中使用的采样率相同的AudioRecord。

    • 最后需要澄清的是Endianness。 Endianness依赖于cpu架构。大多数Android设备都使用Little Endian约定,因此您无需更改服务器代码中的任何内容。但是,您应该知道某些设备可能正在使用Big Endian。更多解释here