Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/180.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
强制Java Android套接字立即发送数据_Java_Android_Sockets - Fatal编程技术网

强制Java Android套接字立即发送数据

强制Java Android套接字立即发送数据,java,android,sockets,Java,Android,Sockets,作为一个爱好项目,我正在编写一个android voip客户端。在将语音数据写入套接字(Vars.mediaSocket)时,很多时候,数据不会立即通过wifi发送出去,而是会暂停,然后一次发送20秒的语音。然后它将再次暂停并等待30秒,然后发送30秒的语音。等待不一致,但一段时间后,它将立即连续发送语音数据。我尝试了各种方法,从使用DataOutputStream到设置套接字输出缓冲区大小,将sendbuffer大小设置为大、小,最后,将语音数据从32字节块缓冲到128字节到32kb

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

        Utils.logcat(Const.LOGD, encTag, "MediaCodec encoder thread has started");
        isEncoding = true;
        byte[] amrbuffer = new byte[32];
        short[] wavbuffer = new short[160];
        int outputCounter = 0;

        //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, 160);
        wavRecorder.startRecording();
        AmrEncoder.init(0);

        while(!micMute)
        {
            int totalRead = 0, dataRead;
            while(totalRead < 160)
            {//although unlikely to be necessary, buffer the mic input
                dataRead = wavRecorder.read(wavbuffer, totalRead, 160 - totalRead);
                totalRead = totalRead + dataRead;
            }
            int encodeLength = AmrEncoder.encode(AmrEncoder.Mode.MR122.ordinal(), wavbuffer, amrbuffer);

            try
            {
                Vars.mediaSocket.getOutputStream().write(amrbuffer);
                Vars.mediaSocket.getOutputStream().flush();
            }
            catch (IOException i)
            {
                Utils.logcat(Const.LOGE, encTag, "Cannot send amr out the media socket");
                Utils.dumpException(tag, i);
            }
Utils.logcat(Const.LOGD,encTag,“MediaCodec编码器线程已启动”);
isEncoding=真;
字节[]amrbuffer=新字节[32];
short[]wavbuffer=新的short[160];
int outputCounter=0;
//设置波形音频记录器。由于它已被释放并重新启动,因此需要在此处进行设置,而不是一次创建
wavRecorder=null//为安全起见,请将指针移到旧记录器上
wavRecorder=新的音频记录(MediaRecorder.AudioSource.MIC,SAMPLESWAV,AudioFormat.CHANNEL,单声道,格式,160);
wavRecorder.startRecording();
AmrEncoder.init(0);
而(!micMute)
{
int TOTALLEAD=0,数据读取;
而(总读数<160)
{//虽然不太必要,但缓冲麦克风输入
dataRead=wavRecorder.read(wavbuffer,totalRead,160-totalRead);
totalRead=totalRead+dataRead;
}
int encodeLength=AmrEncoder.encode(AmrEncoder.Mode.MR122.ordinal(),wavbuffer,amrbuffer);
尝试
{
Vars.mediaSocket.getOutputStream().write(amrbuffer);
Vars.mediaSocket.getOutputStream().flush();
}
捕获(IOI异常)
{
Utils.logcat(Const.LOGE,encTag,“无法将amr发送到媒体套接字”);
Utils.dumpException(标记,i);
}
有什么我遗漏的吗?为了模拟第二部手机,我有另一个客户端,它只是简单地读取语音数据,扔掉它,然后在循环中再次读取。我可以在模拟的第二部手机中确认,当真实的手机停止发送语音时,模拟手机的socket.read将挂起,直到真实的手机再次开始发送语音在

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


案例结束:这是一个服务器端错误,但简化回到基础的建议仍然是一个好主意。

您在写入任何数据之前读取大量数据,从而增加了大部分延迟。您应该只使用标准Java copy循环:

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];
移除(见下文)

删除
输出计数器

        //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);

无意义。删除。套接字发送缓冲区应尽可能大。除非您知道其默认大小为<
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);
拆下所有上述部件并更换

        Vars.mediaSocket.getOutputStream().write(amrbuffer, 0, encodeLength);
这也意味着您可以像承诺的那样去掉“outputBuffer”


注意:不要刷新内部循环。事实上,刷新套接字输出流没有任何作用,但一般原则仍然适用。

我在直接执行out.write(缓冲区)之后添加了“写入前读取大量数据”。这是我第一次尝试,但仍然存在这个问题。编解码器输出32字节的块。如果它与我上面所写的内容不一致,那就太复杂了。缓冲区越大,在写任何东西之前尝试填充的次数越多,延迟就越大。这当然是显而易见的吗?非常感谢您的评论。真的吗ng超出了职责范围:)。我不确定您是否看到了我的编辑,但我将代码改回了原始实现,我认为它没有您不喜欢的不必要的内容。原始实现仍然存在问题。经过进一步调试,我的服务器端代码中出现了问题,但因为o在做设备端时涉及了很多尝试和错误,我认为这是一个设备问题,看起来确实如此。我仍然在做你的简化建议:-)不要在循环内部刷新。如果没有缓冲,它是毫无意义的(如本例中),如果有缓冲,它会破坏它。
        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);