音频数据有问题
Posted
技术标签:
【中文标题】音频数据有问题【英文标题】:something wrong with audio data 【发布时间】:2012-05-16 18:19:19 【问题描述】:我认为主要问题来自 MicrophoneManager 中的读取方法,但看不到问题出在哪里。我的 bytesread 控制台输出为 0(这是在另一个类 AudioTransmitter 中)。在我看来,它不是流式传输音频数据,因为发送的数据没有变化,就像我说的读取字节数为 0。
public class MicrophoneManager
// private TargetDataLine targetDataLine;
private float sampleRate = 8000.0F; //8000,11025,16000,22050,44100
private int sampleSizeInBits = 16; //8,16
private int channels = 1; //1,2
private boolean signed = true; //true,false
private boolean bigEndian = false; //true,false
private AudioFormat audioFormat;
// private AudioRecord audioRecord;
// private AudioInputStream ais;
private static MicrophoneManager singletonMicrophoneManager = null;
public AudioRecord audioRecord;
public int mSamplesRead; //how many samples read
public int buffersizebytes;
public int buflen;
public int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
public static byte[] buffer; //+-32767
public static final int SAMPPERSEC = 8000; //samp per sec 8000, 11025, 22050 44100 or 48000
public class MicrophoneManager
// private TargetDataLine targetDataLine;
private float sampleRate = 8000.0F; //8000,11025,16000,22050,44100
private int sampleSizeInBits = 16; //8,16
private int channels = 1; //1,2
private boolean signed = true; //true,false
private boolean bigEndian = false; //true,false
private AudioFormat audioFormat;
// private AudioRecord audioRecord;
// private AudioInputStream ais;
private static MicrophoneManager singletonMicrophoneManager = null;
public AudioRecord audioRecord;
public int mSamplesRead; //how many samples read
public int buffersizebytes;
public int buflen;
public int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
public static short[] buffer; //+-32767
public static final int SAMPPERSEC = 8000; //samp per sec 8000, 11025, 22050 44100 or 48000
public MicrophoneManager()
System.out.println("Initializing");
// audioFormat = new AudioFormat(sampleRate,sampleSizeInBits,channels,signed,bigEndian);
// audioRecord = new AudioRecord(MediaRecorder.Audiosource.DEFAULT, (int) sampleRate, channels, AudioFormat.ENCODING_PCM_16BIT, buffersizebytes);
buffersizebytes = AudioRecord.getMinBufferSize(SAMPPERSEC,channelConfiguration,audioEncoding); //4096 on ion
buffer = new short[buffersizebytes];
buflen=buffersizebytes/2;
audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,
channelConfiguration,audioEncoding,buffersizebytes); //constructor
public static MicrophoneManager getMicrophoneManager() throws Exception
if (singletonMicrophoneManager == null)
singletonMicrophoneManager = new MicrophoneManager();
singletonMicrophoneManager.initialize();
return singletonMicrophoneManager;
public void initialize() throws Exception
public void startAudioInput()
try
audioRecord.startRecording();
mSamplesRead = audioRecord.read(buffer, 0, buffer.length);
audioRecord.stop();
catch (Throwable t)
// Log.e("AudioRecord", "Recording Failed");
System.out.println("Error Starting audio input"+t);
public void stopAudioInput()
audioRecord.stop();
System.out.println("Stopping audio input");
public void finishAudioInput()
audioRecord.release();
System.out.println("Finishing audio input");
public boolean available() throws Exception
return true;
public int read(byte[] inBuf) throws Exception
return audioRecord.read(inBuf,0,inBuf.length);
音频发射器:
public class AudioTransmitter extends Thread
private MicrophoneManager mm=null;
private boolean transmittingAudio = false;
private String host;
private int port;
private long id=0;
boolean run=true;
public AudioTransmitter(String host, int port, long id)
this.host = host;
this.port = port;
this.id = id;
this.start();
public void run()
System.out.println("creating audio transmitter host "+host+" port "+port+" id "+id);
TrustManager[] trustAllCerts = new TrustManager[]
new X509TrustManager()
public java.security.cert.X509Certificate[] getAcceptedIssuers()
return null;
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain, String authType)
for (int j=0; j<chain.length; j++)
System.out.println("Client certificate information:");
System.out.println(" Subject DN: " + chain[j].getSubjectDN());
System.out.println(" Issuer DN: " + chain[j].getIssuerDN());
System.out.println(" Serial number: " + chain[j].getSerialNumber());
System.out.println("");
;
while (run)
if(transmittingAudio)
try
if(mm==null)
mm = new MicrophoneManager();
// mm.initialize();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory sslFact = sc.getSocketFactory();
SSLSocket socket = (SSLSocket)sslFact.createSocket(host, port);
socket.setSoTimeout(10000);
InputStream inputStream = socket.getInputStream();
DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream));
OutputStream outputStream = socket.getOutputStream();
DataOutputStream os = new DataOutputStream(new BufferedOutputStream(outputStream));
PrintWriter socketPrinter = new PrintWriter(os);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// socketPrinter.println("POST /transmitaudio?patient=1333369798370 HTTP/1.0");
socketPrinter.println("POST /transmitaudio?id="+id+" HTTP/1.0");
socketPrinter.println("Content-Type: audio/basic");
socketPrinter.println("Content-Length: 99999");
socketPrinter.println("Connection: Keep-Alive");
socketPrinter.println("Cache-Control: no-cache");
socketPrinter.println();
socketPrinter.flush();
// in.read();
mm.startAudioInput();
int buffersizebytes = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT); //4096 on ion
System.out.println("audio started");
byte[] data = new byte[buffersizebytes];
while(transmittingAudio)
// byte[] data = new byte[mm.available()];
int bytesRead = mm.read(data);
os.write(data,0,bytesRead);
os.flush();
// ca.transmitAxisAudioPacket(data);
// System.out.println("read "+data);
System.out.println("bytesRead "+bytesRead);
System.out.println("data "+Arrays.toString(data));
os.close();
mm.stopAudioInput();
catch (Exception e)
System.out.println("excpetion while transmitting audio connection will be closed"+e);
transmittingAudio=false;
else
try
Thread.sleep(1000);
catch (Exception e)
System.out.println("exception while thread sleeping"+e);
public void setTransmittingAudio(boolean transmittingAudio)
this.transmittingAudio = transmittingAudio;
public void finished()
this.transmittingAudio = false;
mm.finishAudioInput();
【问题讨论】:
您忘记了详细解释“出错”的部分 "我的 bytesread 控制台输出为 0" 基本上它似乎没有读取任何内容。每当我输出从流中读取的字节时,它们都是静态的(总是相同的值)。我不明白为什么 read 方法将返回值输入第一个参数并返回长度。因此,当我尝试提取数据时,我什么也得不到。mm.read(data)
将数据读入data
,然后mm.getBuffer()
将一些其他数据与其他缓冲区一起返回给您。 mm.read()
读取 0 也可能意味着录制没有开始(你在 start 函数中停止它并将数据读入某个缓冲区)。
好的,我现在明白了。最初我认为是因为 mm.read() 返回未设置数据的长度。那么为什么如果我做 System.out.println("read "+data);我一遍又一遍地得到 [B@4053c125。这是地址而不是值吗?以及 bytesread 在输出时为 0 的事实,似乎没有读取任何内容
data
是一个没有定义 toString
方法的对象。所以它会打印出对象 ID (getClass().getName() + '@' + Integer.toHexString(hashCode())
)。 Arrays.toString(data)
应该打印你的实际内容。
【参考方案1】:
你在打电话
mSamplesRead = audioRecord.read(buffer, 0, buffersizebytes);
这有一些问题。
audioRecord.read()
想要您正在读取的数组的长度,而不是字节大小。您已将编码设置为 16 位。你真的应该做这样的事情:
new short[] buffer = short[1024]; // or whatever length you like
mSampleRead = audioRecord.read(buffer,0,buffer.length);
您正在调用阅读buffersizebytes
,但您设置了buffer = new byte[1024];
。没有特别的理由认为buffersizebytes
是正确的数字吗?您想要一个具有 16 位编码的 short[]
数组,并且您希望读取的 SAMPLES(不是字节)数小于或等于该 short[] buffer
的长度。
另外,如果你打印出抛出异常时得到的异常,你的状态会更好,改变
System.out.println("Error Starting audio input");
到
System.out.println("Error Starting audio input" + t);
你至少会知道为什么 android 会把你扔进垃圾箱。
【讨论】:
为什么我想要一个短的[]?因为那时当我去流式传输这些字节时,我的 os.write 不喜欢 short[] 它想要一个 byte[] 数组。将更新上面的代码以反映您概述的其他更改。 audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,channelConfiguration,audioEncoding,buffersizebytes); // 这应该是 buffersizebytes 还是 buffer.length? 我没有检查过,但看起来你可以使用 byte[]。请记住, .read() 您放入 SAMPLES 进行读取,因此您需要 byte[] 数组是您请求的样本数量的 2 倍。对 AudioRecord() 构造函数的调用确实需要以字节为单位的缓冲区大小。因此,您希望它至少是您的读取时间的 2 倍,除非您不介意在读取请求被填充之前阻止每次读取。如果你试图在同一个线程中做其他事情,你应该避免阻塞,如果你把这个读取放在它自己的线程中,你可以阻塞。 阅读 AudioRecord 的文档。您可以在 read() 函数中有 byte[] 。 @mwengler 说的是非常真实的。 developer.android.com/reference/android/media/AudioRecord.html【参考方案2】:感谢你们的帮助,但是我找到了一种更好的方法来做需要的事情 (here)。这是代码。请注意,这也使用 http://www.devdaily.com/java/jwarehouse/android/core/java/android/speech/srec/UlawEncoderInputStream.java.shtml 将音频转换为 ulaw
public class AudioWorker extends Thread
private boolean stopped = false;
private String host;
private int port;
private long id=0;
boolean run=true;
AudioRecord recorder;
//ulaw encoder stuff
private final static String TAG = "UlawEncoderInputStream";
private final static int MAX_ULAW = 8192;
private final static int SCALE_BITS = 16;
private InputStream mIn;
private int mMax = 0;
private final byte[] mBuf = new byte[1024];
private int mBufCount = 0; // should be 0 or 1
private final byte[] mOneByte = new byte[1];
////
/**
* Give the thread high priority so that it's not canceled unexpectedly, and start it
*/
public AudioWorker(String host, int port, long id)
this.host = host;
this.port = port;
this.id = id;
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
// start();
@Override
public void run()
Log.i("AudioWorker", "Running AudioWorker Thread");
recorder = null;
AudioTrack track = null;
short[][] buffers = new short[256][160];
int ix = 0;
/*
* Initialize buffer to hold continuously recorded AudioWorker data, start recording, and start
* playback.
*/
try
int N = AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
recorder = new AudioRecord(AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10);
track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10, AudioTrack.MODE_STREAM);
recorder.startRecording();
track.play();
/*
* Loops until something outside of this thread stops it.
* Reads the data from the recorder and writes it to the AudioWorker track for playback.
*/
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory sslFact = sc.getSocketFactory();
SSLSocket socket = (SSLSocket)sslFact.createSocket(host, port);
socket.setSoTimeout(10000);
InputStream inputStream = socket.getInputStream();
DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream));
OutputStream outputStream = socket.getOutputStream();
DataOutputStream os = new DataOutputStream(new BufferedOutputStream(outputStream));
PrintWriter socketPrinter = new PrintWriter(os);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// socketPrinter.println("POST /transmitaudio?patient=1333369798370 HTTP/1.0");
socketPrinter.println("POST /transmitaudio?id="+id+" HTTP/1.0");
socketPrinter.println("Content-Type: AudioWorker/basic");
socketPrinter.println("Content-Length: 99999");
socketPrinter.println("Connection: Keep-Alive");
socketPrinter.println("Cache-Control: no-cache");
socketPrinter.println();
socketPrinter.flush();
while(!stopped)
Log.i("Map", "Writing new data to buffer");
short[] buffer = buffers[ix++ % buffers.length];
N = recorder.read(buffer,0,buffer.length);
track.write(buffer, 0, buffer.length);
byte[] bytes2 = new byte[buffer.length * 2];
ByteBuffer.wrap(bytes2).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer);
read(bytes2, 0, bytes2.length);
// os.write(bytes2,0,bytes2.length);
os.write(bytes2,0,bytes2.length);
System.out.println("bytesRead "+buffer.length);
System.out.println("data "+Arrays.toString(buffer));
os.close();
catch(Throwable x)
Log.w("AudioWorker", "Error reading voice AudioWorker", x);
/*
* Frees the thread's resources after the loop completes so that it can be run again
*/
finally
recorder.stop();
recorder.release();
track.stop();
track.release();
/**
* Called from outside of the thread in order to stop the recording/playback loop
*/
/**
* Called from outside of the thread in order to stop the recording/playback loop
*/
public void close()
stopped = true;
public void resumeThread()
stopped = false;
run();
TrustManager[] trustAllCerts = new TrustManager[]
new X509TrustManager()
public java.security.cert.X509Certificate[] getAcceptedIssuers()
return null;
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain, String authType)
for (int j=0; j<chain.length; j++)
System.out.println("Client certificate information:");
System.out.println(" Subject DN: " + chain[j].getSubjectDN());
System.out.println(" Issuer DN: " + chain[j].getIssuerDN());
System.out.println(" Serial number: " + chain[j].getSerialNumber());
System.out.println("");
;
public static void encode(byte[] pcmBuf, int pcmOffset,
byte[] ulawBuf, int ulawOffset, int length, int max)
// from 'ulaw' in wikipedia
// +8191 to +8159 0x80
// +8158 to +4063 in 16 intervals of 256 0x80 + interval number
// +4062 to +2015 in 16 intervals of 128 0x90 + interval number
// +2014 to +991 in 16 intervals of 64 0xA0 + interval number
// +990 to +479 in 16 intervals of 32 0xB0 + interval number
// +478 to +223 in 16 intervals of 16 0xC0 + interval number
// +222 to +95 in 16 intervals of 8 0xD0 + interval number
// +94 to +31 in 16 intervals of 4 0xE0 + interval number
// +30 to +1 in 15 intervals of 2 0xF0 + interval number
// 0 0xFF
// -1 0x7F
// -31 to -2 in 15 intervals of 2 0x70 + interval number
// -95 to -32 in 16 intervals of 4 0x60 + interval number
// -223 to -96 in 16 intervals of 8 0x50 + interval number
// -479 to -224 in 16 intervals of 16 0x40 + interval number
// -991 to -480 in 16 intervals of 32 0x30 + interval number
// -2015 to -992 in 16 intervals of 64 0x20 + interval number
// -4063 to -2016 in 16 intervals of 128 0x10 + interval number
// -8159 to -4064 in 16 intervals of 256 0x00 + interval number
// -8192 to -8160 0x00
// set scale factors
if (max <= 0) max = MAX_ULAW;
int coef = MAX_ULAW * (1 << SCALE_BITS) / max;
for (int i = 0; i < length; i++)
int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8);
pcm = (pcm * coef) >> SCALE_BITS;
int ulaw;
if (pcm >= 0)
ulaw = pcm <= 0 ? 0xff :
pcm <= 30 ? 0xf0 + (( 30 - pcm) >> 1) :
pcm <= 94 ? 0xe0 + (( 94 - pcm) >> 2) :
pcm <= 222 ? 0xd0 + (( 222 - pcm) >> 3) :
pcm <= 478 ? 0xc0 + (( 478 - pcm) >> 4) :
pcm <= 990 ? 0xb0 + (( 990 - pcm) >> 5) :
pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) :
pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) :
pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) :
0x80;
else
ulaw = -1 <= pcm ? 0x7f :
-31 <= pcm ? 0x70 + ((pcm - -31) >> 1) :
-95 <= pcm ? 0x60 + ((pcm - -95) >> 2) :
-223 <= pcm ? 0x50 + ((pcm - -223) >> 3) :
-479 <= pcm ? 0x40 + ((pcm - -479) >> 4) :
-991 <= pcm ? 0x30 + ((pcm - -991) >> 5) :
-2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) :
-4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) :
-8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) :
0x00;
ulawBuf[ulawOffset++] = (byte)ulaw;
public static int maxAbsPcm(byte[] pcmBuf, int offset, int length)
int max = 0;
for (int i = 0; i < length; i++)
int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8);
if (pcm < 0) pcm = -pcm;
if (pcm > max) max = pcm;
return max;
public int read(byte[] buf, int offset, int length) throws IOException
if (recorder == null) throw new IllegalStateException("not open");
// return at least one byte, but try to fill 'length'
while (mBufCount < 2)
int n = recorder.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount));
if (n == -1) return -1;
mBufCount += n;
// compand data
int n = Math.min(mBufCount / 2, length);
encode(mBuf, 0, buf, offset, n, mMax);
// move data to bottom of mBuf
mBufCount -= n * 2;
for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2];
return n;
【讨论】:
流式传输时仍有一些暂停,因此可能存在一些阻塞,需要对其进行调整 谢天谢地,我以某种方式打破了这个,这个帖子是我唯一的备份。不会再犯这个错误以上是关于音频数据有问题的主要内容,如果未能解决你的问题,请参考以下文章