Потоковая передача голоса между телефонами Android через WiFi - PullRequest
30 голосов
/ 11 февраля 2012

Я пытаюсь передавать аудио с микрофона с одного Android на другой через WiFi. Изучив несколько примеров, я сделал 2 приложения с одним действием в каждом, одно для захвата и отправки аудио, а другое для получения.

Я использовал классы Audiorecord и Audiotrack для захвата и игры. Тем не менее, я просто слышу какой-то потрескивающий звук (который теперь прекратился после того, как я сделал некоторые изменения, хотя я вернулся назад)

Активность отправки голоса.

public class VoiceSenderActivity extends Activity {

private EditText target;
private TextView streamingLabel;
private Button startButton,stopButton;

public byte[] buffer;
public static DatagramSocket socket;
private int port=50005;         //which port??
AudioRecord recorder;

//Audio Configuration. 
private int sampleRate = 8000;      //How much will be ideal?
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;    
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;       

private boolean status = true;




@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    target = (EditText) findViewById (R.id.target_IP);
    streamingLabel = (TextView) findViewById(R.id.streaming_label);
    startButton = (Button) findViewById (R.id.start_button);
    stopButton = (Button) findViewById (R.id.stop_button);

    streamingLabel.setText("Press Start! to begin");

    startButton.setOnClickListener (startListener);
    stopButton.setOnClickListener (stopListener);
}

private final OnClickListener stopListener = new OnClickListener() {

    @Override
    public void onClick(View arg0) {
                status = false;
                recorder.release();
                Log.d("VS","Recorder released");
    }

};

private final OnClickListener startListener = new OnClickListener() {

    @Override
    public void onClick(View arg0) {
                status = true;
                startStreaming();           
    }

};

public void startStreaming() {


    Thread streamThread = new Thread(new Runnable() {

        @Override
        public void run() {
            try {


                int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
                DatagramSocket socket = new DatagramSocket();
                Log.d("VS", "Socket Created");

                byte[] buffer = new byte[minBufSize];

                Log.d("VS","Buffer created of size " + minBufSize);
                DatagramPacket packet;

                final InetAddress destination = InetAddress.getByName(target.getText().toString());
                Log.d("VS", "Address retrieved");


                recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,minBufSize);
                Log.d("VS", "Recorder initialized");

                recorder.startRecording();


                while(status == true) {


                    //reading data from MIC into buffer
                    minBufSize = recorder.read(buffer, 0, buffer.length);

                    //putting buffer in the packet
                    packet = new DatagramPacket (buffer,buffer.length,destination,port);

                    socket.send(packet);


                }



            } catch(UnknownHostException e) {
                Log.e("VS", "UnknownHostException");
            } catch (IOException e) {
                Log.e("VS", "IOException");
            } 


        }

    });
    streamThread.start();
 }
 }

Активность на получение голоса

public class VoiceReceiverActivity extends Activity {


private Button receiveButton,stopButton;

public static DatagramSocket socket;
private AudioTrack speaker;

//Audio Configuration. 
private int sampleRate = 8000;      //How much will be ideal?
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;    
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;       

private boolean status = true;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    receiveButton = (Button) findViewById (R.id.receive_button);
    stopButton = (Button) findViewById (R.id.stop_button);
    findViewById(R.id.receive_label);

    receiveButton.setOnClickListener(receiveListener);
    stopButton.setOnClickListener(stopListener);

}


private final OnClickListener stopListener = new OnClickListener() {

    @Override
    public void onClick(View v) {
        status = false;
        speaker.release();
        Log.d("VR","Speaker released");

    }

};


private final OnClickListener receiveListener = new OnClickListener() {

    @Override
    public void onClick(View arg0) {
        status = true;
        startReceiving();

    }

};

public void startReceiving() {

    Thread receiveThread = new Thread (new Runnable() {

        @Override
        public void run() {

            try {

                DatagramSocket socket = new DatagramSocket(50005);
                Log.d("VR", "Socket Created");


                byte[] buffer = new byte[256];


                //minimum buffer size. need to be careful. might cause problems. try setting manually if any problems faced
                int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);

                speaker = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRate,channelConfig,audioFormat,minBufSize,AudioTrack.MODE_STREAM);

                speaker.play();

                while(status == true) {
                    try {


                        DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
                        socket.receive(packet);
                        Log.d("VR", "Packet Received");

                        //reading content from packet
                        buffer=packet.getData();
                        Log.d("VR", "Packet data read into buffer");

                        //sending data to the Audiotrack obj i.e. speaker
                        speaker.write(buffer, 0, minBufSize);
                        Log.d("VR", "Writing buffer content to speaker");

                    } catch(IOException e) {
                        Log.e("VR","IOException");
                    }
                }


            } catch (SocketException e) {
                Log.e("VR", "SocketException");
            }


        }

    });
    receiveThread.start();
}

}

Я использовал wireshark, чтобы проверить, отправляются ли пакеты, и я могу видеть пакеты. Однако источником является MAC-адрес отправляющего устройства и адресата, что-то вроде физического адреса. Не уверен, что это уместно.

Так в чем же проблема?

Ответы [ 3 ]

7 голосов
/ 03 декабря 2014

Привет, есть библиотека с открытым исходным кодом под названием «Libstreaming», которая используется для потоковой передачи голоса / видео по сети с использованием WIFI. Просто посмотрите на это:

https://github.com/fyhertz/libstreaming

Есть также несколько примеров, пожалуйста, посмотрите на это:

https://github.com/fyhertz/libstreaming-examples

Я использовал библиотеку для потоковой передачи RTSP Audio по сети, надеюсь, это может быть полезно.

3 голосов
/ 16 февраля 2012

Я бы попробовал разделить проблему на три части.

Часть 1

Убедитесь, что Socket Connection работает нормально, комментируя все, что связано со звуком

Часть 2

Просто отправьте произвольное текстовое сообщение [ Hello WiFi ] от отправителя, затем получите и распечатайте его в получателебоковое применение.

Часть 3

Работает ли сам рекордер?Попробуйте проверить способ записи в отдельном проекте, чтобы увидеть, работает ли он правильно или нет.

Используйте этот код для захвата микрофона и его воспроизведения.

Мой опыт

Однажды я работал над аналогичным проектом и, чтобы проверить его, после записи записал аудиоданные в виде файла на SD-карту.

(это был бы необработанный звук, поэтому большинство музыкальных проигрывателей не смогут его воспроизводить ... Думаю, mPlayer должен его воспроизводить)

2 голосов
/ 31 июля 2014

Вам необходимо внимательно рассмотреть использование UDP (класс DatagramSocket) в качестве сетевого протокола.

UDP - это упрощенный протокол, который не гарантирует сохранение порядка принятых пакетов.Это может быть частью причины, по которой звук искажается.Пакет, полученный не по порядку, приведет к тому, что аудио пакеты будут проигрываться не по порядку.На границе этих пакетов из непоследовательной последовательности вы услышите щелчки / щелчки, где аудио образец эффективно поврежден.Кроме того, UDP-пакеты не гарантированно будут успешно доставлены.Любые отброшенные пакеты, очевидно, добавят к любому искажению или искажению, которое слышно.

TCP (класс Socket) будет лучшим вариантом для оптимального качества звука.TCP является более надежным протоколом, который будет поддерживать порядок получения пакетов.Он также имеет встроенную проверку ошибок и отправит все отброшенные пакеты.Однако из-за этой функциональности внимания у TCP больше сетевых издержек.

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

Если вы хотите воспроизводить видео с ультра низкой задержкой, но готовы пожертвовать качеством звука, тогда UDP будет работать.Однако, чтобы найти наилучший буфер и размер выборки, потребуются некоторые эксперименты.

Если вы хотите получить наилучшее воспроизведение звука с нулевым искажением, но готовы ввести чуть большую задержку, тогда TCP - это путь, по которому нужно идти.

Я не могу сказать, сколько еще прибавит задержка TCP.Но возможно, что это может быть реализовано, не влияя на пользовательский опыт.Единственный способ узнать это - попробовать и посмотреть.

...