Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ Versions after 2.17 are `MAJOR.MINOR.PATCH` (2.17 is followed by 2.17.1 or 2.18.
`docs/testing.md`, "Versions and releases"); the headings below keep the numbers as they
were released.

## 2.18.4 — 2026-10-22

- `udp://` slots and the U cell: the receive thread runs at the audio priority, so a push no
longer loses datagrams in a loaded 3×3 grid; before, key-frame bursts still overflowed the
socket buffer while the thread waited for the CPU (#253).

## 2.18.3 — 2026-10-21

- `udp://` slots and the U cell: a thread of its own reads the socket into a ring of 1024
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ android {
applicationId "com.openipc.decoder"
minSdk 21
targetSdk 36
versionCode 46
versionName "2.18.3"
versionCode 47
versionName "2.18.4"

buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
}
Expand Down
15 changes: 13 additions & 2 deletions android/app/src/main/java/com/openipc/decoder/RtpListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Process;
import android.util.Log;

import java.io.BufferedReader;
Expand All @@ -35,7 +36,9 @@
* <p>
* An app cannot get a socket buffer above {@code rmem_max} (256 KiB on many boxes), which is
* about one 1080p key frame, so a thread of its own does nothing but read the socket into a
* ring; reordering, assembly and the decoder never hold up the receive (#251).
* ring; reordering, assembly and the decoder never hold up the receive (#251). It runs at the
* audio priority: in a loaded grid a thread at the display priority still waited long enough for
* a key-frame burst to fill the socket buffer (#253).
*/
class RtpListener implements Closeable {
private static final String TAG = "OpenIPCDecoder";
Expand Down Expand Up @@ -237,6 +240,13 @@ boolean h265(int pt) {
* four bytes, copied from one large buffer: datagrams are short, slots stay small.
*/
private void readLoop() {
// Nice -19, above the decoder and the UI (Thread.MAX_PRIORITY is only -8): a stalled
// receive is a lost datagram (#253)
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
} catch (RuntimeException e) {
Log.w(TAG, tag + ": UDP receive thread keeps its priority: " + e.getMessage());
}
byte[] buf = new byte[65536];
DatagramPacket p = new DatagramPacket(buf, buf.length);
InetAddress source = url.source;
Expand Down Expand Up @@ -283,7 +293,8 @@ void run(UdpReceiver.Condition keepGoing, Handler handler) throws IOException {
RtpReorder.Sink sink = handler::onPacket;
Thread reader = new Thread(this::readLoop, tag + "-udp");
reader.setDaemon(true);
// Above the decoder and the UI: a stalled receive is a lost packet
Comment thread
compot-dev marked this conversation as resolved.
// Nice -8 before the thread starts; readLoop() raises it to -19 and keeps this when the
// system refuses (Qodo on #254)
reader.setPriority(Thread.MAX_PRIORITY);
reader.start();
try {
Expand Down
Loading