Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capturing several devices simultaneously #154

Closed
gustavovelascoh opened this issue Oct 16, 2018 · 6 comments
Closed

Capturing several devices simultaneously #154

gustavovelascoh opened this issue Oct 16, 2018 · 6 comments

Comments

@gustavovelascoh
Copy link

gustavovelascoh commented Oct 16, 2018

Is it possible to record from several devices simultaneously?

I have 4 devices and I want to capture simultaneaously from them. I have tried 3 approaches in this order:

1. Consecutive calls to sd.rec():

Tried something like:

    sd.rec( ..., device=1)
    sd.rec( ..., device=2)
    sd.rec( ..., device=3)
    sd.rec( ..., device=4)
    sd.wait()

But plotting the data (4 outputs concatenated) I got this. Just device 4 is fully recorded:

wrong

2. Multiprocess:

I wrapped sd.rec() function in a new one, and tried to use it via multiprocess, but got the "freeze_support" error:

RuntimeError:
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

error.txt

3. subprocess (isolated recording script)

Finally I opt to create a python script for recording having as input the device number, and use a "master" script to call it with the required devices, and it works. Something like:

for i in [1,2,3,4]:
    p = Popen("python record_script.py " + str(i))

The only caveat here is that I can't stop or handle the recording once it has started because, obviously, this is a new process in the OS.

Is there any approach more related to my attempts 1 and 2 for recording multiple devices?

@mgeier
Copy link
Member

mgeier commented Oct 18, 2018

I do not have any real experience with using the sounddevice module in multiple threads/processes at the same time. Here are a few related issues: #118, #120, #147.

Your option 1 will definitely not work. The rec() function is made for exclusive use. If you start rec() while another invocation is still running, the previous recording is stopped, as you have noticed.

Your option 2 might work. If you need help avoiding the exception you were mentioning, you should provide some code. If I can reproduce the problem I might be able to help, but no guarantees!

If your option 3 does what you need, that's fine. But I think if option 3 works, the same thing should also work with multiprocessing.

Depending on your OS and host API, it might also be possible to create 4 InputStream objects in the same thread, one for each input device. This is not officially supported, but it might still work for you.
In this case you would have 4 callback functions running at the same time (the underlying PortAudio library will create a separate thread for each of them). You could e.g. have a queue for each callback and the main thread would read the input data from the 4 queues.

Yet another option would be to try to combine the input devices with some OS tool. For example, on macOS it is possible to make an "aggregate device" by combining multiple existing devices.
With a custom ALSA setup, a similar thing might be possible. There might be other tools available.

@gustavovelascoh
Copy link
Author

Hi @mgeier, thanks for your response. At this moment I had a project switch but hopefully next week I will be able to provide some code. In the meantime, I will explain what I need to do:

I have a soundcard with 4 inputs (4 devices), each one with 2 channels. There is needed to start and stop recording on each channel based on external events. (suppose a GUI with 8 start and 8 stop buttons). In the first stage of development, I have a fixed recording duration, so I can avoid stop buttons and start recording using start buttons.

For that reason my approach 3 is working; with each start button, I can run the recording script for the respective device. This implies I will start recording both channels when one is requested.

I will provide the code as soon as I can. Thanks.

@mgeier
Copy link
Member

mgeier commented Jan 6, 2019

A similar question on Stack Overflow: https://stackoverflow.com/q/54036977/.

@mgeier
Copy link
Member

mgeier commented Sep 25, 2019

@gustavovelascoh Any news?

@gustavovelascoh
Copy link
Author

Sorry, I totally forgot this thread. In the end, I created a thread class based on the "Recording an arbitrary duration" example, in which I can select the device when an object is created, and added methods for start and stop the recording, and change the destination file.

From the main process, I create the needed recording objects and control the recording based on the external asynchronous events.

@mgeier
Copy link
Member

mgeier commented Sep 30, 2019

OK, thanks for the update!

I guess I can close this issue now. If you have further questions, feel free to open further issues or add comments here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants