Обработка микрофонного входа

Я пытаюсь получить аудиоданные с микрофона. Я достиг этого, используя класс AudioRecord, который заполняет буфер короткими типами.

В конце концов я хотел бы построить график этого буфера, чтобы получить изображение, похожее на осциллограф (информация в реальном времени). Проблема в том, что если я хочу отобразить значение (скажем, в тексте), мне нужен другой поток для обновления пользовательского интерфейса. В настоящее время я делаю это, используя AsyncTask и обновляя пользовательский интерфейс с помощью AsyncTasks.publishProgress(). До сих пор я не был очень успешным и хотел бы знать, на правильном ли я пути? Являются ли ручки лучшим способом пойти? Есть ли кто-нибудь, кто делал что-то подобное раньше, и если да, то какой метод сработал для вас? Кроме того, возможно ли просто опросить микрофон?


Вот мой код. Он предназначен для вывода каждого прочитанного образца с микрофона. Кажется, что это происходит с приемлемой скоростью, но иногда отображается ноль. Почему?

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 Optimus Black. Пожалуйста, помогите мне сделать этот код максимально эффективным.


person user893825    schedule 14.08.2011    source источник


Ответы (2)


  1. Если вам нужно обновить поток пользовательского интерфейса из любого потока, вы всегда можете использовать Activity.runOnUiThread(Runnable action). Подробности см. в Activity javadoc класса.
  2. Я не уверен, что именно вы подразумеваете под «просто опросить микрофон», но, на мой взгляд, AudioRecord — это хороший способ записи с микрофона. Вот ссылка на пример реализации, который считывает частоту записанного звука в реальном времени: http://www.anddev.org/novice-tutorials-f8/get-frequency-data-from-microphone-in-real-time-t16774.html

Надеюсь это поможет.

person pkk    schedule 14.08.2011
comment
Спасибо, это очень помогает. Я использовал ссылку на код, и у меня есть кое-что, что теперь работает. К сожалению, он работает очень медленно. Не могли бы вы помочь с кодом? - person user893825; 15.08.2011
comment
Ну, трудно вам помочь, не видя кода. Найдите часть кода, которая запускается чаще всего (например, в AsyncTask.run()) и оптимизируйте ее, например: удалите ненужные журналы отладки, длительные операции и т. д. - person pkk; 15.08.2011
comment
Я разместил свой код. Я должен был напечатать это здесь, а не как ответ? Спасибо :) - person user893825; 24.08.2011