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 chunkSystem.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 chunkSystem.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 = 16offset += 4;System.arraycopy(new byte[]{1, 0}, 0, header, offset, 2); // format = 1 for PCMoffset += 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 chunkSystem.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 headerheader[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 ' chunkheader[13] = 'm';header[14] = 't';header[15] = ' ';header[16] = 16; // 4 bytes: size of 'fmt ' chunkheader[17] = 0;header[18] = 0;header[19] = 0;header[20] = 1; // format = 1header[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 alignheader[33] = 0;header[34] = 16; // bits per sampleheader[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;@Overrideprotected 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();}@Overrideprotected 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");//文件长度 = 比特率*时间//= 采样率*位数*声道 / 8totalLength = (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();}}}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.button_start:try {mRecordingKeepGoing = true;new Thread() {@Overridepublic 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 stubmediaPlayer.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() {@Overridepublic void onChronometerTick(Chronometer chronometer) {}});seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic 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");}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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) {}}@Overrideprotected void onPause() {super.onPause();stopRecord();}@Overrideprotected 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;}}
Android 录音声波图相关推荐
- Android录音转为MP2的实现
Android录音转为MP2的实现 利用Android提供的AudioRecord类以及开源编码库twolame,实现了android手机边录音边编码,录音完成直接得到MP2音频文件.由于Androi ...
- Android录音下————AudioRecord源码分析
Android录音下----AudioRecord源码分析 文章目录 Android录音下----AudioRecord源码分析 一.概述 1.主要分析点 2.储备知识 二.getMinBufferS ...
- android 录音的格式,Android录音mp3格式实例详解
Android录音支持的格式有amr.aac,但这两种音频格式在跨平台上表现并不好. MP3显然才是跨平台的最佳选择. 项目地址 实现思路概述 在分析代码前,我们需要明确几个问题 1. 如何最终生成M ...
- Android音频录制方案,Android录音,录制其他App播放的声音
Android录音,录制其他App播放的声音 从Android10(SDK 29)版本开始,可以设置录音App的源为其他App,这样就可以录制其他App播放的声音 此方案有以下注意几点 设置了源为其他 ...
- Android录音amr实时转成MP3格式
文章目录 MP3 录音使用说明 步骤一:下载NDK,并配置(Mac) 步骤二:修改C代码相关路径,编译成so库 步骤三:应用层代码代码调用系统AudioRecord类开始录音 开始录音 start() ...
- Android录音并进行本地转码为MP3
** Android录音并进行本地转码 ** 通过安卓手机进行录音, 录音后,使用lame进行转码操作 开发中需要使用这个功能,只是一个简单的进行转码的工具,具体的代码信息如下 项目的基本结构图 1. ...
- Android录音-SoundTouch移植到Android
Android录音-SoundTouch移植到Android 文章目录 Android录音-SoundTouch移植到Android 一.SoundTouch介绍 二.移植SoundTouch(And ...
- Androidの录音实现
Androidの录音实现 1. 录音功能需要使用android.media.MediaRecorder来完成,这里我们列出几个重要的使用方法,也是最常用的录音接口. 1.MediaRecorder r ...
- Android录音控件
做项目一直不得空,好不容易腾出时间,赶紧把过往的知识整理一下,以下是做项目时用到的录音控件,在同事写的基础上修改改成,支持后台录音,页面比较简单.写这个组件之前做了简单的调研,如果有不 ...
最新文章
- 5加载stm32 keil_快速入门STM32单片机-软件篇
- oracle监听静态注册,oracle监听器动态注册于静态注册的区别
- 互联网资讯简报2019-05-14
- noip2017初赛的一些知识点
- 虚拟地址空间及内存管理方式
- 贾跃亭向全体债权人道歉!个人资产曝光:总额14亿美元,国内三套房
- 大萧条来临前的几大征兆
- 如何使用SSH密钥登录你的云服务器?使用SSH密钥的好处
- sourcemointor评价代码
- php做图书管理系统绪论,基于PHP图书管理系统的设计与实现本科毕业论文
- 邮件服务器备案,关于企业邮箱域名备案事项通知
- React实现H5横屏电子签名板
- window10 tar解压
- MFC添加鼠标右键菜单
- 发送QQ邮件报证书不被信任 Error in certificate
- 高防服务器防御的原理是什么呢
- 1949-2020年各省全要素生产率(年度)
- element-ui清除表单验证提示语
- 杨辉三角fac的C语言代码,程序设计基础B(陈雪龙)-中国大学mooc-题库零氪
- office 和 wps 对于超链接的处理浅析
热门文章
- springboot-thymeleaf踩坑记录
- AC米兰球队一百年年鉴(1899-1999)
- 一堆被称之为大学的东西——思想和精神(送给不仅仅是计算机专业的同学)
- 嘀嗒出行一直显示服务器错误,嘀嗒出行注册账号,显示身份信息异常!
- 瑞萨单片机之Flash存储
- 应用WSDK-实现和使用DIME的Web Services(上)
- win10任务管理器网络使用率一直为0%的解决方法
- 【guava】 谷歌guava工具包的常用方法 双key的map 、驼峰转下划线等小结
- 大数据架构师应该做到的
- 23 - JavaScript 通过style对象设置行内样式