作为一个爱好项目,我正在写一个android voip客户端。在将语音数据写入套接字(Vars.mediaSocket)时,很多时候,数据不会立即通过wifi发送,而只是停顿,然后立即发送它将发送20秒的语音。然后它会再次失速并等待30秒然后发送30秒的声音。等待不一致,但一段时间后它会立即连续发送语音数据。我已经尝试了从使用DataOutputStream到设置套接字输出缓冲区大小,将sendbuffer大小设置为大,小,最后将语音数据从其32字节块缓冲到128bytes到32kb的所有内容。
self
有什么我想念的吗?为了模拟第二部手机,我有另一个客户端,它只是简单地读取语音数据,将其丢弃,然后再循环读取。我可以在模拟的第二部手机中确认当真正的手机停止发送语音时,模拟的一个socket.read挂起,直到真人再次开始发送声音。
我真的希望不必为套接字编写jni,因为我对此一无所知,并且希望我可以将应用程序编写为标准的Java应用程序。
CASE CLOSED :原来是服务器方面的错误,但简化回归基础建议仍然是一个好主意。
答案 0 :(得分:1)
通过在编写任何数据之前读取大量数据,您自己会添加大部分延迟。您应该只使用标准的Java拷贝循环:
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
您需要对此进行调整以合并您的编解码器步骤。请注意,您不需要整个输入大小的缓冲区。您可以调整其大小以适合自己,但8192是一个很好的起点。你可以把它增加到32k,但不要减少它。如果您的编解码器需要固定大小的数据块,请使用该大小的缓冲区DataInputStream.readFully()
。但缓冲区越大,延迟就越多。
编辑您的代码的具体问题:
byte[] amrbuffer = new byte[AMRBUFFERSIZE];
byte[] outputbuffer = new byte [outputBufferSize];
删除(见下文)。
short[] wavbuffer = new short[WAVBUFFERSIZE];
int outputCounter = 0;
删除outputCounter
。
//setup the wave audio recorder. since it is released and restarted, it needs to be setup here and not onCreate
wavRecorder = null; //remove pointer to the old recorder for safety
毫无意义的。删除。
wavRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLESWAV, AudioFormat.CHANNEL_IN_MONO, FORMAT, WAVBUFFERSIZE);
wavRecorder.startRecording();
AmrEncoder.init(0);
行。
try
{
Vars.mediaSocket.setSendBufferSize(outputBufferSize);
}
catch (SocketException e)
{
e.printStackTrace();
}
毫无意义的。去掉。套接字发送缓冲区应尽可能大。除非你知道它的默认大小是< outputBufferSize
这对此没有任何好处。无论如何,我们完全摆脱outputBuffer
。
while(!micMute)
{
int totalRead = 0, dataRead;
while(totalRead < WAVBUFFERSIZE)
{//although unlikely to be necessary, buffer the mic input
dataRead = wavRecorder.read(wavbuffer, totalRead, WAVBUFFERSIZE - totalRead);
totalRead = totalRead + dataRead;
}
int encodeLength = AmrEncoder.encode(AmrEncoder.Mode.MR122.ordinal(), wavbuffer, amrbuffer);
行。
if(outputCounter == outputBufferSize)
{
Utils.logcat(Const.LOGD, encTag, "Sending output buffer");
try
{
Vars.mediaSocket.getOutputStream().write(outputbuffer);
Vars.mediaSocket.getOutputStream().flush();
}
catch (IOException i)
{
Utils.logcat(Const.LOGE, encTag, "Cannot send amr out the media socket");
Utils.dumpException(tag, i);
}
outputCounter = 0;
}
System.arraycopy(amrbuffer, 0, outputbuffer, outputCounter, encodeLength);
outputCounter = outputCounter + encodeLength;
Utils.logcat(Const.LOGD, encTag, "Output buffer fill: " + outputCounter);
删除以上所有内容并替换
Vars.mediaSocket.getOutputStream().write(amrbuffer, 0, encodeLength);
这也意味着你可以按照承诺摆脱'outputBuffer'。
注意不要冲洗内部循环。事实上,刷新套接字输出流什么都不做,但一般原则仍然存在。