0

请同时查看我的其他问题,因为我认为它们是相关的:
问题 1
问题 2
问题 3
这是我正在使用的代码,当我按下按钮时,它会将麦克风上获得的音频信号传递到扬声器:

public class MainActivity extends Activity {
    AudioManager am = null;
    AudioRecord record =null;
    AudioTrack track =null;
    final int SAMPLE_FREQUENCY = 44100;
    final int SIZE_OF_RECORD_ARRAY = 1024;  // 1024 ORIGINAL
    final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
    int i= 0;
    boolean isPlaying = false;
    private volatile boolean keepThreadRunning;
    private RandomAccessFile stateFile, stateFileTemp;
    private File delFile, renFile;
    String stateFileLoc = Environment.getExternalStorageDirectory().getPath(); 
    class MyThread extends Thread{
        private volatile boolean needsToPassThrough;
        // /*
        MyThread(){
            super();
        }

        MyThread(boolean newPTV){
            this.needsToPassThrough = newPTV;
        }
        // */

        // /*
        @Override
        public void run(){
            // short[] lin = new short[SIZE_OF_RECORD_ARRAY];
            byte[] lin = new byte[SIZE_OF_RECORD_ARRAY];
            int num = 0;
            // /*
            if(needsToPassThrough){
                record.startRecording();
                track.play();
            }
            // */
            while (keepThreadRunning) {
            // while (!isInterrupted()) {
                num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
                for(i=0;i<lin.length;i++)
                    lin[i] *= WAV_SAMPLE_MULTIPLICATION_FACTOR; 
                track.write(lin, 0, num);
            }
            // /*
            record.stop();
            track.stop();
            record.release();
            track.release();
            // */
        }
        // */

        // /*
        public void stopThread(){
            keepThreadRunning = false;
        }
        // */
    }

    MyThread newThread;

    private void init() {
        int min = AudioRecord.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
        record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO,
                                 AudioFormat.ENCODING_PCM_16BIT, min);
        int maxJitter = AudioTrack.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO,
                               AudioFormat.ENCODING_PCM_16BIT, maxJitter, AudioTrack.MODE_STREAM);
        am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
        am.setMode(AudioManager.MODE_IN_COMMUNICATION);

        try {
            stateFile = new RandomAccessFile(stateFileLoc+"/appState.txt", "rwd");
            stateFileTemp = new RandomAccessFile(stateFileLoc+"/appStateTemp.txt", "rwd");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        delFile = new File(stateFileLoc+"/appState.txt");
        renFile = new File(stateFileLoc+"/appStateTemp.txt");

    }

    @Override
    protected void onResume(){
        super.onResume();
        // newThread.stopThread();
        Log.d("MYLOG", "onResume() called");
        init();
        keepThreadRunning = true;
        try {
            if(stateFile.readInt() == 1){
                isPlaying = true;
                Log.d("MYLOG", "readInt == 1");
            }
            else{
                isPlaying = false;
                Log.d("MYLOG", "readInt <> 1");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // */


        // newThread = new MyThread(true);
        newThread = new MyThread(isPlaying);
        newThread.start();

    }

    @Override
    protected void onPause(){
        super.onPause();
        Log.d("MYLOG", "onPause() called");
        newThread.stopThread();
        // android.os.Process.killProcess(android.os.Process.myPid());
        try {
            if(isPlaying)
                stateFileTemp.writeInt(1);
            else
                stateFileTemp.writeInt(0);

            delFile.delete();

            renFile.renameTo(delFile);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
        Log.d("MYLOG","onCreate() called");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        newThread.stopThread();
        // android.os.Process.killProcess(android.os.Process.myPid());
        // killProcess(android.os.Process.myPid());
        // newThread.interrupt();
        delFile.delete();
         Log.d("MYLOG", "onDestroy() called");
    }

    public void passStop(View view){
        Button playBtn = (Button) findViewById(R.id.button1);  
        // /*
        if(!isPlaying){
            record.startRecording();
            track.play();
            isPlaying = true;
            playBtn.setText("Pause");
        }
        else{
           record.stop();
           track.pause();
           isPlaying=false;
           playBtn.setText("Pass through");
        }
        // */
    }  

这些文件appState.txt并被appStateTemp.txt添加以保存应用程序上次失去焦点时是否正在执行传递,但这在这里可能不是很重要。我想知道的是:

  1. record.read()被调用而不调用时会发生什么record.startrecording()

  2. 有什么意义SIZE_OF_RECORD_ARRAY?我认为它至少应该是返回的值,AudioRecord.getMinBufferSize()但在这个程序中它根本不会影响输出,即使我将它设置为 1。

  3. 如果我使用 16 位 PCM 编码,我至少需要一个短变量来存储音频样本的数字等价物。然而,在这段代码中,即使我将 lin 变量从短数组更改为字节数组,输出也没有明显变化。那么 read 函数是如何将数字样本存储在数组中的呢?它会自动为每个样本分配 2 个字节的元素吗?如果是这样的话,它是小端还是大端?

4

2 回答 2

2

问题 1 和 3 应该很容易让您检查您的应用程序,但这里是:

1:如果在没有调用 record.startrecording() 的情况下调用 record.read() 会发生什么?

我希望没有来自底层音频输入流的数据流,read()因此返回 0 或可能返回错误代码,表示没有读取任何数据。


2:SIZE_OF_RECORD_ARRAY的意义是什么?我认为它至少应该是 AudioRecord.getMinBufferSize() 返回的值,但在这个程序中,即使我将其设置为 1,它也不会影响输出。

当您在对构造函数getMinBufferSize的调用中指定缓冲区大小时,的值很重要。AudioRecord您要更改SIZE_OF_RECORD_ARRAY的只是每次调用时读取的数据量read()- 虽然read()每个字节调用一次并不是一个特别好的主意(因为所有这些函数调用的开销),但我可以想象它仍然可以工作。


3:如果我使用 16 位 PCM 编码,我至少需要一个短变量来存储音频样本的数字等价物。然而,在这段代码中,即使我将 lin 变量从短数组更改为字节数组,输出也没有明显变化。那么 read 函数是如何将数字样本存储在数组中的呢?它会自动为每个样本分配 2 个字节的元素吗?如果是这样的话,它是小端还是大端?

底层本机代码始终使用该byte版本。short版本只是版本的包装byte。所以是的,在这种情况下,每个样本都将使用一对字节。
至于字节序;在绝大多数 Android 设备上,它将是小端的。

于 2013-08-23T06:24:55.983 回答
0

试试这个,我希望能 100% 工作

  MediaRecorder mRecorder = null;
    String mFileName;
private void startRecording() {

        try {
            mRecorder = new MediaRecorder();
            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mFileName = getRecordDefaultFileName();
            mRecorder.setOutputFile(mFileName);
            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

            try {
                mRecorder.prepare();
            } catch (IOException e) {
                System.out.println("prepare() failed");
            }

            mRecorder.start();
        } catch (Exception e) {

            return;
        }

    }

private void stopRecording() {
        try {
            if (mRecorder != null) {
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;
            }
        } catch (Exception e) {
        }
    }

private String getRecordDefaultFileName() {

        File wallpaperDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "recordingFolder" + "/");
        if (!wallpaperDirectory.exists()) {
            wallpaperDirectory.mkdirs();
        }

        return wallpaperDirectory.getAbsolutePath() + File.separator + "iarecord" + ".3gp";
    }
于 2013-08-23T04:43:36.620 回答