We can't control whether the instantiation mutex is held when
~Weakable() is called, so we need to implement this via a static raw
pointer instead to ensure that all operations on it are effectively
atomic.
We should be fine to just fall back to zero or the last returned value
if we encounter an error in PlaybackStream::total_time_played(), and
this also simplifies the using code.
The SharedSingleProducerCircularQueue used here has dubious value, This
queue is used to pass commands to the audio thread, such as play/pause/
seek/volume change/etc. We can make do with a simple locked vector, as
we were blocking to enqueue tasks anyways. We can also use an atomic
bool to tell the audio thread when it needs to take a lock on the task
queue, to keep the thread lock-free most of the time.
Instead of having to duplicate the audio stream backend conditions, just
define PlaybackStream::create in each audio backend implementation file.
We provide a weak definition in PlaybackStream.cpp as the fallback.