Ticket #7517: volume_control_mythtv_r22928.patch

File volume_control_mythtv_r22928.patch, 128.0 KB (added by mythtv@…, 16 years ago)
  • configure

     
    595595    eval "$var=\"\$$var $*\""
    596596}
    597597
     598prepend(){
     599    var=$1
     600    shift
     601    flags_saved && eval "SAVE_$var=\"$* \$SAVE_$var\""
     602    eval "$var=\"$* \$$var\""
     603}
     604
    598605add_cflags(){
    599606    append CFLAGS "$@"
    600607}
     
    33253332    enable  audio_alsa ||
    33263333    disable audio_alsa
    33273334
     3335# OSS probe
     3336if ! disabled audio_oss ; then
     3337    if test -f /usr/"${libdir_name}"/oss/include/sys/soundcard.h &&
     3338       check_cpp_condition /usr/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then
     3339        disable soundcard_h
     3340        enable sys_soundcard_h
     3341        prepend CONFIG_INCLUDEPATH "/usr/${libdir_name}/oss/include"
     3342    elif test -f /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h &&
     3343       check_cpp_condition /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then
     3344        disable soundcard_h
     3345        enable sys_soundcard_h
     3346        prepend CONFIG_INCLUDEPATH "/usr/local/${libdir_name}/oss/include"
     3347    else
     3348        if enabled soundcard_h ; then
     3349            check_cpp_condition soundcard.h "SOUND_VERSION >= 0x040000" &&
     3350            enable  audio_oss ||
     3351            disable audio_oss
     3352        elif enabled sys_soundcard_h ; then
     3353            check_cpp_condition sys/soundcard.h "SOUND_VERSION >= 0x040000" &&
     3354            enable  audio_oss ||
     3355            disable audio_oss
     3356        fi
     3357    fi
     3358fi
     3359
    33283360# JACK probe
    33293361! disabled audio_jack &&
    33303362    check_lib jack/jack.h jack_client_new $audio_jack_libs &&
     
    40224054if enabled audio_oss; then
    40234055    append CCONFIG "using_oss"
    40244056fi
     4057
    40254058if enabled audio_alsa; then
    40264059    append CCONFIG "using_alsa"
    40274060  echo "CONFIG_AUDIO_ALSA_LIBS=$audio_alsa_libs" >> $MYTH_CONFIG_MAK
  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    141141    kDisplayNUVTeletextCaptions,
    142142};
    143143
    144 NuppelVideoPlayer::NuppelVideoPlayer(bool muted)
     144NuppelVideoPlayer::NuppelVideoPlayer()
    145145    : decoder(NULL),                decoder_change_lock(QMutex::Recursive),
    146146      videoOutput(NULL),            player_ctx(NULL),
    147147      no_hardware_decoders(false),
     
    209209      audio_channels(2),            audio_codec(0),
    210210      audio_bits(-1),               audio_samplerate(44100),
    211211      audio_stretchfactor(1.0f),    audio_lock(QMutex::Recursive),
    212       audio_muted_on_creation(muted),
    213212      // Picture-in-Picture stuff
    214213      pip_active(false),            pip_visible(true),
    215214      // Preview window support
     
    402401    audio_samplerate      = (int)samplerate;
    403402}
    404403
    405 uint NuppelVideoPlayer::GetVolume(void)
    406 {
    407     QMutexLocker lock(&audio_lock);
    408     if (audioOutput)
    409         return audioOutput->GetCurrentVolume();
    410     return 0;
    411 }
    412 
    413 bool NuppelVideoPlayer::SetMuted(bool mute)
    414 {
    415     QMutexLocker lock(&audio_lock);
    416     bool is_muted = IsMuted();
    417 
    418     if (audioOutput && !is_muted && mute &&
    419         (kMuteAll == SetMuteState(kMuteAll)))
    420     {
    421         VERBOSE(VB_AUDIO, "muting sound " <<IsMuted());
    422         return true;
    423     }
    424     else if (audioOutput && is_muted && !mute &&
    425              (kMuteOff == SetMuteState(kMuteOff)))
    426     {
    427         VERBOSE(VB_AUDIO, "unmuting sound "<<IsMuted());
    428         return true;
    429     }
    430 
    431     VERBOSE(VB_AUDIO, "not changing sound mute state "<<IsMuted());
    432 
    433     return false;
    434 }
    435 
    436 MuteState NuppelVideoPlayer::SetMuteState(MuteState mstate)
    437 {
    438     QMutexLocker lock(&audio_lock);
    439     if (audioOutput)
    440         return audioOutput->SetMuteState(mstate);
    441     return kMuteAll;
    442 }
    443 
    444 MuteState NuppelVideoPlayer::IncrMuteState(void)
    445 {
    446     QMutexLocker lock(&audio_lock);
    447     MuteState mstate = kMuteAll;
    448     if (audioOutput)
    449         mstate = SetMuteState(VolumeBase::NextMuteState(GetMuteState()));
    450     return mstate;
    451 }
    452 
    453 MuteState NuppelVideoPlayer::GetMuteState(void)
    454 {
    455     QMutexLocker lock(&audio_lock);
    456     if (audioOutput)
    457         return audioOutput->GetMuteState();
    458     return kMuteAll;
    459 }
    460 
    461 uint NuppelVideoPlayer::AdjustVolume(int change)
    462 {
    463     QMutexLocker lock(&audio_lock);
    464     if (audioOutput)
    465         audioOutput->AdjustCurrentVolume(change);
    466     return GetVolume();
    467 }
    468 
    469404void NuppelVideoPlayer::PauseDecoder(void)
    470405{
    471406    decoder_lock.lock();
     
    904839
    905840    if (!audioOutput && !using_null_videoout && player_ctx->IsAudioNeeded())
    906841    {
    907         bool setVolume = gContext->GetNumSetting("MythControlsVolume", 1);
    908842        audioOutput = AudioOutput::OpenAudio(audio_main_device,
    909843                                             audio_passthru_device,
    910844                                             audio_bits, audio_channels,
    911845                                             audio_codec, audio_samplerate,
    912846                                             AUDIOOUTPUT_VIDEO,
    913                                              setVolume, audio_passthru);
     847                                             audio_passthru);
    914848        if (!audioOutput)
    915849            errMsg = QObject::tr("Unable to create AudioOutput.");
    916850        else
     
    932866            VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio");
    933867            no_audio_out = false;
    934868        }
    935         if (audio_muted_on_creation)
    936         {
    937             SetMuteState(kMuteAll);
    938             audio_muted_on_creation = false;
    939         }
    940869    }
    941870
    942871    if (audioOutput)
  • libs/libmythtv/avformatdecoder.cpp

     
    464464      audioSamples(NULL),           audioSamplesResampled(NULL),
    465465      reformat_ctx(NULL),           audio_src_fmt(SAMPLE_FMT_NONE),
    466466      allow_ac3_passthru(false),    allow_dts_passthru(false),
    467       internal_vol(false),
    468467      disable_passthru(false),      max_channels(2),
    469468      last_ac3_channels(0),         dummy_frame(NULL),
    470469      // DVD
     
    487486    max_channels = (uint) gContext->GetNumSetting("MaxChannels", 2);
    488487    allow_ac3_passthru = (max_channels > 2) ? gContext->GetNumSetting("AC3PassThru", false) : false;
    489488    allow_dts_passthru = (max_channels > 2) ? gContext->GetNumSetting("DTSPassThru", false) : false;
    490     internal_vol = gContext->GetNumSetting("MythControlsVolume", 0);
    491489
    492490    audioIn.sample_size = -32; // force SetupAudioStream to run once
    493491    itv = GetNVP()->GetInteractiveTV();
     
    43704368
    43714369    if (ctx->codec_id == CODEC_ID_AC3)
    43724370        passthru = allow_ac3_passthru &&
    4373                    ctx->channels >= (int)max_channels &&
    4374                    !internal_vol;
     4371                   ctx->channels >= (int)max_channels;
    43754372    else if (ctx->codec_id == CODEC_ID_DTS)
    4376         passthru = allow_dts_passthru && !internal_vol;
     4373        passthru = allow_dts_passthru;
    43774374
    43784375    passthru &= !transcoding && !disable_passthru;
    43794376    // Don't know any cards that support spdif clocked at < 44100
  • libs/libmythtv/tv_play.h

     
    3434#include "programlist.h"
    3535#include "channelutil.h"
    3636#include "videoouttypes.h"
    37 #include "volumebase.h"
     37#include "volumecontrolmanager.h"
    3838#include "inputinfo.h"
    3939#include "channelgroup.h"
    4040
     
    297297    void AddUDPNotifyEvent(const QString &name, const UDPNotifyOSDSet*);
    298298    void ClearUDPNotifyEvents(void);
    299299
     300    void VolumeChanged(int volume);
     301    void MuteChanged(bool mute);
     302
    300303  protected:
    301304    void TreeMenuEntered(OSDListTreeItemEnteredEvent *e);
    302305    void TreeMenuSelected(OSDListTreeItemSelectedEvent *e);
     
    306309    virtual void run(void);
    307310    void TVEventThreadChecks(void);
    308311
    309     void SetMuteTimer(PlayerContext*, int timeout);
    310     bool MuteChannelChange(PlayerContext *ctx);
    311 
    312312    bool eventFilter(QObject *o, QEvent *e);
    313313    static QStringList lastProgramStringList;
    314314    static EMBEDRETURNPROGRAM RunPlaybackBoxPtr;
     
    498498
    499499    vector<long long> TeardownAllNVPs(PlayerContext*);
    500500    void RestartAllNVPs(PlayerContext *lctx,
    501                         const vector<long long> &pos,
    502                         MuteState mctx_mute);
     501                        const vector<long long> &pos);
    503502    void RestartMainNVP(PlayerContext *mctx);
    504503
    505504    void PxPToggleView(  PlayerContext *actx, bool wantPBP);
     
    660659    /// Picture attribute to modify (on arrow left or right)
    661660    PictureAttribute  adjustingPictureAttribute;
    662661
     662    QSharedPointer<VolumeControl> volumeControl; ///< Volume Control interface
     663
    663664    // Ask Allow state
    664665    AskAllowType                 askAllowType;
    665666    QMap<QString,AskProgramInfo> askAllowPrograms;
     
    817818    TimerContextMap      stateChangeTimerId;
    818819    TimerContextMap      signalMonitorTimerId;
    819820    TimerContextMap      tvchainUpdateTimerId;
    820     TimerContextMap      unmuteTimerId;
    821821
    822822    /// Condition to signal that the Event thread is up and running
    823823    QWaitCondition mainLoopCond;
     
    838838
    839839    ///< Timeout for entry modes in msec
    840840    static const uint kInputModeTimeout;
    841     /// Channel changing mute timeout in msec
    842     static const uint kMuteTimeout;
    843841    /// Timeout for updating LCD info in msec
    844842    static const uint kLCDTimeout;
    845843    /// Timeout for browse mode exit in msec
  • libs/libmythtv/playercontext.cpp

     
    430430
    431431bool PlayerContext::CreateNVP(TV *tv, QWidget *widget,
    432432                              TVState desiredState,
    433                               WId embedwinid, const QRect *embedbounds,
    434                               bool muted)
     433                              WId embedwinid, const QRect *embedbounds)
    435434{
    436435    int exact_seeking = gContext->GetNumSetting("ExactSeeking", 0);
    437436
     
    442441        return false;
    443442    }
    444443
    445     NuppelVideoPlayer *_nvp = new NuppelVideoPlayer(muted);
     444    NuppelVideoPlayer *_nvp = new NuppelVideoPlayer();
    446445
    447446    if (nohardwaredecoders)
    448447        _nvp->DisableHardwareDecoders();
     
    492491                VERBOSE(VB_IMPORTANT, LOC_ERR + errMsg);
    493492        }
    494493    }
    495     else if (pipState == kPBPRight)
    496         nvp->SetMuted(true);
    497494
    498495    int maxWait = -1;
    499496    //if (isPIP())
  • 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"
     
    104103    friend class PlayerContext;
    105104
    106105  public:
    107     NuppelVideoPlayer(bool muted = false);
     106    NuppelVideoPlayer();
    108107   ~NuppelVideoPlayer();
    109108
    110109    // Initialization
     
    127126    void SetAudioInfo(const QString &main, const QString &passthru, uint rate);
    128127    void SetAudioParams(int bits, int channels, int codec, int samplerate, bool passthru);
    129128    void SetEffDsp(int dsprate);
    130     uint AdjustVolume(int change);
    131     bool SetMuted(bool mute);
    132     MuteState SetMuteState(MuteState);
    133     MuteState IncrMuteState(void);
    134129    void SetAudioCodec(void *ac);
    135130
    136131    // Sets
     
    187182    float   GetVideoAspect(void) const        { return video_aspect; }
    188183    float   GetFrameRate(void) const          { return video_frame_rate; }
    189184
    190     uint    GetVolume(void);
    191185    int     GetSecondsBehind(void) const;
    192186    AspectOverrideMode GetAspectOverride(void) const;
    193187    AdjustFillMode     GetAdjustFill(void) const;
    194     MuteState          GetMuteState(void);
    195188    CommSkipMode       GetAutoCommercialSkip(void) const;
    196189
    197190    int     GetFFRewSkip(void) const          { return ffrew_skip; }
     
    227220    bool    HasAudioOut(void) const           { return !no_audio_out; }
    228221    bool    IsPIPActive(void) const           { return pip_active; }
    229222    bool    IsPIPVisible(void) const          { return pip_visible; }
    230     bool    IsMuted(void)              { return GetMuteState() == kMuteAll; }
    231223    bool    UsingNullVideo(void) const { return using_null_videoout; }
    232224    bool    HasTVChainNext(void) const;
    233225
     
    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;
  • libs/libmythtv/tv_play.cpp

     
    8383
    8484
    8585const uint TV::kInputModeTimeout             = 5000;
    86 const uint TV::kMuteTimeout                  = 800;
    8786const uint TV::kLCDTimeout                   = 1000;
    8887const uint TV::kBrowseTimeout                = 30000;
    8988const uint TV::kKeyRepeatTimeout             = 300;
     
    967966    player.push_back(new PlayerContext("player"));
    968967    playerActive = 0;
    969968    playerLock.unlock();
     969
     970    volumeControl = VolumeControlManager::GetControl(gContext->GetSetting("MixerDevice"));
     971    if (volumeControl)
     972    {
     973        connect(volumeControl.data(), SIGNAL(changedVolume(int)),
     974                this, SLOT(VolumeChanged(int)), Qt::QueuedConnection);
     975        connect(volumeControl.data(), SIGNAL(changedMute(bool)),
     976                this, SLOT(MuteChanged(bool)), Qt::QueuedConnection);
     977    }
     978
    970979    VERBOSE(VB_PLAYBACK, LOC + "ctor -- end");
    971980}
    972981
     
    28292838    if (handled)
    28302839        return;
    28312840
    2832     // Check unmute..
    2833     ctx = NULL;
    2834     {
    2835         QMutexLocker locker(&timerIdLock);
    2836         TimerContextMap::iterator it = unmuteTimerId.find(timer_id);
    2837         if (it != unmuteTimerId.end())
    2838         {
    2839             KillTimer(timer_id);
    2840             ctx = *it;
    2841             unmuteTimerId.erase(it);
    2842         }
    2843     }
    2844 
    2845     if (ctx)
    2846     {
    2847         PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    2848         if (find_player_index(ctx) >= 0)
    2849         {
    2850             ctx->LockDeleteNVP(__FILE__, __LINE__);
    2851             if (ctx->nvp && ctx->nvp->IsMuted())
    2852                 ctx->nvp->SetMuted(false);
    2853             ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    2854         }
    2855         ReturnPlayerLock(mctx);
    2856         handled = true;
    2857     }
    2858 
    28592841    if (handled)
    28602842        return;
    28612843
     
    54215403        }
    54225404    }
    54235405
    5424     MuteState mctx_mute = kMuteOff;
    5425     mctx->LockDeleteNVP(__FILE__, __LINE__);
    5426     if (mctx->nvp)
    5427         mctx_mute = mctx->nvp->GetMuteState();
    5428     mctx->UnlockDeleteNVP(__FILE__, __LINE__);
    5429 
    54305406    vector<long long> pos = TeardownAllNVPs(mctx);
    54315407
    54325408    if (wantPBP)
     
    54445420        }
    54455421    }
    54465422
    5447     RestartAllNVPs(mctx, pos, mctx_mute);
     5423    RestartAllNVPs(mctx, pos);
    54485424
    54495425    VERBOSE(VB_PLAYBACK, LOC +
    54505426            QString("PxPToggleType() converting from %1 to %2 -- end")
     
    55885564* \brief Recreate Main and PIP windows. Could be either PIP or PBP views.
    55895565*/
    55905566void TV::RestartAllNVPs(PlayerContext *lctx,
    5591                         const vector<long long> &pos,
    5592                         MuteState mctx_mute)
     5567                        const vector<long long> &pos)
    55935568{
    55945569    QString loc = LOC + QString("RestartAllNVPs(): ");
    55955570
     
    56365611            pipctx->LockDeleteNVP(__FILE__, __LINE__);
    56375612            if (pipctx->nvp)
    56385613            {
    5639                 pipctx->nvp->SetMuted(true);
    56405614                pipctx->nvp->JumpToFrame(pos[i]);
    56415615            }
    56425616            pipctx->UnlockDeleteNVP(__FILE__, __LINE__);
     
    56485622            ForceNextStateNone(pipctx);
    56495623        }
    56505624    }
    5651 
    5652     // If old main player had a kMuteAll | kMuteOff setting,
    5653     // apply old main player's mute setting to new main player.
    5654     mctx->LockDeleteNVP(__FILE__, __LINE__);
    5655     if (mctx->nvp && ((kMuteAll == mctx_mute) || (kMuteOff == mctx_mute)))
    5656         mctx->nvp->SetMuteState(mctx_mute);
    5657     mctx->UnlockDeleteNVP(__FILE__, __LINE__);
    56585625}
    56595626
    56605627void TV::PxPSwap(PlayerContext *mctx, PlayerContext *pipctx)
     
    56825649        return;
    56835650    }
    56845651
    5685     MuteState mctx_mute = mctx->nvp->GetMuteState();
    56865652    mctx->deleteNVPLock.unlock();
    56875653    pipctx->deleteNVPLock.unlock();
    56885654
     
    56965662    playerActive = (ctx_index == playerActive) ?
    56975663        0 : ((ctx_index == 0) ? ctx_index : playerActive);
    56985664
    5699     RestartAllNVPs(mctx, pos, mctx_mute);
     5665    RestartAllNVPs(mctx, pos);
    57005666
    57015667    SetActive(mctx, playerActive, false);
    57025668
     
    57175683        mctx->deleteNVPLock.unlock();
    57185684        return;
    57195685    }
    5720 
    5721     MuteState mctx_mute = mctx->nvp->GetMuteState();
    5722 
    5723     // HACK - FIXME
    5724     // workaround muted audio when NVP is re-created
    5725     mctx_mute = kMuteOff;
    5726     // FIXME - end
    57275686    mctx->deleteNVPLock.unlock();
    57285687
    57295688    vector<long long> pos = TeardownAllNVPs(mctx);
    5730     RestartAllNVPs(mctx, pos, mctx_mute);
     5689    RestartAllNVPs(mctx, pos);
    57315690    SetActive(mctx, playerActive, false);
    57325691
    57335692    VERBOSE(VB_PLAYBACK, LOC + "Restart main player -- end");
     
    58525811
    58535812    VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- begin");
    58545813
    5855     bool muted = false;
    5856 
    58575814    ctx->LockDeleteNVP(__FILE__, __LINE__);
    58585815    if (!ctx->nvp)
    58595816    {
     
    58615818        return false;
    58625819    }
    58635820
    5864     if (ctx == GetPlayer(ctx, 0))
    5865         muted = MuteChannelChange(ctx);
    5866 
    58675821    bool res = false;
    58685822
    58695823    if (LONG_LONG_MIN != audiosyncBaseline)
     
    58845838    }
    58855839    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    58865840
    5887     if (muted)
    5888         SetMuteTimer(ctx, kMuteTimeout);
    5889 
    58905841    VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- end");
    58915842
    58925843    return res;
     
    61676118    if (StateIsLiveTV(GetState(ctx)))
    61686119        return;
    61696120
    6170     ctx->LockDeleteNVP(__FILE__, __LINE__);
    6171     bool muted = MuteChannelChange(ctx);
    6172     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6173 
    61746121    struct StatusPosInfo posInfo;
    61756122    ctx->CalcNVPSliderPosition(posInfo);
    61766123
     
    61896136    if (ctx->nvp)
    61906137        ctx->nvp->SkipCommercials(direction);
    61916138    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6192 
    6193     if (muted)
    6194         SetMuteTimer(ctx, kMuteTimeout);
    61956139}
    61966140
    61976141void TV::SwitchSource(uint source_direction)
     
    63616305        if (mctx != ctx)
    63626306            PIPRemovePlayer(mctx, ctx);
    63636307
    6364         bool muted = false;
    6365         ctx->LockDeleteNVP(__FILE__, __LINE__);
    6366         if (ctx->nvp && ctx->nvp->IsMuted())
    6367             muted = true;
    6368         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    6369 
    63706308        // pause the decoder first, so we're not reading too close to the end.
    63716309        ctx->buffer->IgnoreLiveEOF(true);
    63726310        ctx->buffer->StopReads();
     
    64186356
    64196357            if (ctx->CreateNVP(
    64206358                    this, gContext->GetMainWindow(), ctx->GetState(),
    6421                     mctx->embedWinID, &mctx->embedBounds, muted))
     6359                    mctx->embedWinID, &mctx->embedBounds))
    64226360            {
    64236361                ScheduleStateChange(ctx);
    64246362                ok = true;
     
    67756713
    67766714void TV::ChangeChannel(PlayerContext *ctx, int direction)
    67776715{
    6778     bool muted = false;
    6779 
    67806716    if ((browse_changrp || (direction == CHANNEL_DIRECTION_FAVORITE)) &&
    67816717        (channel_group_id > -1))
    67826718    {
     
    68076743
    68086744    QString oldinputname = ctx->recorder->GetInput();
    68096745
    6810     muted = MuteChannelChange(ctx);
    6811 
    68126746    if (ctx->paused)
    68136747    {
    68146748        OSD *osd = GetOSDLock(ctx);
     
    68366770    ctx->recorder->ChangeChannel(direction);
    68376771    ClearInputQueues(ctx, false);
    68386772
    6839     if (muted)
    6840         SetMuteTimer(ctx, kMuteTimeout * 2);
    6841 
    68426773    UnpauseLiveTV(ctx);
    68436774
    68446775    if (oldinputname != ctx->recorder->GetInput())
     
    68556786
    68566787    QString channum = chan;
    68576788    QStringList reclist;
    6858     bool muted = false;
    68596789
    68606790    QString oldinputname = ctx->recorder->GetInput();
    68616791
     
    69256855    if (getit || !ctx->recorder || !ctx->recorder->CheckChannel(channum))
    69266856        return;
    69276857
    6928     muted = MuteChannelChange(ctx);
    6929 
    69306858    OSD *osd = GetOSDLock(ctx);
    69316859    if (osd && ctx->paused)
    69326860    {
     
    69526880
    69536881    ctx->recorder->SetChannel(channum);
    69546882
    6955     if (muted)
    6956         SetMuteTimer(ctx, kMuteTimeout * 2);
    6957 
    69586883    UnpauseLiveTV(ctx);
    69596884
    69606885    if (oldinputname != ctx->recorder->GetInput())
     
    80667991
    80677992void TV::ChangeVolume(PlayerContext *ctx, bool up)
    80687993{
    8069     ctx->LockDeleteNVP(__FILE__, __LINE__);
    8070     if (!ctx->nvp)
     7994    if (volumeControl)
    80717995    {
    8072         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8073         return;
     7996        if (up)
     7997            volumeControl->increaseVolume();
     7998        else
     7999            volumeControl->decreaseVolume();
    80748000    }
    8075     uint curvol = ctx->nvp->AdjustVolume((up) ? +2 : -2);
    8076     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8077 
    8078     QString text = tr("Volume %1 %").arg(curvol);
    8079 
    8080     OSD *osd = GetOSDLock(ctx);
    8081     if (osd && !browsemode)
    8082     {
    8083         osd->ShowStatus(curvol * 10, true, tr("Adjust Volume"), text, 5,
    8084                         kOSDFunctionalType_PictureAdjust);
    8085         SetUpdateOSDPosition(false);
    8086     }
    8087     ReturnOSDLock(ctx, osd);
    80888001}
    80898002
    80908003void TV::ToggleTimeStretch(PlayerContext *ctx)
     
    82338146
    82348147void TV::ToggleMute(PlayerContext *ctx)
    82358148{
    8236     ctx->LockDeleteNVP(__FILE__, __LINE__);
    8237     if (!ctx->nvp || !ctx->nvp->HasAudioOut())
    8238     {
    8239         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8240         return;
    8241     }
    8242 
    8243     MuteState mute_status;
    8244 
    8245     if (!MuteIndividualChannels)
    8246     {
    8247         ctx->nvp->SetMuted(!ctx->nvp->IsMuted());
    8248         mute_status = (ctx->nvp->IsMuted()) ? kMuteAll : kMuteOff;
    8249     }
    8250     else
    8251     {
    8252         mute_status = ctx->nvp->IncrMuteState();
    8253     }
    8254     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8255 
    8256     QString text;
    8257 
    8258     switch (mute_status)
    8259     {
    8260         case kMuteOff:   text = tr("Mute Off"); break;
    8261         case kMuteAll:   text = tr("Mute On"); break;
    8262         case kMuteLeft:  text = tr("Left Channel Muted"); break;
    8263         case kMuteRight: text = tr("Right Channel Muted"); break;
    8264     }
    8265 
    8266     OSD *osd = GetOSDLock(ctx);
    8267     if (osd && !browsemode)
    8268         osd->SetSettingsText(text, 5);
    8269     ReturnOSDLock(ctx, osd);
     8149    if (volumeControl)
     8150        volumeControl->setMute(!volumeControl->mute());
    82708151}
    82718152
    82728153void TV::ToggleSleepTimer(const PlayerContext *ctx)
     
    84268307    ReturnOSDLock(ctx, osd);
    84278308}
    84288309
    8429 void TV::SetMuteTimer(PlayerContext *ctx, int timeout)
    8430 {
    8431     // message to set the timer will be posted to the main UI thread
    8432     // where it will be caught in eventFilter and processed as CustomEvent
    8433     // this will properly set the mute timer
    8434     // otherwise it never fires on Win32
    8435     QString message = QString("UNMUTE %1 %2").arg((long long)ctx).arg(timeout);
    8436     qApp->postEvent(gContext->GetMainWindow(), new MythEvent(message));
    8437 }
    8438 
    8439 bool TV::MuteChannelChange(PlayerContext *ctx)
    8440 {
    8441     if (!ctx)
    8442         return false;
    8443 
    8444     bool muted = false;
    8445     ctx->LockDeleteNVP(__FILE__, __LINE__);
    8446     if (ctx->nvp && !ctx->nvp->IsMuted())
    8447         muted = ctx->nvp->SetMuted(true);
    8448     ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    8449 
    8450     return muted;
    8451 }
    8452 
    84538310void TV::customEvent(QEvent *e)
    84548311{
    84558312    if ((MythEvent::Type)(e->type()) == kOSDClosedEventType)
     
    87258582        }
    87268583    }
    87278584
    8728     if (message.left(6) == "UNMUTE")
    8729     {
    8730         if (tokens.size() >= 3)
    8731         {
    8732             long long target = tokens[1].toLongLong();
    8733             PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    8734             for (uint i = 0; i < player.size(); i++)
    8735             {
    8736                 PlayerContext *ctx = GetPlayer(mctx, i);
    8737                 if (((long long)ctx) == target)
    8738                 {
    8739                     QMutexLocker locker(&timerIdLock);
    8740                     unmuteTimerId[StartTimer(tokens[2].toUInt(), __LINE__)] = ctx;
    8741                 }
    8742             }
    8743             ReturnPlayerLock(mctx);
    8744         }
    8745     }
    8746 
    87478585    if (message.left(9) == "START_EPG")
    87488586    {
    87498587        int editType = tokens[1].toInt();
     
    92179055        {
    92189056            value = ctx->nvp->getVideoOutput()->GetPictureAttribute(attr);
    92199057        }
    9220         else if (ctx->nvp->HasAudioOut())
     9058        else if (ctx->nvp->HasAudioOut() && volumeControl)
    92219059        {
    9222             value = ctx->nvp->GetVolume();
     9060            value = volumeControl->volume();
    92239061            title = tr("Adjust Volume");
    92249062        }
    92259063    }
     
    1172311561    ReturnPlayerLock(mctx);
    1172411562}
    1172511563
     11564void TV::VolumeChanged(int volume)
     11565{
     11566    OSD *osd = GetOSDL(__FILE__, __LINE__);
     11567    if (osd && !browsemode)
     11568    {
     11569        osd->ShowStatus(volume * 10, true, tr("Adjust Volume"),
     11570                        tr("Volume %1 %").arg(volume), 5,
     11571                        kOSDFunctionalType_PictureAdjust);
     11572        SetUpdateOSDPosition(false);
     11573    }
     11574    ReturnOSDLock(osd);
     11575}
     11576
     11577void TV::MuteChanged(bool mute)
     11578{
     11579    OSD *osd = GetOSDL(__FILE__, __LINE__);
     11580    if (osd && !browsemode)
     11581        osd->SetSettingsText(mute ? tr("Mute On") : tr("Mute Off"), 5);
     11582    ReturnOSDLock(osd);
     11583}
     11584
     11585
    1172611586OSD *TV::GetOSDL(const char *file, int location)
    1172711587{
    1172811588    PlayerContext *actx = GetPlayerReadLock(-1, file, location);
  • 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);
  • libs/libmythtv/avformatdecoder.h

     
    263263
    264264    bool              allow_ac3_passthru;
    265265    bool              allow_dts_passthru;
    266     bool              internal_vol;
    267266    bool              disable_passthru;
    268267    uint              max_channels;
    269268    uint              last_ac3_channels;
  • libs/libmyth/audiooutputwin.cpp

     
    280280{
    281281    return m_nPkts * fragment_size;
    282282}
    283 
    284 int AudioOutputWin::GetVolumeChannel(int channel) const
    285 {
    286     DWORD dwVolume = 0xffffffff;
    287     int Volume = 100;
    288     if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
    289     {
    290         Volume = (channel == 0) ?
    291             (LOWORD(dwVolume) / (0xffff / 100)) :
    292             (HIWORD(dwVolume) / (0xffff / 100));
    293     }
    294 
    295     VERBOSE(VB_AUDIO, "GetVolume(" << channel << ") "
    296             << Volume << "(" << dwVolume << ")");
    297 
    298     return Volume;
    299 }
    300 
    301 void AudioOutputWin::SetVolumeChannel(int channel, int volume)
    302 {
    303     if (channel > 1)
    304     {
    305         Error(QString("Error setting channel: %1. "
    306                       "Only stereo volume supported").arg(channel));
    307         return;
    308     }
    309 
    310     DWORD dwVolume = 0xffffffff;
    311     if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
    312     {
    313         if (channel == 0)
    314             dwVolume = dwVolume & 0xffff0000 | volume * (0xffff / 100);
    315         else
    316             dwVolume = dwVolume & 0xffff | ((volume * (0xffff / 100)) << 16);
    317     }
    318     else
    319     {
    320         dwVolume = volume * (0xffff / 100);
    321         dwVolume |= (dwVolume << 16);
    322     }
    323 
    324     VERBOSE(VB_AUDIO, QString("SetVolume(%1) %2(%3)")
    325             .arg(channel).arg(volume).arg(dwVolume));
    326     waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, dwVolume);
    327 }
  • 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}
  • libs/libmyth/volumecontrolalsa.cpp

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

     
    2121AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
    2222    AudioOutputBase(settings),
    2323    pcm_handle(NULL),
    24     numbadioctls(0),
    25     mixer_handle(NULL),
    26     mixer_control(QString::null)
     24    numbadioctls(0)
    2725{
    2826    // Set everything up
    2927    Reconfigure(settings);
     
    252250    // it really is
    253251    audio_buffer_unused = soundcard_buffer_size - (fragment_size * 4);
    254252
    255     if (internal_vol)
    256         OpenMixer(set_initial_vol);
    257    
    258253    // Device opened successfully
    259254    return true;
    260255}
    261256
    262257void AudioOutputALSA::CloseDevice()
    263258{
    264     CloseMixer();
    265259    if (pcm_handle != NULL)
    266260    {
    267261        snd_pcm_close(pcm_handle);
     
    620614
    621615    return 0;
    622616}
    623 
    624 
    625 int AudioOutputALSA::GetVolumeChannel(int channel) const
    626 {
    627     long actual_volume;
    628 
    629     if (mixer_handle == NULL)
    630         return 100;
    631 
    632     QByteArray mix_ctl = mixer_control.toAscii();
    633     snd_mixer_selem_id_t *sid;
    634     snd_mixer_selem_id_alloca(&sid);
    635     snd_mixer_selem_id_set_index(sid, 0);
    636     snd_mixer_selem_id_set_name(sid, mix_ctl.constData());
    637 
    638     snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);
    639     if (!elem)
    640     {
    641         VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")
    642                 .arg(mixer_control));
    643         return 100;
    644     }
    645 
    646     snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
    647     if (!snd_mixer_selem_has_playback_channel(elem, chan))
    648     {
    649         snd_mixer_selem_id_set_index(sid, channel);
    650         if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)
    651         {
    652             VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1 %2")
    653                     .arg(mixer_control).arg(channel));
    654             return 100;
    655         }
    656     }
    657 
    658     ALSAVolumeInfo vinfo = GetVolumeRange(elem);
    659 
    660     snd_mixer_selem_get_playback_volume(
    661         elem, (snd_mixer_selem_channel_id_t)channel, &actual_volume);
    662 
    663     return vinfo.ToMythRange(actual_volume);
    664 }
    665 
    666 void AudioOutputALSA::SetVolumeChannel(int channel, int volume)
    667 {
    668     SetCurrentVolume(mixer_control, channel, volume);
    669 }
    670 
    671 void AudioOutputALSA::SetCurrentVolume(QString control, int channel, int volume)
    672 {
    673     VERBOSE(VB_AUDIO, QString("Setting %1 volume to %2")
    674             .arg(control).arg(volume));
    675 
    676     if (!mixer_handle)
    677         return; // no mixer, nothing to do
    678 
    679     QByteArray ctl = control.toAscii();
    680     snd_mixer_selem_id_t *sid;
    681     snd_mixer_selem_id_alloca(&sid);
    682     snd_mixer_selem_id_set_index(sid, 0);
    683     snd_mixer_selem_id_set_name(sid, ctl.constData());
    684 
    685     snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);
    686     if (!elem)
    687     {
    688         VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")
    689                 .arg(control));
    690         return;
    691     }
    692 
    693     snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
    694     if (!snd_mixer_selem_has_playback_channel(elem, chan))
    695     {
    696         snd_mixer_selem_id_set_index(sid, channel);
    697         if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)
    698         {
    699             VERBOSE(VB_IMPORTANT,
    700                     QString("mixer unable to find control %1 %2")
    701                     .arg(control).arg(channel));
    702             return;
    703         }
    704     }
    705 
    706     ALSAVolumeInfo vinfo = GetVolumeRange(elem);
    707 
    708     long set_vol = vinfo.ToALSARange(volume);
    709 
    710     int err = snd_mixer_selem_set_playback_volume(elem, chan, set_vol);
    711     if (err < 0)
    712     {
    713         VERBOSE(VB_IMPORTANT, QString("mixer set channel %1 err %2: %3")
    714                 .arg(channel).arg(err).arg(snd_strerror(err)));
    715     }
    716     else
    717     {
    718         VERBOSE(VB_AUDIO, QString("channel %1 vol set to %2")
    719                 .arg(channel).arg(set_vol));
    720     }
    721 
    722     if (snd_mixer_selem_has_playback_switch(elem))
    723     {
    724         int unmute = (0 != set_vol);
    725         if (snd_mixer_selem_has_playback_switch_joined(elem))
    726         {
    727             // Only mute if all the channels should be muted.
    728             for (int i = 0; i < audio_channels; i++)
    729             {
    730                 if (0 != GetVolumeChannel(i))
    731                     unmute = 1;
    732             }
    733         }
    734 
    735         err = snd_mixer_selem_set_playback_switch(elem, chan, unmute);
    736         if (err < 0)
    737         {
    738             VERBOSE(VB_IMPORTANT, LOC_ERR +
    739                     QString("Mixer set playback switch %1 err %2: %3")
    740                     .arg(channel).arg(err).arg(snd_strerror(err)));
    741         }
    742         else
    743         {
    744             VERBOSE(VB_AUDIO, LOC +
    745                     QString("channel %1 playback switch set to %2")
    746                     .arg(channel).arg(unmute));
    747         }
    748     }
    749 }
    750 
    751 void AudioOutputALSA::OpenMixer(bool setstartingvolume)
    752 {
    753     int volume;
    754 
    755     mixer_control = gContext->GetSetting("MixerControl", "PCM");
    756 
    757     SetupMixer();
    758 
    759     if (mixer_handle != NULL && setstartingvolume)
    760     {
    761         volume = gContext->GetNumSetting("MasterMixerVolume", 80);
    762         SetCurrentVolume("Master", 0, volume);
    763         SetCurrentVolume("Master", 1, volume);
    764 
    765         volume = gContext->GetNumSetting("PCMMixerVolume", 80);
    766         SetCurrentVolume("PCM", 0, volume);
    767         SetCurrentVolume("PCM", 1, volume);
    768     }
    769 }
    770 
    771 void AudioOutputALSA::CloseMixer(void)
    772 {
    773     if (mixer_handle != NULL)
    774         snd_mixer_close(mixer_handle);
    775     mixer_handle = NULL;
    776 }
    777 
    778 void AudioOutputALSA::SetupMixer(void)
    779 {
    780     int err;
    781 
    782     QString alsadevice = gContext->GetSetting("MixerDevice", "default");
    783     QString device = alsadevice.remove(QString("ALSA:"));
    784 
    785     if (mixer_handle != NULL)
    786         CloseMixer();
    787 
    788     if (alsadevice.toLower() == "software")
    789         return;
    790 
    791     VERBOSE(VB_AUDIO, QString("Opening mixer %1").arg(device));
    792 
    793     // TODO: This is opening card 0. Fix for case of multiple soundcards
    794     if ((err = snd_mixer_open(&mixer_handle, 0)) < 0)
    795     {
    796         Warn(QString("Mixer device open error %1: %2")
    797              .arg(err).arg(snd_strerror(err)));
    798         mixer_handle = NULL;
    799         return;
    800     }
    801 
    802     QByteArray dev = device.toAscii();
    803     if ((err = snd_mixer_attach(mixer_handle, dev.constData())) < 0)
    804     {
    805         Warn(QString("Mixer attach error %1: %2"
    806                      "\n\t\t\tCheck Mixer Name in Setup: '%3'")
    807              .arg(err).arg(snd_strerror(err)).arg(device));
    808         CloseMixer();
    809         return;
    810     }
    811 
    812     if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0)
    813     {
    814         Warn(QString("Mixer register error %1: %2")
    815              .arg(err).arg(snd_strerror(err)));
    816         CloseMixer();
    817         return;
    818     }
    819 
    820     if ((err = snd_mixer_load(mixer_handle)) < 0)
    821     {
    822         Warn(QString("Mixer load error %1: %2")
    823              .arg(err).arg(snd_strerror(err)));
    824         CloseMixer();
    825         return;
    826     }
    827 }
    828 
    829 ALSAVolumeInfo AudioOutputALSA::GetVolumeRange(snd_mixer_elem_t *elem) const
    830 {
    831     long volume_min, volume_max;
    832 
    833     int err = snd_mixer_selem_get_playback_volume_range(
    834         elem, &volume_min, &volume_max);
    835 
    836     if (err < 0)
    837     {
    838         static bool first_time = true;
    839         if (first_time)
    840         {
    841             VERBOSE(VB_IMPORTANT,
    842                     "snd_mixer_selem_get_playback_volume_range()" + ENO);
    843             first_time = false;
    844         }
    845     }
    846 
    847     ALSAVolumeInfo vinfo(volume_min, volume_max);
    848 
    849     VERBOSE(VB_AUDIO, QString("Volume range is %1 to %2, mult=%3")
    850             .arg(vinfo.volume_min).arg(vinfo.volume_max)
    851             .arg(vinfo.range_multiplier));
    852 
    853     return vinfo;
    854 }
  • 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 "mythcontext.h"
    11 
    12 VolumeBase::VolumeBase() :
    13     internal_vol(false), volume(80),
    14     current_mute_state(kMuteOff)
    15 {
    16     swvol = swvol_setting =
    17         (gContext->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 = gContext->GetSetting("MixerControl", "PCM");
    43     controlLabel += "MixerVolume";
    44     gContext->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 
  • 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
  • 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
  • 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
     9QHash<QString, QString> VolumeControlCoreAudio::Enumerate()
     10{
     11    QHash<QString, QString> result;
     12
     13    result.insert("CoreAudio:default", "Default Core Audio device");
     14
     15    UInt32 size;
     16    AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
     17                                 &size, NULL); 
     18    UInt32 count = size / sizeof(AudioDeviceID);
     19
     20    AudioDeviceID* devices = new AudioDeviceID[count];
     21    AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
     22                             &size, devices);
     23
     24    for (unsigned int index = 0; index < count; ++index)
     25    {
     26        bool output = false;
     27
     28        AudioDeviceGetPropertyInfo(devices[index], 0, 0,
     29                                   kAudioDevicePropertyStreamConfiguration,
     30                                   &size, NULL);
     31        if (!size)
     32            continue;
     33
     34        AudioBufferList* buffers = static_cast<AudioBufferList*>(malloc(size));
     35        AudioDeviceGetProperty(devices[index], 0, 0,
     36                               kAudioDevicePropertyStreamConfiguration,
     37                               &size, buffers);
     38        for (UInt32 buffer = 0; buffer < buffers->mNumberBuffers; ++buffer)
     39        {
     40            if (buffers->mBuffers[buffer].mNumberChannels)
     41            {
     42                output = true;
     43                break;
     44            }
     45        }
     46
     47        free(buffers);
     48
     49        if (!output)
     50            continue;
     51
     52        QString uid;
     53        CFStringRef uidcf;
     54        size = sizeof(CFStringRef);
     55        AudioDeviceGetProperty(devices[index], 0, 0,
     56                               kAudioDevicePropertyDeviceUID,
     57                               &size, &uidcf);
     58        if (uidcf)
     59        {
     60            char buffer[256];
     61            CFStringGetCString(uidcf, buffer, 256,
     62                               CFStringGetFastestEncoding(uidcf));
     63            uid = QString(buffer);
     64            CFRelease(uidcf);
     65        }
     66
     67        AudioDeviceGetPropertyInfo(devices[index], 0, 0,
     68                                   kAudioDevicePropertyDeviceName,
     69                                   &size, NULL);
     70        if (!size)
     71            continue;
     72
     73        char* name = static_cast<char*>(malloc(size));
     74        AudioDeviceGetProperty(devices[index], 0, 0,
     75                               kAudioDevicePropertyDeviceName,
     76                               &size, name);
     77
     78        result.insert(QString("CoreAudio:") + uid, name);
     79
     80        free(name);
     81    }
     82
     83    delete devices;
     84
     85    return result;
     86}
     87
     88VolumeControlCoreAudio::VolumeControlCoreAudio(QString device) :
     89    m_DeviceId(kAudioDeviceUnknown)
     90{
     91    if (device == QString("default"))
     92    {
     93        UInt32 size = sizeof(AudioDeviceID);
     94        AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
     95                                 &size, &m_DeviceId);       
     96    }
     97    else
     98    {
     99        CFStringRef cfString =
     100            CFStringCreateWithCharacters(kCFAllocatorDefault,
     101                reinterpret_cast<const UniChar*>(device.unicode()),
     102                device.length());
     103
     104        AudioValueTranslation translateUidToId = {
     105            mInputData:      &cfString,
     106            mInputDataSize:  sizeof(CFStringRef),
     107            mOutputData:     &m_DeviceId,
     108            mOutputDataSize: sizeof(AudioDeviceID)
     109        };
     110
     111        UInt32 translateUidToIdSize = sizeof(AudioValueTranslation);
     112        AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID,
     113                                 &translateUidToIdSize,
     114                                 &translateUidToId);
     115        CFRelease(cfString);
     116    }
     117
     118    AudioDeviceAddPropertyListener(m_DeviceId, 1, false,
     119                                   kAudioDevicePropertyVolumeScalar,
     120                                   &event,
     121                                   this);
     122
     123    AudioDeviceAddPropertyListener(m_DeviceId, 1, false,
     124                                   kAudioDevicePropertyVolumeDecibels,
     125                                   &event,
     126                                   this);
     127
     128    AudioDeviceAddPropertyListener(m_DeviceId, 0, false,
     129                                   kAudioDevicePropertyMute,
     130                                   &event,
     131                                   this);
     132
     133    m_Volume = volume();
     134    m_Mute = mute();
     135}
     136
     137VolumeControlCoreAudio::~VolumeControlCoreAudio()
     138{
     139    AudioDeviceRemovePropertyListener(m_DeviceId, 1, false,
     140                                      kAudioDevicePropertyVolumeScalar,
     141                                      &event);
     142
     143    AudioDeviceRemovePropertyListener(m_DeviceId, 1, false,
     144                                      kAudioDevicePropertyVolumeDecibels,
     145                                      &event);
     146
     147    AudioDeviceRemovePropertyListener(m_DeviceId, 0, false,
     148                                      kAudioDevicePropertyMute,
     149                                      &event);
     150}
     151
     152int VolumeControlCoreAudio::volume() const
     153{
     154    Float32 volume = 0;
     155
     156    if (!mute())
     157    {
     158        UInt32 size = sizeof(Float32);
     159        AudioDeviceGetProperty(m_DeviceId, 1, false,
     160                               kAudioDevicePropertyVolumeScalar,
     161                               &size, &volume);
     162    }
     163    else
     164        volume = static_cast<Float32>(m_Volume) / 100.0f;
     165
     166    VERBOSE(VB_AUDIO,
     167            QString("VolumeControlCoreAudio::volume() = %1")
     168            .arg(static_cast<int>(100.0f * volume)));
     169
     170    return static_cast<int>(100.0f * volume);
     171}
     172
     173void VolumeControlCoreAudio::setVolume(int volume)
     174{
     175    VERBOSE(VB_AUDIO,
     176            QString("VolumeControlCoreAudio::setVolume(%1)")
     177            .arg(volume));
     178
     179    volume = std::min(std::max(0, volume), 100);
     180
     181    if (mute() && volume > VolumeControlCoreAudio::volume())
     182        setMute(false);
     183
     184    if (!mute())
     185    {
     186        Float32 value = static_cast<Float32>(volume) / 100.0f;
     187        AudioDeviceSetProperty(m_DeviceId, NULL, 1, false,
     188                               kAudioDevicePropertyVolumeScalar,
     189                               sizeof(UInt32), &value);
     190    }
     191
     192    if (m_Volume.fetchAndStoreRelaxed(volume) != volume)
     193        emit changedVolume(volume);
     194}
     195
     196void VolumeControlCoreAudio::increaseVolume()
     197{
     198    setVolume(volume() + 10);
     199}
     200
     201void VolumeControlCoreAudio::decreaseVolume()
     202{
     203    setVolume(volume() - 10);
     204}
     205
     206bool VolumeControlCoreAudio::mute() const
     207{
     208    UInt32 mute = false;
     209
     210    UInt32 size = sizeof(UInt32);
     211    AudioDeviceGetProperty(m_DeviceId, 0, false,
     212                           kAudioDevicePropertyMute, &size, &mute);
     213
     214    VERBOSE(VB_AUDIO,
     215            QString("VolumeControlCoreAudio::mute() = %1")
     216            .arg(mute ? "mute" : "unmute"));
     217
     218    return mute;
     219}
     220
     221void VolumeControlCoreAudio::setMute(bool mute)
     222{
     223    VERBOSE(VB_AUDIO,
     224            QString("VolumeControlCoreAudio::setMute(%1)")
     225            .arg(mute ? "mute" : "unmute"));
     226
     227    if (VolumeControlCoreAudio::mute())
     228    {
     229        Float32 value = static_cast<Float32>(m_Volume) / 100.0f;
     230        AudioDeviceSetProperty(m_DeviceId, NULL, 1, false,
     231                               kAudioDevicePropertyVolumeScalar,
     232                               sizeof(UInt32), &value);   
     233    }
     234
     235    UInt32 value = mute;
     236    AudioDeviceSetProperty(m_DeviceId, NULL, 0, false,
     237                           kAudioDevicePropertyMute, sizeof(UInt32), &value);
     238
     239    if (m_Mute.fetchAndStoreRelaxed(mute) != mute)
     240        emit changedMute(mute);
     241}
     242
     243// static
     244OSStatus VolumeControlCoreAudio::event(AudioDeviceID deviceId, UInt32 channel,
     245                                       Boolean input,
     246                                       AudioDevicePropertyID property,
     247                                       void* context)
     248{
     249    VolumeControlCoreAudio* that =
     250        static_cast<VolumeControlCoreAudio*>(context);
     251
     252    if (deviceId == that->m_DeviceId && !input)
     253        switch(property)
     254        {
     255        case kAudioDevicePropertyVolumeScalar:
     256        case kAudioDevicePropertyVolumeDecibels:
     257            int volume = that->volume();
     258            if (that->m_Volume.fetchAndStoreRelaxed(volume) != volume)
     259                emit that->changedVolume(volume);
     260            break;
     261
     262        case kAudioDevicePropertyMute:
     263            bool mute = that->mute();
     264            if (that->m_Mute.fetchAndStoreRelaxed(mute) != mute)
     265                emit that->changedMute(mute);
     266            break;
     267        }
     268
     269    return noErr;
     270}
  • 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__
  • 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
  • libs/libmyth/volumecontrolsoftware.cpp

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

     
    244244        return false;
    245245    }
    246246
    247     if (internal_vol && set_initial_vol)
    248     {
    249         QString controlLabel = gContext->GetSetting("MixerControl", "PCM");
    250         controlLabel += "MixerVolume";
    251         SetCurrentVolume(gContext->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,
  • 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);
  • libs/libmyth/audiooutputjack.cpp

     
    148148    audio_buffer_unused = JACK_GetBytesFreeSpace(audioid);
    149149    JACK_SetPosition(audioid, BYTES, 0);
    150150
    151     // Setup volume control
    152     if (internal_vol)
    153         VolumeInit();
    154 
    155151    // Device opened successfully
    156152    return true;
    157153}
     
    206202
    207203    return space;
    208204}
    209 
    210 void AudioOutputJACK::VolumeInit(void)
    211 {
    212     int volume = 100;
    213     if (set_initial_vol)
    214         volume = gContext->GetNumSetting("MasterMixerVolume", 80);
    215 
    216     JACK_SetAllVolume(audioid, volume);
    217 }
    218 
    219 int AudioOutputJACK::GetVolumeChannel(int channel) const
    220 {
    221     unsigned int vol = 0;
    222    
    223     if (!internal_vol)
    224         return 100;
    225 
    226     JACK_GetVolumeForChannel(audioid, channel, &vol);
    227     return vol;
    228 }
    229 
    230 void AudioOutputJACK::SetVolumeChannel(int channel, int volume)
    231 {
    232     if (internal_vol)
    233         JACK_SetVolumeForChannel(audioid, channel, volume);
    234 }
    235 
  • 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
  • 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) ? gContext->GetNumSetting("AC3PassThru", false) : false;
    111109
     110    if (gContext->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 = gContext->GetNumSetting("MythControlsVolume", 0);
    282282
    283283    numlowbuffer = 0;
    284284
     
    359359        return;
    360360    }
    361361
    362     // Only used for software volume
    363     if (set_initial_vol && internal_vol)
    364         volume = gContext->GetNumSetting("PCMMixerVolume", 80);
    365     {
    366         QString controlLabel = gContext->GetSetting("MixerControl", "PCM");
    367         controlLabel += "MixerVolume";
    368         volume = gContext->GetNumSetting(controlLabel, 80);
    369     }
    370 
    371     SyncVolume();
    372     VolumeBase::UpdateVolume();
    373 
    374362    VERBOSE(VB_AUDIO, LOC + QString("Audio fragment size: %1")
    375363            .arg(fragment_size));
    376364
     
    664652     return audbuf_timecode - GetAudiotime();
    665653}
    666654
    667 void AudioOutputBase::SetSWVolume(int new_volume, bool save)
    668 {
    669     volume = new_volume;
    670     if (save)
    671     {
    672         QString controlLabel = gContext->GetSetting("MixerControl", "PCM");
    673         controlLabel += "MixerVolume";
    674         gContext->SaveSetting(controlLabel, volume);
    675     }
    676 }
    677 
    678 int AudioOutputBase::GetSWVolume()
    679 {
    680     return volume;
    681 }
    682 
    683655void AudioOutputBase::AdjustVolume(void *buffer, int len, bool music)
    684656{
    685657    if (audio_bits == 8)
     
    691663template <class AudioDataType>
    692664void AudioOutputBase::_AdjustVolume(AudioDataType *buffer, int len, bool music)
    693665{
     666    int volume = volume_control->mute() ? 0 : volume_control->volume();
     667 
    694668    float g = volume / 100.0;
    695669
    696670    // Should probably be exponential - this'll do
     
    10991073        }
    11001074    }
    11011075
    1102     if (internal_vol && SWVolume())
     1076    if (volume_control)
    11031077    {
    11041078        int bdiff = kAudioRingBufferSize - waud;
    11051079        bool music = (timecode < 1);
     
    13601334    audio_buflock.unlock();
    13611335
    13621336    // Mute individual channels through mono->stereo duplication
    1363     MuteState mute_state = GetMuteState();
     1337//    MuteState mute_state = GetMuteState();
    13641338    if (written_size &&
    1365         audio_channels > 1 &&
    1366         (mute_state == kMuteLeft || mute_state == kMuteRight))
     1339        audio_channels > 1 //&&
     1340//        (mute_state == kMuteLeft || mute_state == kMuteRight)
     1341       )
    13671342    {
    13681343        int offset_src = 0;
    13691344        int offset_dst = 0;
    13701345 
    1371         if (mute_state == kMuteLeft)
    1372             offset_src = audio_bits / 8;    // copy channel 1 to channel 0
    1373         else if (mute_state == kMuteRight)
    1374             offset_dst = audio_bits / 8;    // copy channel 0 to channel 1
     1346//        if (mute_state == kMuteLeft)
     1347//            offset_src = audio_bits / 8;    // copy channel 1 to channel 0
     1348//        else if (mute_state == kMuteRight)
     1349//            offset_dst = audio_bits / 8;    // copy channel 0 to channel 1
    13751350     
    13761351        for (int i = 0; i < written_size; i += audio_bytes_per_sample)
    13771352        {
  • 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
  • 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
     
    4546SOURCES += output.cpp
    4647SOURCES += settings.cpp
    4748SOURCES += uilistbtntype.cpp uitypes.cpp util.cpp mythuifilebrowser.cpp
    48 SOURCES += volumebase.cpp xmlparse.cpp
     49SOURCES += volumecontrolmanager.cpp volumecontrolsoftware.cpp
     50SOURCES += xmlparse.cpp
    4951SOURCES += mythhdd.cpp mythcdrom.cpp storagegroup.cpp dbutil.cpp
    5052SOURCES += mythcommandlineparser.cpp mythterminal.cpp
    5153SOURCES += mythhttppool.cpp mythhttphandler.cpp
     
    8385# Install headers so that plugins can compile independently
    8486inc.path = $${PREFIX}/include/mythtv/
    8587inc.files  = dialogbox.h mythcontext.h
    86 inc.files += mythwidgets.h remotefile.h oldsettings.h volumecontrol.h
     88inc.files += mythwidgets.h remotefile.h oldsettings.h
    8789inc.files += settings.h uitypes.h xmlparse.h mythplugin.h mythdialogs.h
    8890inc.files += audiooutput.h audiosettings.h util.h
    8991inc.files += inetcomms.h mythmedia.h mythwizard.h schemawizard.h dbutil.h
    9092inc.files += uilistbtntype.h generictree.h managedlist.h mythmediamonitor.h
    91 inc.files += visual.h volumebase.h output.h langsettings.h
     93inc.files += visual.h volumecontrol.h volumecontrolmanager.h output.h langsettings.h
    9294inc.files += mythexp.h mythpluginapi.h storagegroup.h
    9395inc.files += mythconfigdialogs.h mythconfiggroups.h
    9496inc.files += mythterminal.h mythdeque.h mythuifilebrowser.h
     
    103105
    104106using_oss {
    105107    DEFINES += USING_OSS
    106     SOURCES += audiooutputoss.cpp
    107     HEADERS += audiooutputoss.h
     108    SOURCES += audiooutputoss.cpp volumecontroloss.cpp
     109    HEADERS += audiooutputoss.h volumecontroloss.h
    108110    LIBS += $$OSS_LIBS
    109111}
    110112
     
    132134
    133135mingw {
    134136    DEFINES += USING_MINGW
    135     SOURCES += mediamonitor-windows.cpp audiooutputwin.cpp audiooutputdx.cpp
    136     HEADERS += mediamonitor-windows.h   audiooutputwin.h   audiooutputdx.h
    137     LIBS += -lpthread -lwinmm -lws2_32
     137    SOURCES += mediamonitor-windows.cpp
     138    HEADERS += mediamonitor-windows.h
     139    SOURCES += audiooutputwin.cpp audiooutputdx.cpp volumecontrolendpoint.cpp
     140    HEADERS += audiooutputwin.h   audiooutputdx.h   volumecontrolendpoint.h
     141    LIBS += -lpthread -lwinmm -lws2_32 -lole32
    138142}
    139143
    140144macx {
    141     HEADERS += audiooutputca.h
    142     SOURCES += audiooutputca.cpp
     145    DEFINES += USE_COREAUDIO
     146    HEADERS += audiooutputca.h volumecontrolcoreaudio.h
     147    SOURCES += audiooutputca.cpp volumecontrolcoreaudio.cpp
    143148    HEADERS += mythcdrom-darwin.h
    144149    SOURCES += mythcdrom-darwin.cpp
    145150
     
    179184
    180185using_alsa {
    181186    DEFINES += USE_ALSA
    182     HEADERS += audiooutputalsa.h
    183     SOURCES += audiooutputalsa.cpp
     187    HEADERS += audiooutputalsa.h volumecontrolalsa.h
     188    SOURCES += audiooutputalsa.cpp volumecontrolalsa.cpp
    184189    LIBS += $$ALSA_LIBS
    185190}
    186191
  • 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;
  • 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
  • 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 = gContext->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 = gContext->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 = gContext->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 = gContext->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 
  • libs/libmyth/audiooutputdx.cpp

     
    369369    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
    370370                    | DSBCAPS_GLOBALFOCUS       /* Allows background playing */
    371371                    | DSBCAPS_LOCHARDWARE;      /* Needed for 5.1 on emu101k */
    372     if (!m_UseSPDIF)
    373         dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME;  /* Allow volume control */
    374372    dsbdesc.dwBufferBytes = soundcard_buffer_size;   /* buffer size */
    375373    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf;
    376374
     
    517515    return buffered;
    518516}
    519517
    520 int AudioOutputDX::GetVolumeChannel(int channel) const
    521 {
    522     HRESULT dsresult;
    523     long dxVolume = 0;
    524     int volume;
    525 
    526     if (m_UseSPDIF)
    527         return 100;
    528 
    529     dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);
    530     volume = (int)(pow(10,(float)dxVolume/20)*100);
    531 
    532     if (dsresult != DS_OK)
    533     {
    534         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to get volume %1")
    535                                                 .arg(dxVolume));
    536         return volume;
    537     }
    538 
    539     VERBOSE(VB_AUDIO, LOC + QString("Got volume %1").arg(volume));
    540     return volume;
    541 }
    542 
    543 void AudioOutputDX::SetVolumeChannel(int channel, int volume)
    544 {
    545     HRESULT dsresult;
    546     float dbAtten = 20 * log10((float)volume/100);
    547     long dxVolume = (volume == 0) ? DSBVOLUME_MIN : (long)(100.0f * dbAtten);
    548 
    549     if (m_UseSPDIF)
    550         return;
    551 
    552     // dxVolume is attenuation in 100ths of a decibel
    553     dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);
    554 
    555     if (dsresult != DS_OK)
    556     {
    557         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to set volume %1")
    558                                                 .arg(dxVolume));
    559         return;
    560     }
    561    
    562     VERBOSE(VB_AUDIO, LOC + QString("Set volume %1").arg(dxVolume));
    563 }
    564 
    565518/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • 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:
  • 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() { };
  • 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
  • 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
  • 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);
  • libs/libmyth/audiooutputalsa.h

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

     
    2828#include "iso639.h"
    2929#include "playbackbox.h"
    3030#include "globalsettings.h"
     31#include "libmyth/volumecontrolmanager.h"
    3132#include "recordingprofile.h"
    3233#include "mythxdisplay.h"
    3334#include "DisplayRes.h"
     
    179180    return gc;
    180181}
    181182
    182 static HostCheckBox *MythControlsVolume()
    183 {
    184     HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
    185     gc->setLabel(QObject::tr("Use internal volume controls"));
    186     gc->setValue(true);
    187     gc->setHelpText(QObject::tr("MythTV can control the PCM and master "
    188                     "mixer volume.  If you prefer to control the volume externally "
    189                     "(like your amplifier) or use an external mixer "
    190                     "program, disable this option."));
    191     return gc;
    192 }
    193 
    194183static HostComboBox *MixerDevice()
    195184{
    196185    HostComboBox *gc = new HostComboBox("MixerDevice", true);
    197186    gc->setLabel(QObject::tr("Mixer Device"));
     187    gc->addSelection(QObject::tr("Disabled"), QString());
    198188
    199 #ifdef USING_OSS
    200     QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
    201     gc->fillSelectionsFromDir(dev);
     189    QHash<QString, QString> controls = VolumeControlManager::Enumerate();
    202190
    203     dev.setPath("/dev/sound");
    204     if (dev.exists())
     191    for (QHash<QString, QString>::const_iterator control = controls.begin();
     192         control != controls.end(); ++control)
    205193    {
    206         gc->fillSelectionsFromDir(dev);
     194        gc->addSelection(control.value(), control.key());
    207195    }
    208 #endif
    209 #ifdef USING_ALSA
    210     gc->addSelection("ALSA:default", "ALSA:default");
    211 #endif
    212 #ifdef USING_MINGW
    213     gc->addSelection("DirectX:", "DirectX:");
    214     gc->addSelection("Windows:", "Windows:");
    215 #endif
    216 #if !defined(USING_MINGW)
    217     gc->addSelection("software", "software");
    218     gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" lets MythTV control "
    219                                 "the volume of all audio at the expense of a slight quality loss."));
    220 #endif
    221196
    222197    return gc;
    223198}
    224199
    225 static const char* MixerControlControls[] = { "PCM",
    226                                               "Master" };
    227 
    228 static HostComboBox *MixerControl()
    229 {
    230     HostComboBox *gc = new HostComboBox("MixerControl", true);
    231     gc->setLabel(QObject::tr("Mixer Controls"));
    232     for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
    233          ++i)
    234     {
    235         gc->addSelection(QObject::tr(MixerControlControls[i]),
    236                          MixerControlControls[i]);
    237     }
    238 
    239     gc->setHelpText(QObject::tr("Changing the volume adjusts the selected mixer."));
    240     return gc;
    241 }
    242 
    243 static HostSlider *MixerVolume()
    244 {
    245     HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
    246     gs->setLabel(QObject::tr("Master Mixer Volume"));
    247     gs->setValue(70);
    248     gs->setHelpText(QObject::tr("Initial volume for the Master Mixer.  "
    249                     "This affects all sound created by the sound card.  "
    250                     "Note: Do not set this too low."));
    251     return gs;
    252 }
    253 
    254 static HostSlider *PCMVolume()
    255 {
    256     HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
    257     gs->setLabel(QObject::tr("PCM Mixer Volume"));
    258     gs->setValue(70);
    259     gs->setHelpText(QObject::tr("Initial volume for PCM output.  Using the "
    260                     "volume keys in MythTV will adjust this parameter."));
    261     return gs;
    262 }
    263 
    264200static HostCheckBox *IndividualMuteControl()
    265201{
    266202    HostCheckBox *gc = new HostCheckBox("IndividualMuteControl");
     
    35523488    group2->addChild(AggressiveBuffer());
    35533489
    35543490    return vcg;
    3555 
    35563491}
    35573492
    3558 class AudioMixerSettingsGroup : public TriggeredConfigurationGroup
     3493static ConfigurationGroup *AudioMixerSettingsGroup()
    35593494{
    3560   public:
    3561     AudioMixerSettingsGroup() :
    3562         TriggeredConfigurationGroup(false, true, false, false)
    3563     {
    3564         setLabel(QObject::tr("Audio Mixer"));
    3565         setUseLabel(false);
     3495    ConfigurationGroup *vcg = new VerticalConfigurationGroup(false, true, false, false);
     3496   
     3497    vcg->setLabel(QObject::tr("Audio Mixer"));
     3498    vcg->setUseLabel(false);
    35663499
    3567         Setting *volumeControl = MythControlsVolume();
    3568         addChild(volumeControl);
     3500    vcg->addChild(MixerDevice());
    35693501
    3570         // Mixer settings
    3571         ConfigurationGroup *settings =
    3572             new VerticalConfigurationGroup(false, true, false, false);
    3573         settings->addChild(MixerDevice());
    3574         settings->addChild(MixerControl());
    3575         settings->addChild(MixerVolume());
    3576         settings->addChild(PCMVolume());
    3577         settings->addChild(IndividualMuteControl());
     3502    return vcg;
     3503}
    35783504
    3579         ConfigurationGroup *dummy =
    3580             new VerticalConfigurationGroup(false, true, false, false);
    3581 
    3582         // Show Mixer config only if internal volume controls enabled
    3583         setTrigger(volumeControl);
    3584         addTarget("0", dummy);
    3585         addTarget("1", settings);
    3586     }
    3587 };
    3588 
    35893505static HostComboBox *MythLanguage()
    35903506{
    35913507    HostComboBox *gc = new HostComboBox("Language");
     
    42694185
    42704186    addChild(AudioSystemSettingsGroup());
    42714187
    4272     addChild(new AudioMixerSettingsGroup());
     4188    addChild(AudioMixerSettingsGroup());
    42734189
    42744190    VerticalConfigurationGroup *general =
    42754191        new VerticalConfigurationGroup(false, true, false, false);
  • programs/mythtranscode/transcode.cpp

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