Android实现录音声波图

本文实例为大家分享了Android实现录音声波图的具体代码,供大家参考,具体内容如下

图像类:

package com.akm.test;

/**
 * Created by toge on 15/12/9.
 */
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceView;

import java.util.LinkedList;

/**
 * A view that displays audio data on the screen as a waveform.
 */
public class WaveformView extends SurfaceView {

    // The number of buffer frames to keep around (for a nice fade-out visualization).
    private static final int HISTORY_SIZE = 6;

    // To make quieter sounds still show up well on the display, we use +/- 8192 as the amplitude
    // that reaches the top/bottom of the view instead of +/- 32767. Any samples that have
    // magnitude higher than this limit will simply be clipped during drawing.
    private static final float MAX_AMPLITUDE_TO_DRAW = 8192.0f;

    // The queue that will hold historical audio data.
    private final LinkedList<short[]> mAudioData;

    private final Paint mPaint;

    public WaveformView(Context context) {
        this(context, null, 0);
    }

    public WaveformView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveformView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mAudioData = new LinkedList<short[]>();

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.WHITE);
        mPaint.setStrokeWidth(0);
        mPaint.setAntiAlias(true);
    }

    /**
     * Updates the waveform view with a new "frame" of samples and renders it. The new frame gets
     * added to the front of the rendering queue, pushing the previous frames back, causing them to
     * be faded out visually.
     *
     * @param buffer the most recent buffer of audio samples
     */
    public synchronized void updateAudioData(short[] buffer) {
        short[] newBuffer;

        // We want to keep a small amount of history in the view to provide a nice fading effect.
        // We use a linked list that we treat as a queue for this.
        if (mAudioData.size() == HISTORY_SIZE) {
            newBuffer = mAudioData.removeFirst();
            System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
        } else {
            newBuffer = buffer.clone();
        }

        mAudioData.addLast(newBuffer);

        // Update the display.
        Canvas canvas = getHolder().lockCanvas();
        if (canvas != null) {
            drawWaveform(canvas);
            getHolder().unlockCanvasAndPost(canvas);
        }
    }

    /**
     * Repaints the view's surface.
     *
     * @param canvas the {@link Canvas} object on which to draw
     */
    private void drawWaveform(Canvas canvas) {
        // Clear the screen each time because SurfaceView won't do this for us.
        canvas.drawColor(Color.BLACK);

        float width = getWidth();
        float height = getHeight();
        float centerY = height / 2;

        // We draw the history from oldest to newest so that the older audio data is further back
        // and darker than the most recent data.
        int colorDelta = 255 / (HISTORY_SIZE + 1);
        int brightness = colorDelta;

        for (short[] buffer : mAudioData) {
            mPaint.setColor(Color.argb(brightness, 128, 255, 192));

            float lastX = -1;
            float lastY = -1;

            // For efficiency, we don't draw all of the samples in the buffer, but only the ones
            // that align with pixel boundaries.
            for (int x = 0; x < width; x++) {
                int index = (int) ((x / width) * buffer.length);
                short sample = buffer[index];
                float y = (sample / MAX_AMPLITUDE_TO_DRAW) * centerY + centerY;

                if (lastX != -1) {
                    canvas.drawLine(lastX, lastY, x, y, mPaint);
                }

                lastX = x;
                lastY = y;
            }

            brightness += colorDelta;
        }
    }
}

头文件:

/*
 * Copyright (C) 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.akm.test;

import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by Akm at 15/12/1 上午10:07
 * 文件制作
 */
public class WAVHeader {
    private byte[] mHeader;          // the complete header.
    private int mSampleRate;         // sampling frequency in Hz (e.g. 44100).
    private int mChannels;           // number of channels.
    private int mNumSamples;         // total number of samples per channel.
    private int mNumBytesPerSample;  // number of bytes per sample, all channels included.

    public WAVHeader(int sampleRate, int numChannels, int numSamples) {
        mSampleRate = sampleRate;
        mChannels = numChannels;
        mNumSamples = numSamples;
        mNumBytesPerSample = 2 * mChannels;  // assuming 2 bytes per sample (for 1 channel)
        mHeader = null;
        setHeader();
    }

    public byte[] getWAVHeader() {
        return mHeader;
    }

    public static byte[] getWAVHeader(int sampleRate, int numChannels, int numSamples) {
        return new WAVHeader(sampleRate, numChannels, numSamples).mHeader;
    }

    public String toString() {
        String str = "";
        if (mHeader == null) {
            return str;
        }
        int num_32bits_per_lines = 8;
        int count = 0;
        for (byte b : mHeader) {
            boolean break_line = count > 0 && count % (num_32bits_per_lines * 4) == 0;
            boolean insert_space = count > 0 && count % 4 == 0 && !break_line;
            if (break_line) {
                str += '\n';
            }
            if (insert_space) {
                str += ' ';
            }
            str += String.format("%02X", b);
            count++;
        }

        return str;
    }

    private void setHeader() {
        byte[] header = new byte[46];
        int offset = 0;
        int size;

        // set the RIFF chunk
        System.arraycopy(new byte[]{'R', 'I', 'F', 'F'}, 0, header, offset, 4);
        offset += 4;
        size = 36 + mNumSamples * mNumBytesPerSample;
        header[offset++] = (byte) (size & 0xFF);
        header[offset++] = (byte) ((size >> 8) & 0xFF);
        header[offset++] = (byte) ((size >> 16) & 0xFF);
        header[offset++] = (byte) ((size >> 24) & 0xFF);
        System.arraycopy(new byte[]{'W', 'A', 'V', 'E'}, 0, header, offset, 4);
        offset += 4;

        // set the fmt chunk
        System.arraycopy(new byte[]{'f', 'm', 't', ' '}, 0, header, offset, 4);
        offset += 4;
        System.arraycopy(new byte[]{0x10, 0, 0, 0}, 0, header, offset, 4);  // chunk size = 16
        offset += 4;
        System.arraycopy(new byte[]{1, 0}, 0, header, offset, 2);  // format = 1 for PCM
        offset += 2;
        header[offset++] = (byte) (mChannels & 0xFF);
        header[offset++] = (byte) ((mChannels >> 8) & 0xFF);
        header[offset++] = (byte) (mSampleRate & 0xFF);
        header[offset++] = (byte) ((mSampleRate >> 8) & 0xFF);
        header[offset++] = (byte) ((mSampleRate >> 16) & 0xFF);
        header[offset++] = (byte) ((mSampleRate >> 24) & 0xFF);
        int byteRate = mSampleRate * mNumBytesPerSample;
        header[offset++] = (byte) (byteRate & 0xFF);
        header[offset++] = (byte) ((byteRate >> 8) & 0xFF);
        header[offset++] = (byte) ((byteRate >> 16) & 0xFF);
        header[offset++] = (byte) ((byteRate >> 24) & 0xFF);
        header[offset++] = (byte) (mNumBytesPerSample & 0xFF);
        header[offset++] = (byte) ((mNumBytesPerSample >> 8) & 0xFF);
        System.arraycopy(new byte[]{0x10, 0}, 0, header, offset, 2);
        offset += 2;

        // set the beginning of the data chunk
        System.arraycopy(new byte[]{'d', 'a', 't', 'a'}, 0, header, offset, 4);
        offset += 4;
        size = mNumSamples * mNumBytesPerSample;
        header[offset++] = (byte) (size & 0xFF);
        header[offset++] = (byte) ((size >> 8) & 0xFF);
        header[offset++] = (byte) ((size >> 16) & 0xFF);
        header[offset++] = (byte) ((size >> 24) & 0xFF);

        mHeader = header;
    }

    public static byte[] getHeader(  long totalAudioLen,
                            long totalDataLen, long longSampleRate, int channels, long byteRate) throws IOException {

        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (2 * 16 / 8); // block align
        header[33] = 0;
        header[34] = 16; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

        return header;
    }
}

测试:

package com.akm.test;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.SeekBar;
import android.widget.TextView;

import com.ringdroid.R;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by toge on 15/11/30.
 */
public class Test extends Activity implements View.OnClickListener {

    WaveformView waveformView;
    private Button btnStart;
    private Button btnStop;
    private String filePath;
    private boolean mRecordingKeepGoing;
    private SoundFile soundFile;
    private RandomAccessFile randomAccessFile;
    private int totalLength;//总长
    private int duration;//时长
    private int rate;//采样率
    private int channelConfig;//声道

    private int samples;
    private int startPos;
    private int bufferSize;//缓冲区大小
    private int minBufferSize;//最小缓冲区

    private AudioRecord audioRecord;
    private AudioTrack audioTrack;
    private boolean mThreadFlag;
    private int i;
    private int j;
    private int STATUS = 1;
    private int STATUS_PAUSE = 2;
    private int STATUS_PREPARED = 1;
    private int STATUS_RECORDING = 1;
    private Thread audioTrackThread;
    private Thread thread;
    private int endPos;
    private int curFileLength;
    OnFileChangedListener onFileChangedListener;
    private boolean isRewrite;
    private boolean audioTrackFlag;
    private int frequency = 22050;//22050;
    private int recBufSize;
    private String outPath;
    private byte[] bytes;
    private int time;
    private Button btnPasue;
    private Button btnPlay;
    private Button btnPlay2;
    private long startTime;
    private long restOfTime;
    private int audioFormat;//采集
    private int bufferSizeInBytes;//缓冲区大小
    private Button btnSave;
    //    private ByteBuffer mDecodedBytes;
//    private ByteBuffer mDecodedSamples;
    private byte[] sampleBytes;
    private MediaPlayer mediaPlayer;
    private SeekBar seekBar;
    private android.os.Handler handler = new android.os.Handler();
    Runnable updateThread = new Runnable() {
        public void run() {
            // 获得歌曲现在播放位置并设置成播放进度条的值
            if (mediaPlayer != null) {
                seekBar.setProgress(mediaPlayer.getCurrentPosition());
                Log.e("Test", "run------ updateThread:getCurrentPosition " + mediaPlayer.getCurrentPosition());
                // 每次延迟100毫秒再启动线程
                handler.postDelayed(updateThread, 100);
            }
        }
    };
    private Chronometer et_time;
    private long falgTime;
    private long pauseTime;
    private long subtime;
    private long beginTime;
    private TextView currentTime;
    private int currentProgress;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);

        waveformView = (WaveformView) findViewById(R.id.waveform);
        btnStart = (Button) findViewById(R.id.button_start);
        btnPasue = (Button) findViewById(R.id.button_pasue);
        btnStop = (Button) findViewById(R.id.button2_stop);
        btnPlay = (Button) findViewById(R.id.button_play);
        btnPlay2 = (Button) findViewById(R.id.button_play2);
        btnSave = (Button) findViewById(R.id.button_save);
        seekBar = (SeekBar) findViewById(R.id.sb);
        et_time = (Chronometer) this.findViewById(R.id.et_time);
        currentTime = (TextView) this.findViewById(R.id.currentTime);

        btnStart.setOnClickListener(this);
        btnPasue.setOnClickListener(this);
        btnStop.setOnClickListener(this);
        btnPlay.setOnClickListener(this);
        btnPlay2.setOnClickListener(this);
        btnSave.setOnClickListener(this);

        initPar();
        initRecorder(true);
        initAudioTack();
    }

    @Override
    protected void onResume() {
        super.onResume();

        initRecorder(false);
    }

    private void initAudioTack() {
        minBufferSize = AudioTrack.getMinBufferSize(rate, 3, audioFormat);
        Log.e("Test", "initAudioTack------ minBufferSize:" + minBufferSize);
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, rate, 1, audioFormat, minBufferSize, AudioTrack.MODE_STREAM);
    }

    private void initPar() {
        duration = 60 * 1000;//毫秒
        rate = 44100;//声卡一般提供11.025kHz、22.05kHz和44.1kHz等不同的采样频率
        channelConfig = AudioFormat.CHANNEL_IN_DEFAULT;
        audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        restOfTime = duration;
    }

    private void initRecorder(boolean isNew) {

        initAudioFile(isNew);
        bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
        Log.d("Test", "initRecorder: bufferSize:" + bufferSize);//44100 1 2 = v fc
//        int k = audioFormat * rate / 25;
//        if (bufferSize % k != 0) {
//            bufferSize = (k * (channelConfig + bufferSize / k));
//        }
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, rate, channelConfig, audioFormat, bufferSize);

    }

    public boolean isRecording() {
        return audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING;
    }

    private void initAudioFile(boolean isNew) {

        filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/akm/t.wav";

        new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/akm").mkdir();
        File f = new File(filePath);
        try {
            if (f.exists() && isNew) {
                f.delete();
            }

            randomAccessFile = new RandomAccessFile(filePath, "rw");
            //文件长度 = 比特率*时间
            //= 采样率*位数*声道 / 8

            totalLength = (rate * 1 * 16 / 8) * (duration / 1000);
//            totalLength = (int) (4l * (duration * rate / 1000l));
            createWaveFile(randomAccessFile, true, totalLength);
            totalLength = 44 + totalLength;
            randomAccessFile = new RandomAccessFile(filePath, "rw");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createWaveFile(RandomAccessFile randomAccessFile, boolean b, int totalLength) {

        if (b) {

            try {
//                randomAccessFile.write(WAVHeader.getHeader(rate,channels,samples));
                // long totalAudioLen,long totalDataLen, long longSampleRate, int channels, long byteRate
                //数据长度 文件长度 采样率 声道 比特率

                //比特率(字节/秒)= (采样频率(Hz)× 采样位数(bit) × 声道数)/ 8
                //

                long byteRate = (channelConfig * audioFormat * rate) / 8;
                byte[] bytes = WAVHeader.getHeader(totalLength - 36l, totalLength, rate, channelConfig, byteRate);
                FileChannel localFileChannel = randomAccessFile.getChannel();
                localFileChannel.map(FileChannel.MapMode.READ_WRITE, 0l, 44l).put(bytes);
                localFileChannel.close();
                Log.e("Test", "createWaveFile------ OK ");

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button_start:

                try {

                    mRecordingKeepGoing = true;

                    new Thread() {
                        @Override
                        public void run() {

                            startRecording();

                        }
                    }.start();

                } catch (Exception e) {
                    e.printStackTrace();
                }

                break;

            case R.id.button_pasue:
                mRecordingKeepGoing = false;

                pauseRecord();

                try {//暂停后,设置文件索引为末尾

                    startPos = (int) randomAccessFile.getFilePointer();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                pausePlay();

                break;

            case R.id.button_play:
                startReview(true);

                break;
            case R.id.button2_stop:
                mRecordingKeepGoing = false;

                stopRecord();

                stopPlay();

                break;

            case R.id.button_save:

                startPos = currentProgress;
                if (randomAccessFile==null){
                    try {
                        randomAccessFile = new RandomAccessFile(filePath, "rw");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    Log.e("Test", "onClick: pos" + randomAccessFile.getFilePointer());
                    int size = ((rate * 1 * 16 / 8) * (currentProgress / 1000));
                    Log.e("Test", "onClick------ size "+size);
                    if (size<44){
                        size = 44;
                    }
                    randomAccessFile.seek(size);
                    randomAccessFile.write(sampleBytes);
                    randomAccessFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Log.e("Test", "onClick------pos "+currentProgress);

                break;
            case R.id.button_play2:
                play();
                break;

        }
    }

    private void pausePlay() {

        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            // 暂停音乐播放器
            mediaPlayer.pause();
            btnPasue.setText("续播");
            seekBar.setEnabled(false);
            et_time.stop();

            pauseTime = SystemClock.elapsedRealtime();
            // System.out.println("1 pauseTime" + pauseTime);
        } else if (mediaPlayer != null
                && "续播".equals(btnPasue.getText().toString())) {
            subtime += SystemClock.elapsedRealtime() - pauseTime;
            // System.out.println("2 subtime:" + subtime);
            mediaPlayer.start();
            btnPasue.setText("暂停");
            seekBar.setEnabled(true);
            beginTime = falgTime + subtime;
            // System.out.println("3 beginTime" + beginTime);
            et_time.setBase(beginTime);
            et_time.start();
        }
    }

    private void stopPlay() {

        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
            mediaPlayer = null;
            et_time.setBase(SystemClock.elapsedRealtime());
            et_time.start();
            et_time.stop();
            btnPlay2.setEnabled(true);
            btnPlay2.setClickable(true);
        }
        falgTime = 0;
        subtime = 0;
        seekBar.setProgress(0);
        seekBar.setEnabled(false);

    }

    private void play() {

        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(filePath);
            mediaPlayer.prepareAsync();

            // 为播放器注册
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {

                public void onPrepared(MediaPlayer mp) {
                    // TODO Auto-generated method stub
                    mediaPlayer.start();
                    btnPlay2.setEnabled(false);
                    btnPlay2.setClickable(false);
                    seekBar.setMax(mediaPlayer.getDuration());
                    handler.post(updateThread);
                    seekBar.setEnabled(true);
                }
            });

            // 注册播放完毕后的监听事件
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

                public void onCompletion(MediaPlayer mp) {
//                    mediaPlayer.release();
//                    mediaPlayer = null;
                    btnPlay2.setEnabled(true);
                    btnPlay2.setClickable(true);
                    et_time.setBase(SystemClock.elapsedRealtime());
                    et_time.start();
                    et_time.stop();
                    seekBar.setProgress(0);
                }
            });
            falgTime = SystemClock.elapsedRealtime();
            et_time.setBase(falgTime);
            et_time.start();

            et_time.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
                @Override
                public void onChronometerTick(Chronometer chronometer) {

                }
            });

            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    if (fromUser == true && mediaPlayer != null) {
                        Log.e("Test", "onProgressChanged------ progress "+progress);
                        mediaPlayer.seekTo(progress);
                        falgTime = SystemClock.elapsedRealtime();
                        beginTime = falgTime - seekBar.getProgress();
                        et_time.setBase(beginTime);
//                        et_time.start();

//                        final int ctime = mediaPlayer.getDuration() / progress;
                        //时间*比特率 = 大小 (rate * 1 * 16 / 8) * (duration / 1000);
                        //时间 = 大小/比特率

                        int ctime = progress/((rate * 1 * 16 / 8) * (duration / 1000));
                        currentTime.setText( ctime+ "s");

                    }
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {

                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
//                    startPos = seekBar.getProgress();
                    currentProgress = seekBar.getProgress();

                }
            });

        } catch (IOException e) {
            e.printStackTrace();
        }
        // mediaPlayer.prepare(); // c/c++ 播放器引擎的初始化
        // 同步方法
        // 采用异步的方式

    }

    private OnEventListener onEventListener;

    public void setOnEventListener(OnEventListener onEventListener) {
        this.onEventListener = onEventListener;
    }

    android.os.Handler errorHandler = new android.os.Handler() {
        @Override
        public void handleMessage(Message msg) {

            if (onEventListener != null) {
                onEventListener.onError("error");
            }

        }
    };

    private void startThread() {

        if (startPos == 0) {//开始位置
            try {
                randomAccessFile.seek(44);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        mThreadFlag = true;
        i = 0;
        j = -1;
        STATUS = 1;
        thread = new Thread() {
            @Override
            public void run() {

                if (startTime == 0) {
                    startTime = System.currentTimeMillis();

                }
                byte[] arrayOfByte = new byte[bufferSize];
                short[] arrayOfShort = new short[bufferSize];
                while (mThreadFlag) {

                    try {
                        if (audioRecord == null || STATUS != 1) {
                            continue;
                        }
                        int bufferReadResult = audioRecord.read(arrayOfByte, 0, bufferSize);
                        int bufferReadResult2 = audioRecord.read(arrayOfShort, 0, bufferSize);

                        Log.e("Test", "run------ bufferReadResult "+bufferReadResult);
                        Log.e("Test", "run------ bufferReadResult2 "+bufferReadResult2);

                        if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING || bufferReadResult <= 0) {
                            break;
                        }

                        i = 1;

                        randomAccessFile.write(arrayOfByte);

                        waveformView.updateAudioData(arrayOfShort);

                        byte[] tmpBuf = new byte[bufferReadResult];
                        System.arraycopy(arrayOfByte, 0, tmpBuf, 0, bufferReadResult);
                        audioTrack.write(tmpBuf, 0, tmpBuf.length);

                        pjByteBuffer(tmpBuf);

                        curFileLength = (int) randomAccessFile.length() / 1024;
                        Log.e("Test", "run------ curFilelength:" + curFileLength + ",startPos:" + startPos + ",endPos:" + endPos + ",isRewrite:" + isRewrite);
                        int time = (int) (System.currentTimeMillis() - startTime);
                        Log.e("Test", "run------ time: " + time);
                        Log.e("Test", "run------ bytes:" + arrayOfByte.length);
                        Log.e("Test", "run------ getFilePointer:" + randomAccessFile.getFilePointer());

                        startPos = (int) randomAccessFile.getFilePointer();

                        if (time >= restOfTime) {
                            stopRecord();
                        }
                        onFileChangedListener.onBufferRecevied(startPos, endPos, arrayOfByte, curFileLength, isRewrite);

//                        Test t1 = Test.this;
//                        t1.i = 1+t1.i;
//
//                        long length = randomAccessFile.getFilePointer() + arrayOfByte.length;
//                        xxx(this,length);
//                        if (endPos>curFileLength){
//                            xxx(this,endPos);
//                        }
//                        randomAccessFile.write(arrayOfByte);
//                        onFileChangedListener.onBufferRecevied(startPos,endPos,arrayOfByte,curFileLength,isRewrite);
//
//                        Test t2 =Test.this;
//                        t2.j = 1+t2.j;
//                        if (i!=0||j!=0){
//                            continue;
//                        }
//                        xxx(this,false);
//                        errorHandler.sendEmptyMessage(0);

                    } catch (Exception e) {
                        e.printStackTrace();
                        errorHandler.sendEmptyMessage(0);
                    }

                }

            }
        };
        thread.start();

    }

    private byte[] pjArray(byte[] src, byte[] dest) {
        byte[] newBytes = new byte[src.length + dest.length];

        System.arraycopy(src, 0, newBytes, 0, src.length);
        System.arraycopy(dest, 0, newBytes, src.length, dest.length);

        return newBytes;
    }

    private void pjByteBuffer(byte[] tmpBuf) {

        if (sampleBytes == null) {
            sampleBytes = tmpBuf;
        } else {
            sampleBytes = pjArray(sampleBytes, tmpBuf);
        }

    }

    private void pauseReview() {
        audioTrackFlag = false;
        audioTrack.pause();
        audioTrack.flush();
        Log.e("Test", "pauseReview------ ");

    }

    private void startReview(boolean b) {
        if (audioTrack == null) {
            initAudioTack();
        }
        audioTrack.play();
        audioTrackFlag = true;
        audioTrackThread = new Thread() {
            @Override
            public void run() {
                try {
                    bytes = new byte[minBufferSize];
                    while (randomAccessFile.read(bytes) != -1 && audioTrackFlag) {

                        Log.e("Test", "run------ ");
                        Log.e("Test", "run------audiotrackflag is  " + audioTrackFlag);
                        Log.e("Test", "run------wrtie data in audiotrack ");

                    }
                    Log.e("Test", "run------ audiotrack end.");

                } catch (Exception e) {

                }
            }
        };
        audioTrackThread.start();

    }

    public void pauseRecord() {

        if (audioRecord != null) {
            audioRecord.stop();
            mThreadFlag = false;
        }
    }

    private void reset() {
        startPos = 0;
        endPos = 0;
        curFileLength = 44;
        isRewrite = false;
    }

    private void resumeRecord() {

        while (isRewrite) {//写文件

            try {
                if (randomAccessFile.getFilePointer() != endPos || !isRewrite) {//不可写 ,或者选中位置不是文件指针所在位置
                    startPos = (int) randomAccessFile.getFilePointer(); // 从文件指针位置开始
                }
                if (!isRewrite) {//不写文件

                    if (44 + startPos >= endPos) {//
                        continue;
                    }

                    isRewrite = true;

                }

            } catch (IOException e) {
                e.printStackTrace();
            }

            audioRecord.startRecording();
            if (thread == null || !mThreadFlag) {
                startThread();
            }

        }
    }

    private void startRecording() {
        try {
            audioRecord.startRecording();

//            if (thread==null||!mThreadFlag){
//                startThread();
//            }
            startThread();
            Log.e("Test", "startRecording------ ");
        } catch (Exception e) {
            initRecorder(true);
        }

    }

    public int getMinBufferSize() {
        return minBufferSize;
    }

    public void getMinBufSize() {
        recBufSize = AudioRecord.getMinBufferSize(frequency, 12, 2);
    }

    public void setOnFileChangedListener(OnFileChangedListener onFileChangedListener) {
        this.onFileChangedListener = onFileChangedListener;
    }

    public void setDuration(int duration) {
        this.duration = duration;
    }

    interface OnFileChangedListener {
        void onBufferRecevied(long startPos, long endPos, byte[] b1, long currenFileLength, boolean isRew);
    }

    interface OnEventListener {
        void onError(String s);

        void onRecordComplete();

        void onVolumnChanged(double vl);
    }

    public String creatFile() {
//        copyWaveFile(filePath,filePath,true);
        return outPath;
    }

    private void moveToPrevious(long pl) {
        try {
            long l = 44 + 4 * (pl * rate / 1000l);
            randomAccessFile.seek(l);
            Log.e("Test", "moveToPrevious------ offset:" + l + " length:" + randomAccessFile.length());

        } catch (Exception e) {

        }

    }

    @Override
    protected void onPause() {
        super.onPause();
        stopRecord();
    }

    @Override
    protected void onStop() {
        super.onStop();
        closeStream();
    }

    private void stopRecord() {

        try {
            mThreadFlag = false;
            time = 0;
            thread = null;

            if (audioRecord != null) {
                if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                    audioRecord.stop();
                    Log.e("Test", "stopRecord------ ");
                }
                audioRecord.release();
                audioRecord = null;

            }
            closeStream();

        } catch (Exception e) {

        }

    }

    private void closeStream() {
        try {
            if (randomAccessFile != null) {
                randomAccessFile.close();
            }
        } catch (Exception e) {

        }

    }

    float getDensity() {
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        return metrics.density;
    }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2022-08-05

Android实现语音播放与录音功能

本文实例为大家分享了Android实现语音播放与录音的具体代码,供大家参考,具体内容如下 项目用到的技术点和亮点 语音录音 (单个和列表) 语音播放(单个和列表) 语音录音封装 语音播放器封装 语音列表顺序播放 语音列表单个播放 复用问题处理 因为安装原生录音不能录mp3格式文件 而mp3格式是安卓和ios公用的,所以我们需要的是能直接录取mp3文件或者录完的格式转成mp3格式 下面添加这个库 能直接录mp3文件,我觉得是最方便的 compile 'com.czt.mp3recorder:lib

Android实现录音功能实现实例(MediaRecorder)

本文介绍了Android实现录音的实例代码(MediaRecorder),分享给大家,具体如下: Android提供了两个API用于录音的实现:MediaRecorder 和 AudioRecord,各有优劣. 1.MediaRecorder 已经集成了录音.编码.压缩等,支持少量的录音音频格式,大概有.aac(API = 16) .amr .3gp 优点:大部分已经集成,直接调用相关接口即可,代码量小 缺点:无法实时处理音频:输出的音频格式不是很多,例如没有输出mp3格式文件 2.AudioR

Android应用开发:电话监听和录音代码示例

在oncreate 中执行: 复制代码 代码如下: public void onCreate() {  super.onCreate();  Log.i("TAG", "服务启动了"); // 对电话的来电状态进行监听  TelephonyManager telManager = (TelephonyManager) this    .getSystemService(Context.TELEPHONY_SERVICE);  // 注册一个监听器对电话状态进行监听 

Android实现录音方法(仿微信语音、麦克风录音、发送语音、解决5.0以上BUG)

先给大家展示下效果图,如果大家感觉不错,请参考使用方法, 效果图如下所示: 使用方法: 录音工具类:AudioRecoderUtils.java,代码如下: public class AudioRecoderUtils { //文件路径 private String filePath; //文件夹路径 private String FolderPath; private MediaRecorder mMediaRecorder; private final String TAG = "fan&q

Android开发四大组件之实现电话拦截和电话录音

一.问题描述 使用BordercastReceiver和Service组件实现下述功能: 1.当手机处于来电状态,启动监听服务,对来电进行监听录音. 2.设置电话黑名单,当来电是黑名单电话,则直接挂断. 当拨打电话或电话状态发生改变时,系统就会发出有序广播,因此我们可以使用BordercastReceiver接受广播,因BordercastReceiver执行时间短不能执行耗时任务也不能使用子线程,因此我们应启动一个Service来监听电话并进行处理 二.加入AIDL文件 Android没有对外

Android音频录制MediaRecorder之简易的录音软件实现代码

使用MediaRecorder的步骤:1.创建MediaRecorder对象2.调用MediRecorder对象的setAudioSource()方法设置声音的来源,一般传入MediaRecorder.MIC3.调用MediaRecorder对象的setOutputFormat()设置所录制的音频文件的格式4.调用MediaRecorder对象的setAudioRncoder().setAudioEncodingBitRate(int bitRate).setAudioSamlingRate(i

Android编程实现录音及保存播放功能的方法【附demo源码下载】

本文实例讲述了Android编程实现录音及保存播放功能的方法.分享给大家供大家参考,具体如下: 在android中进行录音相对来说是比较简单的,使用系统提供的MediaRecorder类进行录音并保存,然后调用MediaPlayer进行播放.以下为xml配置文件代码: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas

详解Android开发录音和播放音频的步骤(动态获取权限)

步骤: 配置权限: <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.work.mediaplay"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission> <us

Android简单的利用MediaRecorder进行录音的实例代码

复制代码 代码如下: package com.ppmeet; import java.io.IOException; import android.app.Activity;  import android.graphics.PixelFormat;  import android.media.MediaRecorder;  import android.os.Bundle;  import android.view.View;  import android.view.View.OnClick

Android App调用MediaRecorder实现录音功能的实例

MediaRecorder Android的MediaRecorder包含了Audio和video的记录功能,在Android的界面上,Music和Video两个应用程序都是调用MediaRecorder实现的. MediaRecorder在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaRecorder程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制. 以开源的Android为例MediaRecorder的

Android App增量更新详解及实例代码

Android App增量更新实例--Smart App Updates        介绍 你所看到的,是一个用于Android应用程序增量更新的开源库. 包括客户端.服务端两部分代码. 原理 自从 Android 4.1 开始,Google引入了应用程序的增量更新. Link: http://developer.android.com/about/versions/jelly-bean.html Smart app updates is a new feature of Google Pla

Android App后台服务报告工作状态实例

本节讲运行在后台服务里的工作请求,如何向发送请求者报告状态.推荐用LocalBroadcastManager发送和接收状态,它限制了只有本app才能接收到广播. 从IntentService汇报状态 从IntentService发送工作请求状态给其他组件,先创建一个包含状态和数据的Intent.也可以添加action和URI到intent里. 下一步,调用 LocalBroadcastManager.sendBroadcast()发送Intent,应用中所有注册了接收该广播的接收器都能收到.Lo

Android Java调用自己C++类库的实例讲解

Android Java 如何调用自己的 C++ 的类库 下面以 Java 调用 C++ 的加法运算函数为例,做简单说明. (使用 Android Studio 3 编译) 首先编译 c++ 类库 创建独立目录存放 c++ 文件,例如 "app/src/main/cpp/add.cpp",内容如下 #include <jni.h> extern "C" JNIEXPORT jint JNICALL Java_com_example_liyi_demo_U

Android App中自定义View视图的实例教程

一.基础 很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章.先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 3.重写onMesure 4.重写onDraw 我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的. 1.自定义View的属性,首先在res/values/  下建立一个attrs.xm

通过实例简单讲解Android App中的Activity组件

Activity是Android应用中,最直接与用户接触的组件,它负责加载View组件,使其展现给用户,并保持与用户的交互.所有的Activity组件均需要继承Activity类,这是一个Content的间接子类,包装了一些Activity的基本特性. View组件是所有UI组件.容器组件的基类,也就是说,它可以是一个布局容器,也可以是一个布局容器内的基本UI组件.View组件一般通过XML布局资源文件定义,同时Android系统也对这些View组件提供了对应的实现类.如果需要通过某个Activ

Android App中各种数据保存方式的使用实例总结

少量数据保存之SharedPreferences接口实例 SharedPreferences数据保存主要是通过键值的方式存储在xml文件中 xml文件在data/此程序的包名/XX.xml. 格式: <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <int name="count" value="3" /> <string name="t

Android App中使用ListFragment的实例教程

ListFragment继承于Fragment.因此它具有Fragment的特性,能够作为activity中的一部分,目的也是为了使页面设计更加灵活. 相比Fragment,ListFragment的内容是以列表(list)的形式显示的.ListFragment的布局默认包含一个ListView.因此,在ListFragment对应的布局文件中,必须指定一个 android:id 为 "@android:id/list" 的ListView控件! ListFragment基础使用 下面

Android App中实现图片异步加载的实例分享

一.概述 一般大量图片的加载,比如GridView实现手机的相册功能,一般会用到LruCache,线程池,任务队列等:那么异步消息处理可以用哪呢? 1.用于UI线程当Bitmap加载完成后更新ImageView 2.在图片加载类初始化时,我们会在一个子线程中维护一个Loop实例,当然子线程中也就有了MessageQueue,Looper会一直在那loop停着等待消息的到达,当有消息到达时,从任务队列按照队列调度的方式(FIFO,LIFO等),取出一个任务放入线程池中进行处理. 简易的一个流程:当