2014-02-27 37 views
1

我正在嘗試爲我的一個課程建立一個藍牙對講機應用程序,但我似乎無法使其正常工作。我修改了BluetoothChat示例(http://developer.android.com/guide/topics/connectivity/bluetooth.html)以適應我的需求,並且我可以成功地將語音錄製從一部手機傳輸到另一部手機,但它顯得非常笨拙。我正在使用AudioRecord和AudioTrack進行錄製和播放。如何使用藍牙將音頻從Android手機流式傳輸到其他Android手機?

我有這些全局變量

private static final int RECORDER_SAMPLERATE = 8000; 
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO; 
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT; 

private AudioRecord recorder = null; 
private AudioTrack audioTrack = null; 
private int bufferSize = 0; 
private Thread recordingThread = null; 
private boolean isRecording = false; 

,在我的onCreate方法我設置了緩衝區大小和初始化AudioTrack。

bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING); 

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 
      RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_STEREO, 
      RECORDER_AUDIO_ENCODING, bufferSize, AudioTrack.MODE_STREAM); 

這裏是我的代碼記錄時按下/發送鍵(我目前只把它記錄的數據爲3秒。)

private void startRecording() { 
    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 
      RECORDER_SAMPLERATE, RECORDER_CHANNELS, 
      RECORDER_AUDIO_ENCODING, bufferSize); 

     int i = recorder.getState(); 
     if (i == 1) 
      recorder.startRecording(); 

     isRecording = true; 

     new Timer().schedule(new TimerTask() { 

      @Override 
      public void run() { 
       runOnUiThread(new Runnable() { 

        @Override 
        public void run() 
        { 
         enableButtons(false); 
         if(null != recorder){ 
           isRecording = false; 

           recorder.stop(); 
           recorder.release(); 

           recorder = null; 
           recordingThread = null; 
         } 
        } 
       }); 

      } 
     }, 3000); 

    recordingThread = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      writeOutAudioData(); 
     } 
    }, "AudioRecorder Thread"); 

    recordingThread.start(); 
} 

private void writeOutAudioData() { 

    byte data[] = new byte[bufferSize]; 

    int read = 0; 

     while (isRecording) 
     { 
      read = recorder.read(data, 0, bufferSize); 

      if (AudioRecord.ERROR_INVALID_OPERATION != read) 
      { 
        mChatService.write(data); 
        //TODO 

      } 
     } 
} 

這裏是處理所有傳入和傳出的代碼傳輸

private class ConnectedThread extends Thread { 
    private final BluetoothSocket mmSocket; 
    private final InputStream mmInStream; 
    private final OutputStream mmOutStream; 

    public ConnectedThread(BluetoothSocket socket, String socketType) { 
     Log.d(TAG, "create ConnectedThread: " + socketType); 
     mmSocket = socket; 
     InputStream tmpIn = null; 
     OutputStream tmpOut = null; 

     // Get the BluetoothSocket input and output streams 
     try { 
      tmpIn = socket.getInputStream(); 
      tmpOut = socket.getOutputStream(); 
     } catch (IOException e) { 
      Log.e(TAG, "temp sockets not created", e); 
     } 

     mmInStream = tmpIn; 
     mmOutStream = tmpOut; 
    } 

    public void run() { 
     Log.i(TAG, "BEGIN mConnectedThread"); 
     byte[] buffer = new byte[1024]; 
     int bytes; 

     // Keep listening to the InputStream while connected 
     while (true) { 
      try { 
       // Read from the InputStream 
       bytes = mmInStream.read(buffer); 

       // Send the obtained bytes to the UI Activity 
       mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer) 
         .sendToTarget(); 
      } catch (IOException e) { 
       Log.e(TAG, "disconnected", e); 
       connectionLost(); 
       // Start the service over to restart listening mode 
       BluetoothChatService.this.start(); 
       break; 
      } 
     } 
    } 

    /** 
    * Write to the connected OutStream. 
    * @param buffer The bytes to write 
    */ 
    public void write(byte[] buffer) { 
     try { 
      mmOutStream.write(buffer); 

      // Share the sent message back to the UI Activity 
      mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget(); 
     } catch (IOException e) { 
      Log.e(TAG, "Exception during write", e); 
     } 
    } 

這裏是從BluetoothChatService

獲取信息回我的處理程序代碼10
private final Handler mHandler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     switch (msg.what) { 
     case MESSAGE_STATE_CHANGE: 
      if (D) 
       Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); 
      switch (msg.arg1) { 
      case BluetoothChatService.STATE_CONNECTED: 
       setStatus(getString(R.string.title_connected_to, 
         mConnectedDeviceName)); 
       mConversationArrayAdapter.clear(); 
       break; 
      case BluetoothChatService.STATE_CONNECTING: 
       setStatus(R.string.title_connecting); 
       break; 
      case BluetoothChatService.STATE_LISTEN: 
      case BluetoothChatService.STATE_NONE: 
       setStatus(R.string.title_not_connected); 
       break; 
      } 
      break; 
     case MESSAGE_WRITE: 
      //byte[] writeBuf = (byte[]) msg.obj; 
      break; 
     case MESSAGE_READ: 
      final byte[] readBuf = (byte[]) msg.obj; 
      final byte bytes = (byte) msg.arg1; 

      Thread audioPlay = new Thread() 
      { 
       public void run(){ 
        audioTrack.play(); 
        audioTrack.write(readBuf, 0, readBuf.length); 
        audioTrack.stop(); 
       } 

      }; 
      audioPlay.start(); 
      break; 
     } 
    } 
}; 

我只是不明白在ConnectedThread類中byte []緩衝區的大小應該是多少。我應該把它放在1024處還是改成別的東西?我無法弄清楚讀取這些傳入字節並將它們寫入AudioTrack進行播放(無靜態)的正確方法。 我在一部手機上使用Android 4.3,在另一部手機上使用4.2.2。 任何幫助將不勝感激!謝謝!

+0

的確找到了解決辦法 – kId

回答

0

我知道它一年左右,但我也有這個問題。

您必須確保您發送的內容正是您要發送的內容,並且您向AudioTrack寫入的內容正是您收到的內容。一個簡單的測試是計算髮送的字節數並與收到的(感知的收到的)字節進行比較。

我相信關鍵是使用您的參數爲audiotrack計算的最小緩衝區大小。

int minsize = AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); 

你可以在任何你想要的塊大小發送數據,但是你會看到它的通常1007個字節,一個藍牙套接字(這是我在我的測試中看到的)。我懷疑如果你允許套接字爲你做最好的表現,因爲它會去執行檢查,因此你可能想發送相同的minsize

我還建議改變你的音頻格式爲單聲道,除非你的設備有雙耳話筒?

我承認我沒有試圖消化所有的代碼,但我認爲在將消息封裝在數據中時會產生一些不必要的開銷。它的數據流,我不認爲它需要封裝。我建議使用BluetoothSocketServerBluetoothSocket

最後要說明的是,我正在爲任何碰到此問題的其他人寫這篇文章。請注意,流式傳輸模式下的AudioTrack.write()將會阻塞,除非您向其寫入minsize數據。雖然這是在Android參考站點上解釋的,但我想強調它的重要性,以避免浪費時間調試死鎖。

相關問題