Commit Graph

1721 Commits

Author SHA1 Message Date
Chris Spencer
05ca59ed48 [client] audio/pw: increase startup latency
PipeWire startup latency varies wildly depending on what else is, or was
last using the audio device. In the worst case, PipeWire can request two
full buffers within a very short period of time immediately at the start of
playback, so make sure we've got enough data in the buffer to support this.
2022-02-04 16:27:12 +11:00
Chris Spencer
e1e60fdaa6 [client] audio: tune target latency
The target latency is now based upon the device maximum period size
(which may be configured by setting the `PIPEWIRE_LATENCY` environment
variable if using PipeWire), with some allowance for timing jitter from
Spice and the audio device.

PipeWire can change the period size dynamically at any time which must be
taken into account when selecting the target latency to avoid underruns
when the period size is increased. This is explained in detail within the
commit body.
2022-02-04 16:27:12 +11:00
Chris Spencer
ca29fe80a6 Revert "[client] audio: tune the target latency based on the latency jitter"
This reverts commit febd081202.

This causes severe underruns when the quantum size increases.
2022-02-04 16:27:12 +11:00
Geoffrey McRae
febd081202 [client] audio: tune the target latency based on the latency jitter 2022-01-28 12:11:56 +11:00
Geoffrey McRae
5bbc1d44bf [client] audio/pw: get the period size to determine when to start audio
Previously this was hardcoded to 100ms which is far too high in most
instances, instead we get the initial period size and use whichever is
greater out of 50ms or the period size.

The idea is to reduce the amount of time it takes for the latency to
come down after initial stream start.
2022-01-28 12:08:58 +11:00
Geoffrey McRae
22b968ff53 [client] audio: change the audio latency graph sample point
This removes the need for locking while also giving a better result in
the graph output. Also when the graph is disabled via the overlay
options it will no longer cause redraws.
2022-01-28 10:59:12 +11:00
Geoffrey McRae
a0477466d2 Revert "[client] audio: allow the audiodev to return the periodFrames"
This reverts commit 41884bfcc5.

PipeWire can change it's period size on the fly on us making this
approach invalid.
2022-01-28 10:00:35 +11:00
Geoffrey McRae
c2a766c2ee [client] audio: fix setfault due to failure to properly reset 2022-01-27 19:20:16 +11:00
Geoffrey McRae
a560a610d9 [client] audio: allow building without any audio support 2022-01-27 18:03:11 +11:00
Geoffrey McRae
a7db3d3a0f [client] audio: check for malloc failure 2022-01-27 18:03:11 +11:00
Geoffrey McRae
016001da67 [client] audio: cosmetics 2022-01-27 18:03:11 +11:00
Geoffrey McRae
41884bfcc5 [client] audio: allow the audiodev to return the periodFrames
This change allows the audiodevs to return the minimum period frames
needed to start playback instead of having to rely on a pull to obtain
these details.

Additionally we are using this information to select an initial start
latency as well as to train the desired latency in order to keep it as
low as possible.
2022-01-27 18:03:11 +11:00
Chris Spencer
dd2d84a080 [client] audio: adjust playback speed to match audio device clock
This change is based on the techniques described in [1] and [2].

The input audio stream from Spice is not synchronised to the audio playback
device. While the input and output may be both nominally running at 48 kHz,
when compared against each other, they will differ by a tiny fraction of a
percent. Given enough time (typically on the order of a few hours), this
will result in the ring buffer becoming completely full or completely
empty. It will stay in this state permanently, periodically resulting in
glitches as the buffer repeatedly underruns or overruns.

To address this, adjust the speed of the received data to match the rate at
which it is being consumed by the audio device. This will result in a
slight pitch shift, but the changes should be small and smooth enough that
this is unnoticeable to the user.

The process works roughly as follows:
1. Every time audio data is received from Spice, or consumed by the audio
   device, sample the current time. These are fed into a pair of delay
   locked loops to produce smoothed approximations of the two clocks.
2. Compute the difference between the two clocks and compare this against
   the target latency to produce an error value. This error value will be
   quite stable during normal operation, but can change quite rapidly due
   to external factors, particularly at the start of playback. To smooth
   out any sudden changes in playback speed, which would be noticeable to
   the user, this value is also filtered through another delay locked loop.
3. Feed this error value into a PI controller to produce a ratio value.
   This is the target playback speed in order to bring the error value
   towards zero.
4. Resample the input audio using the computed ratio to apply the speed
   change. The output of the resampler is what is ultimately inserted into
   the ring buffer for consumption by the audio device.

Since this process targets a specific latency value, rather than simply
trying to rate match the input and output, it also has the effect of
'correcting' latency issues. If a high latency application (such as a media
player) is already running, the time between requesting the start of
playback and the audio device actually starting to consume samples can be
very high, easily in the hundreds of milliseconds. The changes here will
automatically adjust the playback speed over the course of a few minutes to
bring the latency back down to the target value.

[1] https://kokkinizita.linuxaudio.org/papers/adapt-resamp.pdf
[2] https://kokkinizita.linuxaudio.org/papers/usingdll.pdf
2022-01-27 18:03:11 +11:00
Chris Spencer
599fdd6ffd [common] ringbuffer: add unbounded mode
In unbounded mode, the read and write pointers are free to move
independently of one another. This is useful where the input and output
streams are progressing at the same rate on average, and we want to keep
the latency stable in the event than an underrun or overrun occurs.

If an underrun occurs (i.e., there is not enough data in the buffer to
satisfy a read request), the missing values with be filled with zeros. When
the writer catches up, the same number of values will be skipped from the
input.

If an overrun occurs (i.e., there is not enough free space in the buffer to
satisfy a write request), excess values will be discarded. When the reader
catches up, the same number of values will be zeroed in the output.

Unbounded mode is currently unused since our audio input and output
streams are not synchronised. This will be implemented in a later commit.

Also reimplemented as a lock-free queue which is safer for use in audio
device callbacks.
2022-01-27 18:03:11 +11:00
Chris Spencer
b34b253814 [client] audio: stop playback immediately if new playback is started
If a new playback is started while the previous playback is still flushing,
we simply allow the stream to continue playing and effectively cancel the
flush. In general this is not safe because there may not be enough data in
the buffer to avoid underrunning. We could handle this better later by
trying to insert the right number of silent samples into the buffer, but
for now just completely stop the previous stream before starting the new
one.
2022-01-27 18:03:11 +11:00
Chris Spencer
68b42e1c1a [client] audio/pw: drop restarting state
Automatically restarting playback once draining has completed could result
in playback starting too early (i.e., before there is enough data in the
ring buffer to avoid underrunning). `audio_playbackData` will keep invoking
`start` until it returns true anyway, so we can just allow draining to
complete normally and wait for `start` to be called again.
2022-01-27 18:03:11 +11:00
Chris Spencer
8580978321 [client] audio/pw: drop redundant flushing state
We do not stop the audio device until after the internal buffer has already
been flushed, so this state does nothing useful.
2022-01-27 18:03:11 +11:00
Geoffrey McRae
b0568ca404 [client] egl: use a sigmoid curve for nv 2022-01-26 23:03:35 +11:00
Geoffrey McRae
3c9b9e6370 [client] main: fix heap-buffer-overflow on cursor update 2022-01-26 20:05:51 +11:00
Geoffrey McRae
efa49391fc [client] fix race segfault on pointer queue unsubscribe/timeout 2022-01-26 17:20:12 +11:00
Geoffrey McRae
fb4bdaee2b [client] egl: set the active preset if specified at launch 2022-01-26 16:07:17 +11:00
Geoffrey McRae
c7389285f9 [client] egl: fix null pointer access when no preset is set 2022-01-26 16:04:15 +11:00
Geoffrey McRae
aa426d13a7 [client] egl: added egl:preset to load a default preset at startup 2022-01-26 16:00:07 +11:00
Geoffrey McRae
89c83dafc1 [client] egl: make egl less noisy unless debug is specified 2022-01-26 15:42:33 +11:00
Geoffrey McRae
05e363e009 [client] x11: cleanup duplicated code 2022-01-26 15:30:38 +11:00
Geoffrey McRae
e17b289759 [client] x11: sync the mouse on meta resize 2022-01-26 14:55:30 +11:00
Geoffrey McRae
79e986cc60 [client] x11: fix failure to unfocus when performing meta resize/move 2022-01-26 14:43:11 +11:00
Geoffrey McRae
22f3cf5ba6 [client] egl: fix masked color cursor blend operation for xor drawing 2022-01-26 12:23:05 +11:00
Geoffrey McRae
3067bdaa15 [client] egl: properly apply xor mask to masked color cursors 2022-01-26 12:11:43 +11:00
Quantum
11800029f0 [client] core: redraw cursor after warping guest cursor 2022-01-24 17:07:15 +11:00
Quantum
71901414d1 [client] overlay: realign cursor when turning off overlay
This is only done in non-capture mode to avoid messing up games.
2022-01-24 17:07:15 +11:00
Geoffrey McRae
96fa8891c8 [client] egl: fixed incorrect drawing of masked color cursors 2022-01-24 06:56:32 +11:00
Geoffrey McRae
1082875b8e [client] opengl: fix startup since ImGui upgrade 2022-01-24 06:42:16 +11:00
Geoffrey McRae
dc918c55b6 [client] main: only copy the needed cursor data instead of everything 2022-01-24 06:36:15 +11:00
Geoffrey McRae
a8ba014b52 [client] main: lgmpClientMessageDone is not idempotent 2022-01-24 04:10:49 +11:00
Quantum
9a6aa3ce66 [client] egl: remove duplicate #include "app.h" 2022-01-23 08:49:15 +11:00
Quantum
f2fbb2b27c [client] opengl: make draw functions static 2022-01-23 08:49:01 +11:00
Geoffrey McRae
9601bc677f [client] audio: report the buffered frames and not the buffer length 2022-01-22 16:06:16 +11:00
Geoffrey McRae
c84879717f [client] audio: fix failure to properly handle restart if draining 2022-01-20 07:02:00 +11:00
Geoffrey McRae
b3c81bcedf [client] audio: fix use after free race 2022-01-19 18:50:39 +11:00
Geoffrey McRae
15f76339c8 [client] audio: move the memory copy into the pull function 2022-01-19 10:29:49 +11:00
Geoffrey McRae
04ae9217e8 [client] audio: allow the audiodev to determine the start fill level 2022-01-19 01:52:19 +11:00
Geoffrey McRae
46da447429 [client] audio: fix latency calculation 2022-01-19 00:58:48 +11:00
Geoffrey McRae
4b080f7610 [client] audio: don't lock when consuming frames from the buffer 2022-01-19 00:25:52 +11:00
Geoffrey McRae
d6bbc4f89c [client] audio/pw: return the actual playback latency 2022-01-19 00:03:16 +11:00
Geoffrey McRae
4fadf3a130 [client] audio: tell the audiodev to stop on the last packet, not after 2022-01-18 23:43:12 +11:00
Geoffrey McRae
73dc08e5f9 [client] audio: remove duplicated line 2022-01-18 23:42:02 +11:00
Geoffrey McRae
07c92ec2e8 [client] audio: drain buffers on stop instead of just discarding them 2022-01-18 23:39:05 +11:00
Geoffrey McRae
b334f22223 [client] audio: rework audiodevs to be pull model from a common buffer 2022-01-18 09:02:44 +11:00
Geoffrey McRae
aad65c1cab [client] graphs: overlay on removal of graph 2022-01-17 22:53:52 +11:00
Geoffrey McRae
0ad26b7da7 [client] audio: redraw the graphs if they have been updated 2022-01-17 22:49:19 +11:00
Geoffrey McRae
775ac7ce8b [client] audio: reduce timing graph sample count to 30 seconds 2022-01-17 22:23:37 +11:00
Geoffrey McRae
689cc53255 [client] audio: add audio playback latency interface and graph 2022-01-17 22:13:41 +11:00
Geoffrey McRae
5629655f74 [client] audio/pw: fix memory leak and gracefully shutdown 2022-01-17 22:10:41 +11:00
Geoffrey McRae
54e7542414 [client] overlay/graph: actually remove unregistered overlays
ll now supports removal of elements, so actually do it
2022-01-17 22:09:41 +11:00
Geoffrey McRae
464fee3e20 [client] overlay/graphs: allow the graph to have a custom title format 2022-01-17 22:08:56 +11:00
Geoffrey McRae
42ed0d7638 [client] app: allow key-repeat to work with keybinds 2022-01-17 20:33:57 +11:00
Geoffrey McRae
5a3fe151e4 [client] main: don't use Linux keybinds if the guest is not Linux 2022-01-17 20:26:45 +11:00
Jonathan Rubenstein
745169fae2 [client] Add capture mode support for media keys
Supports Play/Pause, Stop, Next, and Previous
2022-01-17 15:09:36 +11:00
Jonathan Rubenstein
7f79352320 [client] Add support for volume keys in capture mode
These include Volume Up, Volume Down, and Mute

Co-authored-by: Quantum <quantum2048@gmail.com>
2022-01-17 15:09:36 +11:00
Quantum
b020372972 [client] imgui: allow arrows to be displayed 2022-01-17 15:09:03 +11:00
Quantum
5fe529f213 [client] spice: allow volume control keys to be sent to the guest
These are implemented as ScrollLock+Up/Down for volume up and down, and
ScrollLock+M to toggle audio mute. These should prove useful especially
when Looking Glass now supports streaming audio, and the volume is
defined in the guest and set on the output stream.
2022-01-17 15:09:03 +11:00
Quantum
7c91c922e6 [client] input: avoid reentrancy when realigning guest cursor
This prevents LGMP_ERR_QUEUE_FULL from happening with high polling rate
mice, which is caused by receiving many more mouse events while the
guest cursor warps, triggering more warps.
2022-01-15 19:25:30 +11:00
Chris Spencer
f635077a2c [client] egl: increase texture processing timeout
On my machine (Intel UHD Graphics 770), texture processing occasionally
(about 5% of the time) takes more than 20ms (the highest I have seen is
around 32ms) when the host resolution is 2560x1440. This results in the
frame being discarded and the client displays a stale image. Increase the
timeout to 40ms.
2022-01-14 12:31:02 +11:00
Chris Spencer
786a252b23 [client] x11: don't use primary selection for clipboard
This behaviour is more consistent with other applications where text
selections do not influence explicit clipboard operations.
2022-01-13 08:18:56 +11:00
Geoffrey McRae
6bba9bc25d [client/common] move ll from the client into the common code module 2022-01-12 12:22:18 +11:00
Geoffrey McRae
1851002fc1 [client] all: remove ll_walk and migrate over to ll_forEachNL 2022-01-12 12:17:29 +11:00
Geoffrey McRae
b99e1ea38e [client] ll: fix error in ll_forEachNL macro 2022-01-12 12:17:06 +11:00
Geoffrey McRae
2ecfa0a3ec [client] msg: add missing header file 2022-01-12 10:08:29 +11:00
Geoffrey McRae
ca0bc7c514 [client] close message boxes if the client connects 2022-01-12 10:04:16 +11:00
Geoffrey McRae
4122841b09 [client] spice: fix memory leak 2022-01-12 10:03:56 +11:00
Geoffrey McRae
e94252ad65 squash with ll 2022-01-12 10:03:31 +11:00
Geoffrey McRae
6fc0c69b2e [client] overlay/msg: provide a method to close messages from code 2022-01-12 09:35:09 +11:00
Geoffrey McRae
ced952a4c6 [client] ll: add new functionallity to allow removal of items 2022-01-12 09:33:36 +11:00
Geoffrey McRae
4411d21135 [client] spice: update submodule to prevent segfault on shutdown 2022-01-12 07:42:01 +11:00
Chris Spencer
8a61c8ebc2 [client] audio/pw: use rate matching
This can prevent glitches when the PipeWire quantum size changes.
2022-01-11 09:45:30 +11:00
Chris Spencer
ef9b2958ec [client] audio/pw: set maximum node latency
This prevents severe buffer underruns if the PipeWire quantum is bigger
than the ring buffer size. This could happen if a media player is running
at the same time as Looking Glass if it requests a very large quantum size,
for example.
2022-01-11 09:45:30 +11:00
Chris Spencer
e72e138267 [client] audio/pw: delay playback to avoid glitches 2022-01-11 09:45:30 +11:00
Chris Spencer
4c389a9274 [client] audio/pw: flush playback buffers before stopping
This stops the end of the playback from being truncated. It also prevents
an audible glitch when playback next starts due to the truncated data being
left behind in the ring buffer.
2022-01-11 09:45:30 +11:00
Chris Spencer
b9c646074d [client] audio/pw: don't discard playback data
This can cause significant glitching, particularly around the start of
playback.
2022-01-11 09:45:30 +11:00
Geoffrey McRae
0fc87576f3 [client] core: fallback to manual realignment if the LGMP message fails 2022-01-09 21:25:40 +11:00
Geoffrey McRae
24193aaaa6 [client] main: added user feedback during LGMP/KVMFR version check 2022-01-09 02:15:18 +11:00
Geoffrey McRae
f9b907a6b1 [client] msg: allow messages to contain blank lines and separators 2022-01-09 02:14:01 +11:00
Geoffrey McRae
d42e409728 [client] spice: show message when connected to the wrong guest 2022-01-08 19:32:58 +11:00
Geoffrey McRae
780cf5f362 [client] overlay: add modal message dialog support 2022-01-08 18:58:48 +11:00
Geoffrey McRae
0080e5f1b9 [client] overlay: add app_invalidateOverlay method 2022-01-08 15:18:40 +11:00
Geoffrey McRae
ad6fa5a504 [client] app: move all alert management into overlay/alert.c 2022-01-08 14:33:12 +11:00
Geoffrey McRae
db2e38ae4d [client] overlay: add 25Hz tick function
This allows an overlay to manage itself for timed events like
alerts/messages, etc.
2022-01-08 14:33:07 +11:00
Geoffrey McRae
35334333ac [client] imgui: render twice for alerts
When using jitRender, or on the first frame of an alert the window
doesn't get resized immediately causing it to cut off the end of the
text.

ImGui needs two passes to calulate the bounding box for automatically
sized windows, this is per it's design and not a bug, see:

https://github.com/ocornut/imgui/issues/2158#issuecomment-434223618
2022-01-08 00:46:16 +11:00
Geoffrey McRae
ec0bd6adc8 [client] imgui: update to cimgui 1.86 2022-01-08 00:26:12 +11:00
Quantum
8e8d8834de [client] main: print guest CPU socket count information 2022-01-07 21:03:20 +11:00
Geoffrey McRae
32134b33ea [client] audio: remove more debug output spam 2022-01-07 16:35:46 +11:00
Geoffrey McRae
9d894065c8 [client] audio: remove debug spam 2022-01-07 16:27:29 +11:00
Geoffrey McRae
7263159428 [client] audio/pw: implement record support 2022-01-07 00:54:44 +11:00
Geoffrey McRae
52f06ec332 [client] audio: don't call record.mute if it's not supported 2022-01-07 00:22:35 +11:00
Geoffrey McRae
7f93bbd675 [client] audio/pw: fixed another search/replace mistake 2022-01-07 00:09:34 +11:00
Geoffrey McRae
5c20a851c6 [client] audio/pw: fix search/replace error 2022-01-06 23:58:02 +11:00
Geoffrey McRae
11acaa2957 [client] audio/pw: refactor to use playback for playback methods 2022-01-06 23:56:12 +11:00
Geoffrey McRae
fe7973ea24 [client] audio: implement record interface and glue 2022-01-06 23:49:20 +11:00
Geoffrey McRae
ff2ca20235 [client] audio: always store the volume & mute state for restore 2022-01-06 23:31:39 +11:00