Android语音采集
Android端的语音采集主要是调用AudioRecord,首先说几个参数
?
private static AudioRecord mRecord;// 音频获取源private int audioSource = MediaRecorder.AudioSource.MIC;// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025private static int sampleRateInHz = 8000;// 44100;// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道private static int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;// AudioFormat.CHANNEL_IN_STEREO;// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;// 音频大小private int bufSize;
?然后初始化一下AudioRecord,过程如下:
?
?
bufSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig,audioFormat);mRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig,audioFormat, bufSize);
?初始化完毕以后就需要采集音频数据了:
?
mRecord.startRecording();short audiodata[] = new short[bufSize];while (isRecord) {int readsize = 0;while (isRecord == true) {readsize = mRecord.read(audiodata, 0, bufSize);try {for (int i = 0; i < readsize; i++) {//dout.writeShort(audiodata[i]); //数据处理}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}mRecord.stop();audiodata = null;
?接下来是一个语音的播放了,我们这边不放的是采集到的语音流,即PCM无损格式的语音数据,如下:
参数:
?
private static AudioTrack mTrack;// 音频类型private int streamType = AudioManager.STREAM_MUSIC;// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025private int sampleRateInHz = 8000;// 44100;// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;// AudioFormat.CHANNEL_IN_STEREO;// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;// 音频大小private int bufSize;// 音频模式private int mode = AudioTrack.MODE_STREAM;protected boolean keepRuning = true;
?然后初始化播放器:
?
bufSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig,audioFormat);mTrack = new AudioTrack(streamType, sampleRateInHz, channelConfig,audioFormat, bufSize, mode);
?然后是播放:
?
DataOutputStream dos = null;mTrack.play();try {revSocket = server.accept();dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));din = new DataInputStream(revSocket.getInputStream());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}while (keepRuning) {short[] buffer = new short[bufSize / 4];try {Log.i("状态", "接收数据");for (int i = 0; din.available() > 0 && i < buffer.length; i++) {buffer[i] = din.readShort();dos.writeShort(buffer[i]);Log.i("状态", "接收数据," + String.valueOf(i));}short[] bytes_pkg = buffer.clone();mTrack.write(bytes_pkg, 0, bytes_pkg.length);} catch (Exception e) {e.printStackTrace();}}mTrack.stop();try {dos.close();din.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
将语音数据保存到文件,并且将裸数据文件保存成可播放的WAV文件
/** * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频, * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。 */private void writeDateTOFile() {// new一个byte数组用来存一些字节数据,大小为缓冲区大小byte[] audiodata = new byte[minBufSize];FileOutputStream fos = null;int readsize = 0;try {File file = new File(AudioName);if (file.exists()) {file.delete();}fos = new FileOutputStream(file);// 建立一个可存取字节的文件} catch (Exception e) {e.printStackTrace();}while (isRecord == true) {readsize = mRecord.read(audiodata, 0, minBufSize);Log.i("采集大小", String.valueOf(readsize));if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {try {fos.write(audiodata);} catch (IOException e) {e.printStackTrace();}}}try {fos.close();// 关闭写入流} catch (IOException e) {e.printStackTrace();}}// 这里得到可播放的音频文件private void copyWaveFile(String inFilename, String outFilename) {FileInputStream in = null;FileOutputStream out = null;long totalAudioLen = 0;long totalDataLen = totalAudioLen + 36;long longSampleRate = sampleRateInHz;int channels = 2;long byteRate = 16 * sampleRateInHz * channels / 8;byte[] data = new byte[minBufSize];try {in = new FileInputStream(inFilename);out = new FileOutputStream(outFilename);totalAudioLen = in.getChannel().size();totalDataLen = totalAudioLen + 36;WriteWaveFileHeader(out, totalAudioLen, totalDataLen,longSampleRate, channels, byteRate);while (in.read(data) != -1) {out.write(data);}in.close();out.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/** * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有 自己特有的头文件。 */private void WriteWaveFileHeader(FileOutputStream out, 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);out.write(header, 0, 44);}?播放裸语音数据文件
short[] buffer = new short[bufferSize / 4];try {// 定义输入流,将音频写入到AudioTrack类中,实现播放DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile)));// 实例AudioTrackAudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,frequence, channelConfig, audioEncoding, bufferSize,AudioTrack.MODE_STREAM);// 开始播放track.play();// 由于AudioTrack播放的是流,所以,我们需要一边播放一边读取while (isPlaying && dis.available() > 0) {int i = 0;while (dis.available() > 0 && i < buffer.length) {buffer[i] = dis.readShort();i++;}// 然后将数据写入到AudioTrack中track.write(buffer, 0, buffer.length);}// 播放结束track.stop();dis.close();} catch (Exception e) {// TODO: handle exception}?