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

add callback API for detecting connection/removal of devices (aka "hotplug") #11

Open
PortAudio-admin opened this issue Aug 23, 2006 · 20 comments
Labels
P3 Priority: Normal public-api The public API defined in include/PortAudio.h

Comments

@PortAudio-admin
Copy link
Collaborator

Issue created by @RossBencina

Add an API to allow clients to be notified (or to poll) for whether audio devices have been connected or disconnected.

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

Robert Bielik adds: As it is now, the available audio devices are discovered during Pa_Initialize(). I'd like to have it possible to check if any new devices have been added (such as a headset), while still playing a stream with connected devices. Would that be possible?

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

Erik Bunce submitted a patch for this in October 2007:
http://techweb.rfa.org/pipermail/portaudio/2007-October/007719.html

There were a number of issues raised, see discussion in October:
http://techweb.rfa.org/pipermail/portaudio/2007-October/thread.html#7719
and November:
http://techweb.rfa.org/pipermail/portaudio/2007-November/

All under the subject "Plug-and-play patch for portaudio"

From memory one of the issues was concerned with dealing with concurrency issues.

This issue needs to revisited and a decision reached.

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

r1663:
merged initial two-stage-commit hot-plug patch from David Stuart into branches/hotplug, with ds implementation only, including:

  • include\portaudio.h: added note about available device list lifetime to Pa_Initialize() doc comment. added Pa_UpdateAvailableDeviceList() declaration and doc comment.
  • src\common\pa_front.c: added Pa_UpdateAvailableDeviceList implementation
  • src\common\pa_hostapi.h: added function pointers for ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos.
  • src\hostapi\dsound\pa_win_ds.c added ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos implementation.
  • src\hostapi\dsound\pa_win_wmme.c zeroed ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos ptrs.
  • added test\patest_update_available_device_list.c simple test case.

Open questions:

  • Is it only the PaDeviceInfo struct ptrs from disconnected devices that should become invalidated, or all of them? doccomment currently says all of them may change but perhaps this is undesirable.
  • CommitDeviceInfos() should probably not be permitted to fail and therefore should not be able to return an error.
  • Currently PaUtilHostApiRepresentation function ptrs for ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos are not zeroed by other host API impls but pa_front.c assumes that they are. (only pa_win_ds.c and pa_win_wmme.c are ok in commit r1663).

r1664 includes a cleaned up version of pa_win_ds.c where the scanning code is also used by Initialize()

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

TRAC migration: propagating ticket status from TRAC

@PortAudio-admin
Copy link
Collaborator Author

PortAudio-admin commented Jan 27, 2012

Comment by @RossBencina

portaudio-deviceschanged.patch.txt

portaudio-deviceschanged.patch (44.7 KB) - added by rossb 4 years ago.
Eric Bunce's Plug-and-play patch for portaudio, see http://techweb.rfa.org/pipermail/portaudio/2007-October/007719.html

[Portaudio] Plug-and-play patch for portaudio
Erik Bunce
Mon Oct 29 23:02:01 EDT 2007
"""
Please see the attached patch against todays portaudio v19-devel r1296.
It defines API's to support plug-and-play
and adds an implementation to the hostapi for Mac OS X.

Highlights includes the following:

  • A callback mechanism to notify API users when the list of devices
    and/or the default input/output devices change.
  • If one of these callback is registered, and the native implementation
    detects that the devices has changed,
    the system will automatically rescan the devices and adjust the
    device lists accordingly.
  • To maintain backwards compatiblity, if no callback is registered, the
    system leaves the device list alone and the
    previous behavior is mainained.
  • Existing host API's that don't support rescanning, just have to set
    the new RescanDevices member of the
    PaUtilHostApiRepresentation structure to 0.
  • API users can call the Pa_RescanDevices() to force the native
    implementation to rescan it's list of devices.
  • Mac OS X CoreAudio implementation.
  • Designed so that it could be used with or without native host
    notifications of device list changes.
    I'm successfully using this in iaxclient.

Thank you for your consideration.

Thanks and Enjoy,
Erik Bunce
"""

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

Patches from Ingo Bauersachs of jitsi:

This is the source we're currently using:
https://github.com/jitsi/libsrc/blob/master/portaudio.zip

The should be the diff from SVN-1677 to what is in the above .zip:
ibauersachs/portaudio@df0179c28863ae122e5d37f4a9b4
2b7a8dd806fc

And the wmme-patch is on our list archives:
http://lists.jitsi.org/pipermail/dev/2012-July/004183.html

There are useful commit messages with details about the patches here:
https://github.com/jitsi/libsrc/commits/master/portaudio.zip

This is now in PortAudio GIT as a sequence of commits here:
https://app.assembla.com/spaces/portaudio/git/merge_requests/3784323?section=commits

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

Here is my review of the jitsi patch from here:
https://github.com/jitsi/libsrc/blob/master/portaudio.zip (relative to r1677)
Diff here: ibauersachs/portaudio@df0179c28863ae122e5d37f4a9b4
2b7a8dd806fc

Also available in PortAudio GIT:
https://app.assembla.com/spaces/portaudio/git/merge_requests/3784323?section=commits

(Note: the MME mailing list patch seems redundant. It is slightly different from 5ca6fed, but doesn't appear to contain any functional differences. http://lists.jitsi.org/pipermail/dev/2012-July/004183.html)

The changes seem to fall into the following categories:

  1. Refactor device enumeration to support the hotplug refresh interface. Mostly moving code around. The patch includes this code for pa_linux_alsa, pa_mac_core, and pa_win_wmme.
  2. Rework timeouts and/or add additional timeouts to deal with devices timing out when disconnected while a stream is running (quite a lot of this code for ALSA, CoreAudio and WMME).
  3. Device inserted notification engines for Mac and Linux. The Linux one is very rudimentary and uses a sleep()/polling loop. The Mac one is simple, but uses core audio notifications as you'd expect.
  4. Addition of deviceUID and transportType to PaDeviceInfo. We won't accept this but maybe some of it will be used internally, especially deviceUID
  5. A few behavioral tweaks (e.g. disable wavemapper on Windows). Some of these we won't accept.

Broken down by file. I've marked changes that we won't accept with WONTFIX

Routine Changes

Makefile.in

  • add patest_refesh_device_list to TESTS
  • add src/os/mac_osx to SRC_DIRS

configure
configure.in

  • add new objects and flags

Major Changes Incl. Hotplug

src/hostapi/alsa/pa_linux_alsa.c

  • Modify BuildDeviceList, FillInDevInfo to return scan results (straight-forward refactoring of the device enumeration code to implement the device list rescanning.)
  • Support hotplug: ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos
  • Commented out alsa_snd_config_update_free_global(); see comment line 832
  • additional xrun handling lines 3585, 3606, 3660, 3757, 4396 (possibly related to timeouts)

src/hostapi/coreaudio/pa_mac_core.c

  • Support hotplug: ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos
  • WONTFIX big block of code at 529 to get deviceUID and transportType (UID will probably be needed to implement connectionId unless there's a better way)
  • WONTFIX transportType is set with a range of values
  • timeouts added to avoid infinite loop when device is removed (e.g. at line 2480)

src/hostapi/coreaudio/pa_mac_core_blocking.c

  • add timeouts to avoid infinite blocking (presumably for disconnected devices?)

src/hostapi/coreaudio/pa_mac_core_blocking.h

  • timeout #defines

src/os/win/pa_win_hotplug.c

  • Add 2 second delay between OS notification and PA notification

src/hostapi/wmme/pa_win_wmme.c

  • Support hotplug: ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos
  • ScanDeviceInfos implementation looks like a more-or-less direct pull from PaWinMme_Initialize
  • WONTFIX extract transport type for device: only ever set to USB
  • WONTFIX extract endpoint GUID for device (might be useful for connectionId?)
  • WONTFIX: disable enumeration of WAVE_MAPPER
  • use timeouts to avoid infinite waiting in StopStream, ReadStream, WriteStream (on device disconnection)

New Files Incl. Hotplug

src/os/mac_osx/pa_osx_hotplug.c

  • CoreAudio hotplug notification engine (missing locking)

src/os/unix/pa_linux_hotplug.c

  • hotplug notification engine. Non-ideal impl: (1) runs in loop sleeping for 1 second then counting devices using snd_card_next(). (2) Notifies if # cards changes (!).

Non-Hotplug Tweaks We Might Want (or not)

include/pa_mac_core.h

  • reinstate commented out #include AudioToolbox.h

src/hostapi/wdmks/pa_win_wdmks.c

  • tweak #define _WIN32_WINNT, WINVER for gcc
  • comment out #include winioctl for TDM-GCC
  • WONTFIX: disable hotplug rescan

Changes Already In PA/hotplug

src/hostapi/asio/pa_asio.cpp
src/hostapi/jack/pa_jack.c
src/hostapi/oss/pa_unix_oss.c
src/hostapi/skeleton/pa_hostapi_skeleton.c
src/hostapi/wasapi/pa_win_wasapi.c

  • zero ScanDeviceInfos et al. No hotplug support.

WONTFIX

include/portaudio.h

  • WONTFIX: add transportType and deviceUID to PaDeviceInfo

src/common/pa_front.c

  • WONTFIX: move debug print

src/hostapi/dsound/pa_win_ds.c

  • WONTFIX: copy GUID to PaDeviceInfo

test/patest_update_available_device_list.c

  • WONTFIX: add #include <unistd.h> and possibly non meaningful(?) reformatting

@PortAudio-admin
Copy link
Collaborator Author

Comment by @RossBencina

Here's a breakdown of the separated Jitsi commits that are available in PortAudio GIT here:
https://app.assembla.com/spaces/portaudio/git/merge_requests/3784323?section=commits

b77a1f8

  • initial commit with configuration and housekeeping for hotplug on all platforms (configure.in, Makefile.in, zero hotplug function ptrs on non-supported platforms)
  • alsa device rescanning
  • alsa timeout fixes
  • linux connection/disconnection notification engine
  • mac core audio device rescanning
  • mac connection/disconnection notification engine
  • disable WDM/KS
  • windows sleep for 2 seconds before notifying

e7a2749

  • add transportType and deviceUID in portaudio.h
  • implement transportType and deviceUID for mac

0a7b80c

  • implement transportType and deviceUID in for wmme and dsound

15d7741

  • wmme: device rescanning

6c62694

  • changes to pa_win_wdmks.c #defines/includes for GCC
  • wmme: disable wavemapper
  • wmme: changes to set device info transport type

c534056

  • wmme: fixes "incorrect causes of paInvalidChannelCount errors in PortAudio on Windows/WMME"
  • wmme: changes to stream wait/timeout mechanism for dealing with device disconnection

ab8b640

  • wmme: refinements to transportType

66bda13

  • mac core: changes to timeouts to avoid blocking when device is disconnected

@raveslave
Copy link

checking in whats the status for connectionId and identifying sound cards (if many) by the raw usb-descriptor serial number

@RossBencina
Copy link
Collaborator

@raveslave status is that connectionId iss part of hotplug spec, there is partial implementation in the stale branch. I don't think most USB devices have serial numbers.

@raveslave
Copy link

any plans on merging? I've tried a bunch of various sound cards and they all have serial-nos in the main descriptor.

@RossBencina
Copy link
Collaborator

@raveslave: out of interest, can you give examples of the devices with unique serial numbers?

@raveslave
Copy link

@RossBencina

Here is the top level descriptor for a Motu M2:

 Product ID:	0x000b
 Vendor ID:	0x07fd
 Version:	2.03
 Serial Number:	M2AE0F58N7
 Speed:	Up to 480 Mb/s
 Manufacturer:	MOTU
 Location ID:	0x14800000 / 25
 Current Available (mA):	500
 Current Required (mA):	500
 Extra Operating Current (mA):	0

would be great if portaudio exposes pid, vid, version, serial, mfg as well as usb port
this way we can better identify whats connected, especially when dealing with multiple sound-cards
...and in my case, I need to calibrate each sound-card so this would be stored linked to the serial-no

related when used with sounddevice,
serial would be essential here

sounddevice.query_devices(2)
{'name': 'M2', 'index': 2, 'hostapi': 0, 'max_input_channels': 2, 'max_output_channels': 2, 
 'default_low_input_latency': 0.01, 'default_low_output_latency': 0.0045578231292517, 
 'default_high_input_latency': 0.1, 'default_high_output_latency': 0.014716553287981859, 
 'default_samplerate': 44100.0}_

@JoergAtGithub
Copy link

The USB Serial Number is not a good identifier for this purpose:

  1. It only work for USB sound devices, but not for Bluetooth, Firewire, etc.
  2. Many cheap devices have no programmable memory. Therefore the manufacturers use the same Serial Number for all devices of a type - this is a violation of the USB specification, but unfortunately common in the field.

Instead you should use the unique device identifiers, which the operating systems assigned at runtime. These are:

  1. On Windows you have DEVPKEY_Device_ContainerId which suits perfect here
  2. On MacOS you've LocationIDs like kUSBDevicePropertyLocationID (every MacOS subsystem API calls them slightly different)
  3. On Linux you have to use libudev, determine the parent device using udev_device_get_syspath (might need multiple iterations) and than get it's syspath string using udev_device_get_syspath

@raveslave
Copy link

I still think the usb descriptor serial should be exposed as this is the only identifier (available on most pro-sumer / professional sound cards) to allow calibration, i.e. measured setups, needing to know which exact soundcard is connected.

The location-id is good to but changes upon each reconnect or reboot. How about offer both and let the application choose how to use them?

@JoergAtGithub
Copy link

The location-id will always work, it's a guranteed unique identifier. Using this unique identifier as reference, you can gather any additional information, like the USB serial number.
The other way around, it wouldn't work reliable, because there could be more than one device using the same USB serial number.

@raveslave
Copy link

how about offering both, with location-id being the primary?

its important you can move a soundcard from one machine to another and still knowing which one it is
afaik, location-id will not be same in that use-case

@Chum4k3r
Copy link

Chum4k3r commented Jan 10, 2023 via email

@MrKepzie
Copy link

What's the status on the hotplug branch ? It looks like it is stale for almost 7 years now; How far is it to be usable ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P3 Priority: Normal public-api The public API defined in include/PortAudio.h
Projects
None yet
Development

No branches or pull requests

6 participants