2012-02-11 4 views
29

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

Я использовал классы 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-адрес отправляющего устройства и адресата, что-то вроде физического адреса. Не уверен, что это актуально.

В чем проблема?

+1

Существует по крайней мере три проблемы, с которыми вам приходится иметь дело: с задержкой (или отсутствием) данных, общей пропускной способностью данных и возможностью слегка несогласованных частот дискретизации. Практическая IP-телефония должна иметь возможность общаться со всеми тремя. Несоответствующие часы на удивление сложны - изначально вы можете ввести задержку, чтобы дать некоторую надбавку для буферизации, но если отправитель работает медленнее, вы будете использовать буфер, и приемник будет голодать за данные; в то время как если отправитель быстрее, буфер, в конечном счете, переполняется неиграемыми данными. –

+0

Мне действительно удалось добиться этого. На самом деле не было проблемы с несоответствующими частотами. Задержка в данных, да. Имел свой собственный протокол, чтобы соответствовать часам приемника/отправителя. В конце он работал, но только с некоторым отставанием (которое увеличивалось с расстоянием от беспроводного маршрутизатора) – Alabhya

+0

Эй, я применил тестовое приложение для кода, который у вас есть выше, внеся все необходимые изменения, предложенные ниже, но у меня все еще есть проблема , Я получаю сообщение между двумя телефонами без проблем, но я не думаю, что микрофон записывается правильно, поскольку я не слышу звук на другом конце. Возможно, у вас есть ссылка на примерное решение, на которое я могу взглянуть? – chuckliddell0

ответ

3

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

Часть 1

Обеспечить гнездо для подключения работает отлично по комментируя все, что связано с аудио

Часть 2

Отправить просто просто произвольный текст сообщение [Ад o WiFi] от отправителя, а затем получение и печать в приложении-получателе.

Часть 3

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

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

Мой опыт

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

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

+0

Хорошо, я заработал. Голос разрастается слишком сильно, и есть отставание. Нужно выяснить правильную частоту дискретизации и размер буфера для этого. Было бы здорово, если бы какие-либо входы в это. В любом случае, большое спасибо. что вы сказали. – Alabhya

+0

В вашей деятельности приемника метод startReceiving() не использует 256 в качестве размера буфера, а использует minBufSize, который вы получаете в следующей строке. Помимо этого, возможно, захочется немного поиграть с разными частотами выборки, но даже 8k должно быть хорошим. –

+1

Хорошо, я заработал. По-видимому, minBufSize было слишком много и, следовательно, отставание и разрыв. Установите minBufSize на 256, а при инициализации объектов AudioRecord и AudioTrack установите размер буфера на minBufSize * 10. Пробовали разные комбинации частот выборки и это и получило удовлетворительное сейчас. Спасибо большое! – Alabhya

2

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

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

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

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

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

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

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

7

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

https://github.com/fyhertz/libstreaming

Есть также некоторые примеры, приведенные, любезно посмотреть на него:

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

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

+0

Можете ли вы руководствоваться, как вы делали только аудиопоток без потокового видео? – kAmol

Смежные вопросы