2014-09-11 80 views
1

我正在開發一個android應用程序。我想完成下面的功能。 我將使用手機的內置麥克風進行錄音,同時我希望通過手機的揚聲器或耳機播放錄製的音頻。 可行嗎?如果是的話,請幫助我。Android中的音頻錄製和流式傳輸

+0

當您錄製時,您是在錄製文件還是暫存緩衝區? – 2014-09-11 06:29:05

回答

0

首先在onCreate方法,MediaRecorder類對象和要保存記錄數據的文件路徑中創建對象。

String outputFile = Environment.getExternalStorageDirectory(). 
    getAbsolutePath() + "/myrecording.3gp"; // Define outputFile outside onCreate method 

    MediaRecorder myAudioRecorder = new MediaRecorder(); // Define this outside onCreate method 

    myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
    myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
    myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB); 
    myAudioRecorder.setOutputFile(outputFile); 

這三個函數可以在任何按鈕上調用它,以便播放Rec,停止Rec並啓動Rec;

public void start(View view){ 
    try { 
    myAudioRecorder.prepare(); 
    myAudioRecorder.start(); 
    } catch (IllegalStateException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } 
    start.setEnabled(false); 
    stop.setEnabled(true); 
    Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show(); 
    } 

    public void stop(View view){ 

    myAudioRecorder.stop(); 
    myAudioRecorder.release(); 
    myAudioRecorder = null; 
    stop.setEnabled(false); 
    play.setEnabled(true); 
    Toast.makeText(getApplicationContext(), "Audio recorded successfully", 
    Toast.LENGTH_LONG).show(); 
    } 



    public void play(View view) throws IllegalArgumentException, 

    SecurityException, IllegalStateException, IOException{ 
    MediaPlayer m = new MediaPlayer(); 
    m.setDataSource(outputFile); 
    m.prepare(); 
    m.start(); 
    Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_LONG).show(); 

    } 
0

當我讀到開發文檔here,Android支持RTSP協議(實時流媒體),還HTTP/HTTPS協議直播流媒體草案。

還有一個例子here。您必須擁有Streaming服務器的基礎知識,例如Red5或Wowza。

0

這是一個簡單的錄音和回放應用程序。
採用Android AudioRecordAudioTrack

設計

錄製的音頻被寫入緩衝區,並從同一個緩衝播放,這一機制在運行一個循環(使用Android的線程)控制按鈕。


代碼

private String TAG = "AUDIO_RECORD_PLAYBACK"; 
private boolean isRunning = true; 
private Thread m_thread;    /* Thread for running the Loop */ 

private AudioRecord recorder = null; 
private AudioTrack track = null; 

int bufferSize = 320;     /* Buffer for recording data */ 
byte buffer[] = new byte[bufferSize]; 

/* Method to Enable/Disable Buttons */ 
private void enableButton(int id,boolean isEnable){ 
    ((Button)findViewById(id)).setEnabled(isEnable); 
} 

的GUI有兩個按鈕STARTSTOP
啓用按鈕:

enableButton(R.id.StartButton,true); 
enableButton(R.id.StopButton,false); 

/* Assign Button Click Handlers */ 
((Button)findViewById(R.id.StartButton)).setOnClickListener(btnClick); 
((Button)findViewById(R.id.StopButton)).setOnClickListener(btnClick); 

映射START和STOP按鈕OnClickListener

private View.OnClickListener btnClick = new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     switch(v.getId()){ 
     case R.id.StartButton: 
     { 
      Log.d(TAG, "======== Start Button Pressed =========="); 
      isRunning = true; 
      do_loopback(isRunning); 
      enableButton(R.id.StartButton,false); 
      enableButton(R.id.StopButton,true); 
      break; 
     } 
     case R.id.StopButton: 
     { 
      Log.d(TAG, "======== Stop Button Pressed =========="); 
      isRunning = false; 
      do_loopback(isRunning); 
      enableButton(R.id.StopButton,false); 
      enableButton(R.id.StartButton,true); 
      break; 
     } 
    } 
} 

啓動線程:

private void do_loopback(final boolean flag) 
{ 
    m_thread = new Thread(new Runnable() { 
     public void run() { 
      run_loop(flag); 
     } 
    }); 
    m_thread.start(); 
} 

用於初始化AudioRecord和AudioTrack方法:

public AudioTrack findAudioTrack (AudioTrack track) 
{ 
    Log.d(TAG, "===== Initializing AudioTrack API ===="); 
    int m_bufferSize = AudioTrack.getMinBufferSize(8000, 
      AudioFormat.CHANNEL_OUT_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 

    if (m_bufferSize != AudioTrack.ERROR_BAD_VALUE) 
    { 
     track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, 
       AudioFormat.CHANNEL_OUT_MONO, 
       AudioFormat.ENCODING_PCM_16BIT, m_bufferSize, 
       AudioTrack.MODE_STREAM); 

     if (track.getState() == AudioTrack.STATE_UNINITIALIZED) { 
      Log.e(TAG, "===== AudioTrack Uninitialized ====="); 
      return null; 
     } 
    } 
    return track; 
} 

public AudioRecord findAudioRecord (AudioRecord recorder) 
{ 
    Log.d(TAG, "===== Initializing AudioRecord API =====");  
    int m_bufferSize = AudioRecord.getMinBufferSize(8000, 
      AudioFormat.CHANNEL_IN_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 

    if (m_bufferSize != AudioRecord.ERROR_BAD_VALUE) 
    { 
     recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, 
       AudioFormat.CHANNEL_IN_MONO, 
       AudioFormat.ENCODING_PCM_16BIT, m_bufferSize); 

     if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) { 
      Log.e(TAG, "====== AudioRecord UnInitilaised ====== "); 
      return null; 
     } 
    } 
    return recorder; 
} 

的值findAudioRecordfindAudioTrack可以改變基於設備。
請參考this的問題。


代碼運行循環:

public void run_loop (boolean isRunning) 
{ 

    /** == If Stop Button is pressed == **/ 
    if (isRunning == false) { 
     Log.d(TAG, "===== Stop Button is pressed ===== "); 

     if (AudioRecord.STATE_INITIALIZED == recorder.getState()){ 
      recorder.stop(); 
      recorder.release(); 
     } 
     if (AudioTrack.STATE_INITIALIZED == track.getState()){ 
      track.stop(); 
      track.release(); 
     } 
     return; 
    } 


    /** ======= Initialize AudioRecord and AudioTrack ======== **/ 
    recorder = findAudioRecord(recorder); 
    if (recorder == null) { 
     Log.e(TAG, "======== findAudioRecord : Returned Error! =========== "); 
     return; 
    } 

    track = findAudioTrack(track); 
    if (track == null) { 
     Log.e(TAG, "======== findAudioTrack : Returned Error! ========== "); 
     return; 
    } 

    if ((AudioRecord.STATE_INITIALIZED == recorder.getState()) && 
      (AudioTrack.STATE_INITIALIZED == track.getState())) 
    { 
     recorder.startRecording(); 
     Log.d(TAG, "========= Recorder Started... ========="); 
     track.play(); 
     Log.d(TAG, "========= Track Started... ========="); 
    } 
    else 
    { 
     Log.d(TAG, "==== Initilazation failed for AudioRecord or AudioTrack ====="); 
     return; 
    } 

    /** ------------------------------------------------------ **/ 

    /* Recording and Playing in chunks of 320 bytes */ 
    bufferSize = 320; 

    while (isRunning == true) 
    { 
     /* Read & Write to the Device */ 
     recorder.read(buffer, 0, bufferSize); 
     track.write(buffer, 0, bufferSize); 

    } 
    Log.i(TAG, "Loopback exit"); 
    return; 
} 

請在AndroidManifest.xml

<uses-permission android:name="android.permission.RECORD_AUDIO" > </uses-permission> 

這上面的程序以下也可以通過使用寫入/從文件讀取相同的API。
爲什麼要使用audioRecord而不是mediaRecorder - See here

該代碼已經過測試(在Google Nexus 5上)並且工作正常。

注意:請爲recorder.readtrack.write添加一些錯誤檢查代碼,以防萬一您失敗。同樣適用於findAudioRecordfindAudioTrack