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

RtApiAlsa: fix device with same "pretty name" not added to device list #367

Merged
merged 1 commit into from
May 31, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 75 additions & 39 deletions RtAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class RtApiAlsa: public RtApi
void callbackEvent( void );

private:
std::vector< std::string > deviceIds_;
std::vector<std::pair<std::string, unsigned int>> deviceIdPairs_;

void probeDevices( void ) override;
bool probeDeviceInfo( RtAudio::DeviceInfo &info, std::string name );
Expand Down Expand Up @@ -7846,25 +7846,23 @@ void RtApiAlsa :: probeDevices( void )
snd_pcm_info_t *pcminfo;
snd_ctl_card_info_alloca(&ctlinfo);
snd_pcm_info_alloca(&pcminfo);
std::vector<std::string> deviceIds;
std::vector<std::string> deviceNames;
// First element isthe device hw ID, second is the device "pretty name"
std::vector<std::pair<std::string, std::string>> deviceID_prettyName;
snd_pcm_stream_t stream;
std::string defaultDeviceName;

// Add the default interface if available.
result = snd_ctl_open( &handle, "default", 0 );
if (result == 0) {
deviceIds.push_back( "default" );
deviceNames.push_back( "Default ALSA Device" );
defaultDeviceName = deviceNames[0];
deviceID_prettyName.push_back({"default", "Default ALSA Device"});
defaultDeviceName = deviceID_prettyName[0].second;
snd_ctl_close( handle );
}

// Add the Pulse interface if available.
result = snd_ctl_open( &handle, "pulse", 0 );
if (result == 0) {
deviceIds.push_back( "pulse" );
deviceNames.push_back( "PulseAudio Sound Server" );
deviceID_prettyName.push_back({"pulse", "PulseAudio Sound Server"});
snd_ctl_close( handle );
}

Expand Down Expand Up @@ -7920,9 +7918,10 @@ void RtApiAlsa :: probeDevices( void )
else continue;
}
sprintf( name, "hw:%s,%d", snd_ctl_card_info_get_id(ctlinfo), device );
deviceIds.push_back( name );
std::string id(name);
sprintf( name, "%s (%s)", snd_ctl_card_info_get_name(ctlinfo), snd_pcm_info_get_id(pcminfo) );
deviceNames.push_back( name );
std::string prettyName(name);
deviceID_prettyName.push_back( {id, prettyName} );
if ( card == 0 && device == 0 && defaultDeviceName.empty() )
defaultDeviceName = name;
}
Expand All @@ -7932,46 +7931,83 @@ void RtApiAlsa :: probeDevices( void )
snd_card_next( &card );
}

if ( deviceIds.size() == 0 ) {
if ( deviceID_prettyName.size() == 0 ) {
deviceList_.clear();
deviceIds_.clear();
deviceIdPairs_.clear();
return;
}

// Clean removed devices
for ( auto it = deviceIdPairs_.begin(); it != deviceIdPairs_.end(); )
{
bool found = false;
for(auto& d: deviceID_prettyName)
{
if(d.first == (*it).first)
{
found = true;
break;
}
}

if(found)
{
++it;
}
else
{
it = deviceIdPairs_.erase(it);
}
}

// Fill or update the deviceList_ and also save a corresponding list of Ids.
unsigned int m, n;
for ( n=0; n<deviceNames.size(); n++ ) {
for ( m=0; m<deviceList_.size(); m++ ) {
if ( deviceList_[m].name == deviceNames[n] )
for (auto& d : deviceID_prettyName)
{
bool found = false;
for ( auto& dID : deviceIdPairs_ ) {
if ( d.first == dID.first ) {
found = true;
break; // We already have this device.
}
if ( m == deviceList_.size() ) { // new device
RtAudio::DeviceInfo info;
info.name = deviceNames[n];
if ( probeDeviceInfo( info, deviceIds[n] ) == false ) continue; // ignore if probe fails
info.ID = currentDeviceId_++; // arbitrary internal device ID
if ( info.name == defaultDeviceName ) {
if ( info.outputChannels > 0 ) info.isDefaultOutput = true;
if ( info.inputChannels > 0 ) info.isDefaultInput = true;
}
deviceList_.push_back( info );
deviceIds_.push_back( deviceIds[n] );
// I don't see that ALSA provides property listeners to know if
// devices are removed or added.
}

if(found)
continue;

// new device
RtAudio::DeviceInfo info;
info.name = d.second;
if ( probeDeviceInfo( info, d.first ) == false ) continue; // ignore if probe fails
info.ID = currentDeviceId_++; // arbitrary internal device ID
if ( info.name == defaultDeviceName ) {
if ( info.outputChannels > 0 ) info.isDefaultOutput = true;
if ( info.inputChannels > 0 ) info.isDefaultInput = true;
}
deviceList_.push_back( info );
deviceIdPairs_.push_back({d.first, info.ID});
// I don't see that ALSA provides property listeners to know if
// devices are removed or added.
}

// Remove any devices left in the list that are no longer available.
for ( std::vector<RtAudio::DeviceInfo>::iterator it=deviceList_.begin(); it!=deviceList_.end(); ) {
for ( m=0; m<deviceNames.size(); m++ ) {
if ( (*it).name == deviceNames[m] ) {
++it;
for ( std::vector<RtAudio::DeviceInfo>::iterator it=deviceList_.begin(); it!=deviceList_.end(); )
{
auto itID = deviceIdPairs_.begin();
while ( itID != deviceIdPairs_.end() ) {
if ( (*it).ID == (*itID).second ) {
break;
}
++itID;
}
if ( m == deviceNames.size() ) { // not found so remove it from our list
it = deviceList_.erase( it );
deviceIds_.erase( deviceIds_.begin() + distance(deviceList_.begin(), it ) );

if( itID == deviceIdPairs_.end() )
{
// not found so remove it from our list
it = deviceList_.erase( it );
}
else
{
++it;
}
}
}
Expand Down Expand Up @@ -8160,9 +8196,9 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig
#endif

std::string name;
for ( unsigned int m=0; m<deviceList_.size(); m++ ) {
if ( deviceList_[m].ID == deviceId ) {
name = deviceIds_[m];
for ( auto& id : deviceIdPairs_) {
if ( id.second == deviceId ) {
name = id.first;
break;
}
}
Expand Down