【问题标题】:Java Client to Send Audio to UDP ServerJava 客户端向 UDP 服务器发送音频
【发布时间】:2014-06-20 22:06:02
【问题描述】:

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

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

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();
    }
}
}

【问题讨论】:

    标签: java android tcp udp streaming


    【解决方案1】:

    首先要澄清一点:您想要做的是音频流(只是让您知道 - 它会帮助您进行任何未来的谷歌搜索)。

    好的,一次回答一个:

    1. “使用UDP还是TCP服务器更好?”

      • TCP 协议的特殊性使其不是真正的流式传输的好选择(除非您知道如何正确使用它,这并不容易但可能)。 TCP不好的原因是重传机制的存在。当数据包在网络中损坏或丢失时,TCP 协议会请求重新传输此数据包(这是模型的简化,但足以用于解释目的)。在传输需要实时播放的音频数据时,重传效果不佳。想象一下,您正在听某人的声音,突然声音停止,然后又重新开始(有延迟)。

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

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

    2. “如何创建能够向上述服务器发送音频的安卓客户端?”

      • 我可以看到您正在使用 AudioFormat 作为处理音频的东西。

      • 您需要做的是找到可以从 android 麦克风中获取与您的服务器应用中的 AudioFormat 可以播放的格式相同的音频。

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

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

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

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

    【讨论】:

    • 哇,谢谢你的详细回答。我会尝试编写 RTP 服务器的代码吗?或者在使用这个应用程序的同时继续开发应用程序?正如我尝试过但失败得很惨。或者我应该去学习 RTP 吗?因为我只有 2 周的时间来完成这项工作......希望得到一些指导 :)
    • 我认为第一步应该是制作安卓客户端,因为录音会变得很烦人。 udp 服务器可以正常工作(但它不是最好的解决方案)。当您使用完您的 android 客户端(您完成了成功的音频传输)并且您认为您有足够的时间重新设计您的传输模型时,您可以开始学习 RTP。
    • 好,我开始编写android客户端,你有这方面的经验吗?如果我遇到任何障碍,我可以向你寻求更多帮助吗?非常感谢您的回复,我真的很感激。
    • 我最近一直在使用一个使用 audiorecord 的应用程序,所以我必须尽可能地理解它。我有经验吗?谁知道...?:D AudioRecord 有时对我来说还是有点烦人:P。你可以问我你是否有一些严重的阻滞剂。如果我有时间,我会尽力回答,但我不能保证任何事情。
    • 顺便说一句,如果您认为我的回答回答了您的问题,请使用投票箭头下的勾号(复选标记)接受它,请:)。
    猜你喜欢
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多