DecodeState
Mutable per-device decode state carried across packets (sample cursor and battery level).
One instance per stream; the decoder advances lastSample as it emits samples (including gap-fill dummies) and reads batteryPct for each frame.
Constructors
Properties
When true, the next packet sets lastSample to its own first sample index before decoding, so it is never gap-filled against an earlier position; the decoder then clears the flag. A stream starts this way: firmware 3.7.0 restarts the device counter at 0 on every STREAM_START, older firmware kept it running across STOP/START, and an anchored first packet is right for both. The cost: a loss inside the very first packet is not detectable.
Last known battery percentage; -1 until the first battery notification.
Normal-mode packets the cursor could not follow: one only partly behind lastSample (its samples are appended at the running cursor), a jump further than the decoder fills (PacketCodec.MAX_FILLED_GAP_SECONDS; the cursor then resyncs to the wire without dummies), and a counter that moved back and stayed there (the cursor resyncs to it; see stalePackets). Each is a gap lastSample cannot account for, so it is counted here instead of in the dummy stream.
Index of the next sample expected from the device. The device counter is an unsigned 32-bit number: past 2^31 this Int holds its bits (read it with toLong() and 0xFFFFFFFFL), and the decoder compares it modulo 2^32.
Normal-mode packets skipped because every sample number in them was already emitted or gap-filled (for example a duplicate). They decode to nothing and leave lastSample alone.