Comments (11)
PortAudio is not claiming to be thread-safe: https://app.assembla.com/wiki/show/portaudio/Tips_Threading
Since opening and closing a stream doesn't work for you, you can try writing your own callback function and implement the "stop" functionality without actually stopping the stream (but just writing zeros afterwards).
Or you can try to somehow have play()
and stop()
on the same thread.
Often creating a separate thread isn't even necessary, since the callback function is called in a dedicated thread (created by PortAudio) anyway.
from python-sounddevice.
I am never creating multiple simultaneous threads, my application has a GUI thread and either one (if currently playing a sound) or zero (if not playing) audio thread. Both play()
and stop()
always happen in the same thread. This doesn't seem to be a multithreading issue as described in the above PortAudio documentation, but I most certainly don't understand the internals of PortAudio as well as you do.
I'd be fine with calling play()
asynchronously if I could ask for the current status as to whether it is still playing audio or not. Is there a way to do this in the API? If I could query whether playback was still in progress, I wouldn't need the extra thread. My example code doesn't show it, but by asking whether Thread.is_alive()
I can tell whether the blocking play()
is still playing or not.
from python-sounddevice.
But in your code example, play()
and stop()
are called from different threads ... is your real use case different than that?
Currently, there is no API function to check if playing or not. The idea is that you use sd.wait()
, which returns once playback has stopped. Is this not applicable in your case?
If not, I guess this could be implemented based on the active
property of the underlying stream.
If you need that, please make a new issue giving reasons why you would like to have that, how the API should look like and why sd.wait()
doesn't suffice. You can of course also make a PR!
from python-sounddevice.
My use case is that users are playing audio which may be as long as 150 seconds, and at the press of a button it should stop the audio if currently playing, or replay the audio from the start if not currently playing. I cannot have the GUI thread block while playing, so neither the non-blocking play()
nor wait()
would work.
I locally modified sd.play()
to return a handle on its underlying OutputStream. If I replace the above example code's run()
method to query the stream's active
property, as you suggest, I am able to stop the non-blocking play()
:
def run(self):
samplerate, signal = wavfile.read(self.fname)
stream = sounddevice.play(signal, samplerate, blocking=False)
while stream.active:
time.sleep(0.001)
Given that sd.play()
and sd.stop()
exist at the module level in an imperative style, it seems intuitive to me that there would also be a module-level sd.is_active()
(or similar) to correspond with the use of those functions.
Alternatively, returning a handle on the OutputStream from sd.play()
seems like a reasonable enough compromise.
I'm happy to write an issue (and PR) for either of these two options if you feel that I'm going down the right path. Again, I apologize that I don't have intimate knowledge of PortAudio... but that's exactly why I'm using your sounddevice module!
from python-sounddevice.
Thanks for providing your use case, there is indeed something missing in the sounddevice
module ...
I don't really like the idea of returning something from play()
, since this would look awkward when using it interactively (which is still its most important use case IMHO).
I also don't really like is_active()
, although I can't really tell why ...
But here's another idea: what about returning the stream itself?
Something like sd.get_stream()
?
With this, you could get your "active" information with sd.get_stream().active
, but you could also get more details about the stream, like latency
and cpu_load
.
What do you think about this idea?
from python-sounddevice.
I have no problem with a top-level get_stream()
function as opposed to having play()
, rec()
, and recplay()
return the stream.
It looks like its implementation should be trivial, it need just hand back the global _last_context.stream
reference.
I like that your Stream
acts as context manager, so returning it directly you could do things like:
with sd.play(signal, samplerate) as stream:
while stream.active:
try:
sleep(0.001) # or whatever...
except KeyboardInterrupt:
stream.stop()
(Note: blocking play()
or a call to wait()
prevents KeyboardInterrupt
on my Mac so that it can never be used to stop audio playback; I have to do tricks like the above to kill non-blocking playback if using the interpreter interactively. This is counter to what the docs say for wait()
.)
I'm not sure how useful a context manager is for the imperative API anyway, so it probably doesn't really matter... just as long as there's some way to get a handle on the stream. Thanks for considering this long-winded discussion!
from python-sounddevice.
It looks like its implementation should be trivial
Yes, most of sounddevice
's implementation is trivial! It's just a wrapper after all. And CFFI does a great job simplifying the access to the C world.
The hard thing is getting the API right.
I have to do tricks like the above
I know a much better trick: Use Python 3!
I know that interrupting doesn't work with Python 2. That's because threading.Event.wait()
doesn't support it. I was just too lazy to document this ...
Anyway ... your call to stream.stop()
shouldn't be necessary because it's done anyway by the context manager.
it probably doesn't really matter...
I guess it doesn't.
So yes, please make a PR!
from python-sounddevice.
I don't know if it has anything to do with this issue, but I just saw that there was a thread-related issue on macOS with PyAudio: https://people.csail.mit.edu/hubert/git/?p=pyaudio.git;a=commit;h=884cedae7f2dca14b30ad3606cfa98653d57ae5e
AFAIK, CFFI releases the GIL for all C function calls anyway, so this is probably irrelevant here ...
from python-sounddevice.
@riggsd Shall we keep this open?
Is there something else (other than #70) to do?
from python-sounddevice.
from python-sounddevice.
Fixed by #70
from python-sounddevice.
Related Issues (20)
- Enhancement Request: Integrate Playback Status Check into Simple `play`/`stop` API in `sounddevice` HOT 4
- Feature request for loopback of output device. HOT 3
- 设备解码错误?utf-8' codec can't decode byte 0xc2 in position 6: invalid continuation byte HOT 4
- Sounddevice + big dict + OOP = Segfault / Bus Error HOT 11
- Update device list by reloading portaudio dll HOT 1
- Won't be able to import sounddevice due to unknown issue with `libportaudio64bit.dll` HOT 5
- Error opening OutputStream: Unanticipated host error', -9999, (2, 0, 'Failed to load ASIO driver
- Use sounddevice with virtual audio device and minimize latency HOT 1
- Achieving stable latency between calls of "playrec" HOT 8
- sounddevice not recognize all devices?
- Issues with playing concurrently with Youtube HOT 1
- Latency 30mSec HOT 9
- Advice on asynchronous playback HOT 7
- docker node minimal image
- Can I continue recording until the volume drops below a threshold? HOT 4
- Simultaneous audio playback datatype issue HOT 2
- Does sd.wait() block all other threads? HOT 1
- OSERROR portaudio library not found
- Advice on detecting when Sounddevice has stopped playing audio (and using multiple OutputStreams)
- Inconsistent order of channels HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from python-sounddevice.