Ticket #5473: pulse-audio-disable-proof-of-concept.patch

File pulse-audio-disable-proof-of-concept.patch, 15.2 KB (added by danielk, 17 years ago)

Proof of concept patch for disabling pulse audio at startup. This IS NOT usable for production purposes.

  • configure

     
    10401040'
    10411041
    10421042MYTHTV_LIST='
     1043    audio_pulse
    10431044    audio_alsa
    10441045    audio_arts
    10451046    audio_jack
     
    13111312CONFIG_INCLUDEPATH=""
    13121313PROFILEFLAGS=""
    13131314
     1315audio_pulse="default"
     1316audio_pulse_libs="-lpulse"
    13141317audio_alsa="default"
    13151318audio_alsa_libs="-lasound"
    13161319audio_arts="default"
     
    28392842check_header sys/soundcard.h
    28402843check_header soundcard.h
    28412844
     2845# PulseAudio probe
     2846! disabled audio_pulse &&
     2847    check_lib pulse/version.h pa_get_library_version $audio_pulse_libs &&
     2848    enable  audio_pulse ||
     2849    disable audio_pulse
     2850
    28422851# ALSA probe
    28432852! disabled audio_alsa &&
    28442853    check_lib alsa/asoundlib.h snd_asoundlib_version $audio_alsa_libs &&
     
    33213330if enabled frontend; then
    33223331  echo
    33233332  echo "# Sound Output Support"
     3333  echo "PulseAudio support        ${audio_pulse-no}"
    33243334  echo "OSS support               ${audio_oss-no}"
    33253335  echo "ALSA support              ${audio_alsa-no}"
    33263336  echo "aRts support              ${audio_arts-no}"
     
    35173527  echo "CONFIG_AUDIO_ALSA_LIBS=$audio_alsa_libs" >> $MYTH_CONFIG_MAK
    35183528fi
    35193529
     3530if enabled audio_pulse; then
     3531  append CCONFIG "using_pulse"
     3532  echo "CONFIG_AUDIO_PULSE_LIBS=$audio_pulse_libs" >> $MYTH_CONFIG_MAK
     3533fi
     3534
    35203535if enabled audio_arts; then
    35213536    append CCONFIG "using_arts"
    35223537  echo "CONFIG_AUDIO_ARTS_LIBS=$audio_arts_libs" >> $MYTH_CONFIG_MAK
  • libs/libmyth/audiopulseutil.h

     
     1bool suspend_pulseaudio(void);
     2
     3int handle_pulseaudio(void);
  • libs/libmyth/libmyth.pro

     
    105105    LIBS += $$OSS_LIBS
    106106}
    107107
     108using_pulse {
     109    DEFINES += USING_PULSE
     110    SOURCES += audiopulseutil.cpp
     111    HEADERS += audiopulseutil.h
     112    LIBS += $$PULSE_LIBS
     113}
     114
    108115unix:!cygwin {
    109116    SOURCES += mediamonitor-unix.cpp
    110117    HEADERS += mediamonitor-unix.h
  • libs/libmyth/audiopulseutil.cpp

     
     1/***
     2 *   This file was part of PulseAudio, the license has been upgraded to GPL v2
     3 *   or later as per the LGPL grant this was originally distributed under.
     4 *
     5 *   Copyright 2004-2006 Lennart Poettering
     6 *
     7 *   MythTV is free software; you can redistribute it and/or modify
     8 *   it under the terms of the GNU General Public License as published by
     9 *   the Free Software Foundation; either version 2 of the License, or
     10 *   (at your option) any later version.
     11 *
     12 *   This program is distributed in the hope that it will be useful,
     13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 *   GNU General Public License for more details.
     16 *
     17 *   You should have received a copy of the GNU General Public License
     18 *   along with this program; if not, write to the Free Software
     19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 */
     21
     22#include <sys/types.h>
     23#include <sys/wait.h>
     24
     25#include <signal.h>
     26#include <string.h>
     27#include <errno.h>
     28#include <unistd.h>
     29#include <assert.h>
     30#include <stdio.h>
     31#include <stdlib.h>
     32#include <limits.h>
     33#include <getopt.h>
     34#include <locale.h>
     35
     36#ifdef __linux__
     37#include <sys/prctl.h>
     38#endif
     39
     40#include <pulse/pulseaudio.h>
     41
     42#include <QThread>
     43#include <QMutex>
     44#include <QWaitCondition>
     45#include "mythverbose.h"
     46#include "util.h" // for IsPulseAudioRunning()
     47#include "exitcodes.h"
     48
     49#define BUFSIZE 1024
     50
     51#define LOC      QString("AudioPulseUtil: ")
     52#define LOC_WARN QString("AudioPulseUtil, Warning: ")
     53#define LOC_ERR  QString("AudioPulseUtil, Error: ")
     54#define pa_assert(X) assert(X)
     55#define pa_assert_se(X) do { bool i = (bool) X; assert(i); } while (0)
     56#define _(X) X
     57
     58static pa_context *context = NULL;
     59static pa_mainloop_api *mainloop_api = NULL;
     60static int dead = 1;
     61static QMutex pa_lock;
     62static QWaitCondition pa_wait;
     63enum pa_values {
     64    kPA_undefined                   = -1,
     65    kPA_suspended                   = +0,
     66    kPA_not_suspended_remote_server = +1,
     67    kPA_not_suspended_error         = +2,
     68    kPA_not_suspended_success       = +3,
     69};
     70static int pa_value = -1;
     71
     72static void set_pa_value(int new_value)
     73{
     74    QMutexLocker ml(&pa_lock);
     75    pa_value = new_value;
     76    pa_wait.wakeAll();
     77}
     78
     79static void quit(int ret) {
     80    pa_assert(mainloop_api);
     81    mainloop_api->quit(mainloop_api, ret);
     82}
     83
     84
     85static void context_drain_complete(pa_context *c, void *userdata) {
     86    pa_context_disconnect(c);
     87}
     88
     89static void drain(void) {
     90    pa_operation *o;
     91
     92    if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
     93        pa_context_disconnect(context);
     94    else
     95        pa_operation_unref(o);
     96}
     97
     98static void suspend_complete(pa_context *c, int success, void *userdata)
     99{
     100    if (!success)
     101    {
     102        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failure to suspend: %1")
     103                .arg(pa_strerror(pa_context_errno(c))));
     104
     105        set_pa_value(kPA_not_suspended_error);
     106
     107        return;
     108    }
     109
     110    VERBOSE(VB_GENERAL, LOC + "Suspend Success");
     111
     112    set_pa_value(kPA_suspended);
     113}
     114
     115static void resume_complete(pa_context *c, int success, void *userdata)
     116{
     117    static int n = 0;
     118
     119    n++;
     120
     121    if (!success)
     122    {
     123        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failure to resume: %1")
     124                .arg(pa_strerror(pa_context_errno(c))));
     125        return;
     126    }
     127
     128    if (n >= 2)
     129        drain(); /* drain and quit */
     130
     131    VERBOSE(VB_GENERAL, LOC + "Resume Success");
     132
     133    set_pa_value(kPA_not_suspended_success);
     134}
     135
     136static void context_state_callback(pa_context *c, void *userdata)
     137{
     138    pa_assert(c);
     139
     140    switch (pa_context_get_state(c))
     141    {
     142        case PA_CONTEXT_CONNECTING:
     143        case PA_CONTEXT_AUTHORIZING:
     144        case PA_CONTEXT_SETTING_NAME:
     145            break;
     146
     147        case PA_CONTEXT_READY:
     148            if (pa_context_is_local(c))
     149            {
     150                pa_operation_unref(
     151                    pa_context_suspend_sink_by_index(
     152                        c, PA_INVALID_INDEX, 1, suspend_complete, NULL));
     153                pa_operation_unref(
     154                    pa_context_suspend_source_by_index(
     155                        c, PA_INVALID_INDEX, 1, suspend_complete, NULL));
     156            }
     157            else
     158            {
     159                VERBOSE(VB_IMPORTANT, LOC_ERR +
     160                        "Sound server is not local, can not suspend.");
     161
     162                set_pa_value(kPA_not_suspended_remote_server);
     163            }
     164
     165            break;
     166
     167        case PA_CONTEXT_TERMINATED:
     168            quit(0);
     169            break;
     170
     171        case PA_CONTEXT_FAILED:
     172        default:
     173            VERBOSE(VB_IMPORTANT, LOC_WARN +
     174                    "Can not connect to sound server, can not suspend." +
     175                    QString("\n\t\t\t%1")
     176                    .arg(pa_strerror(pa_context_errno(c))));
     177
     178            set_pa_value(kPA_not_suspended_error);
     179
     180            pa_context_unref(context);
     181            context = NULL;
     182
     183            //if (child_pid == (pid_t) -1)
     184            //    /* not started yet, then we do it now */
     185            //    start_child();
     186            //else if (dead)
     187            //    /* already started, and dead, so let's quit */
     188            //    quit(1);
     189
     190            break;
     191    }
     192}
     193
     194static void sigchld_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
     195
     196    return;//**//
     197
     198    int status = 0;
     199    pid_t p;
     200
     201    p = waitpid(-1, &status, WNOHANG);
     202
     203    //if (p != child_pid)
     204    //    return;
     205
     206    dead = 1;
     207
     208    if (WIFEXITED(status))
     209    {
     210        //child_ret = WEXITSTATUS(status);
     211    }
     212    else if (WIFSIGNALED(status)) {
     213        fprintf(stderr, _("WARNING: Child process terminated by signal %u\n"), WTERMSIG(status));
     214        //child_ret = 1;
     215    }
     216
     217    if (context) {
     218        if (pa_context_is_local(context)) {
     219            /* A context is around, so let's resume */
     220            pa_operation_unref(pa_context_suspend_sink_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL));
     221            pa_operation_unref(pa_context_suspend_source_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL));
     222        } else
     223            drain();
     224    } else
     225        /* Hmm, no context here, so let's terminate right away */
     226        quit(0);
     227}
     228
     229void suspend_pulseaudio_internal(void) {
     230    pa_mainloop* m = NULL;
     231    int ret = 1;
     232    char *server = NULL;
     233    const char *bn = "mythtv";
     234
     235    //setlocale(LC_ALL, "");
     236    //bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
     237
     238    if (!(m = pa_mainloop_new())) {
     239        fprintf(stderr, _("pa_mainloop_new() failed.\n"));
     240        goto quit;
     241    }
     242
     243    mainloop_api = pa_mainloop_get_api(m);
     244    if (!mainloop_api)
     245        goto quit;
     246
     247    if (pa_signal_init(mainloop_api) != 0)
     248        goto quit;
     249
     250    pa_signal_new(SIGCHLD, sigchld_callback, NULL);
     251
     252    if (!(context = pa_context_new(mainloop_api, bn))) {
     253        fprintf(stderr, _("pa_context_new() failed.\n"));
     254        goto quit;
     255    }
     256
     257    pa_context_set_state_callback(context, context_state_callback, NULL);
     258    pa_context_connect(context, server, PA_CONTEXT_NOAUTOSPAWN, NULL);
     259
     260    if (pa_mainloop_run(m, &ret) < 0) {
     261        fprintf(stderr, _("pa_mainloop_run() failed.\n"));
     262        goto quit;
     263    }
     264
     265quit:
     266    if (context)
     267        pa_context_unref(context);
     268
     269    if (m) {
     270        pa_signal_done();
     271        pa_mainloop_free(m);
     272    }
     273
     274    pa_xfree(server);
     275}
     276
     277class PAThread : public QThread
     278{
     279  public:
     280    void run(void)
     281    {
     282        VERBOSE(VB_IMPORTANT, LOC + "Here - begin");
     283        suspend_pulseaudio_internal();
     284        VERBOSE(VB_IMPORTANT, LOC + "Here - end");
     285    }
     286};
     287
     288/// \returns true if successful
     289bool suspend_pulseaudio(void)
     290{
     291    QThread *t = new PAThread();
     292    t->start();
     293
     294    QMutexLocker ml(&pa_lock);
     295    while (pa_value < 0)
     296        pa_wait.wait(&pa_lock);
     297
     298    return kPA_suspended == pa_value;
     299}
     300
     301int handle_pulseaudio(void)
     302{
     303#ifndef USING_PULSE
     304    if (IsPulseAudioRunning())
     305    {
     306        VERBOSE(VB_IMPORTANT, "ERROR: ***Pulse Audio is running!!!!***");
     307        VERBOSE(VB_IMPORTANT, "ERROR: But MythTV has not been compiled "
     308                "with Pulse Audio disabling support. EXITING!");
     309        return GENERIC_EXIT_NOT_OK;
     310    }
     311#else
     312    if (getenv("EXPERIMENTALLY_ALLOW_PULSE_AUDIO"))
     313    {
     314        VERBOSE(VB_IMPORTANT, "WARNING: ");
     315        VERBOSE(VB_IMPORTANT, "WARNING: ***Pulse Audio is running!!!!***");
     316        VERBOSE(VB_IMPORTANT, "WARNING: ");
     317        VERBOSE(VB_IMPORTANT, "WARNING: You have told MythTV to ignore it.");
     318        VERBOSE(VB_IMPORTANT, "WARNING: ");
     319    }
     320    else if (IsPulseAudioRunning() && !suspend_pulseaudio())
     321    {
     322        VERBOSE(VB_IMPORTANT, "ERROR: ***Pulse Audio is running!!!!***");
     323        VERBOSE(VB_IMPORTANT,
     324                "ERROR: But MythTV was not able to suspend it. EXITING!");
     325
     326        return GENERIC_EXIT_NOT_OK;
     327    }
     328#endif
     329
     330    return GENERIC_EXIT_OK;
     331}
  • programs/mythfrontend/main.cpp

     
    6161#include "mythuihelper.h"
    6262#include "mythdirs.h"
    6363#include "mythosdmenueditor.h"
    64 #include "util.h" // for IsPulseAudioRunning()
     64#include "audiopulseutil.h"
    6565
    6666static ExitPrompter   *exitPopup = NULL;
    6767static MythThemedMenu *menu;
     
    10381038
    10391039int main(int argc, char **argv)
    10401040{
    1041     if (IsPulseAudioRunning())
    1042     {
    1043         cerr << "***Pulse Audio is running!!!!***" << endl
    1044              << "Pulse Audio is incompatible with MythTV." << endl;
    1045         return GENERIC_EXIT_NOT_OK;
    1046     }
    1047 
    10481041    bool bPromptForBackend    = false;
    10491042    bool bBypassAutoDiscovery = false;
    10501043    bool upgradeAllowed = false;
     
    11671160    }
    11681161    QMap<QString,QString> settingsOverride = cmdline.GetSettingsOverride();
    11691162
     1163    int pa_ret = handle_pulseaudio();
     1164    if (GENERIC_EXIT_OK != pa_ret)
     1165        return pa_ret;
     1166
    11701167    if (logfile.size())
    11711168    {
    11721169        if (log_rotate(1) < 0)
  • programs/mythfrontend/mythfrontend.pro

     
    6363using_opengl_video:DEFINES += USING_OPENGL_VIDEO
    6464using_vdpau:DEFINES += USING_VDPAU
    6565
     66using_pulse:DEFINES += USING_PULSE
    6667using_alsa:DEFINES += USING_ALSA
    6768using_arts:DEFINES += USING_ARTS
    6869using_jack:DEFINES += USING_JACK
  • programs/mythtv/main.cpp

     
    2020#include "compat.h"
    2121#include "mythuihelper.h"
    2222#include "dbcheck.h"
    23 #include "util.h" // for IsPulseAudioRunning()
    2423#include "myththemebase.h"
     24#include "audiopulseutil.h"
    2525
     26
    2627static void *run_priv_thread(void *data)
    2728{
    2829    (void)data;
     
    7778
    7879int main(int argc, char *argv[])
    7980{
    80     if (IsPulseAudioRunning())
    81     {
    82         cerr << "***Pulse Audio is running!!!!***" << endl
    83              << "Pulse Audio is incompatible with MythTV." << endl;
    84         return GENERIC_EXIT_NOT_OK;
    85     }
    86 
    8781    bool cmdline_err;
    8882    MythCommandLineParser cmdline(
    8983        kCLPOverrideSettings     |
     
    207201   
    208202    GetMythUI()->LoadQtConfig();
    209203
     204    int pa_ret = handle_pulseaudio();
     205    if (GENERIC_EXIT_OK != pa_ret)
     206        return pa_ret;
     207
    210208#if defined(Q_OS_MACX)
    211209    // Mac OS X doesn't define the AudioOutputDevice setting
    212210#else
  • programs/mythtv/mythtv.pro

     
    2323}
    2424
    2525using_x11:DEFINES += USING_X11
     26using_xv:DEFINES += USING_XV
     27using_ivtv:DEFINES += USING_IVTV
     28using_xvmc:DEFINES += USING_XVMC
     29using_xvmc_vld:DEFINES += USING_XVMC_VLD
     30using_xrandr:DEFINES += USING_XRANDR
     31using_opengl_vsync:DEFINES += USING_OPENGL_VSYNC
     32using_opengl_video:DEFINES += USING_OPENGL_VIDEO
     33using_vdpau:DEFINES += USING_VDPAU
     34
     35using_pulse:DEFINES += USING_PULSE
     36using_alsa:DEFINES += USING_ALSA
     37using_arts:DEFINES += USING_ARTS
     38using_jack:DEFINES += USING_JACK
     39using_oss: DEFINES += USING_OSS
     40macx:      DEFINES += USING_COREAUDIO
  • settings.pro

     
    123123ALSA_LIBS = $$CONFIG_AUDIO_ALSA_LIBS
    124124ARTS_LIBS = $$CONFIG_AUDIO_ARTS_LIBS
    125125JACK_LIBS = $$CONFIG_AUDIO_JACK_LIBS
     126PULSE_LIBS = $$CONFIG_AUDIO_PULSE_LIBS
    126127
    127128EXTRA_LIBS = $$FREETYPE_LIBS
    128129EXTRA_LIBS += $$CONFIG_FIREWIRE_LIBS
     
    135136EXTRA_LIBS += $$CONFIG_XVMC_LIBS
    136137EXTRA_LIBS += $$CONFIG_OPENGL_LIBS
    137138EXTRA_LIBS += $$FRIBIDI_LIBS
     139using_pulse:EXTRA_LIBS += $$PULSE_LIBS
    138140
    139141LIRC_LIBS = $$CONFIG_LIRC_LIBS