Отправка потока аудио через TCP, UnsupportedAudioFileException

Мне удалось отправить и прочитать текстовые и графические данные через сокеты TCP. Но я не могу отправлять и читать данные аудиопотока.

пример кода на сервере:

public class ServerAudio {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        try {
            ServerSocket serverSocker = new ServerSocket();
            Socket client = null;
            serverSocker.bind(new InetSocketAddress(6666));
            if (serverSocker.isBound()) {
                client = serverSocker.accept();
                OutputStream out = client.getOutputStream();
                while (true) {
                    AudioInputStream ain = testPlay("C:/Users/Public/Music/Sample Music/adios.wav");
                    if (ain != null) {
                        AudioSystem.write(ain, AudioFileFormat.Type.WAVE, out);
                    }
                }
            }
            serverSocker.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static AudioInputStream testPlay(String filename) {
        AudioInputStream din = null;
        try {
            File file = new File(filename);
            AudioInputStream in = AudioSystem.getAudioInputStream(file);
            System.out.println("Before :: " + in.available());

            AudioFormat baseFormat = in.getFormat();
            AudioFormat decodedFormat =
                    new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED, baseFormat.getSampleRate(),
                            8, baseFormat.getChannels(), baseFormat.getChannels(),
                            baseFormat.getSampleRate(), false);
            din = AudioSystem.getAudioInputStream(decodedFormat, in);
            System.out.println("After :: " + din.available());
            return din;
        } catch (Exception e) {
            // Handle exception.
            e.printStackTrace();
        }
        return din;
    }
}

пример кода на клиенте:

public class RDPPlayAudioBytes {
    private static Socket socket;
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // SocketAddress socketAddress = new InetSocketAddress("172.19.1.50", 4444);
        try {
            Socket socket = new Socket("172.19.0.109", 6666);
            // socket.connect(socketAddress, 10000);
            if (socket != null && socket.isConnected()) {
                InputStream inputStream = socket.getInputStream();
                // DataInputStream din=new DataInputStream(inputStream);
                while (inputStream != null) {
                    if (inputStream.available() > 0) {
                        System.out.println(inputStream.available());
                        InputStream bufferedIn = new BufferedInputStream(inputStream);
                        System.out.println("********** Buffred *********" + bufferedIn.available());
                        AudioInputStream ais = AudioSystem.getAudioInputStream(bufferedIn);
                    }
                }
            }


        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } /*
           * catch (LineUnavailableException e) { // TODO Auto-generated catch block
           * e.printStackTrace(); }
           */catch (UnsupportedAudioFileException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Где я получаю исключение как

javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream
    at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)

Где я заметил, что сервер отправляет 35394 байта данных клиенту, но на стороне клиента мы получаем 8192 байта данных. Я не могу понять, почему на стороне клиента отсутствуют байты.

Пожалуйста, помогите мне, как отправить аудиопоток через TCP-сокеты.

Ответ 1

Сервер: Сервер просто передает байты звукового файла. Нет задействованного AudioSytem. Передайте звуковой файл в качестве аргумента:

java AudioServer "C:/Users/Public/Music/Sample Music/adios.wav"

Код для класса AudioServer:

import java.io.*;
import java.net.*;

public class AudioServer {
    public static void main(String[] args) throws IOException {
        if (args.length == 0)
            throw new IllegalArgumentException("expected sound file arg");
        File soundFile = AudioUtil.getSoundFile(args[0]);

        System.out.println("server: " + soundFile);

        try (ServerSocket serverSocker = new ServerSocket(6666); 
            FileInputStream in = new FileInputStream(soundFile)) {
            if (serverSocker.isBound()) {
                Socket client = serverSocker.accept();
                OutputStream out = client.getOutputStream();

                byte buffer[] = new byte[2048];
                int count;
                while ((count = in.read(buffer)) != -1)
                    out.write(buffer, 0, count);
            }
        }

        System.out.println("server: shutdown");
    }
}

Клиент: Клиент может воспроизводить звуковой файл, переданный через командную строку для тестирования, если он работает:

java AudioClient "C:/Users/Public/Music/Sample Music/adios.wav"

Вызывается без аргумента, который он подключает к серверу и воспроизводит файл, полученный через Socket:

java AudioClient

код:

import java.io.*;
import java.net.*;
import javax.sound.sampled.*;


public class AudioClient {
    public static void main(String[] args) throws Exception {
        if (args.length > 0) {
            // play a file passed via the command line
            File soundFile = AudioUtil.getSoundFile(args[0]);
            System.out.println("Client: " + soundFile);
            try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(soundFile))) {
                play(in);
            }
        }
        else {
            // play soundfile from server
            System.out.println("Client: reading from 127.0.0.1:6666");
            try (Socket socket = new Socket("127.0.0.1", 6666)) {
                if (socket.isConnected()) {
                    InputStream in = new BufferedInputStream(socket.getInputStream());
                    play(in);
                }
            }
        }

        System.out.println("Client: end");
    }


    private static synchronized void play(final InputStream in) throws Exception {
        AudioInputStream ais = AudioSystem.getAudioInputStream(in);
        try (Clip clip = AudioSystem.getClip()) {
            clip.open(ais);
            clip.start();
            Thread.sleep(100); // given clip.drain a chance to start
            clip.drain();
        }
    }
}

Утилитный класс, используемый AudioServer и AudioClient:

import java.io.File;

public class AudioUtil {
    public static File getSoundFile(String fileName) {
        File soundFile = new File(fileName);
        if (!soundFile.exists() || !soundFile.isFile())
            throw new IllegalArgumentException("not a file: " + soundFile);
        return soundFile;
    }
}

Ответ 2

Байты будут получены полностью, поскольку TCP является надежным. Есть еще одна небольшая проблема. Вам необходимо воспроизвести принятый звук из аудиопотока, только создание потока входного аудиосигнала не будет воспроизводиться. Могут быть разные возможные способы воспроизведения полученного звука. Вы можете использовать Клип или SourceDataLine из Java Sound API. Кроме того, не создавайте AudioInputStream несколько раз. Просто создайте его один раз и используйте его.

Здесь одно из возможных решений, которое вы можете использовать для воспроизведения полученного звука.

public class RDPPlayAudioBytes {

private static Socket socket;
private static BufferedInputStream inputStream;

/**
 * @param args
 * @throws javax.sound.sampled.LineUnavailableException
 */
public static void main(String[] args) throws LineUnavailableException {
    // TODO Auto-generated method stub
    // SocketAddress socketAddress = new InetSocketAddress("172.19.1.50", 4444);
    try {
        socket = new Socket("127.0.0.1", 6666);

        if (socket.isConnected()) {

            inputStream = new BufferedInputStream(socket.getInputStream());

            Clip clip = AudioSystem.getClip();
            AudioInputStream ais = AudioSystem.getAudioInputStream(inputStream);
            clip.open(ais);
            clip.start();

            while (inputStream != null) {
                if (clip.isActive()) {

                    System.out.println("********** Buffred *********" + inputStream.available());

                }
            }

        }

    } catch (IOException | UnsupportedAudioFileException e) {
        System.err.println(e);
    }
}
}

Вам может потребоваться другая реализация, основанная на ваших требованиях. Это просто демонстрация того, как вы можете использовать AudioInputStream для воспроизведения звука с помощью Клип. Вы можете заметить довольно много изменений в коде, который я опубликовал. Надеюсь, вы хорошо это понимаете.

Вы можете ссылаться на документы Java Sound API, чтобы погрузиться в основы воспроизводить аудио.

ПРИМЕЧАНИЕ:

  • Для вашего удобства вам может потребоваться реализовать прослушиватель, чтобы программа не закрывалась до завершения воспроизведения аудиоклипа. В текущей реализации этого не произойдет из-за используемого цикла. Но лучше использовать слушателя. Вы можете называть этот пост.

  • Вы также можете прочитать аудиоданные в байт [], а затем воспроизвести его, как только он будет получен. Реализация немного изменится.