diff options
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/pulsedevice.cpp | 19 | ||||
| -rw-r--r-- | src/model/pulsedevice.h | 2 | ||||
| -rw-r--r-- | src/model/pulsemodel.cpp | 55 | ||||
| -rw-r--r-- | src/model/pulsemodel.h | 3 |
4 files changed, 66 insertions, 13 deletions
diff --git a/src/model/pulsedevice.cpp b/src/model/pulsedevice.cpp index 8bdea54..8fb8d48 100644 --- a/src/model/pulsedevice.cpp +++ b/src/model/pulsedevice.cpp @@ -45,15 +45,20 @@ void PulseDevice::setPAContext( pa_context *ctx, pa_threaded_mainloop *mainloop startMonitoring(); } -void PulseDevice::detach() +void PulseDevice::detach( bool paAlreadyDead ) { - if ( m_monitorStream && m_mainloop ) { - pa_threaded_mainloop_lock( m_mainloop ); - pa_stream_set_read_callback( m_monitorStream, 0, 0 ); - pa_stream_disconnect( m_monitorStream ); - pa_stream_unref( m_monitorStream ); + if ( m_monitorStream ) { + if ( paAlreadyDead ) { + pa_stream_set_read_callback( m_monitorStream, 0, 0 ); + pa_stream_unref( m_monitorStream ); + } else if ( m_mainloop ) { + pa_threaded_mainloop_lock( m_mainloop ); + pa_stream_set_read_callback( m_monitorStream, 0, 0 ); + pa_stream_disconnect( m_monitorStream ); + pa_stream_unref( m_monitorStream ); + pa_threaded_mainloop_unlock( m_mainloop ); + } m_monitorStream = 0; - pa_threaded_mainloop_unlock( m_mainloop ); } m_context = 0; m_mainloop = 0; diff --git a/src/model/pulsedevice.h b/src/model/pulsedevice.h index e974508..27aca02 100644 --- a/src/model/pulsedevice.h +++ b/src/model/pulsedevice.h @@ -40,7 +40,7 @@ public: TQWidget *createWidget( TQWidget *parent ); void setPAContext( pa_context *ctx, pa_threaded_mainloop *mainloop ); - void detach(); // called by PulseModel before tearing down the mainloop + void detach( bool paAlreadyDead = false ); protected: void customEvent( TQCustomEvent *e ); diff --git a/src/model/pulsemodel.cpp b/src/model/pulsemodel.cpp index 640b918..49a17c2 100644 --- a/src/model/pulsemodel.cpp +++ b/src/model/pulsemodel.cpp @@ -2,11 +2,13 @@ #include "pulsedevice.h" #include <tqapplication.h> +#include <tqtimer.h> // Custom events posted from the PA thread to the main thread. static const int PA_EVENT = TQEvent::User + 1; static const int PA_SERVER_EVENT = TQEvent::User + 3; static const int PA_CARD_EVENT = TQEvent::User + 4; +static const int PA_DIED_EVENT = TQEvent::User + 5; struct PAServerEvent : public TQCustomEvent { TQString defaultSinkName; @@ -183,18 +185,27 @@ bool PulseModel::open() void PulseModel::close() { - // Detach monitor streams on all devices before tearing down the mainloop. TQPtrList<PulseDevice> *allLists[4] = { &m_sinks, &m_sources, &m_sinkInputs, &m_sourceOutputs }; + + bool alreadyDead = false; + if ( m_context ) { + pa_context_state_t state = pa_context_get_state( m_context ); + alreadyDead = ( state == PA_CONTEXT_FAILED || + state == PA_CONTEXT_TERMINATED ); + } + for ( int i = 0; i < 4; i++ ) for ( TQPtrListIterator<PulseDevice> it(*allLists[i]); *it; ++it ) - (*it)->detach(); + (*it)->detach( alreadyDead ); if ( m_context ) { - pa_threaded_mainloop_lock( m_mainloop ); - pa_context_disconnect( m_context ); + if ( !alreadyDead ) { + pa_threaded_mainloop_lock( m_mainloop ); + pa_context_disconnect( m_context ); + pa_threaded_mainloop_unlock( m_mainloop ); + } pa_context_unref( m_context ); m_context = 0; - pa_threaded_mainloop_unlock( m_mainloop ); } if ( m_mainloop ) { pa_threaded_mainloop_stop( m_mainloop ); @@ -247,6 +258,7 @@ void PulseModel::contextStateCb( pa_context *c, void *userdata ) break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: + TQApplication::postEvent( self, new TQCustomEvent(PA_DIED_EVENT) ); break; default: break; @@ -437,8 +449,41 @@ void PulseModel::cardInfoCb( pa_context *, const pa_card_info *info, int eol, vo // ---- main thread event handler ---------------------------------------------- +void PulseModel::reconnect() +{ + open(); +} + void PulseModel::customEvent( TQCustomEvent *e ) { + if ( e->type() == PA_DIED_EVENT ) { + if ( !m_mainloop ) return; // already handling a previous die event + // Notify UI that all devices are gone, then tear down and retry. + TQPtrList<PulseDevice> *allLists[4] = { &m_sinks, &m_sources, &m_sinkInputs, &m_sourceOutputs }; + for ( int i = 0; i < 4; i++ ) { + TQPtrListIterator<PulseDevice> it( *allLists[i] ); + while ( *it ) { + PulseDevice *dev = *it; + ++it; + emit deviceRemoved( dev ); + } + } + // Zero out default-device pointers in connected UI before devices are deleted. + emit defaultOutputChanged( 0 ); + emit defaultInputChanged( 0 ); + // Sever all remaining signal connections on every device so that + // close() can delete them safely regardless of cross-device wiring. + for ( int i = 0; i < 4; i++ ) + for ( TQPtrListIterator<PulseDevice> it( *allLists[i] ); *it; ++it ) + disconnect( *it, 0, 0, 0 ); + m_sinksByName.clear(); + m_sourcesByName.clear(); + m_sourceOutputToSource.clear(); + m_cards.clear(); + close(); + TQTimer::singleShot( 2000, this, TQ_SLOT(reconnect()) ); + return; + } if ( e->type() == PA_CARD_EVENT ) { PACardEvent *ev = static_cast<PACardEvent *>(e); if ( ev->removed ) { diff --git a/src/model/pulsemodel.h b/src/model/pulsemodel.h index 52e379f..c1d4561 100644 --- a/src/model/pulsemodel.h +++ b/src/model/pulsemodel.h @@ -80,6 +80,9 @@ signals: void cardRemoved( uint32_t index ); void cardUpdated( uint32_t index ); +private slots: + void reconnect(); + private: static void contextStateCb( pa_context *c, void *userdata ); static void serverInfoCb( pa_context *c, const pa_server_info *info, void *userdata ); |
