title: Android UDP receive drops packets intermittently
body: <p>I have a Nexus 5X that is having intermittent receive problems. I have been able to run the code on an Asus tablet, two Samsung tablets, and a Kindle Fire with no issues. The code is based on this repository:
  <a href="https://github.com/moonlight-stream/moonlight-common/blob/master/src/com/limelight/nvstream/av/video/VideoStream.java" rel="nofollow noreferrer">https://github.com/moonlight-stream/moonlight-common/blob/master/src/com/limelight/nvstream/av/video/VideoStream.java</a></p>
  
  <p>Here is the pertinent code:</p>
  
  <pre><code>WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
  wifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Player");
  wifiLock.setReferenceCounted(false);
  wifiLock.acquire();
  
  rtp = new DatagramSocket(RTP_PORT);
  rtp.setReceiveBufferSize(256*1024);
  
  // Receive thread
  Thread t = new Thread() {
  @Override
  public void run() {
      while (!isInterrupted())
      {
          try {
              // Pull the next buffer in the ring and reset it
              buffer = ring[ringIndex].getBuffer();
  
              // Read the video data off the network
              packet.setData(buffer, 0, buffer.length);
              rtp.receive(packet);
  
              // Do processing here
          } catch (IOException e) {
              return;
          }
      }
  }
  };
  threads.add(t);
  t.setName("Video - Receive");
  t.setPriority(Thread.MAX_PRIORITY - 1);
  t.start();
  </code></pre>
  
  <p>I am as sure as I can be that the UDP stream is properly being sent to the device. Most of the packets are received correctly. However, I've noticed in a method trace that the </p>
  
  <pre><code>rtp.receive(packet);
  </code></pre>
  
  <p>can block for 100s-1000s of milliseconds. When running on a different device in the exact same architecture, I see essentially 100% packet success and a maximum block of maybe 60ms.</p>
  
  <p>I have tried this on 2.4G, and 5G, on multiple routers. The problem follows the device.</p>
  
  <p>The packets being sent are UDP directly to the device. There are no IP conflicts on the network.</p>
  
  <p>Any thoughts on what might be going wrong? Thank you very much!</p>
  
  <p>EDIT: I should note the CPU usage is around 2%, and the memory usage is around 10MB</p>
  
  <p>EDIT 2: I created a bare application to simply investigate this issue. I see the same results. I'll see 30,000+ consecutive packets on several devices without a single drop. I'll drop a range of packets every couple seconds on a Nexus 5X. I've had someone remotely run this test application on their Nexus 5X, and they reported that no packets were dropped. All signs are pointing to a driver / radio issue as far as I know...</p>
  
  <pre><code>package com.udp_receiver_test;
  
  import android.content.Context;
  import android.net.wifi.WifiManager;
  import android.os.Build;
  import android.support.v7.app.AppCompatActivity;
  import android.os.Bundle;
  import android.util.Log;
  
  import java.net.DatagramPacket;
  import java.net.DatagramSocket;
  import java.nio.ByteBuffer;
  
  public class MainActivity extends AppCompatActivity {
  
      private WifiManager.WifiLock wifiLock;
      Thread t;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
  
          WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
          wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Player");
          wifiLock.setReferenceCounted(false);
          wifiLock.acquire();
  
          // Use sustained performance mode on N+ to ensure consistent
          // CPU availability
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.N) {
              getWindow().setSustainedPerformanceMode(true);
          }
  
  
          startListenThread();
      }
  
      private void startListenThread()
      {
          t = new Thread() {
              @Override
              public void run()
              {
                  DatagramSocket socket;
  
                  int nextSequenceNumber = 0;
  
                  ByteBuffer byteBuffer;
  
                  int BufferSize = 1292;
                  int NumRingElements = 784;
                  long correctPacketCounter = 0;
  
                  byte ring[][] = new byte[NumRingElements][1292];
  
                  try {
                      socket = new DatagramSocket(12345);
                      socket.setReceiveBufferSize(256 * 1024);
                  } catch (Exception e) {
                      e.printStackTrace();
                      return;
                  }
  
                  byte[] buffer;
                  int ringCounter = 0;
                  DatagramPacket packet = new DatagramPacket(new byte[1], 1);
                  //short rtpSequenceNumber;
                  int sequenceNumber;
  
                  while (!isInterrupted()) {
                      try {
                          buffer = ring[ringCounter];
  
                          packet.setData(buffer, 0, buffer.length);
                          socket.receive(packet);
  
                          if (packet.getLength() &gt; 20) {
  
                              // Read the RTP sequence number field (big endian)
                              byteBuffer = ByteBuffer.wrap(buffer);
                              byteBuffer.position(16);
                              sequenceNumber = (byteBuffer.getInt() &gt;&gt; 8) &amp; 0xFFFFFF;
  
                              if (sequenceNumber != nextSequenceNumber) {
                                  Log.d("TAG", "Not next sequence number - Got:" + sequenceNumber + " Expected:" + nextSequenceNumber);
                              } else {
  
                                  if (((++correctPacketCounter) % 100) == 0)
                                  {
                                      Log.d("TAG", "Correct packets = " + correctPacketCounter);
                                  }
  
                              }
  
                              nextSequenceNumber = (sequenceNumber + 256) % 65535;
                          } else {
                              Log.d("TAG", "Message too short");
                          }
  
                          ringCounter = (ringCounter + 1) % NumRingElements;
                      } catch (Exception e) {
                          e.printStackTrace();
                          return;
                      }
                  }
              }
          };
          t.setName("Receiver");
          t.setPriority(Thread.MAX_PRIORITY - 1);
          t.start();
      }
  
      @Override
      public void onStop()
      {
          super.onStop();
          wifiLock.release();
          if (t.isAlive()) {
              t.interrupt();
          }
      }
  }
  </code></pre>