From 58858ae83b3df185d4719783ec7490aee25dca8c Mon Sep 17 00:00:00 2001 From: w1z7ard Date: Mon, 21 Jan 2008 03:08:04 +0000 Subject: [PATCH] hacking way to correct behavior in device chooser git-svn-id: https://projectm.svn.sourceforge.net/svnroot/projectm/trunk@754 6778bc44-b910-0410-a7a0-be141de4315d --- .../PulseDeviceChooserDialog.ui | 57 ++---- .../QPulseAudioDeviceChooser.cpp | 55 ++++-- .../QPulseAudioDeviceChooser.hpp | 7 +- .../QPulseAudioThread.cpp | 187 +++++++++++------- .../QPulseAudioThread.hpp | 18 +- .../qprojectM-pulseaudio.cpp | 2 +- 6 files changed, 186 insertions(+), 140 deletions(-) diff --git a/src/qprojectM-pulseaudio/PulseDeviceChooserDialog.ui b/src/qprojectM-pulseaudio/PulseDeviceChooserDialog.ui index 60250adb5..c2f34143d 100644 --- a/src/qprojectM-pulseaudio/PulseDeviceChooserDialog.ui +++ b/src/qprojectM-pulseaudio/PulseDeviceChooserDialog.ui @@ -6,7 +6,7 @@ 0 0 378 - 280 + 243 @@ -32,7 +32,7 @@ 20 - 250 + 210 251 24 @@ -57,22 +57,6 @@ Select a source device below. - - - - 20 - 210 - 111 - 29 - - - - Clicking on this means when projectM starts up, it will try to select the active source device to get its sound data. - - - Set as default - - @@ -89,30 +73,9 @@ true - - - test - - - - buttonBox - accepted() - pulseDeviceChooserDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - buttonBox rejected() @@ -129,5 +92,21 @@ + + buttonBox + accepted() + pulseDeviceChooserDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + diff --git a/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.cpp b/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.cpp index db1461bb4..f10b6bdb3 100644 --- a/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.cpp +++ b/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.cpp @@ -2,35 +2,54 @@ #include #include -void QPulseAudioDeviceChooser::writeSettings() { - - QSettings settings ( "projectM", "qprojectM-pulseaudio"); - settings.setValue ( "tryFirstAvailablePlaybackMonitor", - this->tryFirstPlayBackMonitorCheckBox->checkState() == Qt::Checked); - +void QPulseAudioDeviceChooser::writeSettings() +{ + + QSettings settings ( "projectM", "qprojectM-pulseaudio" ); + settings.setValue ( "tryFirstAvailablePlaybackMonitor", + this->tryFirstPlayBackMonitorCheckBox->checkState() == Qt::Checked ); + } -void QPulseAudioDeviceChooser::readSettings() { - -QSettings settings ( "projectM", "qprojectM-pulseaudio"); +void QPulseAudioDeviceChooser::readSettings() +{ + + QSettings settings ( "projectM", "qprojectM-pulseaudio" ); + + bool tryFirst = settings.value + ( "tryFirstAvailablePlaybackMonitor", true ).toBool() ; + + this->tryFirstPlayBackMonitorCheckBox->setCheckState + ( tryFirst ? Qt::Checked : Qt::Unchecked ); + + if ( !tryFirst ) + { + + + } -this->tryFirstPlayBackMonitorCheckBox->setCheckState - (settings.value("tryFirstAvailablePlaybackMonitor", true).toBool() ? Qt::Checked : Qt::Unchecked); } -QPulseAudioDeviceChooser::QPulseAudioDeviceChooser(const QHash & devices, QWidget * parent = 0, Qt::WindowFlags f) : QDialog(parent, f), m_qpulseAudioDeviceModel(devices, this) { - setupUi(this); +QPulseAudioDeviceChooser::QPulseAudioDeviceChooser ( QPulseAudioThread * qpulseAudioThread, QWidget * parent = 0, Qt::WindowFlags f ) : QDialog ( parent, f ), _qpulseAudioDeviceModel ( qpulseAudioThread->devices(), this ), _qpulseAudioThread ( qpulseAudioThread ) +{ + + setupUi ( this ); readSettings(); qDebug() << "setting model"; - this->devicesListView->setModel(&m_qpulseAudioDeviceModel); + this->devicesListView->setModel ( &_qpulseAudioDeviceModel ); + +// void QAbstractItemView::selectionChanged ( const QItemSelection & selected, const QItemSelection & deselected ) [virtual protected slot] + + connect ( devicesListView, SIGNAL ( doubleClicked ( const QModelIndex& ) ), _qpulseAudioThread, SLOT ( connectDevice ( const QModelIndex& ) ) ); + //connect(buttonBox, SIGNAL(accepted()), _qpulseAudioThread, SLOT(connectDevice(device)); } -void QPulseAudioDeviceChooser::open() { - +void QPulseAudioDeviceChooser::open() +{ + this->show(); - //this->devicesListView->show() - + } diff --git a/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.hpp b/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.hpp index b0cb67daa..51cb7c3a5 100644 --- a/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.hpp +++ b/src/qprojectM-pulseaudio/QPulseAudioDeviceChooser.hpp @@ -2,6 +2,8 @@ #define QPULSEAUDIO_DEV_CHOOSER_HPP #include "ui_PulseDeviceChooserDialog.h" #include "QPulseAudioDeviceModel.hpp" +#include "QPulseAudioThread.hpp" + class QDialog; @@ -10,7 +12,7 @@ class QPulseAudioDeviceChooser : public QDialog, public Ui::pulseDeviceChooserDi Q_OBJECT public: - QPulseAudioDeviceChooser(const QHash & devices, QWidget * parent, Qt::WindowFlags f=0); + QPulseAudioDeviceChooser(QPulseAudioThread * pulseAudioThread, QWidget * parent, Qt::WindowFlags f=0); typedef QHash SourceContainer; public slots: @@ -19,6 +21,7 @@ class QPulseAudioDeviceChooser : public QDialog, public Ui::pulseDeviceChooserDi void readSettings(); void writeSettings(); private: - QPulseAudioDeviceModel m_qpulseAudioDeviceModel; + QPulseAudioDeviceModel _qpulseAudioDeviceModel; + QPulseAudioThread * _qpulseAudioThread; }; #endif diff --git a/src/qprojectM-pulseaudio/QPulseAudioThread.cpp b/src/qprojectM-pulseaudio/QPulseAudioThread.cpp index 6720080c1..7e3e48c8a 100644 --- a/src/qprojectM-pulseaudio/QPulseAudioThread.cpp +++ b/src/qprojectM-pulseaudio/QPulseAudioThread.cpp @@ -74,7 +74,8 @@ static pa_sample_spec sample_spec ; QPulseAudioThread::SourceContainer QPulseAudioThread::sourceList; -QPulseAudioThread::QPulseAudioThread ( int _argc, char **_argv, projectM * _projectM, QObject * parent ) : QThread ( parent ), argc ( _argc ), argv ( _argv ), m_projectM ( _projectM ), sourceIndex ( -1 ) { +QPulseAudioThread::QPulseAudioThread ( int _argc, char **_argv, projectM * _projectM, QObject * parent ) : QThread ( parent ), argc ( _argc ), argv ( _argv ), m_projectM ( _projectM ), _deviceIndex ( -1 ) +{ } @@ -87,7 +88,9 @@ QPulseAudioThread::~QPulseAudioThread() void QPulseAudioThread::cleanup() { + _deviceIndex = -1; pa_threaded_mainloop_stop ( mainloop ); + if ( stream ) pa_stream_unref ( stream ); @@ -136,38 +139,14 @@ void QPulseAudioThread::cleanup() return ; } -void QPulseAudioThread::connectSource ( int index ) +void QPulseAudioThread::connectHelper ( int index ) { - if ( stream ) - pa_stream_disconnect ( stream ); - + assert(stream); pa_stream_flags_t flags = ( pa_stream_flags_t ) 0; - if ( index < 0 ) - { - if ( sourceList.empty() ) - { - qDebug() << "failed to discover any source devices"; - return; - } - - index = -1; - for ( SourceContainer::const_iterator pos = sourceList.begin(); pos != sourceList.end(); ++pos ) - { - index++; - qDebug() << "Scanning " << *pos; - if ( ( *pos).contains ( "monitor" ) ) - { - qDebug() << "connecting to monitor device" << *pos; - break; - } - } - assert ( !sourceList.empty() ); - } - - assert (index < sourceList.count()); int r; + if ( ( ( r = pa_stream_connect_record ( stream, sourceList[index].toStdString().c_str(), NULL, flags ) ) ) < 0 ) { fprintf ( stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror ( pa_context_errno ( context ) ) ); @@ -175,6 +154,71 @@ void QPulseAudioThread::connectSource ( int index ) } +int QPulseAudioThread::scanForPlaybackMonitor() { + + int count = -1; + for ( SourceContainer::const_iterator pos = sourceList.begin(); pos != sourceList.end(); ++pos ) + { + count++; + qDebug() << "Scanning " << *pos; + if ( ( *pos ).contains ( "monitor" ) ) + { + return count; + } + } + + /// @bug return value sucks. think + return 0; + +} + +void QPulseAudioThread::connectDevice ( const QModelIndex & index ) +{ + + if (index.isValid()) + _deviceIndex = index.row(); + else + _deviceIndex = scanForPlaybackMonitor(); + + qDebug() << "connect device: " << _deviceIndex; + + if (stream && (pa_stream_get_state(stream) == PA_STREAM_READY)) + { + //qDebug() << "disconnect"; + pa_stream_disconnect ( stream ); + // pa_stream_unref(stream); + //qDebug() << "* return *"; + + } + + assert(context); + +switch (pa_stream_get_state(stream)) { + case PA_STREAM_UNCONNECTED:// The stream is not yet connected to any sink or source. + qDebug() << "unconnected: connecting..."; + connectHelper(_deviceIndex); + break; +case PA_STREAM_CREATING ://The stream is being created. + break; +case PA_STREAM_READY :// The stream is established, you may pass audio data to it now. + connectHelper(_deviceIndex); + + qDebug() << "stream is still ready, waiting for callback..."; + break; +case PA_STREAM_FAILED :// An error occured that made the stream invalid. + qDebug() << "stream is now invalid. great."; + break; +case PA_STREAM_TERMINATED:// The stream has been terminated cleanly. + qDebug() << "terminated..."; + break; +} + + + + +} + + /* A shortcut for terminating the application */ void QPulseAudioThread::pulseQuit ( int ret ) { @@ -222,38 +266,50 @@ void QPulseAudioThread::stream_read_callback ( pa_stream *s, size_t length, void void QPulseAudioThread::stream_state_callback ( pa_stream *s, void *userdata ) { assert ( s ); + QPulseAudioThread * thread = (QPulseAudioThread *)userdata; switch ( pa_stream_get_state ( s ) ) { - case PA_STREAM_CREATING: - case PA_STREAM_TERMINATED: + case PA_STREAM_UNCONNECTED: + qDebug() << "UNCONNECTED"; + break; + case PA_STREAM_CREATING: + qDebug() << "CREATED"; + break; + case PA_STREAM_TERMINATED: + qDebug() << "TERMINATED"; break; - case PA_STREAM_READY: + qDebug() << "READY"; if ( verbose ) { const pa_buffer_attr *a; - fprintf ( stderr, "Stream successfully created.\n" ); if ( ! ( a = pa_stream_get_buffer_attr ( s ) ) ) fprintf ( stderr, "pa_stream_get_buffer_attr() failed: %s\n", pa_strerror ( pa_context_errno ( pa_stream_get_context ( s ) ) ) ); else { - - //fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize); + fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize); } - } - + } break; - case PA_STREAM_FAILED: + qDebug() << "FAILED"; default: fprintf ( stderr, "Stream error: %s\n", pa_strerror ( pa_context_errno ( pa_stream_get_context ( s ) ) ) ); pulseQuit ( 1 ); } } + +static void stream_moved_callback(pa_stream *s, void *userdata) { + assert(s); + + if (verbose) + fprintf(stderr, "Stream moved to device %s (%u, %ssuspended).\n", pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : "not "); +} + /* This is called whenever the context status changes */ void QPulseAudioThread::context_state_callback ( pa_context *c, void *userdata ) { @@ -270,12 +326,12 @@ void QPulseAudioThread::context_state_callback ( pa_context *c, void *userdata ) { int r; - initialize_callbacks ( ( QPulseAudioThread * ) userdata ); - + assert ( c && !stream ); if ( verbose ) fprintf ( stderr, "Connection established.\n" ); + if ( ! ( stream = pa_stream_new ( c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL ) ) ) { @@ -283,9 +339,11 @@ void QPulseAudioThread::context_state_callback ( pa_context *c, void *userdata ) goto fail; } - pa_stream_set_state_callback ( stream, stream_state_callback, NULL ); - pa_stream_set_read_callback ( stream, stream_read_callback, NULL ); + initialize_callbacks ( ( QPulseAudioThread * ) userdata ); + pa_stream_set_state_callback ( stream, stream_state_callback, userdata ); + pa_stream_set_read_callback ( stream, stream_read_callback, userdata ); + pa_stream_set_moved_callback(stream, stream_moved_callback, userdata); break; } @@ -312,33 +370,6 @@ void QPulseAudioThread::context_drain_complete ( pa_context*c, void *userdata ) pa_context_disconnect ( c ); } -/* Stream draining complete */ -void QPulseAudioThread::stream_drain_complete ( pa_stream*s, int success, void *userdata ) -{ - pa_operation *o; - - if ( !success ) - { - fprintf ( stderr, "Failed to drain stream: %s\n", pa_strerror ( pa_context_errno ( context ) ) ); - pulseQuit ( 1 ); - } - - if ( verbose ) - fprintf ( stderr, "Playback stream drained.\n" ); - - pa_stream_disconnect ( stream ); - pa_stream_unref ( stream ); - stream = NULL; - - if ( ! ( o = pa_context_drain ( context, context_drain_complete, NULL ) ) ) - pa_context_disconnect ( context ); - else - { - if ( verbose ) - fprintf ( stderr, "Draining connection to server.\n" ); - } -} - /* Some data may be written to STDOUT */ void QPulseAudioThread::stdout_callback ( pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata ) { @@ -352,9 +383,13 @@ void QPulseAudioThread::stdout_callback ( pa_mainloop_api*a, pa_io_event *e, int } else { - projectM * prjm = static_cast ( userdata ); - prjm->pcm->addPCMfloat ( buffer+buffer_index, buffer_length/ ( sizeof ( float ) ) ); + //int * int_buf = (int *) buffer; + //qDebug() << int_buf[buffer_index]; + //qDebug() << buffer[buffer_index]; + + prjm->pcm->addPCMfloat + ( buffer+buffer_index, buffer_length / ( sizeof ( float ) ) ); assert ( buffer_length ); pa_xfree ( buffer ); @@ -414,13 +449,14 @@ void QPulseAudioThread::pa_source_info_callback ( pa_context *c, const pa_source int index = i->index; QString name = i->name; - pulseThread->insertSource(index,name); + pulseThread->insertSource ( index,name ); } - else { + else + { qDebug() << "End of device list"; assert ( eol ); - pulseThread->connectSource ( -1 ); + pulseThread->connectDevice (); } } @@ -529,11 +565,11 @@ void QPulseAudioThread::run() mainloop_api = pa_threaded_mainloop_get_api ( mainloop ); - r = pa_signal_init ( mainloop_api ); assert ( r == 0 ); pa_signal_new ( SIGINT, exit_signal_callback, NULL ); pa_signal_new ( SIGTERM, exit_signal_callback, NULL ); + #ifdef SIGUSR1 pa_signal_new ( SIGUSR1, sigusr1_signal_callback, NULL ); #endif @@ -541,7 +577,6 @@ void QPulseAudioThread::run() signal ( SIGPIPE, SIG_IGN ); #endif - if ( ! ( stdio_event = mainloop_api->io_new ( mainloop_api, STDOUT_FILENO, PA_IO_EVENT_OUTPUT, @@ -602,6 +637,8 @@ void QPulseAudioThread::initialize_callbacks ( QPulseAudioThread * pulseThread ) //pa_operation_unref(pa_context_get_source_output_info_list(&c, source_output_info_callback, this)); //pa_operation_unref(pa_context_get_sample_info_list(&c, sample_info_callback, this)); + + //pa_context_set_drain pa_context_set_subscribe_callback ( context, subscribe_callback, pulseThread ); if ( op = pa_context_subscribe ( context, ( enum pa_subscription_mask ) diff --git a/src/qprojectM-pulseaudio/QPulseAudioThread.hpp b/src/qprojectM-pulseaudio/QPulseAudioThread.hpp index 7bddeb699..2358a09c0 100644 --- a/src/qprojectM-pulseaudio/QPulseAudioThread.hpp +++ b/src/qprojectM-pulseaudio/QPulseAudioThread.hpp @@ -1,9 +1,10 @@ -#ifndef PULSE_AUDIO_THREAD +#ifndef QPULSE_AUDIO_THREAD +#define QPULSE_AUDIO_THREAD #include #include #include #include - +#include #include extern "C" @@ -24,7 +25,7 @@ class QPulseAudioThread : public QThread typedef QHash SourceContainer; QPulseAudioThread () {} QPulseAudioThread(int _argc, char **_argv, projectM * projectM, QObject *parent); - virtual ~QPulseAudioThread() ; + virtual ~QPulseAudioThread(); void run(); void cleanup(); @@ -32,13 +33,20 @@ class QPulseAudioThread : public QThread return sourceList; } + inline int deviceIndex() { + return _deviceIndex; + } + public slots: inline void insertSource(int index, const QString & name) { sourceList[index]= name; } - void connectSource(int index); + void connectDevice(const QModelIndex & index = QModelIndex()); + private: + static int scanForPlaybackMonitor(); + static void connectHelper(int index); static void pulseQuit ( int ret ); static void stream_read_callback ( pa_stream *s, size_t length, void *userdata ); static void stream_state_callback ( pa_stream *s, void *userdata ); @@ -56,7 +64,7 @@ class QPulseAudioThread : public QThread static SourceContainer sourceList; - int sourceIndex; + int _deviceIndex; int argc; char ** argv; projectM * m_projectM; diff --git a/src/qprojectM-pulseaudio/qprojectM-pulseaudio.cpp b/src/qprojectM-pulseaudio/qprojectM-pulseaudio.cpp index 09947292d..7c41e95b8 100644 --- a/src/qprojectM-pulseaudio/qprojectM-pulseaudio.cpp +++ b/src/qprojectM-pulseaudio/qprojectM-pulseaudio.cpp @@ -105,7 +105,7 @@ int main ( int argc, char*argv[] ) QPulseAudioThread * pulseThread = new QPulseAudioThread(argc, argv, mainWindow->getQProjectM(), mainWindow); - QPulseAudioDeviceChooser devChooser(pulseThread->devices(), mainWindow); + QPulseAudioDeviceChooser devChooser(pulseThread, mainWindow); QApplication::connect(&pulseAction, SIGNAL(triggered()), &devChooser, SLOT(open())); pulseThread->start();