强制Java Android Socket立即发送数据

时间:2016-06-23 03:41:56

标签: java android sockets

作为一个爱好项目,我正在写一个android voip客户端。在将语音数据写入套接字(Vars.mediaSocket)时,很多时候,数据不会立即通过wifi发送,而只是停顿,然后立即发送它将发送20秒的语音。然后它会再次失速并等待30秒然后发送30秒的声音。等待不一致,但一段时间后它会立即连续发送语音数据。我已经尝试了从使用DataOutputStream到设置套接字输出缓冲区大小,将sendbuffer大小设置为大,小,最后将语音数据从其32字节块缓冲到128bytes到32kb的所有内容。

self

有什么我想念的吗?为了模拟第二部手机,我有另一个客户端,它只是简单地读取语音数据,将其丢弃,然后再循环读取。我可以在模拟的第二部手机中确认当真正的手机停止发送语音时,模拟的一个socket.read挂起,直到真人再次开始发送声音。

我真的希望不必为套接字编写jni,因为我对此一无所知,并且希望我可以将应用程序编写为标准的Java应用程序。

CASE CLOSED :原来是服务器方面的错误,但简化回归基础建议仍然是一个好主意。

1 个答案:

答案 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'。

注意不要冲洗内部循环。事实上,刷新套接字输出流什么都不做,但一般原则仍然存在。