2011-08-14 61 views
3

我正在嘗試從麥克風獲取音頻數據。我已經通過使用填充類型爲shorts的緩衝區的AudioRecord類來實現此目的。麥克風輸入的處理

最後我想繪製這個緩衝區,以便我得到一個像顯示器(實時信息)的示波器。問題是,如果我想顯示一個值(比如說文本),那麼我需要一個不同的線程來更新UI。目前我正在使用AsyncTask並使用AsyncTasks.publishProgress()更新UI。到目前爲止,我還沒有很成功,想知道我是否在正確的軌道上?處理更好的方法去?有沒有人曾經做過類似的事情,如果有的話,你有什麼方法?另外,是否可以簡單地輪詢麥克風?


這是我的代碼。它旨在輸出MIC中的每個讀取樣本。它似乎以可接受的速度執行此操作,但偶爾顯示爲零。爲什麼?

package com.ss.audioacquireapp3; 

import android.app.Activity; 
import android.content.Context; 
import android.media.AudioFormat; 
import android.media.AudioRecord; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.util.Log; 
import android.widget.TextView; 


public class AudioAcquireApp3Activity extends Activity 
{ 
     //Properties (AsyncTask) 
     protected TextView _percentField; 
     protected InitTask _initTask; 

     //Properties (MIC) 
     public AudioRecord audioRecord; 
     public int mSamplesRead; //how many samples read 
     public int recordingState; 
     public int buffersizebytes; 
     public int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; 
     public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
     public static short[] buffer; //+-32767 
     public static final int SAMPPERSEC = 44100; //samp per sec 8000, 11025, 22050 44100 or 48000 

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

     _percentField = (TextView) findViewById(R.id.percent_field); 

     buffersizebytes = AudioRecord.getMinBufferSize(SAMPPERSEC,channelConfiguration,audioEncoding); //4096 on ion 
     buffer = new short[buffersizebytes]; 
     audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,channelConfiguration,audioEncoding,buffersizebytes); //constructor 

     _initTask = new InitTask(); 
     _initTask.execute(this); 
    } 

    /** 
    * sub-class of AsyncTask 
    */ 
    protected class InitTask extends AsyncTask<Context, Integer, String> 
    { 
     // -- run intensive processes here 
     // -- notice that the datatype of the first param in the class definition matches the param passed to this method 
     // -- and that the datatype of the last param in the class definition matches the return type of this method 
       @Override 
       protected String doInBackground(Context... params) 
       { 
         //-- on every iteration 
         //-- runs a while loop that causes the thread to sleep for 50 milliseconds 
         //-- publishes the progress - calls the onProgressUpdate handler defined below 
         //-- and increments the counter variable i by one 
         //int i = 0; 

        audioRecord.startRecording(); 

         while(true) 
         { 
           try{ 
             mSamplesRead = audioRecord.read(buffer, 0, buffersizebytes); 

             int amp; 

             for(int i = 0; i < buffersizebytes - 1; i++){ 
              amp = (int)buffer[i]; 
              publishProgress(amp); 
             } 

           } catch(Exception e){       
           } 
         } 
       } 

       // -- gets called just before thread begins 
       @Override 
       protected void onPreExecute() 
       { 
         //Log.i("makemachine", "onPreExecute()"); 
         super.onPreExecute(); 

       } 

       // -- called from the publish progress 
       // -- notice that the datatype of the second param gets passed to this method 
       @Override 
       protected void onProgressUpdate(Integer... values) 
       { 
         super.onProgressUpdate(values); 
         //Log.i("makemachine", "onProgressUpdate(): " + String.valueOf(values[0])); 
         _percentField.setText(String.valueOf(values[0])); 
       } 

       // -- called as soon as doInBackground method completes 
       // -- notice that the third param gets passed to this method 
       @Override 
       protected void onPostExecute(String result) 
       { 
         super.onPostExecute(result); 
         //Log.i("makemachine", "onPostExecute(): " + result); 
       } 


    } 
} 

這裏是main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:gravity="center_vertical|center_horizontal" 
    > 

<TextView android:id="@+id/percent_field" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:gravity="center_horizontal"/> 

</LinearLayout> 

請注意,你需要把它添加到AndroidManifest.xml中

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

我運行這在LG擎天柱黑。請幫助我儘可能提高此代碼的效率。

回答

1
  1. 如果您需要從任何線程更新UI線程,則可以始終使用Activity.runOnUiThread(Runnable action)。有關詳細信息,請參閱Activity class javadoc。
  2. 我不確定'simpy poll the microphone'是什麼意思,但在我看來,AudioRecord是錄製微型電話時的一個好方法。這裏是一個示例實現的鏈接,它讀取現場錄製的音頻的頻率:http://www.anddev.org/novice-tutorials-f8/get-frequency-data-from-microphone-in-real-time-t16774.html

希望這會有所幫助。

+1

謝謝,這有助於很多。我已經使用了代碼鏈接,並有一些現在有用的東西。不幸的是它的運行非常緩慢你可以幫助代碼嗎? – user893825

+0

那麼,沒有真正看到代碼就很難幫助你。找到運行頻率最高的代碼(例如,在AsyncTask.run())並對其進行優化,例如:刪除不需要的調試日誌,長時間運行的操作等。 – pkk

+1

我已經發布了我的代碼。我是否應該在此輸入而不是回答?謝謝 :) – user893825

1

這是一個遲到的答案,但也許有人需要一個相同的問題的答案。這裏是開放源代碼的Android示波器(OsciPrime)鏈接(http://android.serverbox.ch/?p=268)。源代碼使用線程而不是AsyncTask。如果你看到源代碼,你可以找出Thread如何用Looper和Handler處理AudioRecord。我希望它對其他人有用:)