What would it take to replace pyo?

Well, generally there is the option of using a so-called “blocking” stream (by not providing a callback method), but I don’t think this has any advantages over using a callback function. One of the disadvantages is that it is not available for all host API (which IMHO is already a deal-breaker).

When using a callback function, there are still two ways to stop some sound from being played:

  1. set some state in the callback so that it (the callback) knows it should stop playing
  2. stop the whole stream

I think the first option (as @jon has implemented it) makes more sense.

I would use a single stream for everything, both playing and recording, and keep that same stream active all the time.

BTW, I mentioned in Low sound latency with sounddevice module & wdm-ks driver - #7 by matthias.geier that it would be interesting to try to implement the audio callback in C for more stable, predictable and responsive performance.
In the meantime, I’ve started to do exactly that: GitHub - mgeier/python-rtmixer: 🎤 Reliable low-latency audio playback and recording with Python 🐍. This is still very much work in progress, but it should already support most of the use cases needed for PsychoPy. I would love to hear what you think about it!