diff options
Diffstat (limited to 'src/model/pulsemodel.cpp')
| -rw-r--r-- | src/model/pulsemodel.cpp | 114 |
1 files changed, 111 insertions, 3 deletions
diff --git a/src/model/pulsemodel.cpp b/src/model/pulsemodel.cpp index 49a17c2..31df0ca 100644 --- a/src/model/pulsemodel.cpp +++ b/src/model/pulsemodel.cpp @@ -31,6 +31,9 @@ struct PAEvent : public TQCustomEvent { TQString iconName; TQString paName; // raw PA name (sinks/sources only, for default tracking) uint32_t parentIndex; // for Playback: parent sink PA index + uint32_t cardIdx; // for Output/Input: owning card PA index + TQString activePortName; + TQValueList<PulseDevicePort> devPorts; PAEvent( Kind k, AudioDevice::Category c, uint32_t idx, const TQString &n = TQString(), int vol = 0, bool m = false, @@ -39,7 +42,8 @@ struct PAEvent : public TQCustomEvent { const TQString &pname = TQString() ) : TQCustomEvent(PA_EVENT), kind(k), cat(c), paIndex(idx), name(n), volume(vol), muted(m), channels(ch), pan(p), - monitorName(mon), iconName(icon), paName(pname), parentIndex(parent) {} + monitorName(mon), iconName(icon), paName(pname), parentIndex(parent), + cardIdx(PA_INVALID_INDEX) {} }; struct PACardEvent : public TQCustomEvent { @@ -297,6 +301,15 @@ void PulseModel::sinkInfoCb( pa_context *, const pa_sink_info *info, int eol, vo TQString::fromUtf8( pa_proplist_gets( info->proplist, PA_PROP_DEVICE_ICON_NAME ) ? : "" ), PA_INVALID_INDEX, TQString::fromUtf8( info->name ) ); + ev->cardIdx = info->card; + ev->activePortName = info->active_port + ? TQString::fromUtf8( info->active_port->name ) : TQString(); + for ( uint32_t i = 0; i < info->n_ports; ++i ) { + PulseDevicePort p; + p.name = TQString::fromUtf8( info->ports[i]->name ); + p.description = TQString::fromUtf8( info->ports[i]->description ); + ev->devPorts.append( p ); + } TQApplication::postEvent( self, ev ); } @@ -306,7 +319,7 @@ void PulseModel::sourceInfoCb( pa_context *, const pa_source_info *info, int eol // Skip monitor sources — they're PA internals, not real inputs. if ( info->monitor_of_sink != PA_INVALID_INDEX ) return; PulseModel *self = static_cast<PulseModel *>(userdata); - TQApplication::postEvent( self, new PAEvent( + PAEvent *ev = new PAEvent( PAEvent::DeviceAdded, AudioDevice::Input, info->index, TQString::fromUtf8( info->description ), paVolumeToPercent( info->volume ), info->mute != 0, @@ -314,7 +327,17 @@ void PulseModel::sourceInfoCb( pa_context *, const pa_source_info *info, int eol TQString::fromUtf8( info->name ), TQString::fromUtf8( pa_proplist_gets( info->proplist, PA_PROP_DEVICE_ICON_NAME ) ? : "" ), PA_INVALID_INDEX, - TQString::fromUtf8( info->name ) ) ); + TQString::fromUtf8( info->name ) ); + ev->cardIdx = info->card; + ev->activePortName = info->active_port + ? TQString::fromUtf8( info->active_port->name ) : TQString(); + for ( uint32_t i = 0; i < info->n_ports; ++i ) { + PulseDevicePort p; + p.name = TQString::fromUtf8( info->ports[i]->name ); + p.description = TQString::fromUtf8( info->ports[i]->description ); + ev->devPorts.append( p ); + } + TQApplication::postEvent( self, ev ); } void PulseModel::sinkInputInfoCb( pa_context *, const pa_sink_input_info *info, int eol, void *userdata ) @@ -585,6 +608,16 @@ void PulseModel::customEvent( TQCustomEvent *e ) for ( it = m_sourcesByName.begin(); it != m_sourcesByName.end(); ++it ) { if ( it.data() == dev ) { m_sourcesByName.remove(it); break; } } + // Clean up port tracking maps. + if ( ev->cat == AudioDevice::Output ) { + m_sinkCard.remove( ev->paIndex ); + m_sinkActivePort.remove( ev->paIndex ); + m_sinkPorts.remove( ev->paIndex ); + } else if ( ev->cat == AudioDevice::Input ) { + m_sourceCard.remove( ev->paIndex ); + m_sourceActivePort.remove( ev->paIndex ); + m_sourcePorts.remove( ev->paIndex ); + } // If a recording stream ended, decrement its parent source's count. if ( ev->cat == AudioDevice::Recording ) { TQMap<uint32_t,uint32_t>::Iterator si = m_sourceOutputToSource.find( ev->paIndex ); @@ -610,6 +643,25 @@ void PulseModel::customEvent( TQCustomEvent *e ) if ( sink ) monitorName = sink->monitorName(); } + // Store / update port data for sinks and sources. + if ( ev->cat == AudioDevice::Output ) { + m_sinkCard[ev->paIndex] = ev->cardIdx; + m_sinkPorts[ev->paIndex] = ev->devPorts; + TQString oldPort = m_sinkActivePort.contains(ev->paIndex) + ? m_sinkActivePort[ev->paIndex] : TQString(); + m_sinkActivePort[ev->paIndex] = ev->activePortName; + if ( ev->activePortName != oldPort ) + emit sinkUpdated( ev->paIndex ); + } else if ( ev->cat == AudioDevice::Input ) { + m_sourceCard[ev->paIndex] = ev->cardIdx; + m_sourcePorts[ev->paIndex] = ev->devPorts; + TQString oldPort = m_sourceActivePort.contains(ev->paIndex) + ? m_sourceActivePort[ev->paIndex] : TQString(); + m_sourceActivePort[ev->paIndex] = ev->activePortName; + if ( ev->activePortName != oldPort ) + emit sourceUpdated( ev->paIndex ); + } + PulseDevice *dev = findDevice( *list, ev->paIndex ); if ( dev ) { dev->update( ev->name, ev->volume, ev->muted, ev->channels, ev->pan, monitorName, ev->iconName ); @@ -734,4 +786,60 @@ void PulseModel::setCardProfile( uint32_t cardIndex, const TQString &profileName pa_threaded_mainloop_unlock( m_mainloop ); } +TQValueList<PulseModel::DevicePortInfo> PulseModel::sinksForCard( uint32_t cardIndex ) const +{ + TQValueList<DevicePortInfo> result; + for ( TQPtrListIterator<PulseDevice> it(m_sinks); *it; ++it ) { + uint32_t idx = (*it)->paIndex(); + if ( !m_sinkCard.contains(idx) || m_sinkCard[idx] != cardIndex ) + continue; + DevicePortInfo info; + info.paIndex = idx; + info.description = (*it)->name(); + info.activePort = m_sinkActivePort.contains(idx) ? m_sinkActivePort[idx] : TQString(); + info.ports = m_sinkPorts.contains(idx) ? m_sinkPorts[idx] + : TQValueList<PulseDevicePort>(); + result.append( info ); + } + return result; +} + +TQValueList<PulseModel::DevicePortInfo> PulseModel::sourcesForCard( uint32_t cardIndex ) const +{ + TQValueList<DevicePortInfo> result; + for ( TQPtrListIterator<PulseDevice> it(m_sources); *it; ++it ) { + uint32_t idx = (*it)->paIndex(); + if ( !m_sourceCard.contains(idx) || m_sourceCard[idx] != cardIndex ) + continue; + DevicePortInfo info; + info.paIndex = idx; + info.description = (*it)->name(); + info.activePort = m_sourceActivePort.contains(idx) ? m_sourceActivePort[idx] : TQString(); + info.ports = m_sourcePorts.contains(idx) ? m_sourcePorts[idx] + : TQValueList<PulseDevicePort>(); + result.append( info ); + } + return result; +} + +void PulseModel::setSinkPort( uint32_t sinkPaIndex, const TQString &portName ) +{ + if ( !m_context || !m_mainloop || portName.isEmpty() ) return; + pa_threaded_mainloop_lock( m_mainloop ); + pa_operation *op = pa_context_set_sink_port_by_index( + m_context, sinkPaIndex, portName.utf8().data(), 0, 0 ); + if ( op ) pa_operation_unref( op ); + pa_threaded_mainloop_unlock( m_mainloop ); +} + +void PulseModel::setSourcePort( uint32_t sourcePaIndex, const TQString &portName ) +{ + if ( !m_context || !m_mainloop || portName.isEmpty() ) return; + pa_threaded_mainloop_lock( m_mainloop ); + pa_operation *op = pa_context_set_source_port_by_index( + m_context, sourcePaIndex, portName.utf8().data(), 0, 0 ); + if ( op ) pa_operation_unref( op ); + pa_threaded_mainloop_unlock( m_mainloop ); +} + #include "pulsemodel.moc" |
