您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Android中怎么利用流播放聲音,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
(1)創建AudioRecord和AudioTrack類對象:創建這兩個類的對象比較復雜,通過對文檔的反復和仔細理解,并通過多次失敗的嘗試,并在 北理工的某個Android大牛的網上的文章啟發下,我們也最終成功地創建了這兩個類的對象。創建AudioRecord和AudioTrack類對象的 代碼如下:
AudioRecord類:
m_in_buf_size =AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, m_in_buf_size) ;
AudioTrack類:
m_out_buf_size = android.media.AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT, m_out_buf_size, AudioTrack.MODE_STREAM);
(2)關于AudioRecord和AudioTrack類的監聽函數,不用也行。
(3)調試方面,包括初始化后看logcat信息,以確定類的工作狀態,初始化是否成功等。
編寫好代碼,沒有語法錯誤,調用模擬器運行、調試代碼時,logcat發揮了很好的功用。剛調試時,經常會出現模擬器顯示出現異常,這時我們可以在代碼 的一些關鍵語句后添加如Log.d(“test1″,”OK”);這樣的語句進行標識,出現異常時我們就可以在logcat窗口觀察代碼執行到哪里出現異 常,然后進行相應的修改、調試。模擬器不會出現異常時,又遇到了錄放音的問題。錄音方面,剛開始選擇將語音編碼數據存放在多個固定大小的文件中進行傳送, 但是這種情況下會出現聲音斷續的現象,而且要反復的建立文件,比較麻煩,后來想到要進行網上傳輸,直接將語音編碼數據以數據流的形式傳送,經過驗證,這種 方法可行并且使代碼更加簡潔。放音方面,將接收到的數據流存放在一個數組中,然后將數組中數據寫到AudioTrack中。剛開始只是“嘟”幾聲,經過檢 查發現只是把數據寫一次,加入循環,讓數據反復寫到AudioTrack中,就可以聽到正常的語音了。接下來的工作主要是改善話音質量與話音延遲,在進行 通話的過程中,觀察logcat窗口,發現向數組中寫數據時會出現Bufferflow的情況,于是把重心轉移到數組大小的影響上,經過試驗,發現 AudioRecord一次會讀640個數據,然后就對錄音和放音中有數組的地方進行實驗修改。AudioRecord和AudioTrack進行實例化 時,參數中各有一個數組大小,經過試驗這個數組大小和AudioRecord和AudioTrack能正常實例化所需的最小Buffer大小(即上面實例 化時的m_in_buf_size和m_out_buf_size參數)相等且服務器方進行緩存數據的數組尺寸是上述數值的2倍時,語音質量***。由于錄 音和放音的速度不一致,受到北理工大牛的啟發,在錄音方面,將存放錄音數據的數組放到LinkedList中,當LinkedList中數組個數達到 2(這個也是經過試驗驗證話音質量***時的數據)時,將先錄好的數組中數據傳送出去。經過上述反復試驗和修改,最終使雙方通話質量較好,且延時較短。
(4)通過套接字傳輸和接收數據
數據傳送部分,使用的是套接字。通信雙方,通過不同的端口向服務器發送請求,與服務器連接上后,開始通話向服務器發送數據,服務器通過一個套接字接收到一 方的數據后,先存在一個數組中,然后將該數組中數據以數據流的形式再通過另一個套接字傳送到另一方。這樣就實現了雙方數據的傳送。
(5)代碼架構
為避免反復錄入和讀取數據占用較多資源,使程序在進行錄放音時不能執行其他命令,故將錄音和放音各寫成一個線程類,然后在主程序中,通過MENU控制通話的開始、停止、結束。
***說明,AudioRecord和AudioTrack類可以用,只是稍微復雜些。以下貼出雙方通信的源碼,希望對大家有所幫助:
主程序
package eoe.demo; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class Daudioclient extends Activity { public static final int MENU_START_ID = Menu.FIRST ; public static final int MENU_STOP_ID = Menu.FIRST + 1 ; public static final int MENU_EXIT_ID = Menu.FIRST + 2 ; protected Saudioserver m_player ; protected Saudioclient m_recorder ; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public boolean onCreateOptionsMenu(Menu aMenu) { boolean res = super.onCreateOptionsMenu(aMenu) ; aMenu.add(0, MENU_START_ID, 0, “START”) ; aMenu.add(0, MENU_STOP_ID, 0, “STOP”) ; aMenu.add(0, MENU_EXIT_ID, 0, “EXIT”) ; return res ; } public boolean onOptionsItemSelected(MenuItem aMenuItem) { switch (aMenuItem.getItemId()) { case MENU_START_ID: { m_player = new Saudioserver() ; m_recorder = new Saudioclient() ; m_player.init() ; m_recorder.init() ; m_recorder.start() ; m_player.start() ; } break ; case MENU_STOP_ID: { m_recorder.free() ; m_player.free() ; m_player = null ; m_recorder = null ; } break ; case MENU_EXIT_ID: { int pid = android.os.Process.myPid() ; android.os.Process.killProcess(pid) ; } break ; default: break ; } return super.onOptionsItemSelected(aMenuItem); } }
錄音程序Saudioclient:
package eoe.demo; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.util.LinkedList; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.util.Log; public class Saudioclient extends Thread { protected AudioRecord m_in_rec ; protected int m_in_buf_size ; protected byte [] m_in_bytes ; protected boolean m_keep_running ; protected Socket s; protected DataOutputStream dout; protected LinkedList<byte[]> m_in_q ; public void run() { try { byte [] bytes_pkg ; m_in_rec.startRecording() ; while(m_keep_running) { m_in_rec.read(m_in_bytes, 0, m_in_buf_size) ; bytes_pkg = m_in_bytes.clone() ; if(m_in_q.size() >= 2) { dout.write(m_in_q.removeFirst() , 0, m_in_q.removeFirst() .length); } m_in_q.add(bytes_pkg) ; } m_in_rec.stop() ; m_in_rec = null ; m_in_bytes = null ; dout.close(); } catch(Exception e) { e.printStackTrace(); } } public void init() { m_in_buf_size = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, m_in_buf_size) ; m_in_bytes = new byte [m_in_buf_size] ; m_keep_running = true ; m_in_q=new LinkedList<byte[]>(); try { s=new Socket(“192.168.1.100″,4332); dout=new DataOutputStream(s.getOutputStream()); //new Thread(R1).start(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void free() { m_keep_running = false ; try { Thread.sleep(1000) ; } catch(Exception e) { Log.d(“sleep exceptions…\n”,”") ; } } }
放音程序Saudioserver:
package eoe.demo; import java.io.DataInputStream; import java.io.IOException; import java.net.Socket; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; import android.util.Log; public class Saudioserver extends Thread { protected AudioTrack m_out_trk ; protected int m_out_buf_size ; protected byte [] m_out_bytes ; protected boolean m_keep_running ; private Socket s; private DataInputStream din; public void init() { try { s=new Socket(“192.168.1.100″,4331); din=new DataInputStream(s.getInputStream()); m_keep_running = true ; m_out_buf_size = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, m_out_buf_size, AudioTrack.MODE_STREAM); m_out_bytes=new byte[m_out_buf_size]; // new Thread(R1).start(); } catch(Exception e) { e.printStackTrace(); } } public void free() { m_keep_running = false ; try { Thread.sleep(1000) ; } catch(Exception e) { Log.d(“sleep exceptions…\n”,”") ; } } public void run() { byte [] bytes_pkg = null ; m_out_trk.play() ; while(m_keep_running) { try { din.read(m_out_bytes); bytes_pkg = m_out_bytes.clone() ; m_out_trk.write(bytes_pkg, 0, bytes_pkg.length) ; } catch(Exception e) { e.printStackTrace(); } } m_out_trk.stop() ; m_out_trk = null ; try { din.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
上述就是小編為大家分享的Android中怎么利用流播放聲音了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。