Ticket #7517: volume_control_trunk_r24763.patch

File volume_control_trunk_r24763.patch, 139.3 KB (added by mythtv@…, 16 years ago)
  • mythplugins/mythmusic/mythmusic/playbackbox.cpp

     
    9898
    9999    // Possibly (user-defined) control the volume
    100100
    101     volume_control = false;
    102     volume_display_timer = new QTimer(this);
    103     if (gCoreContext->GetNumSetting("MythControlsVolume", 0))
     101    volume_control = VolumeControlManager::GetControl(gCoreContext->GetSetting("MixerDevice"));
     102    if (volume_control)
    104103    {
    105         volume_control = true;
     104        connect(volume_control.data(), SIGNAL(changedVolume(int)),
     105                this, SLOT(VolumeChanged(int)));
     106        connect(volume_control.data(), SIGNAL(changedMute(bool)),
     107                this, SLOT(MuteChanged(bool)));
    106108    }
     109
     110    volume_display_timer = new QTimer(this);
    107111    volume_display_timer->setSingleShot(true);
    108112    volume_display_timer->start(2000);
    109113    connect(volume_display_timer, SIGNAL(timeout()),
     
    11781182    if (volume_control && gPlayer->getOutput())
    11791183    {
    11801184        if (up_or_down)
    1181             gPlayer->getOutput()->AdjustCurrentVolume(2);
     1185            gPlayer->incVolume();
    11821186        else
    1183             gPlayer->getOutput()->AdjustCurrentVolume(-2);
     1187            gPlayer->decVolume();
    11841188        showVolume(true);
    11851189    }
    11861190}
     
    12011205{
    12021206    if (volume_control && gPlayer->getOutput())
    12031207    {
    1204         gPlayer->getOutput()->ToggleMute();
     1208        gPlayer->toggleMute();
    12051209        showVolume(true);
    12061210    }
    12071211}
     
    12401244        {
    12411245            if (on_or_off)
    12421246            {
    1243                 volume_status->SetUsed(gPlayer->getOutput()->GetCurrentVolume());
     1247                volume_status->SetUsed(gPlayer->getVolume());
    12441248                volume_status->SetOrder(0);
    12451249                volume_status->refresh();
    12461250                volume_display_timer->setSingleShot(true);
     
    24522456
    24532457    return time_string;
    24542458}
     2459
     2460void PlaybackBoxMusic::VolumeChanged(int)
     2461{
     2462     showVolume(true);
     2463}
     2464
     2465void PlaybackBoxMusic::MuteChanged(bool)
     2466{
     2467     showVolume(true);
     2468}
  • mythplugins/mythmusic/mythmusic/musicplayer.h

     
    33
    44#include <mythdialogs.h>
    55#include <audiooutput.h>
     6#include <libmyth/volumecontrolmanager.h>
    67#include <mythobservable.h>
    78
    89#include "metadata.h"
     
    5556
    5657    void setCDDevice(const QString &dev) { m_CDdevice = dev; }
    5758
    58     void      toggleMute(void);
    59     MuteState getMuteState(void) const;
    60     bool      isMuted(void) const { return getMuteState() == kMuteAll; }
     59    void toggleMute(void);
     60    bool isMuted(void) const;
    6161
    6262    void setVolume(int volume);
    6363    void incVolume(void);
     
    176176    AudioOutput *m_output;
    177177    Decoder     *m_decoder;
    178178
     179    QSharedPointer<VolumeControl> volume_control; ///< Volume control interface
     180
    179181    QSet<QObject*>  m_visualisers;
    180182
    181183    QString      m_CDdevice;
  • mythplugins/mythmusic/mythmusic/musicplayer.cpp

     
    8888
    8989    m_autoShowPlayer = (gCoreContext->GetNumSetting("MusicAutoShowPlayer", 1) > 0);
    9090
     91    volume_control = VolumeControlManager::GetControl(gCoreContext->GetSetting("MixerDevice"));
     92
    9193    gCoreContext->addListener(this);
    9294}
    9395
     
    378380
    379381    // TODO: Error checking that device is opened correctly!
    380382    m_output = AudioOutput::OpenAudio(adevice, pdevice, 16, 2, 0, 44100,
    381                                       AUDIOOUTPUT_MUSIC, true, false,
     383                                      AUDIOOUTPUT_MUSIC, false,
    382384                                      gCoreContext->GetNumSetting("MusicDefaultUpmix", 0) + 1);
    383385    m_output->setBufferSize(256 * 1024);
    384386    m_output->SetBlocking(false);
     
    944946
    945947void MusicPlayer::incVolume()
    946948{
    947     if (getOutput())
     949    if (volume_control)
    948950    {
    949         getOutput()->AdjustCurrentVolume(2);
     951        volume_control->increaseVolume();
    950952        sendVolumeChangedEvent();
    951953    }
    952954}
    953955
    954956void MusicPlayer::decVolume()
    955957{
    956     if (getOutput())
     958    if (volume_control)
    957959    {
    958         getOutput()->AdjustCurrentVolume(-2);
     960        volume_control->decreaseVolume();
    959961        sendVolumeChangedEvent();
    960962    }
    961963}
    962964
    963965void MusicPlayer::setVolume(int volume)
    964966{
    965     if (getOutput())
     967    if (volume_control)
    966968    {
    967         getOutput()->SetCurrentVolume(volume);
     969        volume_control->setVolume(volume);
    968970        sendVolumeChangedEvent();
    969971    }
    970972}
    971973
    972974uint MusicPlayer::getVolume(void) const
    973975{
    974     if (m_output)
    975         return m_output->GetCurrentVolume();
     976    if (volume_control)
     977        return volume_control->volume();
    976978    return 0;
    977979}
    978980
    979981void MusicPlayer::toggleMute(void)
    980982{
    981     if (m_output)
     983    if (volume_control)
    982984    {
    983         m_output->ToggleMute();
     985        volume_control->setMute(!volume_control->mute());
    984986        sendVolumeChangedEvent();
    985987    }
    986988}
    987989
    988 MuteState MusicPlayer::getMuteState(void) const
     990bool MusicPlayer::isMuted(void) const
    989991{
    990     if (m_output)
    991         return m_output->GetMuteState();
    992     return kMuteAll;
     992    if (volume_control)
     993        return volume_control->mute();
     994    return true;
    993995}
    994996
    995997void MusicPlayer::toMap(QHash<QString, QString> &map)
  • mythplugins/mythmusic/mythmusic/playbackbox.h

     
    88// mythtv
    99#include <mythwidgets.h>
    1010#include <dialogbox.h>
    11 #include <audiooutput.h>
     11#include <libmyth/volumecontrolmanager.h>
    1212
    1313// mythmusic
    1414#include "mainvisual.h"
     
    101101    bool getInsertPLOptions(InsertPLOption &insertOption,
    102102                            PlayPLOption &playOption, bool &bRemoveDups);
    103103
     104  protected slots:
     105    void VolumeChanged(int volume);
     106    void MuteChanged(bool mute);
     107
    104108  signals:
    105109
    106110    void dummy();   // debugging
     
    172176    bool show_album_art;
    173177    bool show_whole_tree;
    174178    bool keyboard_accelerators;
    175     bool volume_control;
     179    QSharedPointer<VolumeControl> volume_control; ///< Volume control interface
    176180
    177181    QString exit_action;
    178182
  • mythtv/configure

     
    627627    eval "$var=\"\$$var $*\""
    628628}
    629629
     630prepend(){
     631    var=$1
     632    shift
     633    flags_saved && eval "SAVE_$var=\"$* \$SAVE_$var\""
     634    eval "$var=\"$* \$$var\""
     635}
     636
    630637append_uniq(){
    631638    log append_uniq "$@"
    632639    var=$1
     
    36303637    { { ! enabled audio_alsa || die "ERROR: Alsa >= 1.0.16 required"; } &&
    36313638    disable audio_alsa; }
    36323639
     3640# OSS probe
     3641if ! disabled audio_oss ; then
     3642    if test -f /usr/"${libdir_name}"/oss/include/sys/soundcard.h &&
     3643       check_cpp_condition /usr/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then
     3644        disable soundcard_h
     3645        enable sys_soundcard_h
     3646        prepend CONFIG_INCLUDEPATH "/usr/${libdir_name}/oss/include"
     3647    elif test -f /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h &&
     3648       check_cpp_condition /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then
     3649        disable soundcard_h
     3650        enable sys_soundcard_h
     3651        prepend CONFIG_INCLUDEPATH "/usr/local/${libdir_name}/oss/include"
     3652    else
     3653        if enabled soundcard_h ; then
     3654            check_cpp_condition soundcard.h "SOUND_VERSION >= 0x040000" &&
     3655            enable  audio_oss ||
     3656            disable audio_oss
     3657        elif enabled sys_soundcard_h ; then
     3658            check_cpp_condition sys/soundcard.h "SOUND_VERSION >= 0x040000" &&
     3659            enable  audio_oss ||
     3660            disable audio_oss
     3661        fi
     3662    fi
     3663fi
    36333664
    36343665# JACK probe
    36353666! disabled audio_jack &&
  • mythtv/libs/libmythtv/NuppelVideoPlayer.cpp

     
    103103    kDisplayNUVTeletextCaptions,
    104104};
    105105
    106 NuppelVideoPlayer::NuppelVideoPlayer(bool muted)
     106NuppelVideoPlayer::NuppelVideoPlayer()
    107107    : decoder(NULL),                decoder_change_lock(QMutex::Recursive),
    108108      videoOutput(NULL),            player_ctx(NULL),
    109109      no_hardware_decoders(false),
     
    173173      audio_channels(2),            audio_codec(0),
    174174      audio_bits(-1),               audio_samplerate(44100),
    175175      audio_stretchfactor(1.0f),    audio_lock(QMutex::Recursive),
    176       audio_muted_on_creation(muted),
    177176      // Picture-in-Picture stuff
    178177      pip_active(false),            pip_visible(true),
    179178      // Preview window support
     
    373372    audio_samplerate      = (int)samplerate;
    374373}
    375374
    376 uint NuppelVideoPlayer::GetVolume(void)
    377 {
    378     QMutexLocker lock(&audio_lock);
    379     if (audioOutput)
    380         return audioOutput->GetCurrentVolume();
    381     return 0;
    382 }
    383 
    384 bool NuppelVideoPlayer::SetMuted(bool mute)
    385 {
    386     QMutexLocker lock(&audio_lock);
    387     bool is_muted = IsMuted();
    388 
    389     if (audioOutput && !is_muted && mute &&
    390         (kMuteAll == SetMuteState(kMuteAll)))
    391     {
    392         VERBOSE(VB_AUDIO, "muting sound " <<IsMuted());
    393         return true;
    394     }
    395     else if (audioOutput && is_muted && !mute &&
    396              (kMuteOff == SetMuteState(kMuteOff)))
    397     {
    398         VERBOSE(VB_AUDIO, "unmuting sound "<<IsMuted());
    399         return true;
    400     }
    401 
    402     VERBOSE(VB_AUDIO, "not changing sound mute state "<<IsMuted());
    403 
    404     return false;
    405 }
    406 
    407 MuteState NuppelVideoPlayer::SetMuteState(MuteState mstate)
    408 {
    409     QMutexLocker lock(&audio_lock);
    410     if (audioOutput)
    411         return audioOutput->SetMuteState(mstate);
    412     return kMuteAll;
    413 }
    414 
    415 MuteState NuppelVideoPlayer::IncrMuteState(void)
    416 {
    417     QMutexLocker lock(&audio_lock);
    418     MuteState mstate = kMuteAll;
    419     if (audioOutput)
    420         mstate = SetMuteState(VolumeBase::NextMuteState(GetMuteState()));
    421     return mstate;
    422 }
    423 
    424 MuteState NuppelVideoPlayer::GetMuteState(void)
    425 {
    426     QMutexLocker lock(&audio_lock);
    427     if (audioOutput)
    428         return audioOutput->GetMuteState();
    429     return kMuteAll;
    430 }
    431 
    432 uint NuppelVideoPlayer::AdjustVolume(int change)
    433 {
    434     QMutexLocker lock(&audio_lock);
    435     if (audioOutput)
    436         audioOutput->AdjustCurrentVolume(change);
    437     return GetVolume();
    438 }
    439 
    440375void NuppelVideoPlayer::PauseDecoder(void)
    441376{
    442377    decoder_lock.lock();
     
    861796
    862797    if (!audioOutput && !using_null_videoout && player_ctx->IsAudioNeeded())
    863798    {
    864         bool setVolume = gCoreContext->GetNumSetting("MythControlsVolume", 1);
    865799        audioOutput = AudioOutput::OpenAudio(audio_main_device,
    866800                                             audio_passthru_device,
    867801                                             audio_bits, audio_channels,
    868802                                             audio_codec, audio_samplerate,
    869803                                             AUDIOOUTPUT_VIDEO,
    870                                              setVolume, audio_passthru);
     804                                             audio_passthru);
    871805        if (!audioOutput)
    872806            errMsg = QObject::tr("Unable to create AudioOutput.");
    873807        else
     
    889823            VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio");
    890824            no_audio_out = false;
    891825        }
    892         if (audio_muted_on_creation)
    893         {
    894             SetMuteState(kMuteAll);
    895             audio_muted_on_creation = false;
    896         }
    897826    }
    898827
    899828    if (audioOutput)
  • mythtv/libs/libmythtv/avformatdecoder.cpp

     
    496496      audioSamples(NULL),           audioSamplesResampled(NULL),
    497497      reformat_ctx(NULL),           audio_src_fmt(SAMPLE_FMT_NONE),
    498498      allow_ac3_passthru(false),    allow_dts_passthru(false),
    499       internal_vol(false),
    500499      disable_passthru(false),      max_channels(2),
    501500      last_ac3_channels(0),         last_framesRead(0),
    502501      dummy_frame(NULL),
     
    520519    max_channels = (uint) gCoreContext->GetNumSetting("MaxChannels", 2);
    521520    allow_ac3_passthru = (max_channels > 2) ? gCoreContext->GetNumSetting("AC3PassThru", false) : false;
    522521    allow_dts_passthru = (max_channels > 2) ? gCoreContext->GetNumSetting("DTSPassThru", false) : false;
    523     internal_vol = gCoreContext->GetNumSetting("MythControlsVolume", 0);
    524522
    525523    audioIn.sample_size = -32; // force SetupAudioStream to run once
    526524    itv = GetNVP()->GetInteractiveTV();
     
    47014699
    47024700    if (ctx->codec_id == CODEC_ID_AC3)
    47034701        passthru = allow_ac3_passthru &&
    4704                    ctx->channels >= (int)max_channels &&
    4705                    !internal_vol;
     4702                   ctx->channels >= (int)max_channels;
    47064703    else if (ctx->codec_id == CODEC_ID_DTS)
    4707         passthru = allow_dts_passthru && !internal_vol;
     4704        passthru = allow_dts_passthru;
    47084705
    47094706    passthru &= !transcoding && !disable_passthru;
    47104707    // Don't know any cards that support spdif clocked at < 44100
  • mythtv/libs/libmythtv/tv_play.h

     
    3333#include "programinfo.h"
    3434#include "channelutil.h"
    3535#include "videoouttypes.h"
    36 #include "volumebase.h"
     36#include "volumecontrolmanager.h"
    3737#include "inputinfo.h"
    3838#include "channelgroup.h"
    3939
     
    299299    void AddUDPNotifyEvent(const QString &name, const UDPNotifyOSDSet*);
    300300    void ClearUDPNotifyEvents(void);
    301301
     302    void VolumeChanged(int volume);
     303    void MuteChanged(bool mute);
     304
    302305  protected:
    303306    void TreeMenuEntered(OSDListTreeItemEnteredEvent *e);
    304307    void TreeMenuSelected(OSDListTreeItemSelectedEvent *e);
     
    308311    virtual void run(void);
    309312    void TVEventThreadChecks(void);
    310313
    311     void SetMuteTimer(PlayerContext*, int timeout);
    312     bool MuteChannelChange(PlayerContext *ctx);
    313 
    314314    bool eventFilter(QObject *o, QEvent *e);
    315315    static QStringList lastProgramStringList;
    316316    static EMBEDRETURNVOID RunPlaybackBoxPtr;
     
    508508
    509509    vector<long long> TeardownAllNVPs(PlayerContext*);
    510510    void RestartAllNVPs(PlayerContext *lctx,
    511                         const vector<long long> &pos,
    512                         MuteState mctx_mute);
     511                        const vector<long long> &pos);
    513512    void RestartMainNVP(PlayerContext *mctx);
    514513
    515514    void PxPToggleView(  PlayerContext *actx, bool wantPBP);
     
    669668    /// Picture attribute to modify (on arrow left or right)
    670669    PictureAttribute  adjustingPictureAttribute;
    671670
     671    QSharedPointer<VolumeControl> volumeControl; ///< Volume Control interface
     672
    672673    // Ask Allow state
    673674    AskAllowType                 askAllowType;
    674675    QMap<QString,AskProgramInfo> askAllowPrograms;
     
    828829    TimerContextMap      stateChangeTimerId;
    829830    TimerContextMap      signalMonitorTimerId;
    830831    TimerContextMap      tvchainUpdateTimerId;
    831     TimerContextMap      unmuteTimerId;
    832832
    833833    /// Condition to signal that the Event thread is up and running
    834834    QWaitCondition mainLoopCond;
     
    849849
    850850    ///< Timeout for entry modes in msec
    851851    static const uint kInputModeTimeout;
    852     /// Channel changing mute timeout in msec
    853     static const uint kMuteTimeout;
    854852    /// Timeout for updating LCD info in msec
    855853    static const uint kLCDTimeout;
    856854    /// Timeout for browse mode exit in msec
  • mythtv/libs/libmythtv/playercontext.cpp

     
    432432
    433433bool PlayerContext::CreateNVP(TV *tv, QWidget *widget,
    434434                              TVState desiredState,
    435                               WId embedwinid, const QRect *embedbounds,
    436                               bool muted)
     435                              WId embedwinid, const QRect *embedbounds)
    437436{
    438437    int exact_seeking = gCoreContext->GetNumSetting("ExactSeeking", 0);
    439438
     
    444443        return false;
    445444    }
    446445
    447     NuppelVideoPlayer *_nvp = new NuppelVideoPlayer(muted);
     446    NuppelVideoPlayer *_nvp = new NuppelVideoPlayer();
    448447
    449448    if (nohardwaredecoders)
    450449        _nvp->DisableHardwareDecoders();
     
    494493                VERBOSE(VB_IMPORTANT, LOC_ERR + errMsg);
    495494        }
    496495    }
    497     else if (pipState == kPBPRight)
    498         nvp->SetMuted(true);
    499496
    500497    int maxWait = -1;
    501498    //if (isPIP())
  • mythtv/libs/libmythtv/NuppelVideoPlayer.h

     
    44#include <sys/time.h>
    55
    66#include "playercontext.h"
    7 #include "volumebase.h"
    87#include "RingBuffer.h"
    98#include "osd.h"
    109#include "jitterometer.h"
     
    8988    friend class PlayerContext;
    9089
    9190  public:
    92     NuppelVideoPlayer(bool muted = false);
     91    NuppelVideoPlayer();
    9392   ~NuppelVideoPlayer();
    9493
    9594    // Initialization
     
    112111    void SetAudioInfo(const QString &main, const QString &passthru, uint rate);
    113112    void SetAudioParams(int bits, int channels, int codec, int samplerate, bool passthru);
    114113    void SetEffDsp(int dsprate);
    115     uint AdjustVolume(int change);
    116     bool SetMuted(bool mute);
    117     MuteState SetMuteState(MuteState);
    118     MuteState IncrMuteState(void);
    119114    void SetAudioCodec(void *ac);
    120115
    121116    // Sets
     
    172167    float   GetVideoAspect(void) const        { return video_aspect; }
    173168    float   GetFrameRate(void) const          { return video_frame_rate; }
    174169
    175     uint    GetVolume(void);
    176170    int     GetSecondsBehind(void) const;
    177171    AspectOverrideMode GetAspectOverride(void) const;
    178172    AdjustFillMode     GetAdjustFill(void) const;
    179     MuteState          GetMuteState(void);
    180173    CommSkipMode       GetAutoCommercialSkip(void) const;
    181174
    182175    int     GetFFRewSkip(void) const          { return ffrew_skip; }
     
    211204    bool    HasAudioOut(void) const           { return !no_audio_out; }
    212205    bool    IsPIPActive(void) const           { return pip_active; }
    213206    bool    IsPIPVisible(void) const          { return pip_visible; }
    214     bool    IsMuted(void)              { return GetMuteState() == kMuteAll; }
    215207    bool    UsingNullVideo(void) const { return using_null_videoout; }
    216208    bool    HasTVChainNext(void) const;
    217209
     
    719711    float    audio_stretchfactor;
    720712    bool     audio_passthru;
    721713    QMutex   audio_lock;
    722     bool     audio_muted_on_creation;
    723714
    724715    // Picture-in-Picture
    725716    mutable QMutex pip_players_lock;
  • mythtv/libs/libmythtv/tv_play.cpp

     
    8585
    8686
    8787const uint TV::kInputModeTimeout             = 5000;
    88 const uint TV::kMuteTimeout                  = 800;
    8988const uint TV::kLCDTimeout                   = 1000;
    9089const uint TV::kBrowseTimeout                = 30000;
    9190const uint TV::kKeyRepeatTimeout             = 300;
     
    10131012    player.push_back(new PlayerContext(kPlayerInUseID));
    10141013    playerActive = 0;
    10151014    playerLock.unlock();
     1015
     1016    volumeControl = VolumeControlManager::GetControl(gCoreContext->GetSetting("MixerDevice"));
     1017    if (volumeControl)
     1018    {
     1019        connect(volumeControl.data(), SIGNAL(changedVolume(int)),
     1020                this, SLOT(VolumeChanged(int)), Qt::QueuedConnection);
     1021        connect(volumeControl.data(), SIGNAL(changedMute(bool)),
     1022                this, SLOT(MuteChanged(bool)), Qt::QueuedConnection);
     1023    }
     1024
    10161025    VERBOSE(VB_PLAYBACK, LOC + "ctor -- end");
    10171026}
    10181027
     
    28812890    if (handled)
    28822891        return;
    28832892
    2884     // Check unmute..
    2885     ctx = NULL;
    2886     {
    2887         QMutexLocker locker(&timerIdLock);
    2888         TimerContextMap::iterator it = unmuteTimerId.find(timer_id);
    2889         if (it != unmuteTimerId.end())
    2890         {
    2891             KillTimer(timer_id);
    2892             ctx = *it;
    2893             unmuteTimerId.erase(it);
    2894         }
    2895     }
    2896 
    2897     if (ctx)
    2898     {
    2899         PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    2900         if (find_player_index(ctx) >= 0)
    2901         {
    2902             ctx->LockDeleteNVP(__FILE__, __LINE__);
    2903             if (ctx->nvp && ctx->nvp->IsMuted())
    2904                 ctx->nvp->SetMuted(false);
    2905             ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    2906         }
    2907         ReturnPlayerLock(mctx);
    2908         handled = true;
    2909     }
    2910 
    29112893    if (handled)
    29122894        return;
    29132895
     
    54505432        }
    54515433    }
    54525434
    5453     MuteState mctx_mute = kMuteOff;
    5454     mctx->LockDeleteNVP(__FILE__, __LINE__);
    5455     if (mctx->nvp)
    5456         mctx_mute = mctx->nvp->GetMuteState();
    5457     mctx->UnlockDeleteNVP(__FILE__, __LINE__);
    5458 
    54595435    vector<long long> pos = TeardownAllNVPs(mctx);
    54605436
    54615437    if (wantPBP)
     
    54735449        }
    54745450    }
    54755451
    5476     RestartAllNVPs(mctx, pos, mctx_mute);
     5452    RestartAllNVPs(mctx, pos);
    54775453
    54785454    VERBOSE(VB_PLAYBACK, LOC +
    54795455            QString("PxPToggleType() converting from %1 to %2 -- end")
     
    56175593* \brief Recreate Main and PIP windows. Could be either PIP or PBP views.
    56185594*/
    56195595void TV::RestartAllNVPs(PlayerContext *lctx,
    5620                         const vector<long long> &pos,
    5621                         MuteState mctx_mute)
     5596                        const vector<long long> &pos)
    56225597{
    56235598    QString loc = LOC + QString("RestartAllNVPs(): ");
    56245599
     
    56655640            pipctx->LockDeleteNVP(__FILE__, __LINE__);
    56665641            if (pipctx->nvp)
    56675642            {
    5668                 pipctx->nvp->SetMuted(true);
    56695643                pipctx->nvp->JumpToFrame(pos[i]);
    56705644            }
    56715645            pipctx->UnlockDeleteNVP(__FILE__, __LINE__);
     
    56775651            ForceNextStateNone(pipctx);
    56785652        }
    56795653    }
    5680 
    5681     // If old main player had a kMuteAll | kMuteOff setting,
    5682     // apply old main player's mute setting to new main player.
    5683     mctx->LockDeleteNVP(__FILE__, __LINE__);
    5684     if (mctx->nvp && ((kMuteAll == mctx_mute) || (kMuteOff == mctx_mute)))
    5685         mctx->nvp->SetMuteState(mctx_mute);
    5686     mctx->UnlockDeleteNVP(__FILE__, __LINE__);
    56875654}
    56885655
    56895656void TV::PxPSwap(PlayerContext *mctx, PlayerContext *pipctx)
     
    57115678        return;
    57125679    }
    57135680
    5714     MuteState mctx_mute = mctx->nvp->GetMuteState();
    57155681    mctx->deleteNVPLock.unlock();
    57165682    pipctx->deleteNVPLock.unlock();
    57175683
     
    57255691    playerActive = (ctx_index == playerActive) ?
    57265692        0 : ((ctx_index == 0) ? ctx_index : playerActive);
    57275693
    5728     RestartAllNVPs(mctx, pos, mctx_mute);
     5694    RestartAllNVPs(mctx, pos);
    57295695
    57305696    SetActive(mctx, playerActive, false);
    57315697
     
    57465712        mctx->deleteNVPLock.unlock();
    57475713        return;
    57485714    }
    5749 
    5750     MuteState mctx_mute = mctx->nvp->GetMuteState();
    5751 
    5752     // HACK - FIXME
    5753     // workaround muted audio when NVP is re-created
    5754     mctx_mute = kMuteOff;
    5755     // FIXME - end
    57565715    mctx->deleteNVPLock.unlock();
    57575716
    57585717    vector<long long> pos = TeardownAllNVPs(mctx);
    5759     RestartAllNVPs(mctx, pos, mctx_mute);
     5718    RestartAllNVPs(mctx, pos);
    57605719    SetActive(mctx, playerActive, false);
    57615720
    57625721    VERBOSE(VB_PLAYBACK, LOC + "Restart main player -- end");
     
    58815840
    58825841    VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- begin");
    58835842
    5884     bool muted = false;
    5885 
    58865843    ctx->LockDeleteNVP(__FILE__, __LINE__);
    58875844    if (!ctx->nvp)
    58885845    {
     
    58905847        return false;
    58915848    }
    58925849
    5893     if (ctx == GetPlayer(ctx, 0))
    5894         muted = MuteChannelChange(ctx);
    5895 
    58965850    bool res = false;
    58975851
    58985852    if (LONG_LONG_MIN != audiosyncBaseline)
     
    59135867    }
    59145868    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    59155869
    5916     if (muted)
    5917         SetMuteTimer(ctx, kMuteTimeout);
    5918 
    59195870    VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- end");
    59205871
    59215872    return res;
     
    62816232    NormalSpeed(ctx);
    62826233    StopFFRew(ctx);
    62836234
    6284     ctx->LockDeleteNVP(__FILE__, __LINE__);
    6285     bool muted = MuteChannelChange(ctx);
    6286     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6287 
    62886235    struct StatusPosInfo posInfo;
    62896236    ctx->CalcNVPSliderPosition(posInfo);
    62906237
     
    63036250    if (ctx->nvp)
    63046251        ctx->nvp->JumpChapter(chapter);
    63056252    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6306 
    6307     if (muted)
    6308         SetMuteTimer(ctx, kMuteTimeout);
    63096253}
    63106254
    63116255void TV::DoSkipCommercials(PlayerContext *ctx, int direction)
     
    63166260    if (StateIsLiveTV(GetState(ctx)))
    63176261        return;
    63186262
    6319     ctx->LockDeleteNVP(__FILE__, __LINE__);
    6320     bool muted = MuteChannelChange(ctx);
    6321     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6322 
    63236263    struct StatusPosInfo posInfo;
    63246264    ctx->CalcNVPSliderPosition(posInfo);
    63256265
     
    63386278    if (ctx->nvp)
    63396279        ctx->nvp->SkipCommercials(direction);
    63406280    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6341 
    6342     if (muted)
    6343         SetMuteTimer(ctx, kMuteTimeout);
    63446281}
    63456282
    63466283void TV::SwitchSource(PlayerContext *ctx, uint source_direction)
     
    65016438        if (mctx != ctx)
    65026439            PIPRemovePlayer(mctx, ctx);
    65036440
    6504         bool muted = false;
    6505         ctx->LockDeleteNVP(__FILE__, __LINE__);
    6506         if (ctx->nvp && ctx->nvp->IsMuted())
    6507             muted = true;
    6508         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6509 
    65106441        // pause the decoder first, so we're not reading too close to the end.
    65116442        ctx->buffer->IgnoreLiveEOF(true);
    65126443        ctx->buffer->StopReads();
     
    65586489
    65596490            if (ctx->CreateNVP(
    65606491                    this, GetMythMainWindow(), ctx->GetState(),
    6561                     mctx->embedWinID, &mctx->embedBounds, muted))
     6492                    mctx->embedWinID, &mctx->embedBounds))
    65626493            {
    65636494                ScheduleStateChange(ctx);
    65646495                ok = true;
     
    69156846
    69166847void TV::ChangeChannel(PlayerContext *ctx, int direction)
    69176848{
    6918     bool muted = false;
    6919 
    69206849    if ((browse_changrp || (direction == CHANNEL_DIRECTION_FAVORITE)) &&
    69216850        (channel_group_id > -1))
    69226851    {
     
    69476876
    69486877    QString oldinputname = ctx->recorder->GetInput();
    69496878
    6950     muted = MuteChannelChange(ctx);
    6951 
    69526879    if (ctx->paused)
    69536880    {
    69546881        OSD *osd = GetOSDLock(ctx);
     
    69766903    ctx->recorder->ChangeChannel(direction);
    69776904    ClearInputQueues(ctx, false);
    69786905
    6979     if (muted)
    6980         SetMuteTimer(ctx, kMuteTimeout * 2);
    6981 
    69826906    UnpauseLiveTV(ctx);
    69836907
    69846908    if (oldinputname != ctx->recorder->GetInput())
     
    69956919
    69966920    QString channum = chan;
    69976921    QStringList reclist;
    6998     bool muted = false;
    69996922
    70006923    QString oldinputname = ctx->recorder->GetInput();
    70016924
     
    70656988    if (getit || !ctx->recorder || !ctx->recorder->CheckChannel(channum))
    70666989        return;
    70676990
    7068     muted = MuteChannelChange(ctx);
    7069 
    70706991    OSD *osd = GetOSDLock(ctx);
    70716992    if (osd && ctx->paused)
    70726993    {
     
    70927013
    70937014    ctx->recorder->SetChannel(channum);
    70947015
    7095     if (muted)
    7096         SetMuteTimer(ctx, kMuteTimeout * 2);
    7097 
    70987016    UnpauseLiveTV(ctx);
    70997017
    71007018    if (oldinputname != ctx->recorder->GetInput())
     
    82028120
    82038121void TV::ChangeVolume(PlayerContext *ctx, bool up)
    82048122{
    8205     ctx->LockDeleteNVP(__FILE__, __LINE__);
    8206     if (!ctx->nvp)
     8123    if (volumeControl)
    82078124    {
    8208         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8209         return;
     8125        if (up)
     8126            volumeControl->increaseVolume();
     8127        else
     8128            volumeControl->decreaseVolume();
    82108129    }
    8211     uint curvol = ctx->nvp->AdjustVolume((up) ? +2 : -2);
    8212     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8213 
    8214     QString text = tr("Volume %1 %").arg(curvol);
    8215 
    8216     OSD *osd = GetOSDLock(ctx);
    8217     if (osd && !browsemode)
    8218     {
    8219         osd->ShowStatus(curvol * 10, true, tr("Adjust Volume"), text, 5,
    8220                         kOSDFunctionalType_PictureAdjust);
    8221         SetUpdateOSDPosition(false);
    8222     }
    8223     ReturnOSDLock(ctx, osd);
    82248130}
    82258131
    82268132void TV::ToggleTimeStretch(PlayerContext *ctx)
     
    83698275
    83708276void TV::ToggleMute(PlayerContext *ctx)
    83718277{
    8372     ctx->LockDeleteNVP(__FILE__, __LINE__);
    8373     if (!ctx->nvp || !ctx->nvp->HasAudioOut())
    8374     {
    8375         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8376         return;
    8377     }
    8378 
    8379     MuteState mute_status;
    8380 
    8381     if (!MuteIndividualChannels)
    8382     {
    8383         ctx->nvp->SetMuted(!ctx->nvp->IsMuted());
    8384         mute_status = (ctx->nvp->IsMuted()) ? kMuteAll : kMuteOff;
    8385     }
    8386     else
    8387     {
    8388         mute_status = ctx->nvp->IncrMuteState();
    8389     }
    8390     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8391 
    8392     QString text;
    8393 
    8394     switch (mute_status)
    8395     {
    8396         case kMuteOff:   text = tr("Mute Off"); break;
    8397         case kMuteAll:   text = tr("Mute On"); break;
    8398         case kMuteLeft:  text = tr("Left Channel Muted"); break;
    8399         case kMuteRight: text = tr("Right Channel Muted"); break;
    8400     }
    8401 
    8402     OSD *osd = GetOSDLock(ctx);
    8403     if (osd && !browsemode)
    8404         osd->SetSettingsText(text, 5);
    8405     ReturnOSDLock(ctx, osd);
     8278    if (volumeControl)
     8279        volumeControl->setMute(!volumeControl->mute());
    84068280}
    84078281
    84088282void TV::ToggleSleepTimer(const PlayerContext *ctx)
     
    85628436    ReturnOSDLock(ctx, osd);
    85638437}
    85648438
    8565 void TV::SetMuteTimer(PlayerContext *ctx, int timeout)
    8566 {
    8567     // message to set the timer will be posted to the main UI thread
    8568     // where it will be caught in eventFilter and processed as CustomEvent
    8569     // this will properly set the mute timer
    8570     // otherwise it never fires on Win32
    8571     QString message = QString("UNMUTE %1 %2").arg((long long)ctx).arg(timeout);
    8572     qApp->postEvent(GetMythMainWindow(), new MythEvent(message));
    8573 }
    8574 
    8575 bool TV::MuteChannelChange(PlayerContext *ctx)
    8576 {
    8577     if (!ctx)
    8578         return false;
    8579 
    8580     bool muted = false;
    8581     ctx->LockDeleteNVP(__FILE__, __LINE__);
    8582     if (ctx->nvp && !ctx->nvp->IsMuted())
    8583         muted = ctx->nvp->SetMuted(true);
    8584     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8585 
    8586     return muted;
    8587 }
    8588 
    85898439void TV::customEvent(QEvent *e)
    85908440{
    85918441    if (e->type() == OSDCloseEvent::kEventType)
     
    88608710        }
    88618711    }
    88628712
    8863     if (message.left(6) == "UNMUTE")
    8864     {
    8865         if (tokens.size() >= 3)
    8866         {
    8867             long long target = tokens[1].toLongLong();
    8868             PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    8869             for (uint i = 0; i < player.size(); i++)
    8870             {
    8871                 PlayerContext *ctx = GetPlayer(mctx, i);
    8872                 if (((long long)ctx) == target)
    8873                 {
    8874                     QMutexLocker locker(&timerIdLock);
    8875                     unmuteTimerId[StartTimer(tokens[2].toUInt(), __LINE__)] = ctx;
    8876                 }
    8877             }
    8878             ReturnPlayerLock(mctx);
    8879         }
    8880     }
    8881 
    88828713    if (message.left(9) == "START_EPG")
    88838714    {
    88848715        int editType = tokens[1].toInt();
     
    93729203        {
    93739204            value = ctx->nvp->getVideoOutput()->GetPictureAttribute(attr);
    93749205        }
    9375         else if (ctx->nvp->HasAudioOut())
     9206        else if (ctx->nvp->HasAudioOut() && volumeControl)
    93769207        {
    9377             value = ctx->nvp->GetVolume();
     9208            value = volumeControl->volume();
    93789209            title = tr("Adjust Volume");
    93799210        }
    93809211    }
     
    1197511806    ReturnPlayerLock(mctx);
    1197611807}
    1197711808
     11809void TV::VolumeChanged(int volume)
     11810{
     11811    OSD *osd = GetOSDL(__FILE__, __LINE__);
     11812    if (osd && !browsemode)
     11813    {
     11814        osd->ShowStatus(volume * 10, true, tr("Adjust Volume"),
     11815                        tr("Volume %1 %").arg(volume), 5,
     11816                        kOSDFunctionalType_PictureAdjust);
     11817        SetUpdateOSDPosition(false);
     11818    }
     11819    ReturnOSDLock(osd);
     11820}
     11821
     11822void TV::MuteChanged(bool mute)
     11823{
     11824    OSD *osd = GetOSDL(__FILE__, __LINE__);
     11825    if (osd && !browsemode)
     11826        osd->SetSettingsText(mute ? tr("Mute On") : tr("Mute Off"), 5);
     11827    ReturnOSDLock(osd);
     11828}
     11829
     11830
    1197811831OSD *TV::GetOSDL(const char *file, int location)
    1197911832{
    1198011833    PlayerContext *actx = GetPlayerReadLock(-1, file, location);
  • mythtv/libs/libmythtv/playercontext.h

     
    4747    // Actions
    4848    bool CreateNVP(TV *tv, QWidget *widget,
    4949                   TVState desiredState,
    50                    WId embedwinid, const QRect *embedBounds,
    51                    bool muted = false);
     50                   WId embedwinid, const QRect *embedBounds);
    5251    void TeardownPlayer(void);
    5352    bool StartDecoderThread(int maxWait = -1);
    5453    bool StartOSD(TV *tv);
  • mythtv/libs/libmythtv/avformatdecoder.h

     
    305305
    306306    bool              allow_ac3_passthru;
    307307    bool              allow_dts_passthru;
    308     bool              internal_vol;
    309308    bool              disable_passthru;
    310309    uint              max_channels;
    311310    uint              last_ac3_channels;
  • mythtv/libs/libmyth/audiooutputwin.cpp

     
    263263{
    264264    return m_nPkts * fragment_size;
    265265}
    266 
    267 int AudioOutputWin::GetVolumeChannel(int channel) const
    268 {
    269     DWORD dwVolume = 0xffffffff;
    270     int Volume = 100;
    271     if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
    272     {
    273         Volume = (channel == 0) ?
    274             (LOWORD(dwVolume) / (0xffff / 100)) :
    275             (HIWORD(dwVolume) / (0xffff / 100));
    276     }
    277 
    278     VERBOSE(VB_AUDIO, "GetVolume(" << channel << ") "
    279             << Volume << "(" << dwVolume << ")");
    280 
    281     return Volume;
    282 }
    283 
    284 void AudioOutputWin::SetVolumeChannel(int channel, int volume)
    285 {
    286     if (channel > 1)
    287     {
    288         Error(QString("Error setting channel: %1. "
    289                       "Only stereo volume supported").arg(channel));
    290         return;
    291     }
    292 
    293     DWORD dwVolume = 0xffffffff;
    294     if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
    295     {
    296         if (channel == 0)
    297             dwVolume = dwVolume & 0xffff0000 | volume * (0xffff / 100);
    298         else
    299             dwVolume = dwVolume & 0xffff | ((volume * (0xffff / 100)) << 16);
    300     }
    301     else
    302     {
    303         dwVolume = volume * (0xffff / 100);
    304         dwVolume |= (dwVolume << 16);
    305     }
    306 
    307     VERBOSE(VB_AUDIO, QString("SetVolume(%1) %2(%3)")
    308             .arg(channel).arg(volume).arg(dwVolume));
    309     waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, dwVolume);
    310 }
  • mythtv/libs/libmyth/volumecontrolmanager.cpp

     
     1#include "volumecontrolmanager.h"
     2
     3#include "mythverbose.h"
     4#ifdef USE_ALSA
     5#include "volumecontrolalsa.h"
     6#endif
     7#ifdef USE_COREAUDIO
     8#include "volumecontrolcoreaudio.h"
     9#endif
     10#ifdef USING_OSS
     11#include "volumecontroloss.h"
     12#endif
     13#ifdef USING_MINGW
     14#include "volumecontrolendpoint.h"
     15#endif
     16#include "volumecontrolsoftware.h"
     17
     18
     19QHash<QString, QString> VolumeControlManager::Enumerate()
     20{
     21    QHash<QString, QString> result;
     22
     23#ifdef USE_ALSA
     24    result.unite(VolumeControlALSA::Enumerate());
     25#endif
     26#ifdef USE_COREAUDIO
     27    result.unite(VolumeControlCoreAudio::Enumerate());
     28#endif
     29#ifdef USING_OSS
     30    result.unite(VolumeControlOSS::Enumerate());
     31#endif
     32#ifdef USING_MINGW
     33    result.unite(VolumeControlEndpoint::Enumerate());
     34#endif
     35    result.unite(VolumeControlSoftware::Enumerate());
     36
     37    return result;
     38}
     39
     40QSharedPointer<VolumeControl> VolumeControlManager::GetControl(QString device)
     41{
     42    QSharedPointer<VolumeControl> result;
     43    QString api = device.section(':', 0, 0);
     44    device = device.remove(0, api.size() + 1);
     45
     46    if (api == "ALSA")
     47    {
     48#ifdef USE_ALSA
     49        result = QSharedPointer<VolumeControl>(new VolumeControlALSA(device));
     50#else
     51        VERBOSE(VB_IMPORTANT,
     52                QString("Volume control device is set to an ALSA device but "
     53                        "ALSA support is not compiled in!"));
     54#endif
     55    }
     56    else if (api == "CoreAudio")
     57    {
     58#ifdef USE_COREAUDIO
     59        result = QSharedPointer<VolumeControl>(new VolumeControlCoreAudio(device));
     60#else
     61        VERBOSE(VB_IMPORTANT,
     62                QString("Volume control device is set to an Core Audio device "
     63                        "but Core Audio support is not compiled in!"));
     64#endif
     65    }
     66    else if (api == "OSS" || api.isEmpty())
     67    {
     68#ifdef USING_OSS
     69        result = QSharedPointer<VolumeControl>(new VolumeControlOSS(device));
     70#else
     71        VERBOSE(VB_IMPORTANT,
     72                QString("Volume control device is set to an OSS device but OSS "
     73                        "support is not compiled in!"));
     74#endif
     75    }
     76    else if (api == "Endpoint" || api.isEmpty())
     77    {
     78#ifdef USING_MINGW
     79        result = QSharedPointer<VolumeControl>(new VolumeControlEndpoint(device));
     80#else
     81        VERBOSE(VB_IMPORTANT,
     82                QString("Volume control device is set to an Endpoint device "
     83                        "but End Point support is not compiled in!"));
     84#endif
     85    }
     86    else if (api == "Software" || api.isEmpty())
     87    {
     88        result = QSharedPointer<VolumeControl>(new VolumeControlSoftware(device));
     89    }
     90    else
     91    {
     92        VERBOSE(VB_IMPORTANT,
     93               QString("Volume control device is set to an unknown API \"%1\"")
     94               .arg(api));
     95    }
     96
     97    return result;
     98}
  • mythtv/libs/libmyth/volumecontrolalsa.cpp

     
     1#include "volumecontrolalsa.h"
     2
     3#include "mythverbose.h"
     4#include <algorithm>
     5
     6// static
     7QHash<QString, QString> VolumeControlALSA::Enumerate()
     8{
     9    QHash<QString, QString> result;
     10
     11    result.insert("ALSA:default", "Default ALSA device");
     12
     13    int card = -1;
     14    while (snd_card_next(&card) >= 0 && card >= 0)
     15    {
     16        snd_ctl_t* handle;
     17        if (!snd_ctl_open(&handle,
     18                          QString("hw:%1").arg(card).toAscii().constData(), 0))
     19        {
     20            snd_ctl_card_info_t* info;
     21            snd_ctl_card_info_alloca(&info);
     22
     23            if (!snd_ctl_card_info(handle, info))
     24            {
     25                result.insert(QString("ALSA:hw:%1")
     26                              .arg(snd_ctl_card_info_get_id(info)),
     27                              snd_ctl_card_info_get_name(info));
     28            }
     29            snd_ctl_close(handle);
     30        }
     31    }
     32
     33    return result;
     34}
     35
     36VolumeControlALSA::VolumeControlALSA(QString device) :
     37    m_MixerHandle(NULL),
     38    m_MixerElement(NULL),
     39    m_Range(1)
     40{
     41    if (snd_mixer_open(&m_MixerHandle, 0) < 0)
     42    {
     43        VERBOSE(VB_IMPORTANT,
     44                QString("VolumeControlALSA::VolumeControlALSA() - ERROR: "
     45                        "opening mixer"));
     46        return;
     47    }
     48
     49    if (snd_mixer_attach(m_MixerHandle, device.toAscii().constData()) < 0)
     50    {
     51        VERBOSE(VB_IMPORTANT,
     52                QString("VolumeControlALSA::VolumeControlALSA() - ERROR: "
     53                        "attaching mixer \"%1\"")
     54                .arg(device));
     55        return;
     56    }
     57
     58    if (snd_mixer_selem_register(m_MixerHandle, NULL, NULL) < 0)
     59    {
     60        VERBOSE(VB_IMPORTANT,
     61                QString("VolumeControlALSA::VolumeControlALSA() - ERROR: "
     62                        "registering mixer"));
     63        return;
     64    }
     65
     66    if (snd_mixer_load(m_MixerHandle) < 0)
     67    {
     68        VERBOSE(VB_IMPORTANT,
     69                QString("VolumeControlALSA::VolumeControlALSA() - ERROR: "
     70                        "loading mixer"));
     71        return;
     72    }
     73
     74    for (m_MixerElement = snd_mixer_first_elem(m_MixerHandle);
     75         m_MixerElement;
     76         m_MixerElement = snd_mixer_elem_next(m_MixerElement))
     77    {
     78        if (!snd_mixer_selem_is_active(m_MixerElement))
     79            continue;
     80
     81        if (!snd_mixer_selem_has_playback_volume(m_MixerElement))
     82           continue;
     83
     84        VERBOSE(VB_AUDIO,
     85                QString("VolumeControlALSA::VolumeControlALSA() - "
     86                        "Using \"%1\"")
     87                .arg(snd_mixer_selem_get_name(m_MixerElement)));
     88
     89        break;
     90    }
     91
     92    if (!m_MixerElement)
     93    {
     94        VERBOSE(VB_IMPORTANT,
     95                QString("VolumeControlALSA::VolumeControlALSA() - ERROR: "
     96                        "unable to find volume control"));
     97        return;
     98    }
     99
     100    long min, max;
     101    snd_mixer_selem_get_playback_volume_range(m_MixerElement, &min, &max);
     102    m_Range = std::min(std::max(1l, max - min), 100l);
     103
     104    snd_mixer_selem_set_playback_volume_range(m_MixerElement, 0, 100);
     105
     106    snd_mixer_elem_set_callback_private(m_MixerElement, this);
     107    snd_mixer_elem_set_callback(m_MixerElement, &event);
     108
     109    if (!pipe(m_Exit))
     110        start();
     111}
     112
     113VolumeControlALSA::~VolumeControlALSA()
     114{
     115    if (isRunning())
     116    {
     117        write(m_Exit[1], "", 1);
     118
     119        wait();
     120
     121        close(m_Exit[0]);
     122        close(m_Exit[1]);
     123    }
     124
     125    if (m_MixerHandle)
     126        snd_mixer_close(m_MixerHandle);
     127}
     128
     129int VolumeControlALSA::volume() const
     130{
     131    long volume = 0;
     132    if (m_MixerElement)
     133    {
     134        if (snd_mixer_selem_has_playback_switch(m_MixerElement) || !mute())
     135            snd_mixer_selem_get_playback_volume(m_MixerElement,
     136                                                SND_MIXER_SCHN_MONO,
     137                                                &volume);
     138        else
     139            volume = m_Volume;
     140    }
     141
     142    VERBOSE(VB_AUDIO,
     143            QString("VolumeControlALSA::volume() = %1")
     144            .arg(volume));
     145
     146    return volume;
     147}
     148
     149void VolumeControlALSA::setVolume(int volume)
     150{
     151    VERBOSE(VB_AUDIO,
     152            QString("VolumeControlALSA::setVolume(%1)")
     153            .arg(volume));
     154
     155    volume = std::min(std::max(0, volume), 100);
     156
     157    if (mute() && volume > VolumeControlALSA::volume())
     158        setMute(false);
     159
     160    if (m_MixerElement)
     161        if (snd_mixer_selem_has_playback_switch(m_MixerElement) || !mute())
     162            snd_mixer_selem_set_playback_volume_all(m_MixerElement,
     163                                                    volume);
     164
     165    if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     166        emit changedVolume(volume);
     167}
     168
     169void VolumeControlALSA::increaseVolume()
     170{
     171    setVolume((volume() * m_Range + 100) / m_Range);
     172}
     173
     174void VolumeControlALSA::decreaseVolume()
     175{
     176    setVolume((volume() * m_Range - 100) / m_Range);
     177}
     178
     179bool VolumeControlALSA::mute() const
     180{
     181    union {
     182        int _switch;
     183        long int _volume;
     184    } playback;
     185   
     186    playback._switch = true;
     187
     188    if (m_MixerElement)
     189    {
     190        if (snd_mixer_selem_has_playback_switch(m_MixerElement))
     191            snd_mixer_selem_get_playback_switch(m_MixerElement,
     192                                                SND_MIXER_SCHN_MONO,
     193                                                &playback._switch);
     194        else
     195            snd_mixer_selem_get_playback_volume(m_MixerElement,
     196                                                SND_MIXER_SCHN_MONO,
     197                                                &playback._volume);
     198    }
     199
     200    VERBOSE(VB_AUDIO,
     201            QString("VolumeControlALSA::mute() = %1")
     202            .arg(!playback._switch ? "mute" : "unmute"));
     203
     204    return !playback._switch;
     205}
     206
     207void VolumeControlALSA::setMute(bool mute)
     208{
     209    VERBOSE(VB_AUDIO,
     210            QString("VolumeControlALSA::setMute(%1)")
     211            .arg(mute ? "mute" : "unmute"));
     212
     213    if (m_MixerElement)
     214    {
     215        if (snd_mixer_selem_has_playback_switch(m_MixerElement))
     216            snd_mixer_selem_set_playback_switch_all(m_MixerElement,
     217                                                    !mute);
     218        else
     219            snd_mixer_selem_set_playback_volume_all(m_MixerElement,
     220                                                    mute ? 0 : static_cast<int>(m_Volume));
     221    }
     222
     223    if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     224        emit changedMute(mute);
     225}
     226
     227// static
     228int VolumeControlALSA::event(snd_mixer_elem_t* elem, unsigned int mask)
     229{
     230    VERBOSE(VB_AUDIO,
     231            QString("VolumeControlALSA::event(%1)")
     232            .arg(mask));
     233
     234    VolumeControlALSA* that =
     235        static_cast<VolumeControlALSA*>(snd_mixer_elem_get_callback_private(elem));
     236
     237    if (mask == SND_CTL_EVENT_MASK_REMOVE)
     238    {
     239        that->m_MixerElement = NULL;
     240        return 0;
     241    }
     242
     243    if (mask & SND_CTL_EVENT_MASK_VALUE)
     244    {
     245        int volume = that->volume();
     246        if (that->m_Volume.fetchAndStoreRelaxed(volume) != volume)
     247            emit that->changedVolume(volume);
     248
     249        bool mute = that->mute();
     250        if (that->m_Mute.fetchAndStoreRelaxed(mute) != mute)
     251            emit that->changedMute(mute);
     252    }
     253
     254    return 0;
     255}
     256
     257void VolumeControlALSA::run()
     258{
     259    VERBOSE(VB_AUDIO,
     260            QString("VolumeControlALSA::run() - begin"));
     261
     262    m_Volume = volume();
     263    m_Mute = mute();
     264
     265    int poll_descriptors_count = -1;
     266    struct pollfd* poll_descriptors = NULL;
     267
     268    for(;;)
     269    {
     270        int poll_descriptors_count_new =
     271            snd_mixer_poll_descriptors_count(m_MixerHandle);
     272
     273        if (poll_descriptors_count_new < 0)
     274        {
     275            VERBOSE(VB_IMPORTANT,
     276                    QString("VolumeControlALSA::run() - ERROR: "
     277                            "snd_mixer_poll_descriptors_count"));
     278            break;
     279        }
     280
     281        if (poll_descriptors_count != poll_descriptors_count_new)
     282        {
     283            delete(poll_descriptors);
     284
     285            poll_descriptors_count = poll_descriptors_count_new;
     286            poll_descriptors = new struct pollfd[poll_descriptors_count + 1];
     287
     288            if (!poll_descriptors)
     289            {
     290                VERBOSE(VB_IMPORTANT,
     291                        QString("VolumeControlALSA::run() - ERROR: "
     292                                "malloc"));
     293                break;
     294            }
     295        }
     296
     297        bzero(poll_descriptors,
     298              poll_descriptors_count * sizeof (struct pollfd));
     299
     300        poll_descriptors->fd = m_Exit[0];
     301        poll_descriptors->events = POLLIN;
     302
     303        if (snd_mixer_poll_descriptors(m_MixerHandle,
     304                                       poll_descriptors + 1,
     305                                       poll_descriptors_count) !=
     306                                       poll_descriptors_count)
     307        {
     308            VERBOSE(VB_IMPORTANT,
     309                    QString("VolumeControlALSA::run() - ERROR: "
     310                            "snd_mixer_poll_descriptors"));
     311            break;
     312        }
     313
     314        if (poll(poll_descriptors, poll_descriptors_count + 1, -1) < 0)
     315        {
     316            VERBOSE(VB_IMPORTANT,
     317                    QString("VolumeControlALSA::run() - ERROR: "
     318                            "poll %1")
     319                    .arg(errno));
     320            break;
     321        }
     322
     323        if (poll_descriptors->revents & POLLIN)
     324            break;
     325
     326        unsigned short revents;
     327        if (snd_mixer_poll_descriptors_revents(m_MixerHandle,
     328                                               poll_descriptors + 1,
     329                                               poll_descriptors_count,
     330                                               &revents) < 0)
     331        {
     332            VERBOSE(VB_IMPORTANT,
     333                    QString("VolumeControlALSA::run() - ERROR: "
     334                            "snd_mixer_poll_descriptors_revents"));
     335            break;
     336        }
     337
     338        if (revents & (POLLNVAL | POLLERR))
     339        {
     340            VERBOSE(VB_IMPORTANT,
     341                    QString("VolumeControlALSA::run() - ERROR: "
     342                            "snd_mixer_poll_descriptors_revents"));
     343            break;
     344        }
     345
     346        if (snd_mixer_handle_events(m_MixerHandle) < 0)
     347        {
     348            VERBOSE(VB_IMPORTANT,
     349                    QString("VolumeControlALSA::run() - ERROR: "
     350                            "snd_mixer_handle_events"));
     351            break;
     352        }
     353    }
     354
     355    delete(poll_descriptors);
     356
     357    VERBOSE(VB_AUDIO,
     358            QString("VolumeControlALSA::run() - end"));
     359}
  • mythtv/libs/libmyth/audiooutputbase.h

     
    1818#include "audiooutput.h"
    1919#include "samplerate.h"
    2020#include "mythverbose.h"
     21#include "volumecontrolmanager.h"
    2122
    2223namespace soundtouch {
    2324class SoundTouch;
     
    4748
    4849    virtual void Reset(void);
    4950
    50     void SetSWVolume(int new_volume, bool save);
    51     int GetSWVolume(void);
    52 
    5351    // timecode is in milliseconds.
    5452    virtual bool AddSamples(char *buffer, int samples, long long timecode);
    5553    virtual bool AddSamples(char *buffers[], int samples, long long timecode);
     
    113111    int audiolen(bool use_lock); // number of valid bytes in audio buffer
    114112    int audiofree(bool use_lock); // number of free bytes in audio buffer
    115113
    116     void UpdateVolume(void);
    117 
    118114    void SetStretchFactorLocked(float factor);
    119115
    120116    int GetBaseAudioTime()                    const { return audiotime;       }
     
    148144    bool killaudio;
    149145
    150146    bool pauseaudio, audio_actually_paused, was_paused;
    151     bool set_initial_vol;
    152147    bool buffer_output_data_for_use; //  used by AudioOutputNULL
    153148
    154149    int configured_audio_channels;
     
    181176    int surround_mode;
    182177    bool allow_ac3_passthru;
    183178    float old_audio_stretchfactor;
    184     int volume;
     179    QSharedPointer<VolumeControl> volume_control; ///< Volume Control interface
    185180
    186181    bool blocking; // do AddSamples calls block?
    187182
  • mythtv/libs/libmyth/audiooutputalsa.cpp

     
     1#include "audiooutputalsa.h"
     2
    13#include <cstdio>
    24#include <cstdlib>
    35#include <sys/time.h>
     
    79using namespace std;
    810
    911#include "mythcorecontext.h"
    10 #include "audiooutputalsa.h"
    1112   
    1213#define LOC QString("ALSA: ")
    1314#define LOC_WARN QString("ALSA, Warning: ")
     
    1819#undef assert
    1920#define assert(x)
    2021
     22// static
     23QHash<QString, QString> AudioOutputALSA::Enumerate()
     24{
     25    QHash<QString, QString> result;
     26
     27    result.insert("ALSA:default", "Default ALSA device");
     28
     29    int card = -1;
     30    while (snd_card_next(&card) >= 0 && card >= 0)
     31    {
     32        snd_ctl_t* handle;
     33        if (!snd_ctl_open(&handle,
     34                          QString("hw:%1").arg(card).toAscii().constData(), 0))
     35        {
     36            snd_ctl_card_info_t* info;
     37            snd_ctl_card_info_alloca(&info);
     38
     39            if (!snd_ctl_card_info(handle, info))
     40            {
     41                int devices = 0;
     42
     43                for (int device = -1;
     44                     !snd_ctl_pcm_next_device(handle, &device) && device >= 0;)
     45                {
     46                    snd_pcm_info_t* pcminfo;
     47                    snd_pcm_info_alloca(&pcminfo);
     48
     49                    snd_pcm_info_set_device(pcminfo, device);
     50                    snd_pcm_info_set_subdevice(pcminfo, 0);
     51                    snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
     52
     53                    if (!snd_ctl_pcm_info(handle, pcminfo) && devices++)
     54                        break;
     55                }
     56
     57                for (int device = -1;
     58                     !snd_ctl_pcm_next_device(handle, &device) && device >= 0;)
     59                {
     60                    snd_pcm_info_t* pcminfo;
     61                    snd_pcm_info_alloca(&pcminfo);
     62
     63                    snd_pcm_info_set_device(pcminfo, device);
     64                    snd_pcm_info_set_subdevice(pcminfo, 0);
     65                    snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
     66
     67                    if (!snd_ctl_pcm_info(handle, pcminfo))
     68                    {
     69                        if (devices > 1)
     70                        {
     71                            result.insert(QString("ALSA:plughw:%1,%2")
     72                                          .arg(snd_ctl_card_info_get_id(info))
     73                                          .arg(device),
     74                                          QString("%1 %2")
     75                                          .arg(snd_ctl_card_info_get_name(info))
     76                                          .arg(snd_pcm_info_get_name(pcminfo)));
     77                        }
     78                        else
     79                        {
     80                            result.insert(QString("ALSA:plughw:%1,%2")
     81                                          .arg(snd_ctl_card_info_get_id(info))
     82                                          .arg(device),
     83                                          snd_ctl_card_info_get_name(info));
     84                        }
     85                    }
     86                }
     87            }
     88            snd_ctl_close(handle);
     89        }
     90    }
     91
     92    return result;
     93}
     94
    2195AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
    2296    AudioOutputBase(settings),
    2397    pcm_handle(NULL),
    24     numbadioctls(0),
    25     mixer_handle(NULL),
    26     mixer_control(QString::null)
     98    numbadioctls(0)
    2799{
    28100    // Set everything up
    29101    Reconfigure(settings);
     
    253325    // it really is
    254326    audio_buffer_unused = soundcard_buffer_size - (fragment_size * 4);
    255327
    256     if (internal_vol)
    257         OpenMixer(set_initial_vol);
    258    
    259328    // Device opened successfully
    260329    return true;
    261330}
    262331
    263332void AudioOutputALSA::CloseDevice()
    264333{
    265     CloseMixer();
    266334    if (pcm_handle != NULL)
    267335    {
    268336        snd_pcm_close(pcm_handle);
     
    622690    return 0;
    623691}
    624692
    625 
    626 int AudioOutputALSA::GetVolumeChannel(int channel) const
    627 {
    628     long actual_volume;
    629 
    630     if (mixer_handle == NULL)
    631         return 100;
    632 
    633     QByteArray mix_ctl = mixer_control.toAscii();
    634     snd_mixer_selem_id_t *sid;
    635     snd_mixer_selem_id_alloca(&sid);
    636     snd_mixer_selem_id_set_index(sid, 0);
    637     snd_mixer_selem_id_set_name(sid, mix_ctl.constData());
    638 
    639     snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);
    640     if (!elem)
    641     {
    642         VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")
    643                 .arg(mixer_control));
    644         return 100;
    645     }
    646 
    647     snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
    648     if (!snd_mixer_selem_has_playback_channel(elem, chan))
    649     {
    650         snd_mixer_selem_id_set_index(sid, channel);
    651         if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)
    652         {
    653             VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1 %2")
    654                     .arg(mixer_control).arg(channel));
    655             return 100;
    656         }
    657     }
    658 
    659     ALSAVolumeInfo vinfo = GetVolumeRange(elem);
    660 
    661     snd_mixer_selem_get_playback_volume(
    662         elem, (snd_mixer_selem_channel_id_t)channel, &actual_volume);
    663 
    664     return vinfo.ToMythRange(actual_volume);
    665 }
    666 
    667 void AudioOutputALSA::SetVolumeChannel(int channel, int volume)
    668 {
    669     SetCurrentVolume(mixer_control, channel, volume);
    670 }
    671 
    672 void AudioOutputALSA::SetCurrentVolume(QString control, int channel, int volume)
    673 {
    674     VERBOSE(VB_AUDIO, QString("Setting %1 volume to %2")
    675             .arg(control).arg(volume));
    676 
    677     if (!mixer_handle)
    678         return; // no mixer, nothing to do
    679 
    680     QByteArray ctl = control.toAscii();
    681     snd_mixer_selem_id_t *sid;
    682     snd_mixer_selem_id_alloca(&sid);
    683     snd_mixer_selem_id_set_index(sid, 0);
    684     snd_mixer_selem_id_set_name(sid, ctl.constData());
    685 
    686     snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);
    687     if (!elem)
    688     {
    689         VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")
    690                 .arg(control));
    691         return;
    692     }
    693 
    694     snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
    695     if (!snd_mixer_selem_has_playback_channel(elem, chan))
    696     {
    697         snd_mixer_selem_id_set_index(sid, channel);
    698         if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)
    699         {
    700             VERBOSE(VB_IMPORTANT,
    701                     QString("mixer unable to find control %1 %2")
    702                     .arg(control).arg(channel));
    703             return;
    704         }
    705     }
    706 
    707     ALSAVolumeInfo vinfo = GetVolumeRange(elem);
    708 
    709     long set_vol = vinfo.ToALSARange(volume);
    710 
    711     int err = snd_mixer_selem_set_playback_volume(elem, chan, set_vol);
    712     if (err < 0)
    713     {
    714         VERBOSE(VB_IMPORTANT, QString("mixer set channel %1 err %2: %3")
    715                 .arg(channel).arg(err).arg(snd_strerror(err)));
    716     }
    717     else
    718     {
    719         VERBOSE(VB_AUDIO, QString("channel %1 vol set to %2")
    720                 .arg(channel).arg(set_vol));
    721     }
    722 
    723     if (snd_mixer_selem_has_playback_switch(elem))
    724     {
    725         int unmute = (0 != set_vol);
    726         if (snd_mixer_selem_has_playback_switch_joined(elem))
    727         {
    728             // Only mute if all the channels should be muted.
    729             for (int i = 0; i < audio_channels; i++)
    730             {
    731                 if (0 != GetVolumeChannel(i))
    732                     unmute = 1;
    733             }
    734         }
    735 
    736         err = snd_mixer_selem_set_playback_switch(elem, chan, unmute);
    737         if (err < 0)
    738         {
    739             VERBOSE(VB_IMPORTANT, LOC_ERR +
    740                     QString("Mixer set playback switch %1 err %2: %3")
    741                     .arg(channel).arg(err).arg(snd_strerror(err)));
    742         }
    743         else
    744         {
    745             VERBOSE(VB_AUDIO, LOC +
    746                     QString("channel %1 playback switch set to %2")
    747                     .arg(channel).arg(unmute));
    748         }
    749     }
    750 }
    751 
    752 void AudioOutputALSA::OpenMixer(bool setstartingvolume)
    753 {
    754     int volume;
    755 
    756     mixer_control = gCoreContext->GetSetting("MixerControl", "PCM");
    757 
    758     SetupMixer();
    759 
    760     if (mixer_handle != NULL && setstartingvolume)
    761     {
    762         volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
    763         SetCurrentVolume("Master", 0, volume);
    764         SetCurrentVolume("Master", 1, volume);
    765 
    766         volume = gCoreContext->GetNumSetting("PCMMixerVolume", 80);
    767         SetCurrentVolume("PCM", 0, volume);
    768         SetCurrentVolume("PCM", 1, volume);
    769     }
    770 }
    771 
    772 void AudioOutputALSA::CloseMixer(void)
    773 {
    774     if (mixer_handle != NULL)
    775         snd_mixer_close(mixer_handle);
    776     mixer_handle = NULL;
    777 }
    778 
    779 void AudioOutputALSA::SetupMixer(void)
    780 {
    781     int err;
    782 
    783     QString alsadevice = gCoreContext->GetSetting("MixerDevice", "default");
    784     QString device = alsadevice.remove(QString("ALSA:"));
    785 
    786     if (mixer_handle != NULL)
    787         CloseMixer();
    788 
    789     if (alsadevice.toLower() == "software")
    790         return;
    791 
    792     VERBOSE(VB_AUDIO, QString("Opening mixer %1").arg(device));
    793 
    794     // TODO: This is opening card 0. Fix for case of multiple soundcards
    795     if ((err = snd_mixer_open(&mixer_handle, 0)) < 0)
    796     {
    797         Warn(QString("Mixer device open error %1: %2")
    798              .arg(err).arg(snd_strerror(err)));
    799         mixer_handle = NULL;
    800         return;
    801     }
    802 
    803     QByteArray dev = device.toAscii();
    804     if ((err = snd_mixer_attach(mixer_handle, dev.constData())) < 0)
    805     {
    806         Warn(QString("Mixer attach error %1: %2"
    807                      "\n\t\t\tCheck Mixer Name in Setup: '%3'")
    808              .arg(err).arg(snd_strerror(err)).arg(device));
    809         CloseMixer();
    810         return;
    811     }
    812 
    813     if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0)
    814     {
    815         Warn(QString("Mixer register error %1: %2")
    816              .arg(err).arg(snd_strerror(err)));
    817         CloseMixer();
    818         return;
    819     }
    820 
    821     if ((err = snd_mixer_load(mixer_handle)) < 0)
    822     {
    823         Warn(QString("Mixer load error %1: %2")
    824              .arg(err).arg(snd_strerror(err)));
    825         CloseMixer();
    826         return;
    827     }
    828 }
    829 
    830 ALSAVolumeInfo AudioOutputALSA::GetVolumeRange(snd_mixer_elem_t *elem) const
    831 {
    832     long volume_min, volume_max;
    833 
    834     int err = snd_mixer_selem_get_playback_volume_range(
    835         elem, &volume_min, &volume_max);
    836 
    837     if (err < 0)
    838     {
    839         static bool first_time = true;
    840         if (first_time)
    841         {
    842             VERBOSE(VB_IMPORTANT,
    843                     "snd_mixer_selem_get_playback_volume_range()" + ENO);
    844             first_time = false;
    845         }
    846     }
    847 
    848     ALSAVolumeInfo vinfo(volume_min, volume_max);
    849 
    850     VERBOSE(VB_AUDIO, QString("Volume range is %1 to %2, mult=%3")
    851             .arg(vinfo.volume_min).arg(vinfo.volume_max)
    852             .arg(vinfo.range_multiplier));
    853 
    854     return vinfo;
    855 }
    856 
    857693QMap<QString, QString> GetALSADevices(const char *type)
    858694{
    859695    QMap<QString, QString> alsadevs;
  • mythtv/libs/libmyth/volumebase.cpp

     
    1 #include <cstdio>
    2 #include <cstdlib>
    3 
    4 #include <algorithm>
    5 using namespace std;
    6 
    7 #include <QString>
    8 
    9 #include "volumebase.h"
    10 #include "mythcorecontext.h"
    11 
    12 VolumeBase::VolumeBase() :
    13     internal_vol(false), volume(80),
    14     current_mute_state(kMuteOff)
    15 {
    16     swvol = swvol_setting =
    17         (gCoreContext->GetSetting("MixerDevice", "default").toLower() == "software");
    18 }
    19 
    20 bool VolumeBase::SWVolume(void)
    21 {
    22     return swvol;
    23 }
    24 
    25 void VolumeBase::SWVolume(bool set)
    26 {
    27     if (swvol_setting)
    28         return;
    29     swvol = set;
    30 }
    31 
    32 uint VolumeBase::GetCurrentVolume(void) const
    33 {
    34     return volume;
    35 }
    36 
    37 void VolumeBase::SetCurrentVolume(int value)
    38 {
    39     volume = max(min(value, 100), 0);
    40     UpdateVolume();
    41 
    42     QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
    43     controlLabel += "MixerVolume";
    44     gCoreContext->SaveSetting(controlLabel, volume);   
    45 }
    46 
    47 void VolumeBase::AdjustCurrentVolume(int change)
    48 {
    49     SetCurrentVolume(volume + change);
    50 }
    51 
    52 MuteState VolumeBase::SetMuteState(MuteState mstate)
    53 {
    54     current_mute_state = mstate;
    55     UpdateVolume();
    56     return current_mute_state;
    57 }
    58 
    59 void VolumeBase::ToggleMute(void)
    60 {
    61     bool is_muted = GetMuteState() == kMuteAll;
    62     SetMuteState((is_muted) ? kMuteOff : kMuteAll);
    63 }
    64 
    65 MuteState VolumeBase::GetMuteState(void) const
    66 {
    67     return current_mute_state;
    68 }
    69 
    70 MuteState VolumeBase::NextMuteState(MuteState cur)
    71 {
    72     MuteState next = cur;
    73 
    74     switch (cur)
    75     {
    76        case kMuteOff:
    77            next = kMuteLeft;
    78            break;
    79        case kMuteLeft:
    80            next = kMuteRight;
    81            break;
    82        case kMuteRight:
    83            next = kMuteAll;
    84            break;
    85        case kMuteAll:
    86            next = kMuteOff;
    87            break;
    88     }
    89 
    90     return (next);
    91 }
    92 
    93 void VolumeBase::UpdateVolume(void)
    94 {
    95     int new_volume = volume;
    96     bool save = true;
    97     if (current_mute_state == kMuteAll)
    98     {
    99         new_volume = 0;
    100         save = false;
    101     }
    102 
    103     if (swvol)
    104     {
    105         SetSWVolume(new_volume, save);
    106         return;
    107     }
    108    
    109     // TODO: Avoid assumption that there are 2 channels!
    110     for (int i = 0; i < 2; i++)
    111     {
    112         SetVolumeChannel(i, new_volume);
    113     }
    114    
    115     // Individual channel muting is handled in GetAudioData,
    116     // this code demonstrates the old method.
    117     // if (current_mute_state == kMuteLeft)
    118     // {
    119     //     SetVolumeChannel(0, 0);
    120     // }
    121     // else if (current_mute_state == kMuteRight)
    122     // {
    123     //     SetVolumeChannel(1, 0);
    124     // }
    125 }
    126 
    127 void VolumeBase::SyncVolume(void)
    128 {
    129     // Read the volume from the audio driver and setup our internal state to match
    130     if (swvol)
    131         volume = GetSWVolume();
    132     else
    133         volume = GetVolumeChannel(0);
    134 }
    135 
  • mythtv/libs/libmyth/volumecontrolcoreaudio.h

     
     1#ifndef VOLUMECONTROLCOREAUDIO
     2#define VOLUMECONTROLCOREAUDIO
     3
     4#include "volumecontrol.h"
     5
     6#include <QHash>
     7#include <QAtomicInt>
     8#include <CoreAudio/CoreAudio.h>
     9
     10
     11class VolumeControlCoreAudio : public VolumeControl
     12{
     13public:
     14    static QHash<QString, QString> Enumerate();
     15
     16public:
     17    VolumeControlCoreAudio(QString device);
     18    virtual ~VolumeControlCoreAudio();
     19
     20public:
     21    int  volume() const;
     22    void setVolume(int volume);
     23    void increaseVolume();
     24    void decreaseVolume();
     25
     26    bool mute() const;
     27    void setMute(bool mute);
     28
     29protected:
     30    static OSStatus event(AudioDeviceID deviceId, UInt32 channel,
     31                          Boolean input, AudioDevicePropertyID property,
     32                          void* context);
     33
     34private:
     35    AudioDeviceID     m_DeviceId;       //< Core Audio device ID
     36    QAtomicInt        m_Volume;         //< Volume state cache
     37    QAtomicInt        m_Mute;           //< Mute state cache
     38};
     39
     40#endif // VOLUMECONTROLCOREAUDIO
  • mythtv/libs/libmyth/volumecontrolsoftware.h

     
     1#ifndef VOLUMECONTROLSOFTWARE
     2#define VOLUMECONTROLSOFTWARE
     3
     4#include "volumecontrol.h"
     5
     6#include <QHash>
     7#include <QAtomicInt>
     8
     9
     10class VolumeControlSoftware : public VolumeControl
     11{
     12public:
     13    static QHash<QString, QString> Enumerate();
     14
     15public:
     16    VolumeControlSoftware(QString device);
     17    virtual ~VolumeControlSoftware();
     18
     19public:
     20    int  volume() const;
     21    void setVolume(int volume);
     22    void increaseVolume();
     23    void decreaseVolume();
     24
     25    bool mute() const;
     26    void setMute(bool mute);
     27
     28private:
     29    static QAtomicInt m_Volume;         //< Volume state cache
     30    static QAtomicInt m_Mute;           //< Mute state cache
     31};
     32
     33#endif // VOLUMECONTROLSOFTWARE
  • mythtv/libs/libmyth/volumecontrolcoreaudio.cpp

     
     1#include "volumecontrolcoreaudio.h"
     2
     3#include <CoreServices/CoreServices.h>
     4#include <CoreAudio/CoreAudio.h>
     5
     6#include "mythverbose.h"
     7#include <algorithm>
     8
     9// static
     10QHash<QString, QString> VolumeControlCoreAudio::Enumerate()
     11{
     12    QHash<QString, QString> result;
     13
     14    result.insert("CoreAudio:default", "Default Core Audio device");
     15
     16    UInt32 size;
     17    AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
     18                                 &size, NULL); 
     19    UInt32 count = size / sizeof(AudioDeviceID);
     20
     21    AudioDeviceID* devices = new AudioDeviceID[count];
     22    AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
     23                             &size, devices);
     24
     25    for (unsigned int index = 0; index < count; ++index)
     26    {
     27        bool output = false;
     28
     29        AudioDeviceGetPropertyInfo(devices[index], 0, 0,
     30                                   kAudioDevicePropertyStreamConfiguration,
     31                                   &size, NULL);
     32        if (!size)
     33            continue;
     34
     35        AudioBufferList* buffers = static_cast<AudioBufferList*>(malloc(size));
     36        AudioDeviceGetProperty(devices[index], 0, 0,
     37                               kAudioDevicePropertyStreamConfiguration,
     38                               &size, buffers);
     39        for (UInt32 buffer = 0; buffer < buffers->mNumberBuffers; ++buffer)
     40        {
     41            if (buffers->mBuffers[buffer].mNumberChannels)
     42            {
     43                output = true;
     44                break;
     45            }
     46        }
     47
     48        free(buffers);
     49
     50        if (!output)
     51            continue;
     52
     53        QString uid;
     54        CFStringRef uidcf;
     55        size = sizeof(CFStringRef);
     56        AudioDeviceGetProperty(devices[index], 0, 0,
     57                               kAudioDevicePropertyDeviceUID,
     58                               &size, &uidcf);
     59        if (uidcf)
     60        {
     61            char buffer[256];
     62            CFStringGetCString(uidcf, buffer, 256,
     63                               CFStringGetFastestEncoding(uidcf));
     64            uid = QString(buffer);
     65            CFRelease(uidcf);
     66        }
     67
     68        AudioDeviceGetPropertyInfo(devices[index], 0, 0,
     69                                   kAudioDevicePropertyDeviceName,
     70                                   &size, NULL);
     71        if (!size)
     72            continue;
     73
     74        char* name = static_cast<char*>(malloc(size));
     75        AudioDeviceGetProperty(devices[index], 0, 0,
     76                               kAudioDevicePropertyDeviceName,
     77                               &size, name);
     78
     79        result.insert(QString("CoreAudio:") + uid, name);
     80
     81        free(name);
     82    }
     83
     84    delete devices;
     85
     86    return result;
     87}
     88
     89VolumeControlCoreAudio::VolumeControlCoreAudio(QString device) :
     90    m_DeviceId(kAudioDeviceUnknown)
     91{
     92    if (device == QString("default"))
     93    {
     94        UInt32 size = sizeof(AudioDeviceID);
     95        AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
     96                                 &size, &m_DeviceId);       
     97    }
     98    else
     99    {
     100        CFStringRef cfString =
     101            CFStringCreateWithCharacters(kCFAllocatorDefault,
     102                reinterpret_cast<const UniChar*>(device.unicode()),
     103                device.length());
     104
     105        AudioValueTranslation translateUidToId = {
     106            mInputData:      &cfString,
     107            mInputDataSize:  sizeof(CFStringRef),
     108            mOutputData:     &m_DeviceId,
     109            mOutputDataSize: sizeof(AudioDeviceID)
     110        };
     111
     112        UInt32 translateUidToIdSize = sizeof(AudioValueTranslation);
     113        AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID,
     114                                 &translateUidToIdSize,
     115                                 &translateUidToId);
     116        CFRelease(cfString);
     117    }
     118
     119    AudioDeviceAddPropertyListener(m_DeviceId, 1, false,
     120                                   kAudioDevicePropertyVolumeScalar,
     121                                   &event,
     122                                   this);
     123
     124    AudioDeviceAddPropertyListener(m_DeviceId, 1, false,
     125                                   kAudioDevicePropertyVolumeDecibels,
     126                                   &event,
     127                                   this);
     128
     129    AudioDeviceAddPropertyListener(m_DeviceId, 0, false,
     130                                   kAudioDevicePropertyMute,
     131                                   &event,
     132                                   this);
     133
     134    m_Volume = volume();
     135    m_Mute = mute();
     136}
     137
     138VolumeControlCoreAudio::~VolumeControlCoreAudio()
     139{
     140    AudioDeviceRemovePropertyListener(m_DeviceId, 1, false,
     141                                      kAudioDevicePropertyVolumeScalar,
     142                                      &event);
     143
     144    AudioDeviceRemovePropertyListener(m_DeviceId, 1, false,
     145                                      kAudioDevicePropertyVolumeDecibels,
     146                                      &event);
     147
     148    AudioDeviceRemovePropertyListener(m_DeviceId, 0, false,
     149                                      kAudioDevicePropertyMute,
     150                                      &event);
     151}
     152
     153int VolumeControlCoreAudio::volume() const
     154{
     155    Float32 volume = 0;
     156
     157    if (!mute())
     158    {
     159        UInt32 size = sizeof(Float32);
     160        AudioDeviceGetProperty(m_DeviceId, 1, false,
     161                               kAudioDevicePropertyVolumeScalar,
     162                               &size, &volume);
     163    }
     164    else
     165        volume = static_cast<Float32>(m_Volume) / 100.0f;
     166
     167    VERBOSE(VB_AUDIO,
     168            QString("VolumeControlCoreAudio::volume() = %1")
     169            .arg(static_cast<int>(100.0f * volume)));
     170
     171    return static_cast<int>(100.0f * volume);
     172}
     173
     174void VolumeControlCoreAudio::setVolume(int volume)
     175{
     176    VERBOSE(VB_AUDIO,
     177            QString("VolumeControlCoreAudio::setVolume(%1)")
     178            .arg(volume));
     179
     180    volume = std::min(std::max(0, volume), 100);
     181
     182    if (mute() && volume > VolumeControlCoreAudio::volume())
     183        setMute(false);
     184
     185    if (!mute())
     186    {
     187        Float32 value = static_cast<Float32>(volume) / 100.0f;
     188        AudioDeviceSetProperty(m_DeviceId, NULL, 1, false,
     189                               kAudioDevicePropertyVolumeScalar,
     190                               sizeof(UInt32), &value);
     191    }
     192
     193    if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     194        emit changedVolume(volume);
     195}
     196
     197void VolumeControlCoreAudio::increaseVolume()
     198{
     199    setVolume(volume() + 10);
     200}
     201
     202void VolumeControlCoreAudio::decreaseVolume()
     203{
     204    setVolume(volume() - 10);
     205}
     206
     207bool VolumeControlCoreAudio::mute() const
     208{
     209    UInt32 mute = false;
     210
     211    UInt32 size = sizeof(UInt32);
     212    AudioDeviceGetProperty(m_DeviceId, 0, false,
     213                           kAudioDevicePropertyMute, &size, &mute);
     214
     215    VERBOSE(VB_AUDIO,
     216            QString("VolumeControlCoreAudio::mute() = %1")
     217            .arg(mute ? "mute" : "unmute"));
     218
     219    return mute;
     220}
     221
     222void VolumeControlCoreAudio::setMute(bool mute)
     223{
     224    VERBOSE(VB_AUDIO,
     225            QString("VolumeControlCoreAudio::setMute(%1)")
     226            .arg(mute ? "mute" : "unmute"));
     227
     228    if (VolumeControlCoreAudio::mute())
     229    {
     230        Float32 value = static_cast<Float32>(m_Volume) / 100.0f;
     231        AudioDeviceSetProperty(m_DeviceId, NULL, 1, false,
     232                               kAudioDevicePropertyVolumeScalar,
     233                               sizeof(UInt32), &value);   
     234    }
     235
     236    UInt32 value = mute;
     237    AudioDeviceSetProperty(m_DeviceId, NULL, 0, false,
     238                           kAudioDevicePropertyMute, sizeof(UInt32), &value);
     239
     240    if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     241        emit changedMute(mute);
     242}
     243
     244// static
     245OSStatus VolumeControlCoreAudio::event(AudioDeviceID deviceId, UInt32 channel,
     246                                       Boolean input,
     247                                       AudioDevicePropertyID property,
     248                                       void* context)
     249{
     250    VolumeControlCoreAudio* that =
     251        static_cast<VolumeControlCoreAudio*>(context);
     252
     253    if (deviceId == that->m_DeviceId && !input)
     254        switch(property)
     255        {
     256        case kAudioDevicePropertyVolumeScalar:
     257        case kAudioDevicePropertyVolumeDecibels:
     258            int volume = that->volume();
     259            if (that->m_Volume.fetchAndStoreRelaxed(volume) != volume)
     260                emit that->changedVolume(volume);
     261            break;
     262
     263        case kAudioDevicePropertyMute:
     264            bool mute = that->mute();
     265            if (that->m_Mute.fetchAndStoreRelaxed(mute) != mute)
     266                emit that->changedMute(mute);
     267            break;
     268        }
     269
     270    return noErr;
     271}
  • mythtv/libs/libmyth/volumebase.h

     
    1 #ifndef __VOLUME_BASE__
    2 #define __VOLUME_BASE__
    3 
    4 #include "mythexp.h"
    5 
    6 typedef enum {
    7     kMuteOff = 0,
    8     kMuteLeft,
    9     kMuteRight,
    10     kMuteAll,
    11 } MuteState;
    12 
    13 class MPUBLIC VolumeBase
    14 {
    15   public:
    16     VolumeBase();   
    17     virtual ~VolumeBase() {};
    18 
    19     void SWVolume(bool set);
    20     bool SWVolume(void);
    21     virtual uint GetCurrentVolume(void) const;
    22     virtual void SetCurrentVolume(int value);
    23     virtual void AdjustCurrentVolume(int change);
    24     virtual void ToggleMute(void);
    25 
    26     virtual MuteState GetMuteState(void) const;
    27     virtual MuteState SetMuteState(MuteState);
    28 
    29     static MuteState NextMuteState(MuteState);
    30 
    31   protected:
    32 
    33     virtual int GetVolumeChannel(int channel) const = 0; // Returns 0-100
    34     virtual void SetVolumeChannel(int channel, int volume) = 0; // range 0-100 for vol
    35     virtual void SetSWVolume(int new_volume, bool save) = 0;
    36     virtual int GetSWVolume(void) = 0;
    37 
    38     void UpdateVolume(void);
    39     void SyncVolume(void);
    40 
    41     bool internal_vol;
    42 
    43  private:
    44    
    45     int volume;
    46     MuteState current_mute_state;
    47     bool swvol;
    48     bool swvol_setting;
    49 
    50 };
    51 
    52 #endif // __VOLUME_BASE__
  • mythtv/libs/libmyth/volumecontrol.h

     
     1#ifndef VOLUMECONTROL
     2#define VOLUMECONTROL
     3
     4#include <QObject>
     5#include <QString>
     6
     7class VolumeControl : public QObject
     8{
     9    Q_OBJECT
     10
     11public:
     12    virtual int  volume() const = 0;
     13    virtual void setVolume(int volume) = 0;
     14    virtual void increaseVolume() = 0;
     15    virtual void decreaseVolume() = 0;
     16
     17    virtual bool mute() const = 0;
     18    virtual void setMute(bool mute) = 0;
     19
     20signals:
     21    void changedVolume(int volume);
     22    void changedMute(bool mute);
     23};
     24
     25#endif // VOLUMECONTROL
  • mythtv/libs/libmyth/volumecontrolsoftware.cpp

     
     1#include "volumecontrolsoftware.h"
     2
     3#include "mythcorecontext.h"
     4#include "mythverbose.h"
     5#include <algorithm>
     6
     7// static
     8QHash<QString, QString> VolumeControlSoftware::Enumerate()
     9{
     10    QHash<QString, QString> result;
     11
     12    result.insert("Software:", "Software Volume Processing");
     13
     14    return result;
     15}
     16
     17VolumeControlSoftware::VolumeControlSoftware(QString device)
     18{
     19    int volume = gCoreContext->GetNumSetting("SoftwareVolume", 80);
     20    m_Volume = std::min(std::max(0, volume), 100);
     21    m_Mute = gCoreContext->GetNumSetting("SoftwareMute", false) ? true : false;
     22}
     23
     24VolumeControlSoftware::~VolumeControlSoftware()
     25{
     26
     27}
     28
     29int VolumeControlSoftware::volume() const
     30{
     31    int volume = m_Volume;
     32
     33    VERBOSE(VB_AUDIO,
     34            QString("VolumeControlSoftware::volume() = %1")
     35            .arg(volume));
     36
     37    return volume;
     38}
     39
     40void VolumeControlSoftware::setVolume(int volume)
     41{
     42    VERBOSE(VB_AUDIO,
     43            QString("VolumeControlSoftware::setVolume(%1)")
     44            .arg(volume));
     45
     46    volume = std::min(std::max(0, volume), 100);
     47
     48    if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     49    {
     50        gCoreContext->SaveSetting("SoftwareVolume", volume);
     51        emit changedVolume(volume);
     52    }
     53}
     54
     55void VolumeControlSoftware::increaseVolume()
     56{
     57    setVolume(volume() + 1);
     58}
     59
     60void VolumeControlSoftware::decreaseVolume()
     61{
     62    setVolume(volume() - 1);
     63}
     64
     65bool VolumeControlSoftware::mute() const
     66{
     67    bool mute = m_Mute ? true : false;
     68
     69    VERBOSE(VB_AUDIO,
     70            QString("VolumeControlSoftware::mute() = %1")
     71            .arg(mute ? "mute" : "unmute"));
     72
     73    return mute;
     74}
     75
     76void VolumeControlSoftware::setMute(bool mute)
     77{
     78    VERBOSE(VB_AUDIO,
     79            QString("VolumeControlSoftware::setMute(%1)")
     80            .arg(mute ? "mute" : "unmute"));
     81
     82    if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     83    {
     84        gCoreContext->SaveSetting("SoftwareMute", mute);
     85        emit changedMute(mute);
     86    }
     87}
     88
     89QAtomicInt VolumeControlSoftware::m_Volume;
     90QAtomicInt VolumeControlSoftware::m_Mute;
  • mythtv/libs/libmyth/audiooutputpulse.h

     
    3030    AudioOutputPulseAudio(const AudioSettings &settings);
    3131   ~AudioOutputPulseAudio();
    3232
    33     int GetVolumeChannel(int channel) const;
    34     void SetVolumeChannel(int channel, int volume);
    3533    void Pause(bool paused);
    3634    void Reset(void);
    3735    void Drain(void);
  • mythtv/libs/libmyth/volumecontroloss.h

     
     1#ifndef VOLUMECONTROLOSS
     2#define VOLUMECONTROLOSS
     3
     4#include "volumecontrol.h"
     5
     6#include <QHash>
     7#include <QThread>
     8#include <QAtomicInt>
     9
     10
     11class VolumeControlOSS : public VolumeControl, protected QThread
     12{
     13public:
     14    static QHash<QString, QString> Enumerate();
     15
     16public:
     17    VolumeControlOSS(QString device);
     18    virtual ~VolumeControlOSS();
     19
     20public:
     21    int  volume() const;
     22    void setVolume(int volume);
     23    void increaseVolume();
     24    void decreaseVolume();
     25
     26    bool mute() const;
     27    void setMute(bool mute);
     28
     29protected:
     30    virtual void run();
     31
     32private:
     33    int               m_Mixer;              //< OSS mixer file descriptor
     34    int               m_MixerDev;           //< OSS mixer device ID
     35    int               m_VolumeCtrl;         //< OSS control ID for volume
     36    int               m_VolumeMax;          //< OSS maximum for volume
     37    int               m_VolumeType;         //< OSS control type for volume
     38    int               m_VolumeTimestamp;    //< OSS timestamp for volume
     39    int               m_MuteCtrl;           //< OSS control ID for mute
     40    int               m_MuteTimestamp;      //< OSS timestamp for mute
     41    int               m_Range;              //< Range of volume control
     42    volatile bool     m_Exit;               //< Flag to notify thread to exit
     43    QAtomicInt        m_Volume;             //< Volume state cache
     44    QAtomicInt        m_Mute;               //< Mute state cache
     45};
     46
     47#endif // VOLUMECONTROLOSS
  • mythtv/libs/libmyth/volumecontrolalsa.h

     
     1#ifndef VOLUMECONTROLALSA
     2#define VOLUMECONTROLALSA
     3
     4#include "volumecontrol.h"
     5
     6#include <QHash>
     7#include <QThread>
     8#include <QAtomicInt>
     9#include <alsa/asoundlib.h>
     10
     11
     12class VolumeControlALSA : public VolumeControl, protected QThread
     13{
     14public:
     15    static QHash<QString, QString> Enumerate();
     16
     17public:
     18    VolumeControlALSA(QString device);
     19    virtual ~VolumeControlALSA();
     20
     21public:
     22    int  volume() const;
     23    void setVolume(int volume);
     24    void increaseVolume();
     25    void decreaseVolume();
     26
     27    bool mute() const;
     28    void setMute(bool mute);
     29
     30protected:
     31    virtual void run();
     32
     33    static int event(snd_mixer_elem_t* elem, unsigned int mask);
     34
     35private:
     36    snd_mixer_t*      m_MixerHandle;    //< ALSA mixer handle
     37    snd_mixer_elem_t* m_MixerElement;   //< ALSA mixer element handle
     38    int               m_Range;          //< Range of mixer element
     39    int               m_Exit[2];        //< Pipe file descriptors
     40    QAtomicInt        m_Volume;         //< Volume state cache
     41    QAtomicInt        m_Mute;           //< Mute state cache
     42};
     43
     44#endif // VOLUMECONTROLALSA
  • mythtv/libs/libmyth/audiooutputpulse.cpp

     
    268268    return writable;
    269269}
    270270
    271 int AudioOutputPulseAudio::GetVolumeChannel(int channel) const
    272 {
    273     return (float)volume_control.values[channel]
    274         / (float)PA_VOLUME_NORM * 100.0f;
    275 }
    276 
    277 void AudioOutputPulseAudio::SetVolumeChannel(int channel, int volume)
    278 {
    279     QString fn_log_tag = "SetVolumeChannel, ";
    280     if (channel < 0 || channel > PULSE_MAX_CHANNELS || volume < 0)
    281     {
    282         VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +
    283                 QString("bad volume params, channel %1, volume %2")
    284                 .arg(channel).arg(volume));
    285         return;
    286     }
    287     volume_control.values[channel] =
    288         (float)volume / 100.0f * (float)PA_VOLUME_NORM;
    289     volume = min(100, volume);
    290     volume = max(0, volume);
    291     uint32_t sink_index = pa_stream_get_device_index(pstream);
    292     pa_threaded_mainloop_lock(mainloop);
    293     pa_operation *op =
    294         pa_context_set_sink_volume_by_index(pcontext, sink_index,
    295                                             &volume_control,
    296                                             OpCompletionCallback, this);
    297     pa_threaded_mainloop_unlock(mainloop);
    298     if (op)
    299         pa_operation_unref(op);
    300     else
    301         VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +
    302                 QString("set sink volume operation failed, sink: %1, "
    303                         "error: %2 ")
    304                 .arg(sink_index)
    305                 .arg(pa_strerror(pa_context_errno(pcontext))));
    306 }
    307 
    308271void AudioOutputPulseAudio::Pause(bool paused)
    309272{
    310273    pa_operation *op;
     
    545508    pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over");
    546509    pa_stream_set_underflow_callback(pstream, BufferFlowCallback,
    547510                                     (char*)"under");
    548     if (set_initial_vol)
    549     {
    550         int volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
    551         pa_cvolume_set(&volume_control, audio_channels,
    552                        (float)volume * (float)PA_VOLUME_NORM / 100.0f);
    553     }
    554     else
    555         pa_cvolume_reset(&volume_control, audio_channels);
     511    pa_cvolume_reset(&volume_control, audio_channels);
    556512
    557513    // set myth sizes and pa buffer metrics (20 ms)
    558514    // Note: The 20 is an unsigned long (at least 32 bits).
  • mythtv/libs/libmyth/volumecontrolendpoint.cpp

     
     1#include "volumecontrolendpoint.h"
     2
     3#include "mythverbose.h"
     4#include <algorithm>
     5#include <math.h>
     6
     7typedef struct _BYTE_BLOB
     8    {
     9    unsigned long clSize;
     10    byte abData[ 1 ];
     11    }   BYTE_BLOB;
     12
     13typedef struct _tagpropertykey
     14    {
     15    GUID fmtid;
     16    DWORD pid;
     17    }   PROPERTYKEY;
     18
     19#define REFPROPVARIANT const PROPVARIANT &
     20
     21inline void PropVariantInit ( PROPVARIANT * pvar )
     22{
     23    memset ( pvar, 0, sizeof(PROPVARIANT) );
     24}
     25WINOLEAPI PropVariantClear ( PROPVARIANT * pvar );
     26
     27EXTERN_C const CLSID CLSID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C,{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}};
     28EXTERN_C const IID IID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35,{0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}};
     29EXTERN_C const IID IID_IAudioEndpointVolume = {0x5CDF2C82,0x841E,0x4546,{0x97,0x22,0x0C,0xF7,0x40,0x78,0x22,0x9A}};
     30EXTERN_C const IID IID_IAudioEndpointVolumeCallback = {0x657804FA,0xD6AD,0x4496,{0x8A,0x60,0x35,0x27,0x52,0xAF,0x4F,0x89}};
     31EXTERN_C const IID IID_IUnknown = {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
     32#define INITGUID
     33#include <Unknwn.h>
     34#include <mmdeviceapi.h>
     35#include <FunctionDiscoveryKeys_devpkey.h>
     36
     37
     38QHash<QString, QString> VolumeControlEndpoint::Enumerate()
     39{
     40    QHash<QString, QString> result;
     41
     42    HRESULT hr = S_OK;
     43    IMMDeviceEnumerator* pEnumerator = NULL;
     44    IMMDeviceCollection* pCollection = NULL;
     45
     46    CoInitialize(NULL);
     47
     48    // Get enumerator for audio endpoint devices.
     49    hr = CoCreateInstance(CLSID_MMDeviceEnumerator,
     50                          NULL, CLSCTX_INPROC_SERVER,
     51                          IID_IMMDeviceEnumerator,
     52                          (void**)&pEnumerator);
     53    if (!SUCCEEDED(hr) || !pEnumerator)
     54    {
     55        CoUninitialize();
     56        return result;
     57    }
     58
     59    result.insert("Endpoint:default", "Default End Point device");
     60
     61    hr = pEnumerator->EnumAudioEndpoints(eRender,
     62                                         DEVICE_STATE_ACTIVE,
     63                                         &pCollection);
     64    if (!SUCCEEDED(hr) || !pCollection)
     65    {
     66        pEnumerator->Release();
     67        CoUninitialize();
     68        return result;
     69    }
     70
     71    UINT devices = 0;
     72    hr = pCollection->GetCount(&devices);
     73    if (!SUCCEEDED(hr))
     74    {
     75        pCollection->Release();
     76        pEnumerator->Release();
     77        CoUninitialize();
     78        return result;
     79    }
     80
     81    for (UINT device = 0; device < devices; ++device)
     82    {
     83        IMMDevice* pDevice = NULL;
     84        hr = pCollection->Item(device, &pDevice);
     85        if (!SUCCEEDED(hr) || !pDevice)
     86            continue;
     87
     88        LPWSTR pwszID = NULL;
     89        hr = pDevice->GetId(&pwszID);
     90        if (!SUCCEEDED(hr))
     91        {
     92            pDevice->Release();
     93            continue;
     94        }
     95        QString uid(reinterpret_cast<const QChar*>(pwszID), wcslen(pwszID));
     96        CoTaskMemFree(pwszID);
     97
     98        IPropertyStore *pProps = NULL;
     99        hr = pDevice->OpenPropertyStore(STGM_READ, &pProps);
     100        if (!SUCCEEDED(hr) || !pProps)
     101        {
     102            pDevice->Release();
     103            continue;
     104        }
     105
     106        PROPVARIANT varName;
     107        PropVariantInit(&varName);
     108
     109        hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
     110        if (!SUCCEEDED(hr))
     111        {
     112            PropVariantClear(&varName);
     113            pProps->Release();
     114            pDevice->Release();
     115            continue;
     116        }
     117        QString name(reinterpret_cast<const QChar*>(varName.pwszVal),
     118                     wcslen(varName.pwszVal));
     119        PropVariantClear(&varName);
     120
     121        pProps->Release();
     122        pDevice->Release();
     123
     124        result.insert(QString("Endpoint:") + uid, name);
     125    }
     126
     127    pCollection->Release();
     128    pEnumerator->Release();
     129
     130    CoUninitialize();
     131
     132    return result;
     133}
     134
     135VolumeControlEndpoint::VolumeControlEndpoint(QString device) :
     136    m_EndpointVolume(NULL)
     137{
     138    HRESULT hr = S_OK;
     139    IMMDeviceEnumerator* pEnumerator = NULL;
     140    IMMDevice* pDevice = NULL;
     141
     142    CoInitialize(NULL);
     143
     144    // Get enumerator for audio endpoint devices.
     145    hr = CoCreateInstance(CLSID_MMDeviceEnumerator,
     146                          NULL, CLSCTX_INPROC_SERVER,
     147                          IID_IMMDeviceEnumerator,
     148                          (void**)&pEnumerator);
     149    if (!SUCCEEDED(hr) || !pEnumerator)
     150        return;
     151
     152    if (device == QString("default"))
     153        hr = pEnumerator->GetDefaultAudioEndpoint(eRender,
     154                                                  eMultimedia,
     155                                                  &pDevice);
     156    else
     157        hr = pEnumerator->GetDevice((LPCWSTR)device.constData(), &pDevice);
     158
     159    if (!SUCCEEDED(hr) || !pDevice)
     160    {
     161        pEnumerator->Release();
     162        return;
     163    }
     164
     165    hr = pDevice->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL,
     166                           NULL, (void**)&m_EndpointVolume);
     167    if (!SUCCEEDED(hr) || !m_EndpointVolume)
     168    {
     169        pDevice->Release();
     170        pEnumerator->Release();
     171        return;
     172    }
     173
     174    pDevice->Release();
     175    pEnumerator->Release();
     176
     177    hr = m_EndpointVolume->RegisterControlChangeNotify(this);
     178    if (!SUCCEEDED(hr))
     179        return;
     180
     181    UINT step, count;
     182    hr = m_EndpointVolume->GetVolumeStepInfo(&step, &count);
     183    if (!SUCCEEDED(hr))
     184        return;
     185
     186    m_Range = std::min(std::max(1U, count - 1), 100U);
     187
     188    m_Volume = volume();
     189    m_Mute = mute();
     190}
     191
     192VolumeControlEndpoint::~VolumeControlEndpoint()
     193{
     194    if (m_EndpointVolume)
     195    {
     196        m_EndpointVolume->UnregisterControlChangeNotify(this);
     197        m_EndpointVolume->Release();
     198    }
     199
     200    CoUninitialize();
     201}
     202
     203int VolumeControlEndpoint::volume() const
     204{
     205    int volume = 0;
     206
     207    if (!mute())
     208    {
     209                if (m_EndpointVolume)
     210        {
     211            float level;
     212            m_EndpointVolume->GetMasterVolumeLevelScalar(&level);
     213            volume = static_cast<int>(round(level * 100.0f));
     214                }
     215    }
     216    else
     217        volume = m_Volume;
     218
     219    VERBOSE(VB_AUDIO,
     220            QString("VolumeControlEndpoint::volume() = %1")
     221            .arg(volume));
     222
     223    return volume;
     224}
     225
     226void VolumeControlEndpoint::setVolume(int volume)
     227{
     228    VERBOSE(VB_AUDIO,
     229            QString("VolumeControlEndpoint::setVolume(%1)")
     230            .arg(volume));
     231
     232    volume = std::min(std::max(0, volume), 100);
     233
     234    if (mute() && volume > VolumeControlEndpoint::volume())
     235        setMute(false);
     236
     237    if (!mute() && m_EndpointVolume)
     238        m_EndpointVolume->SetMasterVolumeLevelScalar(
     239            round(static_cast<float>(volume * m_Range) / 100.0f) /
     240                  static_cast<float>(m_Range), NULL);
     241
     242    if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     243        emit changedVolume(volume);
     244}
     245
     246void VolumeControlEndpoint::increaseVolume()
     247{
     248    int volume = VolumeControlEndpoint::volume();
     249    float level = (round(static_cast<float>(volume * m_Range) / 100.0f) + 1.0f)
     250                  / static_cast<float>(m_Range);
     251        volume = static_cast<int>(round(level * 100.0f));
     252    setVolume(volume);
     253}
     254
     255void VolumeControlEndpoint::decreaseVolume()
     256{
     257    int volume = VolumeControlEndpoint::volume();
     258    float level = (round(static_cast<float>(volume * m_Range) / 100.0f) - 1.0f)
     259                  / static_cast<float>(m_Range);
     260        volume = static_cast<int>(round(level * 100.0f));
     261    setVolume(volume);
     262}
     263
     264bool VolumeControlEndpoint::mute() const
     265{
     266    BOOL mute = FALSE;
     267
     268    if (m_EndpointVolume)
     269        m_EndpointVolume->GetMute(&mute);
     270
     271    VERBOSE(VB_AUDIO,
     272            QString("VolumeControlEndpoint::mute() = %1")
     273            .arg(mute ? "mute" : "unmute"));
     274
     275    return mute;
     276}
     277
     278void VolumeControlEndpoint::setMute(bool mute)
     279{
     280    VERBOSE(VB_AUDIO,
     281            QString("VolumeControlEndpoint::setMute(%1)")
     282            .arg(mute ? "mute" : "unmute"));
     283
     284    if (m_EndpointVolume)
     285    {
     286        if (VolumeControlEndpoint::mute())
     287            m_EndpointVolume->SetMasterVolumeLevelScalar(
     288                static_cast<float>(m_Volume) / 100.0f, NULL);
     289
     290        m_EndpointVolume->SetMute(mute, NULL);
     291    }
     292
     293    if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     294        emit changedMute(mute);
     295}
     296
     297ULONG STDMETHODCALLTYPE VolumeControlEndpoint::AddRef()
     298{
     299    return 1;
     300}
     301
     302ULONG STDMETHODCALLTYPE VolumeControlEndpoint::Release()
     303{
     304    return 0;
     305}
     306
     307HRESULT STDMETHODCALLTYPE
     308VolumeControlEndpoint::QueryInterface(REFIID riid, VOID **ppvInterface)
     309{
     310    if (IID_IUnknown == riid)
     311    {
     312        AddRef();
     313        *ppvInterface = (IUnknown*)this;
     314    }
     315    else if (IID_IAudioEndpointVolumeCallback == riid)
     316    {
     317        AddRef();
     318        *ppvInterface = (IAudioEndpointVolumeCallback*)this;
     319    }
     320    else
     321    {
     322        *ppvInterface = NULL;
     323        return E_NOINTERFACE;
     324    }
     325    return S_OK;
     326}
     327
     328HRESULT STDMETHODCALLTYPE
     329VolumeControlEndpoint::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify)
     330{
     331    HRESULT hr = E_INVALIDARG;
     332
     333    if (pNotify)
     334    {
     335        int volume = VolumeControlEndpoint::volume();
     336        if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     337            emit changedVolume(volume);
     338
     339        bool mute = VolumeControlEndpoint::mute();
     340        if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     341            emit changedMute(mute);
     342
     343        hr = S_OK;
     344    }
     345
     346    return hr;
     347}
  • mythtv/libs/libmyth/audiooutputjack.h

     
    1111    AudioOutputJACK(const AudioSettings &settings);
    1212    virtual ~AudioOutputJACK();
    1313   
    14     // Volume control
    15     virtual int GetVolumeChannel(int channel) const; // Returns 0-100
    16     virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol
    17  
    1814  protected:
    1915
    2016    // You need to implement the following functions
     
    2723
    2824  private:
    2925
    30     void VolumeInit(void);
    31 
    3226    int audioid;
    3327
    3428};
  • mythtv/libs/libmyth/audiosettings.cpp

     
    1515    channels(-1),
    1616    codec(0),
    1717    samplerate(-1),
    18     set_initial_vol(false),
    1918    use_passthru(false),
    2019    source(AUDIOOUTPUT_UNKNOWN),
    2120    upmixer(0)
     
    2928    channels(other.channels),
    3029    codec(other.codec),
    3130    samplerate(other.samplerate),
    32     set_initial_vol(other.set_initial_vol),
    3331    use_passthru(other.use_passthru),
    3432    source(other.source),
    3533    upmixer(other.upmixer)
     
    4442    int audio_codec,
    4543    int audio_samplerate,
    4644    AudioOutputSource audio_source,
    47     bool audio_set_initial_vol,
    4845    bool audio_use_passthru,
    4946    int upmixer_startup) :
    5047    main_device(audio_main_device),
     
    5350    channels(audio_channels),
    5451    codec(audio_codec),
    5552    samplerate(audio_samplerate),
    56     set_initial_vol(audio_set_initial_vol),
    5753    use_passthru(audio_use_passthru),
    5854    source(audio_source),
    5955    upmixer(upmixer_startup)
     
    7369    channels(audio_channels),
    7470    codec(audio_codec),
    7571    samplerate(audio_samplerate),
    76     set_initial_vol(false),
    7772    use_passthru(audio_use_passthru),
    7873    source(AUDIOOUTPUT_UNKNOWN),
    7974    upmixer(upmixer_startup)
  • mythtv/libs/libmyth/audiooutputca.cpp

     
    244244        return false;
    245245    }
    246246
    247     if (internal_vol && set_initial_vol)
    248     {
    249         QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
    250         controlLabel += "MixerVolume";
    251         SetCurrentVolume(gCoreContext->GetNumSetting(controlLabel, 80));
    252     }
    253 
    254247    return true;
    255248}
    256249
     
    399392    return noErr;
    400393}
    401394
    402 int AudioOutputCA::GetVolumeChannel(int channel) const
    403 {
    404     // FIXME: this only returns global volume
    405     (void)channel;
    406     Float32 volume;
    407 
    408     if (!AudioUnitGetParameter(d->mOutputUnit,
    409                                kHALOutputParam_Volume,
    410                                kAudioUnitScope_Global, 0, &volume))
    411         return (int)lroundf(volume * 100.0);
    412 
    413     return 0;    // error case
    414 }
    415 
    416 void AudioOutputCA::SetVolumeChannel(int channel, int volume)
    417 {
    418     // FIXME: this only sets global volume
    419     (void)channel;
    420      AudioUnitSetParameter(d->mOutputUnit, kHALOutputParam_Volume,
    421                            kAudioUnitScope_Global, 0, (volume * 0.01), 0);
    422 }
    423 
    424395// IOProc style callback for SPDIF audio output
    425396static OSStatus RenderCallbackSPDIF(AudioDeviceID        inDevice,
    426397                                    const AudioTimeStamp *inNow,
  • mythtv/libs/libmyth/audiooutputwin.h

     
    1313    AudioOutputWin(const AudioSettings &settings);
    1414    virtual ~AudioOutputWin();
    1515
    16     // Volume control
    17     virtual int  GetVolumeChannel(int channel) const;
    18     virtual void SetVolumeChannel(int channel, int volume);
    19 
    2016  protected:
    2117    virtual bool OpenDevice(void);
    2218    virtual void CloseDevice(void);
  • mythtv/libs/libmyth/audiooutputjack.cpp

     
    150150    audio_buffer_unused = JACK_GetBytesFreeSpace(audioid);
    151151    JACK_SetPosition(audioid, BYTES, 0);
    152152
    153     // Setup volume control
    154     if (internal_vol)
    155         VolumeInit();
    156 
    157153    // Device opened successfully
    158154    return true;
    159155}
     
    208204
    209205    return space;
    210206}
    211 
    212 void AudioOutputJACK::VolumeInit(void)
    213 {
    214     int volume = 100;
    215     if (set_initial_vol)
    216         volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
    217 
    218     JACK_SetAllVolume(audioid, volume);
    219 }
    220 
    221 int AudioOutputJACK::GetVolumeChannel(int channel) const
    222 {
    223     unsigned int vol = 0;
    224    
    225     if (!internal_vol)
    226         return 100;
    227 
    228     JACK_GetVolumeForChannel(audioid, channel, &vol);
    229     return vol;
    230 }
    231 
    232 void AudioOutputJACK::SetVolumeChannel(int channel, int volume)
    233 {
    234     if (internal_vol)
    235         JACK_SetVolumeForChannel(audioid, channel, volume);
    236 }
    237 
  • mythtv/libs/libmyth/audiooutputoss.h

     
    1212    AudioOutputOSS(const AudioSettings &settings);
    1313    virtual ~AudioOutputOSS();
    1414
    15     // Volume control
    16     virtual int GetVolumeChannel(int channel) const;
    17     virtual void SetVolumeChannel(int channel, int volume);
    18 
    1915  protected:
    2016    // You need to implement the following functions
    2117    virtual bool OpenDevice(void);
     
    2622    vector<int> GetSupportedRates(void);
    2723
    2824  private:
    29     void VolumeInit(void);
    30     void VolumeCleanup(void);
    31    
    3225    void SetFragSize(void);
    3326   
    3427    int audiofd;
    3528    mutable int numbadioctls;
    36 
    37     // Volume related
    38     int mixerfd;
    39     int control;
    4029};
    4130
    4231#endif
  • mythtv/libs/libmyth/audiooutputbase.cpp

     
    3737    pauseaudio(false),          audio_actually_paused(false),
    3838    was_paused(false),
    3939
    40     set_initial_vol(settings.set_initial_vol),
    4140    buffer_output_data_for_use(false),
    4241
    4342    // private
     
    5453    needs_upmix(false),
    5554    surround_mode(FreeSurround::SurroundModePassive),
    5655    old_audio_stretchfactor(1.0),
    57     volume(80),
    5856
    5957    blocking(false),
    6058
     
    109107
    110108    allow_ac3_passthru = (orig_config_channels > 2) ? gCoreContext->GetNumSetting("AC3PassThru", false) : false;
    111109
     110    if (gCoreContext->GetSetting("MixerDevice") == "Software:")
     111        volume_control = VolumeControlManager::GetControl("Software:");
     112   
    112113    // You need to call Reconfigure from your concrete class.
    113114    // Reconfigure(laudio_bits,       laudio_channels,
    114115    //             laudio_samplerate, laudio_passthru);
     
    278279    killaudio = false;
    279280    pauseaudio = false;
    280281    was_paused = true;
    281     internal_vol = gCoreContext->GetNumSetting("MythControlsVolume", 0);
    282282
    283283    numlowbuffer = 0;
    284284
     
    375375        return;
    376376    }
    377377
    378     // Only used for software volume
    379     if (set_initial_vol && internal_vol)
    380     {
    381         QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
    382         controlLabel += "MixerVolume";
    383         volume = gCoreContext->GetNumSetting(controlLabel, 80);
    384     }
    385 
    386     SyncVolume();
    387     VolumeBase::UpdateVolume();
    388 
    389378    VERBOSE(VB_AUDIO, LOC + QString("Audio fragment size: %1")
    390379            .arg(fragment_size));
    391380
     
    679668     return audbuf_timecode - GetAudiotime();
    680669}
    681670
    682 void AudioOutputBase::SetSWVolume(int new_volume, bool save)
    683 {
    684     volume = new_volume;
    685     if (save)
    686     {
    687         QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
    688         controlLabel += "MixerVolume";
    689         gCoreContext->SaveSetting(controlLabel, volume);
    690     }
    691 }
    692 
    693 int AudioOutputBase::GetSWVolume()
    694 {
    695     return volume;
    696 }
    697 
    698671void AudioOutputBase::AdjustVolume(void *buffer, int len, bool music)
    699672{
    700673    if (audio_bits == 8)
     
    706679template <class AudioDataType>
    707680void AudioOutputBase::_AdjustVolume(AudioDataType *buffer, int len, bool music)
    708681{
     682    int volume = volume_control->mute() ? 0 : volume_control->volume();
     683 
    709684    float g = volume / 100.0;
    710685
    711686    // Should probably be exponential - this'll do
     
    11141089        }
    11151090    }
    11161091
    1117     if (internal_vol && SWVolume())
     1092    if (volume_control)
    11181093    {
    11191094        int bdiff = kAudioRingBufferSize - waud;
    11201095        bool music = (timecode < 1);
     
    13781353    audio_buflock.unlock();
    13791354
    13801355    // Mute individual channels through mono->stereo duplication
    1381     MuteState mute_state = GetMuteState();
     1356//    MuteState mute_state = GetMuteState();
    13821357    if (written_size &&
    1383         audio_channels > 1 &&
    1384         (mute_state == kMuteLeft || mute_state == kMuteRight))
     1358        audio_channels > 1 //&&
     1359//        (mute_state == kMuteLeft || mute_state == kMuteRight)
     1360       )
    13851361    {
    13861362        int offset_src = 0;
    13871363        int offset_dst = 0;
    13881364 
    1389         if (mute_state == kMuteLeft)
    1390             offset_src = audio_bits / 8;    // copy channel 1 to channel 0
    1391         else if (mute_state == kMuteRight)
    1392             offset_dst = audio_bits / 8;    // copy channel 0 to channel 1
     1365//        if (mute_state == kMuteLeft)
     1366//            offset_src = audio_bits / 8;    // copy channel 1 to channel 0
     1367//        else if (mute_state == kMuteRight)
     1368//            offset_dst = audio_bits / 8;    // copy channel 0 to channel 1
    13931369     
    13941370        for (int i = 0; i < written_size; i += audio_bytes_per_sample)
    13951371        {
  • mythtv/libs/libmyth/audiooutput.cpp

     
    3434    int audio_bits, int audio_channels,
    3535    int audio_codec, int audio_samplerate,
    3636    AudioOutputSource source,
    37     bool set_initial_vol, bool audio_passthru,
     37    bool audio_passthru,
    3838    int upmixer_startup)
    3939{
    4040    AudioSettings settings(
    4141        main_device, passthru_device, audio_bits,
    4242        audio_channels, audio_codec, audio_samplerate, source,
    43         set_initial_vol, audio_passthru, upmixer_startup);
     43        audio_passthru, upmixer_startup);
    4444
    4545    settings.FixPassThrough();
    4646
  • mythtv/libs/libmyth/libmyth.pro

     
    2323HEADERS += output.h
    2424HEADERS += settings.h
    2525HEADERS += uilistbtntype.h uitypes.h util.h mythuifilebrowser.h
    26 HEADERS += volumebase.h visual.h xmlparse.h
     26HEADERS += volumecontrol.h volumecontrolmanager.h volumecontrolsoftware.h
     27HEADERS += visual.h xmlparse.h
    2728HEADERS += mythhdd.h mythcdrom.h storagegroup.h dbutil.h
    2829HEADERS += mythcommandlineparser.h mythterminal.h
    2930HEADERS += mythhttppool.h mythhttphandler.h
     
    4748SOURCES += output.cpp
    4849SOURCES += settings.cpp
    4950SOURCES += uilistbtntype.cpp uitypes.cpp util.cpp mythuifilebrowser.cpp
    50 SOURCES += volumebase.cpp xmlparse.cpp
     51SOURCES += volumecontrolmanager.cpp volumecontrolsoftware.cpp
     52SOURCES += xmlparse.cpp
    5153SOURCES += mythhdd.cpp mythcdrom.cpp storagegroup.cpp dbutil.cpp
    5254SOURCES += mythcommandlineparser.cpp mythterminal.cpp
    5355SOURCES += mythhttppool.cpp mythhttphandler.cpp
     
    8789# Install headers so that plugins can compile independently
    8890inc.path = $${PREFIX}/include/mythtv/
    8991inc.files  = dialogbox.h mythcontext.h
    90 inc.files += mythwidgets.h remotefile.h oldsettings.h volumecontrol.h
     92inc.files += mythwidgets.h remotefile.h oldsettings.h
    9193inc.files += settings.h uitypes.h xmlparse.h mythplugin.h mythdialogs.h
    9294inc.files += audiooutput.h audiosettings.h util.h
    9395inc.files += inetcomms.h mythmedia.h mythcdrom.h mythwizard.h schemawizard.h dbutil.h
    9496inc.files += uilistbtntype.h generictree.h managedlist.h mythmediamonitor.h
    95 inc.files += visual.h volumebase.h output.h langsettings.h
     97inc.files += visual.h volumecontrol.h volumecontrolmanager.h output.h langsettings.h
    9698inc.files += mythexp.h mythpluginapi.h storagegroup.h
    9799inc.files += mythconfigdialogs.h mythconfiggroups.h
    98100inc.files += mythterminal.h mythdeque.h mythuifilebrowser.h
     
    109111
    110112using_oss {
    111113    DEFINES += USING_OSS
    112     SOURCES += audiooutputoss.cpp
    113     HEADERS += audiooutputoss.h
     114    SOURCES += audiooutputoss.cpp volumecontroloss.cpp
     115    HEADERS += audiooutputoss.h volumecontroloss.h
    114116    LIBS += $$OSS_LIBS
    115117}
    116118
     
    138140
    139141mingw {
    140142    DEFINES += USING_MINGW
    141     SOURCES += mediamonitor-windows.cpp audiooutputwin.cpp audiooutputdx.cpp
    142     HEADERS += mediamonitor-windows.h   audiooutputwin.h   audiooutputdx.h
    143     LIBS += -lpthread -lwinmm -lws2_32
     143    SOURCES += mediamonitor-windows.cpp
     144    HEADERS += mediamonitor-windows.h
     145    SOURCES += audiooutputwin.cpp audiooutputdx.cpp volumecontrolendpoint.cpp
     146    HEADERS += audiooutputwin.h   audiooutputdx.h   volumecontrolendpoint.h
     147    LIBS += -lpthread -lwinmm -lws2_32 -lole32
    144148}
    145149
    146150macx {
    147     HEADERS += audiooutputca.h
    148     SOURCES += audiooutputca.cpp
     151    DEFINES += USE_COREAUDIO
     152    HEADERS += audiooutputca.h volumecontrolcoreaudio.h
     153    SOURCES += audiooutputca.cpp volumecontrolcoreaudio.cpp
    149154    HEADERS += mythcdrom-darwin.h
    150155    SOURCES += mythcdrom-darwin.cpp
    151156
     
    185190
    186191using_alsa {
    187192    DEFINES += USE_ALSA
    188     HEADERS += audiooutputalsa.h
    189     SOURCES += audiooutputalsa.cpp
     193    HEADERS += audiooutputalsa.h volumecontrolalsa.h
     194    SOURCES += audiooutputalsa.cpp volumecontrolalsa.cpp
    190195    LIBS += $$ALSA_LIBS
    191196}
    192197
  • mythtv/libs/libmyth/audiosettings.h

     
    3232        int               audio_codec,
    3333        int               audio_samplerate,
    3434        AudioOutputSource audio_source,
    35         bool              audio_set_initial_vol,
    3635        bool              audio_use_passthru,
    3736        int               upmixer_startup = 0);
    3837
     
    5857    int     channels;
    5958    int     codec;
    6059    int     samplerate;
    61     bool    set_initial_vol;
    6260    bool    use_passthru;
    6361    AudioOutputSource source;
    6462    int     upmixer;
  • mythtv/libs/libmyth/audiooutputca.h

     
    2525    bool RenderAudio(unsigned char *aubuf, int size,
    2626                     unsigned long long timestamp);
    2727
    28     // Volume control
    29     virtual int  GetVolumeChannel(int channel) const;
    30     virtual void SetVolumeChannel(int channel, int volume);
    31 
    3228    void Debug(QString msg)
    3329    {   VERBOSE(VB_AUDIO,     "AudioOutputCA::" + msg);   }
    3430
     
    3733
    3834    void Warn(QString msg)
    3935    {   VERBOSE(VB_IMPORTANT, "AudioOutputCA Warning: " + msg);   }
     36    bool internal_vol;
    4037
    4138protected:
    4239
  • mythtv/libs/libmyth/audiooutputoss.cpp

     
    3030
    3131AudioOutputOSS::AudioOutputOSS(const AudioSettings &settings) :
    3232    AudioOutputBase(settings),
    33     audiofd(-1), numbadioctls(0),
    34     mixerfd(-1), control(SOUND_MIXER_VOLUME)
     33    audiofd(-1), numbadioctls(0)
    3534{
    3635    // Set everything up
    3736    Reconfigure(settings);
     
    194193                " the error was: %1").arg(strerror(errno)));
    195194    }
    196195
    197     // Setup volume control
    198     if (internal_vol)
    199         VolumeInit();
    200 
    201196    // Device opened successfully
    202197    return true;
    203198}
     
    242237        close(audiofd);
    243238
    244239    audiofd = -1;
    245    
    246     VolumeCleanup();
    247240}
    248241
    249242
     
    310303
    311304    return space;
    312305}
    313 
    314 void AudioOutputOSS::VolumeInit()
    315 {
    316     mixerfd = -1;
    317     int volume = 0;
    318 
    319     QString device = gCoreContext->GetSetting("MixerDevice", "/dev/mixer");
    320     if (device.toLower() == "software")
    321         return;
    322 
    323     QByteArray dev = device.toAscii();
    324     mixerfd = open(dev.constData(), O_RDONLY);
    325 
    326     QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
    327 
    328     if (controlLabel == "Master")
    329     {
    330         control = SOUND_MIXER_VOLUME;
    331     }
    332     else
    333     {
    334         control = SOUND_MIXER_PCM;
    335     }
    336 
    337     if (mixerfd < 0)
    338     {
    339         VERBOSE(VB_IMPORTANT, LOC +
    340                 QString("Unable to open mixer: '%1'").arg(device));
    341         return;
    342     }
    343 
    344     if (set_initial_vol)
    345     {
    346         int tmpVol;
    347         volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
    348         tmpVol = (volume << 8) + volume;
    349         int ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_VOLUME), &tmpVol);
    350         if (ret < 0)
    351         {
    352             VERBOSE(VB_IMPORTANT, LOC_ERR +
    353                     QString("Error Setting initial Master Volume") + ENO);
    354         }
    355 
    356         volume = gCoreContext->GetNumSetting("PCMMixerVolume", 80);
    357         tmpVol = (volume << 8) + volume;
    358         ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &tmpVol);
    359         if (ret < 0)
    360         {
    361             VERBOSE(VB_IMPORTANT, LOC_ERR +
    362                     QString("Error setting initial PCM Volume") + ENO);
    363         }
    364     }
    365 }
    366 
    367 void AudioOutputOSS::VolumeCleanup()
    368 {
    369     if (mixerfd >= 0)
    370     {
    371         close(mixerfd);
    372         mixerfd = -1;
    373     }
    374 }
    375 
    376 int AudioOutputOSS::GetVolumeChannel(int channel) const
    377 {
    378     int volume=0;
    379     int tmpVol=0;
    380 
    381     if (mixerfd <= 0)
    382         return 100;
    383 
    384     int ret = ioctl(mixerfd, MIXER_READ(control), &tmpVol);
    385     if (ret < 0) {
    386         VERBOSE(VB_IMPORTANT, QString("Error reading volume for channel %1")
    387                           .arg(channel));
    388         perror("Reading PCM volume: ");
    389         return 0;
    390     }
    391 
    392     if (channel == 0) {
    393         volume = tmpVol & 0xff; // left
    394     } else if (channel == 1) {
    395         volume = (tmpVol >> 8) & 0xff; // right
    396     } else {
    397         VERBOSE(VB_IMPORTANT, QString("Invalid channel. Only stereo volume supported"));
    398     }
    399 
    400     return volume;
    401 }
    402 
    403 void AudioOutputOSS::SetVolumeChannel(int channel, int volume)
    404 {
    405     if (channel > 1) {
    406         // Don't support more than two channels!
    407     VERBOSE(VB_IMPORTANT, QString("Error setting channel: %1.  Only stereo volume supported")
    408                                 .arg(channel));
    409         return;
    410     }
    411 
    412     if (volume > 100)
    413         volume = 100;
    414     if (volume < 0)
    415         volume = 0;
    416 
    417     if (mixerfd >= 0)
    418     {
    419         int tmpVol = 0;
    420         if (channel == 0)
    421             tmpVol = (GetVolumeChannel(1) << 8) + volume;
    422         else
    423             tmpVol = (volume << 8) + GetVolumeChannel(0);
    424 
    425         int ret = ioctl(mixerfd, MIXER_WRITE(control), &tmpVol);
    426         if (ret < 0)
    427         {
    428             VERBOSE(VB_IMPORTANT, QString("Error setting volume on channel: %1").arg(channel));
    429             perror("Setting volume: ");
    430         }
    431     }
    432 }
    433 
  • mythtv/libs/libmyth/audiooutputdx.cpp

     
    465465    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
    466466                    | DSBCAPS_GLOBALFOCUS       /* Allows background playing */
    467467                    | DSBCAPS_LOCHARDWARE;      /* Needed for 5.1 on emu101k */
    468     if (!m_UseSPDIF)
    469         dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME;  /* Allow volume control */
    470468    dsbdesc.dwBufferBytes = soundcard_buffer_size;   /* buffer size */
    471469    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf;
    472470
     
    601599    return buffered;
    602600}
    603601
    604 int AudioOutputDX::GetVolumeChannel(int channel) const
    605 {
    606     HRESULT dsresult;
    607     long dxVolume = 0;
    608     int volume;
    609 
    610     if (m_UseSPDIF)
    611         return 100;
    612 
    613     dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);
    614     volume = (int)(pow(10,(float)dxVolume/20)*100);
    615 
    616     if (dsresult != DS_OK)
    617     {
    618         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to get volume %1")
    619                                                 .arg(dxVolume));
    620         return volume;
    621     }
    622 
    623     VERBOSE(VB_AUDIO, LOC + QString("Got volume %1").arg(volume));
    624     return volume;
    625 }
    626 
    627 void AudioOutputDX::SetVolumeChannel(int channel, int volume)
    628 {
    629     HRESULT dsresult;
    630     float dbAtten = 20 * log10((float)volume/100);
    631     long dxVolume = (volume == 0) ? DSBVOLUME_MIN : (long)(100.0f * dbAtten);
    632 
    633     if (m_UseSPDIF)
    634         return;
    635 
    636     // dxVolume is attenuation in 100ths of a decibel
    637     dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);
    638 
    639     if (dsresult != DS_OK)
    640     {
    641         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to set volume %1")
    642                                                 .arg(dxVolume));
    643         return;
    644     }
    645    
    646     VERBOSE(VB_AUDIO, LOC + QString("Set volume %1").arg(dxVolume));
    647 }
    648 
    649602/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythtv/libs/libmyth/audiooutputnull.h

     
    2727
    2828    virtual void Reset(void);
    2929
    30 
    31     // Volume control
    32     virtual int GetVolumeChannel(int /* channel */) const { return 100; }
    33     virtual void SetVolumeChannel(int /* channel */, int /* volume */){return;}
    34 
    3530    virtual int readOutputData(unsigned char *read_buffer, int max_length);
    3631
    3732  protected:
  • mythtv/libs/libmyth/audiooutput.h

     
    55
    66#include "audiosettings.h"
    77#include "mythcontext.h"
    8 #include "volumebase.h"
    98#include "output.h"
    109
    11 class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners
     10class MPUBLIC AudioOutput : public OutputListeners
    1211{
    1312 public:
    1413    // opens one of the concrete subclasses
     
    1817        int audio_bits, int audio_channels,
    1918        int audio_codec, int audio_samplerate,
    2019        AudioOutputSource source,
    21         bool set_initial_vol, bool audio_passthru,
     20        bool audio_passthru,
    2221        int upmixer_startup = 0);
    2322
    2423    AudioOutput() :
    25         VolumeBase(),             OutputListeners(),
     24        OutputListeners(),
    2625        lastError(QString::null), lastWarn(QString::null) {}
    2726
    2827    virtual ~AudioOutput() { };
  • mythtv/libs/libmyth/volumecontrolmanager.h

     
     1#ifndef VOLUMECONTROLMANAGER
     2#define VOLUMECONTROLMANAGER
     3
     4#include "volumecontrol.h"
     5
     6#include "mythexp.h"
     7
     8#include <QHash>
     9#include <QSharedPointer>
     10#include <QString>
     11
     12class MPUBLIC VolumeControlManager
     13{
     14public:
     15    static QHash<QString, QString> Enumerate();
     16    static QSharedPointer<VolumeControl> GetControl(QString device);
     17};
     18
     19#endif // VOLUMECONTROLMANAGER
  • mythtv/libs/libmyth/volumecontrolendpoint.h

     
     1#ifndef VOLUMECONTROLENDPOINT
     2#define VOLUMECONTROLENDPOINT
     3
     4#include "volumecontrol.h"
     5
     6#include <QHash>
     7#include <QAtomicInt>
     8
     9#include <rpcsal.h>
     10#include <endpointvolume.h>
     11
     12
     13class VolumeControlEndpoint : public VolumeControl,
     14                              protected IAudioEndpointVolumeCallback
     15{
     16public:
     17    static QHash<QString, QString> Enumerate();
     18
     19public:
     20    VolumeControlEndpoint(QString device);
     21    virtual ~VolumeControlEndpoint();
     22
     23public:
     24    int  volume() const;
     25    void setVolume(int volume);
     26    void increaseVolume();
     27    void decreaseVolume();
     28
     29    bool mute() const;
     30    void setMute(bool mute);
     31
     32protected:
     33    ULONG STDMETHODCALLTYPE AddRef();
     34    ULONG STDMETHODCALLTYPE Release();
     35    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface);
     36    HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify);
     37
     38private:
     39    IAudioEndpointVolume* m_EndpointVolume; //< Endpoint volume interface
     40    int                   m_Range;          //< Range of mixer element
     41    QAtomicInt            m_Volume;         //< Volume state cache
     42    QAtomicInt            m_Mute;           //< Mute state cache
     43};
     44
     45#endif // VOLUMECONTROLWINDOWSENDPOINT
  • mythtv/libs/libmyth/audiooutputdx.h

     
    1313    AudioOutputDX(const AudioSettings &settings);
    1414    virtual ~AudioOutputDX();
    1515
    16     virtual int GetVolumeChannel(int channel) const;
    17     virtual void SetVolumeChannel(int channel, int volume);
    18 
    1916  protected:
    2017    virtual bool OpenDevice(void);
    2118    virtual void CloseDevice(void);
  • mythtv/libs/libmyth/audiooutputalsa.h

     
    11#ifndef AUDIOOUTPUTALSA
    22#define AUDIOOUTPUTALSA
    33
     4#include <QHash>
     5#include <QString>
     6
    47#define ALSA_PCM_NEW_HW_PARAMS_API
    58#define ALSA_PCM_NEW_SW_PARAMS_API
    69#include <alsa/asoundlib.h>
     
    1114
    1215using namespace std;
    1316
    14 class ALSAVolumeInfo
     17class AudioOutputALSA : public AudioOutputBase
    1518{
    1619  public:
    17     ALSAVolumeInfo(long  playback_vol_min,
    18                    long  playback_vol_max) :
    19         range_multiplier(1.0f),
    20         volume_min(playback_vol_min), volume_max(playback_vol_max)
    21     {
    22         float range = (float) (volume_max - volume_min);
    23         if (range > 0.0f)
    24             range_multiplier = 100.0f / range;
    25         range_multiplier_inv = 1.0f / range_multiplier;
    26     }
     20    static QHash<QString, QString> Enumerate();
    2721
    28     int ToMythRange(long alsa_volume)
    29     {
    30         long toz = alsa_volume - volume_min;
    31         int val = (int) (toz * range_multiplier);
    32         val = (val < 0)   ? 0   : val;
    33         val = (val > 100) ? 100 : val;
    34         return val;
    35     }
    36 
    37     long ToALSARange(int myth_volume)
    38     {
    39         float tos = myth_volume * range_multiplier_inv;
    40         long val = (long) (tos + volume_min + 0.5);
    41         val = (val < volume_min) ? volume_min : val;
    42         val = (val > volume_max) ? volume_max : val;
    43         return val;
    44     }
    45 
    46     float range_multiplier;
    47     float range_multiplier_inv;
    48     long  volume_min;
    49     long  volume_max;
    50 };
    51 
    52 class AudioOutputALSA : public AudioOutputBase
    53 {
    5422  public:
    5523    AudioOutputALSA(const AudioSettings &settings);
    5624    virtual ~AudioOutputALSA();
    5725
    58     // Volume control
    59     virtual int GetVolumeChannel(int channel) const; // Returns 0-100
    60     virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol
    61 
    62    
    6326  protected:
    6427    // You need to implement the following functions
    6528    virtual bool OpenDevice(void);
     
    7942    void ReorderSmpteToAlsa6ch(void *buf, int frames);
    8043    template <class AudioDataType>
    8144        void _ReorderSmpteToAlsa6ch(AudioDataType *buf, int frames);
    82     // Volume related
    83     void SetCurrentVolume(QString control, int channel, int volume);
    84     void OpenMixer(bool setstartingvolume);
    85     void CloseMixer(void);
    86     void SetupMixer(void);
    87     ALSAVolumeInfo GetVolumeRange(snd_mixer_elem_t *elem) const;
    8845
    8946  private:
    9047    snd_pcm_t   *pcm_handle;
    9148    int          numbadioctls;
    9249    QMutex       killAudioLock;
    93     snd_mixer_t *mixer_handle;
    94     QString      mixer_control; // e.g. "PCM"
    9550    snd_pcm_sframes_t (*pcm_write_func)(snd_pcm_t*, const void*,
    9651                                        snd_pcm_uframes_t);
    9752};
  • mythtv/libs/libmyth/volumecontroloss.cpp

     
     1#include "volumecontroloss.h"
     2
     3#include "mythverbose.h"
     4#include <algorithm>
     5#include <sys/types.h>
     6#include <sys/stat.h>
     7#include <sys/ioctl.h>
     8#include <fcntl.h>
     9
     10#include <QDir>
     11
     12#include "mythconfig.h"
     13#ifdef HAVE_SYS_SOUNDCARD_H
     14    #include <sys/soundcard.h>
     15#elif HAVE_SOUNDCARD_H
     16    #include <soundcard.h>
     17#endif
     18
     19static const unsigned long poll = 250;   //< OSS control poll interval (ms)
     20
     21// static
     22QHash<QString, QString> VolumeControlOSS::Enumerate()
     23{
     24    QHash<QString, QString> result;
     25#if 1
     26    int mixerfd = open("/dev/mixer", O_RDWR, 0);
     27
     28    if (mixerfd == -1)
     29    {
     30        VERBOSE(VB_IMPORTANT,
     31                QString("VolumeControlOSS::Enumerate() - ERROR: "
     32                        "opening \"/dev/mixer\""));
     33        return result;
     34    }
     35
     36    oss_sysinfo sysinfo;
     37    if (ioctl(mixerfd, SNDCTL_SYSINFO, &sysinfo) == -1)
     38    {
     39        VERBOSE(VB_IMPORTANT,
     40                QString("VolumeControlOSS::Enumerate() - ERROR: "
     41                        "obtaining system information"));
     42        return result;
     43    }
     44
     45    for (int mixer = 0; mixer < sysinfo.nummixers; ++mixer)
     46    {
     47        oss_mixerinfo info = {
     48            dev: mixer
     49        };
     50
     51        if (ioctl(mixerfd, SNDCTL_MIXERINFO, &info) != -1)
     52            result.insert(QString("OSS:%1").arg(info.devnode), info.name);
     53    }
     54
     55    close(mixerfd);
     56
     57#else
     58    QDir devs("/dev", "mixer*", QDir::Name, QDir::System);
     59
     60    QFileInfoList files = devs.entryInfoList();
     61    QFileInfoList::Iterator file;
     62    for (file = files.begin(); file != files.end(); ++file)
     63    {
     64        result.insert("OSS:" + file->absoluteFilePath(),
     65                      file->absoluteFilePath());
     66    }
     67
     68    devs.setPath("/dev/sound");
     69    files = devs.entryInfoList();
     70    for (file = files.begin(); file != files.end(); ++file)
     71    {
     72        result.insert("OSS:" + file->absoluteFilePath(),
     73                      file->absoluteFilePath());
     74    }
     75#endif
     76    return result;
     77}
     78
     79VolumeControlOSS::VolumeControlOSS(QString device) :
     80   m_VolumeCtrl(-1), m_MuteCtrl(-1), m_Exit(false)
     81{
     82    m_Mixer = open(device.toAscii().constData(), O_RDWR, 0);
     83
     84    if (m_Mixer == -1)
     85    {
     86        VERBOSE(VB_IMPORTANT,
     87                QString("VolumeControlOSS::VolumeControlOSS() - ERROR: "
     88                        "opening \"%1\"").arg(device));
     89        return;
     90    }
     91
     92    oss_sysinfo sysinfo;
     93    if (ioctl(m_Mixer, SNDCTL_SYSINFO, &sysinfo) == -1)
     94    {
     95        VERBOSE(VB_IMPORTANT,
     96                QString("VolumeControlOSS::VolumeControlOSS() - ERROR: "
     97                        "obtaining system information"));
     98        return;
     99    }
     100
     101    for (m_MixerDev = 0; m_MixerDev < sysinfo.nummixers; ++m_MixerDev)
     102    {
     103        oss_mixerinfo info = {
     104            dev: m_MixerDev
     105        };
     106
     107        if (ioctl(m_Mixer, SNDCTL_MIXERINFO, &info) != -1)
     108            if (QString(info.devnode) == device)
     109                break;
     110    }
     111
     112    int extensions = m_MixerDev;
     113    if (ioctl(m_Mixer, SNDCTL_MIX_NREXT, &extensions) == -1)
     114    {
     115        VERBOSE(VB_IMPORTANT,
     116                QString("VolumeControlOSS::VolumeControlOSS() - ERROR: "
     117                        "obtaining number of extensions"));
     118        return;
     119    }
     120
     121    for (int control = 0; control < extensions; ++control)
     122    {
     123        oss_mixext info = {
     124            dev:  m_MixerDev,
     125            ctrl: control
     126        };
     127
     128        if (ioctl(m_Mixer, SNDCTL_MIX_EXTINFO, &info) == -1)
     129            continue;
     130
     131        switch (info.type)
     132        {
     133        case MIXT_MONODB:
     134        case MIXT_MONOSLIDER:
     135        case MIXT_MONOSLIDER16:
     136        case MIXT_SLIDER:
     137        case MIXT_STEREOSLIDER:
     138        case MIXT_STEREOSLIDER16:
     139            if (m_VolumeCtrl == -1)
     140            {
     141                m_VolumeCtrl = info.ctrl;
     142                m_VolumeMax = info.maxvalue;
     143                m_VolumeType = info.type;
     144                m_VolumeTimestamp = info.timestamp;
     145            }
     146            break;
     147
     148        case MIXT_ONOFF:
     149        case MIXT_MUTE:
     150            if (m_MuteCtrl == -1)
     151            {
     152                m_MuteCtrl = info.ctrl;
     153                m_MuteTimestamp = info.timestamp;
     154            }
     155            break;
     156        }
     157
     158        if (m_VolumeCtrl != -1 && m_MuteCtrl != -1)
     159            break;
     160    }
     161
     162    m_Range = std::min(std::max(1, m_VolumeMax), 100);
     163
     164    if (m_VolumeCtrl != -1)
     165        start();
     166}
     167
     168VolumeControlOSS::~VolumeControlOSS()
     169{
     170    m_Exit = true;
     171
     172    if (isRunning())
     173        wait();
     174
     175    if (m_Mixer != -1)
     176        close(m_Mixer);
     177}
     178
     179int VolumeControlOSS::volume() const
     180{
     181    int volume = 0;
     182
     183    if (m_VolumeCtrl != -1)
     184    {
     185        if (m_MuteCtrl != -1 || !mute())
     186        {
     187            oss_mixer_value value;
     188            memset(&value, 0, sizeof(value));
     189
     190            value.dev = m_MixerDev;
     191            value.ctrl = m_VolumeCtrl;
     192            value.timestamp = m_VolumeTimestamp;
     193
     194            if (ioctl(m_Mixer, SNDCTL_MIX_READ, &value) != -1)
     195            {
     196                switch (m_VolumeType)
     197                {
     198                case MIXT_MONODB:
     199                case MIXT_MONOSLIDER:
     200                    volume = value.value & 0xFF;
     201                    break;
     202
     203                case MIXT_MONOSLIDER16:
     204                    volume = value.value & 0xFFFF;
     205                    break;
     206
     207                case MIXT_SLIDER:
     208                    volume = value.value & 0x7FFFFFFF;
     209                    break;
     210
     211                case MIXT_STEREOSLIDER:
     212                    volume = std::max(value.value & 0xFF,
     213                                      (value.value >> 8) & 0xFF);
     214                    break;
     215
     216                case MIXT_STEREOSLIDER16:
     217                    volume = std::max(value.value & 0xFFFF,
     218                                      (value.value >> 16) & 0xFFFF);
     219                    break;
     220                }
     221
     222                volume = ((200 * volume) + m_VolumeMax) / (2 * m_VolumeMax);
     223            }
     224        }
     225        else
     226            volume = m_Volume;
     227    }
     228
     229    VERBOSE(VB_AUDIO,
     230            QString("VolumeControlOSS::volume() = %1")
     231            .arg(volume));
     232
     233    return volume;
     234}
     235
     236void VolumeControlOSS::setVolume(int volume)
     237{
     238    VERBOSE(VB_AUDIO,
     239            QString("VolumeControlOSS::setVolume(%1)")
     240            .arg(volume));
     241
     242    volume = std::min(std::max(0, volume), 100);
     243
     244    if (mute() && volume > VolumeControlOSS::volume())
     245        setMute(false);
     246
     247    if (m_VolumeCtrl != -1 && (m_MuteCtrl != -1 || !mute()))
     248    {
     249        oss_mixer_value value;
     250        memset(&value, 0, sizeof(value));
     251
     252        value.dev = m_MixerDev;
     253        value.ctrl = m_VolumeCtrl;
     254        value.timestamp = m_VolumeTimestamp;
     255        value.value = (m_VolumeMax * volume) / 100;
     256
     257        switch (m_VolumeType)
     258        {
     259        case MIXT_STEREOSLIDER:
     260            value.value = value.value | (value.value << 8);
     261            break;
     262
     263        case MIXT_STEREOSLIDER16:
     264            value.value = value.value | (value.value << 16);
     265            break;
     266        }
     267
     268        ioctl(m_Mixer, SNDCTL_MIX_WRITE, &value);
     269    }
     270
     271    if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     272        emit changedVolume(volume);
     273}
     274
     275void VolumeControlOSS::increaseVolume()
     276{
     277    setVolume((volume() * m_Range + 100) / m_Range);
     278}
     279
     280void VolumeControlOSS::decreaseVolume()
     281{
     282    setVolume((volume() * m_Range - 100) / m_Range);
     283}
     284
     285bool VolumeControlOSS::mute() const
     286{
     287    bool mute = false;
     288
     289    if (m_VolumeCtrl != -1)
     290    {
     291        oss_mixer_value value;
     292        memset(&value, 0, sizeof(value));
     293
     294        value.dev = m_MixerDev;
     295
     296        if (m_MuteCtrl != -1)
     297        {
     298            value.ctrl = m_MuteCtrl;
     299            value.timestamp = m_MuteTimestamp;
     300
     301            if (ioctl(m_Mixer, SNDCTL_MIX_READ, &value) != -1)
     302                mute = value.value;
     303        }
     304        else
     305        {
     306            value.ctrl = m_VolumeCtrl;
     307            value.timestamp = m_VolumeTimestamp;
     308
     309            if (ioctl(m_Mixer, SNDCTL_MIX_READ, &value) != -1)
     310                mute = !value.value;
     311        }
     312    }
     313
     314    VERBOSE(VB_AUDIO,
     315            QString("VolumeControlOSS::mute() = %1")
     316            .arg(mute ? "mute" : "unmute"));
     317
     318    return mute;
     319}
     320
     321void VolumeControlOSS::setMute(bool mute)
     322{
     323    VERBOSE(VB_AUDIO,
     324            QString("VolumeControlOSS::setMute(%1)")
     325            .arg(mute ? "mute" : "unmute"));
     326
     327    if (m_VolumeCtrl != -1)
     328    {
     329        oss_mixer_value value;
     330        memset(&value, 0, sizeof(value));
     331
     332        value.dev = m_MixerDev;
     333
     334        if (m_MuteCtrl != -1)
     335        {
     336            value.ctrl = m_MuteCtrl;
     337            value.timestamp = m_MuteTimestamp;
     338            value.value = mute;
     339        }
     340        else
     341        {
     342            value.ctrl = m_VolumeCtrl;
     343            value.timestamp = m_VolumeTimestamp;
     344            value.value = mute ? 0 : (m_VolumeMax * m_Volume) / 100;
     345
     346            switch (m_VolumeType)
     347            {
     348            case MIXT_STEREOSLIDER:
     349                value.value = value.value | (value.value << 8);
     350                break;
     351
     352            case MIXT_STEREOSLIDER16:
     353                value.value = value.value | (value.value << 16);
     354                break;
     355            }
     356        }
     357
     358        ioctl(m_Mixer, SNDCTL_MIX_WRITE, &value);
     359    }
     360
     361    if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     362        emit changedMute(mute);
     363}
     364
     365void VolumeControlOSS::run()
     366{
     367    VERBOSE(VB_AUDIO,
     368            QString("VolumeControlOSS::run() - begin"));
     369
     370    m_Volume = volume();
     371    m_Mute = mute();
     372
     373    while(!m_Exit)
     374    {
     375        msleep(poll);
     376
     377        int pollvolume = volume();
     378        if (m_Volume.fetchAndStoreRelaxed(pollvolume) != pollvolume)
     379            emit changedVolume(pollvolume);
     380
     381        bool pollmute = mute();
     382        if (m_Mute.fetchAndStoreRelaxed(pollmute) != pollmute)
     383            emit changedMute(pollmute);
     384    }
     385
     386    VERBOSE(VB_AUDIO,
     387            QString("VolumeControlOSS::run() - end"));
     388}
     389
  • mythtv/programs/mythfrontend/globalsettings.cpp

     
    3232#include "iso639.h"
    3333#include "playbackbox.h"
    3434#include "globalsettings.h"
     35#include "libmyth/volumecontrolmanager.h"
    3536#include "recordingprofile.h"
    3637#include "mythxdisplay.h"
    3738#include "DisplayRes.h"
     
    196197    return gc;
    197198}
    198199
    199 static HostCheckBox *MythControlsVolume()
    200 {
    201     HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
    202     gc->setLabel(QObject::tr("Use internal volume controls"));
    203     gc->setValue(true);
    204     gc->setHelpText(QObject::tr("MythTV can control the PCM and master "
    205                     "mixer volume.  If you prefer to control the volume externally "
    206                     "(like your amplifier) or use an external mixer "
    207                     "program, disable this option."));
    208     return gc;
    209 }
    210 
    211200static HostComboBox *MixerDevice()
    212201{
    213202    HostComboBox *gc = new HostComboBox("MixerDevice", true);
    214203    gc->setLabel(QObject::tr("Mixer Device"));
     204    gc->addSelection(QObject::tr("Disabled"), QString());
    215205
    216 #ifdef USING_OSS
    217     QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
    218     gc->fillSelectionsFromDir(dev);
     206    QHash<QString, QString> controls = VolumeControlManager::Enumerate();
    219207
    220     dev.setPath("/dev/sound");
    221     if (dev.exists())
     208    for (QHash<QString, QString>::const_iterator control = controls.begin();
     209         control != controls.end(); ++control)
    222210    {
    223         gc->fillSelectionsFromDir(dev);
     211        gc->addSelection(control.value(), control.key());
    224212    }
    225 #endif
    226 #ifdef USING_ALSA
    227     gc->addSelection("ALSA:default", "ALSA:default");
    228 #endif
    229 #ifdef USING_MINGW
    230     gc->addSelection("DirectX:", "DirectX:");
    231     gc->addSelection("Windows:", "Windows:");
    232 #endif
    233 #if !defined(USING_MINGW)
    234     gc->addSelection("software", "software");
    235     gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" lets MythTV control "
    236                                 "the volume of all audio at the expense of a slight quality loss."));
    237 #endif
    238213
    239214    return gc;
    240215}
    241216
    242 static const char* MixerControlControls[] = { "PCM",
    243                                               "Master" };
    244 
    245 static HostComboBox *MixerControl()
    246 {
    247     HostComboBox *gc = new HostComboBox("MixerControl", true);
    248     gc->setLabel(QObject::tr("Mixer Controls"));
    249     for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
    250          ++i)
    251     {
    252         gc->addSelection(QObject::tr(MixerControlControls[i]),
    253                          MixerControlControls[i]);
    254     }
    255 
    256     gc->setHelpText(QObject::tr("Changing the volume adjusts the selected mixer."));
    257     return gc;
    258 }
    259 
    260 static HostSlider *MixerVolume()
    261 {
    262     HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
    263     gs->setLabel(QObject::tr("Master Mixer Volume"));
    264     gs->setValue(70);
    265     gs->setHelpText(QObject::tr("Initial volume for the Master Mixer.  "
    266                     "This affects all sound created by the sound card.  "
    267                     "Note: Do not set this too low."));
    268     return gs;
    269 }
    270 
    271 static HostSlider *PCMVolume()
    272 {
    273     HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
    274     gs->setLabel(QObject::tr("PCM Mixer Volume"));
    275     gs->setValue(70);
    276     gs->setHelpText(QObject::tr("Initial volume for PCM output.  Using the "
    277                     "volume keys in MythTV will adjust this parameter."));
    278     return gs;
    279 }
    280 
    281217static HostCheckBox *IndividualMuteControl()
    282218{
    283219    HostCheckBox *gc = new HostCheckBox("IndividualMuteControl");
     
    34903426    group2->addChild(AggressiveBuffer());
    34913427
    34923428    return vcg;
    3493 
    34943429}
    34953430
    3496 class AudioMixerSettingsGroup : public TriggeredConfigurationGroup
     3431static ConfigurationGroup *AudioMixerSettingsGroup()
    34973432{
    3498   public:
    3499     AudioMixerSettingsGroup() :
    3500         TriggeredConfigurationGroup(false, true, false, false)
    3501     {
    3502         setLabel(QObject::tr("Audio Mixer"));
    3503         setUseLabel(false);
     3433    ConfigurationGroup *vcg = new VerticalConfigurationGroup(false, true, false, false);
     3434   
     3435    vcg->setLabel(QObject::tr("Audio Mixer"));
     3436    vcg->setUseLabel(false);
    35043437
    3505         Setting *volumeControl = MythControlsVolume();
    3506         addChild(volumeControl);
     3438    vcg->addChild(MixerDevice());
    35073439
    3508         // Mixer settings
    3509         ConfigurationGroup *settings =
    3510             new VerticalConfigurationGroup(false, true, false, false);
    3511         settings->addChild(MixerDevice());
    3512         settings->addChild(MixerControl());
    3513         settings->addChild(MixerVolume());
    3514         settings->addChild(PCMVolume());
    3515         settings->addChild(IndividualMuteControl());
     3440    return vcg;
     3441}
    35163442
    3517         ConfigurationGroup *dummy =
    3518             new VerticalConfigurationGroup(false, true, false, false);
    3519 
    3520         // Show Mixer config only if internal volume controls enabled
    3521         setTrigger(volumeControl);
    3522         addTarget("0", dummy);
    3523         addTarget("1", settings);
    3524     }
    3525 };
    3526 
    35273443static HostComboBox *MythLanguage()
    35283444{
    35293445    HostComboBox *gc = new HostComboBox("Language");
     
    42074123
    42084124    addChild(AudioSystemSettingsGroup());
    42094125
    4210     addChild(new AudioMixerSettingsGroup());
     4126    addChild(AudioMixerSettingsGroup());
    42114127
    42124128    VerticalConfigurationGroup *general =
    42134129        new VerticalConfigurationGroup(false, true, false, false);
  • mythtv/programs/mythtranscode/transcode.cpp

     
    168168        return last_audiotime;
    169169    }
    170170
    171     virtual int GetVolumeChannel(int) const
    172     {
    173         // Do nothing
    174         return 100;
    175     }
    176     virtual void SetVolumeChannel(int, int)
    177     {
    178         // Do nothing
    179     }
    180     virtual void SetVolumeAll(int)
    181     {
    182         // Do nothing
    183     }
    184     virtual uint GetCurrentVolume(void) const
    185     {
    186         // Do nothing
    187         return 100;
    188     }
    189     virtual void SetCurrentVolume(int)
    190     {
    191         // Do nothing
    192     }
    193     virtual void AdjustCurrentVolume(int)
    194     {
    195         // Do nothing
    196     }
    197     virtual void SetMute(bool)
    198     {
    199         // Do nothing
    200     }
    201     virtual void ToggleMute(void)
    202     {
    203         // Do nothing
    204     }
    205     virtual MuteState GetMuteState(void) const
    206     {
    207         // Do nothing
    208         return kMuteOff;
    209     }
    210     virtual MuteState IterateMutedChannels(void)
    211     {
    212         // Do nothing
    213         return kMuteOff;
    214     }
    215171    virtual bool ToggleUpmix(void)
    216172    {
    217173        // Do nothing
    218174        return false;
    219175    }
    220176
    221     virtual void SetSWVolume(int new_volume, bool save)
    222     {
    223         // Do nothing
    224         return;
    225     }
    226     virtual int GetSWVolume(void)
    227     {
    228         // Do nothing
    229         return 100;
    230     }
    231 
    232177    //  These are pure virtual in AudioOutput, but we don't need them here
    233178    virtual void bufferOutputData(bool){ return; }
    234179    virtual int readOutputData(unsigned char*, int ){ return 0; }