Ticket #7517: volume_control_mythtv_r22928.patch
| File volume_control_mythtv_r22928.patch, 128.0 KB (added by , 16 years ago) |
|---|
-
configure
595 595 eval "$var=\"\$$var $*\"" 596 596 } 597 597 598 prepend(){ 599 var=$1 600 shift 601 flags_saved && eval "SAVE_$var=\"$* \$SAVE_$var\"" 602 eval "$var=\"$* \$$var\"" 603 } 604 598 605 add_cflags(){ 599 606 append CFLAGS "$@" 600 607 } … … 3325 3332 enable audio_alsa || 3326 3333 disable audio_alsa 3327 3334 3335 # OSS probe 3336 if ! 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 3358 fi 3359 3328 3360 # JACK probe 3329 3361 ! disabled audio_jack && 3330 3362 check_lib jack/jack.h jack_client_new $audio_jack_libs && … … 4022 4054 if enabled audio_oss; then 4023 4055 append CCONFIG "using_oss" 4024 4056 fi 4057 4025 4058 if enabled audio_alsa; then 4026 4059 append CCONFIG "using_alsa" 4027 4060 echo "CONFIG_AUDIO_ALSA_LIBS=$audio_alsa_libs" >> $MYTH_CONFIG_MAK -
libs/libmythtv/NuppelVideoPlayer.cpp
141 141 kDisplayNUVTeletextCaptions, 142 142 }; 143 143 144 NuppelVideoPlayer::NuppelVideoPlayer( bool muted)144 NuppelVideoPlayer::NuppelVideoPlayer() 145 145 : decoder(NULL), decoder_change_lock(QMutex::Recursive), 146 146 videoOutput(NULL), player_ctx(NULL), 147 147 no_hardware_decoders(false), … … 209 209 audio_channels(2), audio_codec(0), 210 210 audio_bits(-1), audio_samplerate(44100), 211 211 audio_stretchfactor(1.0f), audio_lock(QMutex::Recursive), 212 audio_muted_on_creation(muted),213 212 // Picture-in-Picture stuff 214 213 pip_active(false), pip_visible(true), 215 214 // Preview window support … … 402 401 audio_samplerate = (int)samplerate; 403 402 } 404 403 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 469 404 void NuppelVideoPlayer::PauseDecoder(void) 470 405 { 471 406 decoder_lock.lock(); … … 904 839 905 840 if (!audioOutput && !using_null_videoout && player_ctx->IsAudioNeeded()) 906 841 { 907 bool setVolume = gContext->GetNumSetting("MythControlsVolume", 1);908 842 audioOutput = AudioOutput::OpenAudio(audio_main_device, 909 843 audio_passthru_device, 910 844 audio_bits, audio_channels, 911 845 audio_codec, audio_samplerate, 912 846 AUDIOOUTPUT_VIDEO, 913 setVolume,audio_passthru);847 audio_passthru); 914 848 if (!audioOutput) 915 849 errMsg = QObject::tr("Unable to create AudioOutput."); 916 850 else … … 932 866 VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio"); 933 867 no_audio_out = false; 934 868 } 935 if (audio_muted_on_creation)936 {937 SetMuteState(kMuteAll);938 audio_muted_on_creation = false;939 }940 869 } 941 870 942 871 if (audioOutput) -
libs/libmythtv/avformatdecoder.cpp
464 464 audioSamples(NULL), audioSamplesResampled(NULL), 465 465 reformat_ctx(NULL), audio_src_fmt(SAMPLE_FMT_NONE), 466 466 allow_ac3_passthru(false), allow_dts_passthru(false), 467 internal_vol(false),468 467 disable_passthru(false), max_channels(2), 469 468 last_ac3_channels(0), dummy_frame(NULL), 470 469 // DVD … … 487 486 max_channels = (uint) gContext->GetNumSetting("MaxChannels", 2); 488 487 allow_ac3_passthru = (max_channels > 2) ? gContext->GetNumSetting("AC3PassThru", false) : false; 489 488 allow_dts_passthru = (max_channels > 2) ? gContext->GetNumSetting("DTSPassThru", false) : false; 490 internal_vol = gContext->GetNumSetting("MythControlsVolume", 0);491 489 492 490 audioIn.sample_size = -32; // force SetupAudioStream to run once 493 491 itv = GetNVP()->GetInteractiveTV(); … … 4370 4368 4371 4369 if (ctx->codec_id == CODEC_ID_AC3) 4372 4370 passthru = allow_ac3_passthru && 4373 ctx->channels >= (int)max_channels && 4374 !internal_vol; 4371 ctx->channels >= (int)max_channels; 4375 4372 else if (ctx->codec_id == CODEC_ID_DTS) 4376 passthru = allow_dts_passthru && !internal_vol;4373 passthru = allow_dts_passthru; 4377 4374 4378 4375 passthru &= !transcoding && !disable_passthru; 4379 4376 // Don't know any cards that support spdif clocked at < 44100 -
libs/libmythtv/tv_play.h
34 34 #include "programlist.h" 35 35 #include "channelutil.h" 36 36 #include "videoouttypes.h" 37 #include "volume base.h"37 #include "volumecontrolmanager.h" 38 38 #include "inputinfo.h" 39 39 #include "channelgroup.h" 40 40 … … 297 297 void AddUDPNotifyEvent(const QString &name, const UDPNotifyOSDSet*); 298 298 void ClearUDPNotifyEvents(void); 299 299 300 void VolumeChanged(int volume); 301 void MuteChanged(bool mute); 302 300 303 protected: 301 304 void TreeMenuEntered(OSDListTreeItemEnteredEvent *e); 302 305 void TreeMenuSelected(OSDListTreeItemSelectedEvent *e); … … 306 309 virtual void run(void); 307 310 void TVEventThreadChecks(void); 308 311 309 void SetMuteTimer(PlayerContext*, int timeout);310 bool MuteChannelChange(PlayerContext *ctx);311 312 312 bool eventFilter(QObject *o, QEvent *e); 313 313 static QStringList lastProgramStringList; 314 314 static EMBEDRETURNPROGRAM RunPlaybackBoxPtr; … … 498 498 499 499 vector<long long> TeardownAllNVPs(PlayerContext*); 500 500 void RestartAllNVPs(PlayerContext *lctx, 501 const vector<long long> &pos, 502 MuteState mctx_mute); 501 const vector<long long> &pos); 503 502 void RestartMainNVP(PlayerContext *mctx); 504 503 505 504 void PxPToggleView( PlayerContext *actx, bool wantPBP); … … 660 659 /// Picture attribute to modify (on arrow left or right) 661 660 PictureAttribute adjustingPictureAttribute; 662 661 662 QSharedPointer<VolumeControl> volumeControl; ///< Volume Control interface 663 663 664 // Ask Allow state 664 665 AskAllowType askAllowType; 665 666 QMap<QString,AskProgramInfo> askAllowPrograms; … … 817 818 TimerContextMap stateChangeTimerId; 818 819 TimerContextMap signalMonitorTimerId; 819 820 TimerContextMap tvchainUpdateTimerId; 820 TimerContextMap unmuteTimerId;821 821 822 822 /// Condition to signal that the Event thread is up and running 823 823 QWaitCondition mainLoopCond; … … 838 838 839 839 ///< Timeout for entry modes in msec 840 840 static const uint kInputModeTimeout; 841 /// Channel changing mute timeout in msec842 static const uint kMuteTimeout;843 841 /// Timeout for updating LCD info in msec 844 842 static const uint kLCDTimeout; 845 843 /// Timeout for browse mode exit in msec -
libs/libmythtv/playercontext.cpp
430 430 431 431 bool PlayerContext::CreateNVP(TV *tv, QWidget *widget, 432 432 TVState desiredState, 433 WId embedwinid, const QRect *embedbounds, 434 bool muted) 433 WId embedwinid, const QRect *embedbounds) 435 434 { 436 435 int exact_seeking = gContext->GetNumSetting("ExactSeeking", 0); 437 436 … … 442 441 return false; 443 442 } 444 443 445 NuppelVideoPlayer *_nvp = new NuppelVideoPlayer( muted);444 NuppelVideoPlayer *_nvp = new NuppelVideoPlayer(); 446 445 447 446 if (nohardwaredecoders) 448 447 _nvp->DisableHardwareDecoders(); … … 492 491 VERBOSE(VB_IMPORTANT, LOC_ERR + errMsg); 493 492 } 494 493 } 495 else if (pipState == kPBPRight)496 nvp->SetMuted(true);497 494 498 495 int maxWait = -1; 499 496 //if (isPIP()) -
libs/libmythtv/NuppelVideoPlayer.h
4 4 #include <sys/time.h> 5 5 6 6 #include "playercontext.h" 7 #include "volumebase.h"8 7 #include "RingBuffer.h" 9 8 #include "osd.h" 10 9 #include "jitterometer.h" … … 104 103 friend class PlayerContext; 105 104 106 105 public: 107 NuppelVideoPlayer( bool muted = false);106 NuppelVideoPlayer(); 108 107 ~NuppelVideoPlayer(); 109 108 110 109 // Initialization … … 127 126 void SetAudioInfo(const QString &main, const QString &passthru, uint rate); 128 127 void SetAudioParams(int bits, int channels, int codec, int samplerate, bool passthru); 129 128 void SetEffDsp(int dsprate); 130 uint AdjustVolume(int change);131 bool SetMuted(bool mute);132 MuteState SetMuteState(MuteState);133 MuteState IncrMuteState(void);134 129 void SetAudioCodec(void *ac); 135 130 136 131 // Sets … … 187 182 float GetVideoAspect(void) const { return video_aspect; } 188 183 float GetFrameRate(void) const { return video_frame_rate; } 189 184 190 uint GetVolume(void);191 185 int GetSecondsBehind(void) const; 192 186 AspectOverrideMode GetAspectOverride(void) const; 193 187 AdjustFillMode GetAdjustFill(void) const; 194 MuteState GetMuteState(void);195 188 CommSkipMode GetAutoCommercialSkip(void) const; 196 189 197 190 int GetFFRewSkip(void) const { return ffrew_skip; } … … 227 220 bool HasAudioOut(void) const { return !no_audio_out; } 228 221 bool IsPIPActive(void) const { return pip_active; } 229 222 bool IsPIPVisible(void) const { return pip_visible; } 230 bool IsMuted(void) { return GetMuteState() == kMuteAll; }231 223 bool UsingNullVideo(void) const { return using_null_videoout; } 232 224 bool HasTVChainNext(void) const; 233 225 … … 719 711 float audio_stretchfactor; 720 712 bool audio_passthru; 721 713 QMutex audio_lock; 722 bool audio_muted_on_creation;723 714 724 715 // Picture-in-Picture 725 716 mutable QMutex pip_players_lock; -
libs/libmythtv/tv_play.cpp
83 83 84 84 85 85 const uint TV::kInputModeTimeout = 5000; 86 const uint TV::kMuteTimeout = 800;87 86 const uint TV::kLCDTimeout = 1000; 88 87 const uint TV::kBrowseTimeout = 30000; 89 88 const uint TV::kKeyRepeatTimeout = 300; … … 967 966 player.push_back(new PlayerContext("player")); 968 967 playerActive = 0; 969 968 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 970 979 VERBOSE(VB_PLAYBACK, LOC + "ctor -- end"); 971 980 } 972 981 … … 2829 2838 if (handled) 2830 2839 return; 2831 2840 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 2859 2841 if (handled) 2860 2842 return; 2861 2843 … … 5421 5403 } 5422 5404 } 5423 5405 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 5430 5406 vector<long long> pos = TeardownAllNVPs(mctx); 5431 5407 5432 5408 if (wantPBP) … … 5444 5420 } 5445 5421 } 5446 5422 5447 RestartAllNVPs(mctx, pos , mctx_mute);5423 RestartAllNVPs(mctx, pos); 5448 5424 5449 5425 VERBOSE(VB_PLAYBACK, LOC + 5450 5426 QString("PxPToggleType() converting from %1 to %2 -- end") … … 5588 5564 * \brief Recreate Main and PIP windows. Could be either PIP or PBP views. 5589 5565 */ 5590 5566 void TV::RestartAllNVPs(PlayerContext *lctx, 5591 const vector<long long> &pos, 5592 MuteState mctx_mute) 5567 const vector<long long> &pos) 5593 5568 { 5594 5569 QString loc = LOC + QString("RestartAllNVPs(): "); 5595 5570 … … 5636 5611 pipctx->LockDeleteNVP(__FILE__, __LINE__); 5637 5612 if (pipctx->nvp) 5638 5613 { 5639 pipctx->nvp->SetMuted(true);5640 5614 pipctx->nvp->JumpToFrame(pos[i]); 5641 5615 } 5642 5616 pipctx->UnlockDeleteNVP(__FILE__, __LINE__); … … 5648 5622 ForceNextStateNone(pipctx); 5649 5623 } 5650 5624 } 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__);5658 5625 } 5659 5626 5660 5627 void TV::PxPSwap(PlayerContext *mctx, PlayerContext *pipctx) … … 5682 5649 return; 5683 5650 } 5684 5651 5685 MuteState mctx_mute = mctx->nvp->GetMuteState();5686 5652 mctx->deleteNVPLock.unlock(); 5687 5653 pipctx->deleteNVPLock.unlock(); 5688 5654 … … 5696 5662 playerActive = (ctx_index == playerActive) ? 5697 5663 0 : ((ctx_index == 0) ? ctx_index : playerActive); 5698 5664 5699 RestartAllNVPs(mctx, pos , mctx_mute);5665 RestartAllNVPs(mctx, pos); 5700 5666 5701 5667 SetActive(mctx, playerActive, false); 5702 5668 … … 5717 5683 mctx->deleteNVPLock.unlock(); 5718 5684 return; 5719 5685 } 5720 5721 MuteState mctx_mute = mctx->nvp->GetMuteState();5722 5723 // HACK - FIXME5724 // workaround muted audio when NVP is re-created5725 mctx_mute = kMuteOff;5726 // FIXME - end5727 5686 mctx->deleteNVPLock.unlock(); 5728 5687 5729 5688 vector<long long> pos = TeardownAllNVPs(mctx); 5730 RestartAllNVPs(mctx, pos , mctx_mute);5689 RestartAllNVPs(mctx, pos); 5731 5690 SetActive(mctx, playerActive, false); 5732 5691 5733 5692 VERBOSE(VB_PLAYBACK, LOC + "Restart main player -- end"); … … 5852 5811 5853 5812 VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- begin"); 5854 5813 5855 bool muted = false;5856 5857 5814 ctx->LockDeleteNVP(__FILE__, __LINE__); 5858 5815 if (!ctx->nvp) 5859 5816 { … … 5861 5818 return false; 5862 5819 } 5863 5820 5864 if (ctx == GetPlayer(ctx, 0))5865 muted = MuteChannelChange(ctx);5866 5867 5821 bool res = false; 5868 5822 5869 5823 if (LONG_LONG_MIN != audiosyncBaseline) … … 5884 5838 } 5885 5839 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 5886 5840 5887 if (muted)5888 SetMuteTimer(ctx, kMuteTimeout);5889 5890 5841 VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- end"); 5891 5842 5892 5843 return res; … … 6167 6118 if (StateIsLiveTV(GetState(ctx))) 6168 6119 return; 6169 6120 6170 ctx->LockDeleteNVP(__FILE__, __LINE__);6171 bool muted = MuteChannelChange(ctx);6172 ctx->UnlockDeleteNVP(__FILE__, __LINE__);6173 6174 6121 struct StatusPosInfo posInfo; 6175 6122 ctx->CalcNVPSliderPosition(posInfo); 6176 6123 … … 6189 6136 if (ctx->nvp) 6190 6137 ctx->nvp->SkipCommercials(direction); 6191 6138 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 6192 6193 if (muted)6194 SetMuteTimer(ctx, kMuteTimeout);6195 6139 } 6196 6140 6197 6141 void TV::SwitchSource(uint source_direction) … … 6361 6305 if (mctx != ctx) 6362 6306 PIPRemovePlayer(mctx, ctx); 6363 6307 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 6370 6308 // pause the decoder first, so we're not reading too close to the end. 6371 6309 ctx->buffer->IgnoreLiveEOF(true); 6372 6310 ctx->buffer->StopReads(); … … 6418 6356 6419 6357 if (ctx->CreateNVP( 6420 6358 this, gContext->GetMainWindow(), ctx->GetState(), 6421 mctx->embedWinID, &mctx->embedBounds , muted))6359 mctx->embedWinID, &mctx->embedBounds)) 6422 6360 { 6423 6361 ScheduleStateChange(ctx); 6424 6362 ok = true; … … 6775 6713 6776 6714 void TV::ChangeChannel(PlayerContext *ctx, int direction) 6777 6715 { 6778 bool muted = false;6779 6780 6716 if ((browse_changrp || (direction == CHANNEL_DIRECTION_FAVORITE)) && 6781 6717 (channel_group_id > -1)) 6782 6718 { … … 6807 6743 6808 6744 QString oldinputname = ctx->recorder->GetInput(); 6809 6745 6810 muted = MuteChannelChange(ctx);6811 6812 6746 if (ctx->paused) 6813 6747 { 6814 6748 OSD *osd = GetOSDLock(ctx); … … 6836 6770 ctx->recorder->ChangeChannel(direction); 6837 6771 ClearInputQueues(ctx, false); 6838 6772 6839 if (muted)6840 SetMuteTimer(ctx, kMuteTimeout * 2);6841 6842 6773 UnpauseLiveTV(ctx); 6843 6774 6844 6775 if (oldinputname != ctx->recorder->GetInput()) … … 6855 6786 6856 6787 QString channum = chan; 6857 6788 QStringList reclist; 6858 bool muted = false;6859 6789 6860 6790 QString oldinputname = ctx->recorder->GetInput(); 6861 6791 … … 6925 6855 if (getit || !ctx->recorder || !ctx->recorder->CheckChannel(channum)) 6926 6856 return; 6927 6857 6928 muted = MuteChannelChange(ctx);6929 6930 6858 OSD *osd = GetOSDLock(ctx); 6931 6859 if (osd && ctx->paused) 6932 6860 { … … 6952 6880 6953 6881 ctx->recorder->SetChannel(channum); 6954 6882 6955 if (muted)6956 SetMuteTimer(ctx, kMuteTimeout * 2);6957 6958 6883 UnpauseLiveTV(ctx); 6959 6884 6960 6885 if (oldinputname != ctx->recorder->GetInput()) … … 8066 7991 8067 7992 void TV::ChangeVolume(PlayerContext *ctx, bool up) 8068 7993 { 8069 ctx->LockDeleteNVP(__FILE__, __LINE__); 8070 if (!ctx->nvp) 7994 if (volumeControl) 8071 7995 { 8072 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8073 return; 7996 if (up) 7997 volumeControl->increaseVolume(); 7998 else 7999 volumeControl->decreaseVolume(); 8074 8000 } 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);8088 8001 } 8089 8002 8090 8003 void TV::ToggleTimeStretch(PlayerContext *ctx) … … 8233 8146 8234 8147 void TV::ToggleMute(PlayerContext *ctx) 8235 8148 { 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()); 8270 8151 } 8271 8152 8272 8153 void TV::ToggleSleepTimer(const PlayerContext *ctx) … … 8426 8307 ReturnOSDLock(ctx, osd); 8427 8308 } 8428 8309 8429 void TV::SetMuteTimer(PlayerContext *ctx, int timeout)8430 {8431 // message to set the timer will be posted to the main UI thread8432 // where it will be caught in eventFilter and processed as CustomEvent8433 // this will properly set the mute timer8434 // otherwise it never fires on Win328435 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 8453 8310 void TV::customEvent(QEvent *e) 8454 8311 { 8455 8312 if ((MythEvent::Type)(e->type()) == kOSDClosedEventType) … … 8725 8582 } 8726 8583 } 8727 8584 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 8747 8585 if (message.left(9) == "START_EPG") 8748 8586 { 8749 8587 int editType = tokens[1].toInt(); … … 9217 9055 { 9218 9056 value = ctx->nvp->getVideoOutput()->GetPictureAttribute(attr); 9219 9057 } 9220 else if (ctx->nvp->HasAudioOut() )9058 else if (ctx->nvp->HasAudioOut() && volumeControl) 9221 9059 { 9222 value = ctx->nvp->GetVolume();9060 value = volumeControl->volume(); 9223 9061 title = tr("Adjust Volume"); 9224 9062 } 9225 9063 } … … 11723 11561 ReturnPlayerLock(mctx); 11724 11562 } 11725 11563 11564 void 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 11577 void 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 11726 11586 OSD *TV::GetOSDL(const char *file, int location) 11727 11587 { 11728 11588 PlayerContext *actx = GetPlayerReadLock(-1, file, location); -
libs/libmythtv/playercontext.h
47 47 // Actions 48 48 bool CreateNVP(TV *tv, QWidget *widget, 49 49 TVState desiredState, 50 WId embedwinid, const QRect *embedBounds, 51 bool muted = false); 50 WId embedwinid, const QRect *embedBounds); 52 51 void TeardownPlayer(void); 53 52 bool StartDecoderThread(int maxWait = -1); 54 53 bool StartOSD(TV *tv); -
libs/libmythtv/avformatdecoder.h
263 263 264 264 bool allow_ac3_passthru; 265 265 bool allow_dts_passthru; 266 bool internal_vol;267 266 bool disable_passthru; 268 267 uint max_channels; 269 268 uint last_ac3_channels; -
libs/libmyth/audiooutputwin.cpp
280 280 { 281 281 return m_nPkts * fragment_size; 282 282 } 283 284 int AudioOutputWin::GetVolumeChannel(int channel) const285 {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 else316 dwVolume = dwVolume & 0xffff | ((volume * (0xffff / 100)) << 16);317 }318 else319 {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 19 QHash<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 40 QSharedPointer<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 6 QHash<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 35 VolumeControlALSA::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 112 VolumeControlALSA::~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 128 int 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 148 void 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 168 void VolumeControlALSA::increaseVolume() 169 { 170 setVolume((volume() * m_Range + 100) / m_Range); 171 } 172 173 void VolumeControlALSA::decreaseVolume() 174 { 175 setVolume((volume() * m_Range - 100) / m_Range); 176 } 177 178 bool 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 206 void 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 227 int 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 256 void 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
18 18 #include "audiooutput.h" 19 19 #include "samplerate.h" 20 20 #include "mythverbose.h" 21 #include "volumecontrolmanager.h" 21 22 22 23 namespace soundtouch { 23 24 class SoundTouch; … … 47 48 48 49 virtual void Reset(void); 49 50 50 void SetSWVolume(int new_volume, bool save);51 int GetSWVolume(void);52 53 51 // timecode is in milliseconds. 54 52 virtual bool AddSamples(char *buffer, int samples, long long timecode); 55 53 virtual bool AddSamples(char *buffers[], int samples, long long timecode); … … 113 111 int audiolen(bool use_lock); // number of valid bytes in audio buffer 114 112 int audiofree(bool use_lock); // number of free bytes in audio buffer 115 113 116 void UpdateVolume(void);117 118 114 void SetStretchFactorLocked(float factor); 119 115 120 116 int GetBaseAudioTime() const { return audiotime; } … … 148 144 bool killaudio; 149 145 150 146 bool pauseaudio, audio_actually_paused, was_paused; 151 bool set_initial_vol;152 147 bool buffer_output_data_for_use; // used by AudioOutputNULL 153 148 154 149 int configured_audio_channels; … … 181 176 int surround_mode; 182 177 bool allow_ac3_passthru; 183 178 float old_audio_stretchfactor; 184 int volume;179 QSharedPointer<VolumeControl> volume_control; ///< Volume Control interface 185 180 186 181 bool blocking; // do AddSamples calls block? 187 182 -
libs/libmyth/audiooutputalsa.cpp
21 21 AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) : 22 22 AudioOutputBase(settings), 23 23 pcm_handle(NULL), 24 numbadioctls(0), 25 mixer_handle(NULL), 26 mixer_control(QString::null) 24 numbadioctls(0) 27 25 { 28 26 // Set everything up 29 27 Reconfigure(settings); … … 252 250 // it really is 253 251 audio_buffer_unused = soundcard_buffer_size - (fragment_size * 4); 254 252 255 if (internal_vol)256 OpenMixer(set_initial_vol);257 258 253 // Device opened successfully 259 254 return true; 260 255 } 261 256 262 257 void AudioOutputALSA::CloseDevice() 263 258 { 264 CloseMixer();265 259 if (pcm_handle != NULL) 266 260 { 267 261 snd_pcm_close(pcm_handle); … … 620 614 621 615 return 0; 622 616 } 623 624 625 int AudioOutputALSA::GetVolumeChannel(int channel) const626 {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 do678 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 else717 {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 else743 {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 soundcards794 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) const830 {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) const33 {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) const66 {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 match130 if (swvol)131 volume = GetSWVolume();132 else133 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 11 class VolumeControlCoreAudio : public VolumeControl 12 { 13 public: 14 static QHash<QString, QString> Enumerate(); 15 16 public: 17 VolumeControlCoreAudio(QString device); 18 virtual ~VolumeControlCoreAudio(); 19 20 public: 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 29 protected: 30 static OSStatus event(AudioDeviceID deviceId, UInt32 channel, 31 Boolean input, AudioDevicePropertyID property, 32 void* context); 33 34 private: 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 10 class VolumeControlSoftware : public VolumeControl 11 { 12 public: 13 static QHash<QString, QString> Enumerate(); 14 15 public: 16 VolumeControlSoftware(QString device); 17 virtual ~VolumeControlSoftware(); 18 19 public: 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 28 private: 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 9 QHash<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 88 VolumeControlCoreAudio::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 137 VolumeControlCoreAudio::~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 152 int 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 173 void 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 196 void VolumeControlCoreAudio::increaseVolume() 197 { 198 setVolume(volume() + 10); 199 } 200 201 void VolumeControlCoreAudio::decreaseVolume() 202 { 203 setVolume(volume() - 10); 204 } 205 206 bool 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 221 void 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 244 OSStatus 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 VolumeBase14 {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-10034 virtual void SetVolumeChannel(int channel, int volume) = 0; // range 0-100 for vol35 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 7 class VolumeControl : public QObject 8 { 9 Q_OBJECT 10 11 public: 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 20 signals: 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 7 QHash<QString, QString> VolumeControlSoftware::Enumerate() 8 { 9 QHash<QString, QString> result; 10 11 result.insert("Software:", "Software Volume Processing"); 12 13 return result; 14 } 15 16 VolumeControlSoftware::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 23 VolumeControlSoftware::~VolumeControlSoftware() 24 { 25 26 } 27 28 int 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 39 void 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 54 void VolumeControlSoftware::increaseVolume() 55 { 56 setVolume(volume() + 1); 57 } 58 59 void VolumeControlSoftware::decreaseVolume() 60 { 61 setVolume(volume() - 1); 62 } 63 64 bool 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 75 void 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 88 QAtomicInt VolumeControlSoftware::m_Volume; 89 QAtomicInt VolumeControlSoftware::m_Mute; -
libs/libmyth/audiooutputpulse.h
30 30 AudioOutputPulseAudio(const AudioSettings &settings); 31 31 ~AudioOutputPulseAudio(); 32 32 33 int GetVolumeChannel(int channel) const;34 void SetVolumeChannel(int channel, int volume);35 33 void Pause(bool paused); 36 34 void Reset(void); 37 35 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 11 class VolumeControlOSS : public VolumeControl, protected QThread 12 { 13 public: 14 static QHash<QString, QString> Enumerate(); 15 16 public: 17 VolumeControlOSS(QString device); 18 virtual ~VolumeControlOSS(); 19 20 public: 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 29 protected: 30 virtual void run(); 31 32 private: 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 12 class VolumeControlALSA : public VolumeControl, protected QThread 13 { 14 public: 15 static QHash<QString, QString> Enumerate(); 16 17 public: 18 VolumeControlALSA(QString device); 19 virtual ~VolumeControlALSA(); 20 21 public: 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 30 protected: 31 virtual void run(); 32 33 static int event(snd_mixer_elem_t* elem, unsigned int mask); 34 35 private: 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
268 268 return writable; 269 269 } 270 270 271 int AudioOutputPulseAudio::GetVolumeChannel(int channel) const272 {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 else301 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 308 271 void AudioOutputPulseAudio::Pause(bool paused) 309 272 { 310 273 pa_operation *op; … … 545 508 pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over"); 546 509 pa_stream_set_underflow_callback(pstream, BufferFlowCallback, 547 510 (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); 556 512 557 513 // set myth sizes and pa buffer metrics 558 514 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 7 typedef struct _BYTE_BLOB 8 { 9 unsigned long clSize; 10 byte abData[ 1 ]; 11 } BYTE_BLOB; 12 13 typedef struct _tagpropertykey 14 { 15 GUID fmtid; 16 DWORD pid; 17 } PROPERTYKEY; 18 19 #define REFPROPVARIANT const PROPVARIANT & 20 21 inline void PropVariantInit ( PROPVARIANT * pvar ) 22 { 23 memset ( pvar, 0, sizeof(PROPVARIANT) ); 24 } 25 WINOLEAPI PropVariantClear ( PROPVARIANT * pvar ); 26 27 EXTERN_C const CLSID CLSID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C,{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}}; 28 EXTERN_C const IID IID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35,{0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}}; 29 EXTERN_C const IID IID_IAudioEndpointVolume = {0x5CDF2C82,0x841E,0x4546,{0x97,0x22,0x0C,0xF7,0x40,0x78,0x22,0x9A}}; 30 EXTERN_C const IID IID_IAudioEndpointVolumeCallback = {0x657804FA,0xD6AD,0x4496,{0x8A,0x60,0x35,0x27,0x52,0xAF,0x4F,0x89}}; 31 EXTERN_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 38 QHash<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 135 VolumeControlEndpoint::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 192 VolumeControlEndpoint::~VolumeControlEndpoint() 193 { 194 if (m_EndpointVolume) 195 { 196 m_EndpointVolume->UnregisterControlChangeNotify(this); 197 m_EndpointVolume->Release(); 198 } 199 200 CoUninitialize(); 201 } 202 203 int 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 226 void 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 246 void 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 255 void 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 264 bool 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 278 void 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 297 ULONG STDMETHODCALLTYPE VolumeControlEndpoint::AddRef() 298 { 299 return 1; 300 } 301 302 ULONG STDMETHODCALLTYPE VolumeControlEndpoint::Release() 303 { 304 return 0; 305 } 306 307 HRESULT STDMETHODCALLTYPE 308 VolumeControlEndpoint::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 328 HRESULT STDMETHODCALLTYPE 329 VolumeControlEndpoint::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
11 11 AudioOutputJACK(const AudioSettings &settings); 12 12 virtual ~AudioOutputJACK(); 13 13 14 // Volume control15 virtual int GetVolumeChannel(int channel) const; // Returns 0-10016 virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol17 18 14 protected: 19 15 20 16 // You need to implement the following functions … … 27 23 28 24 private: 29 25 30 void VolumeInit(void);31 32 26 int audioid; 33 27 34 28 }; -
libs/libmyth/audiosettings.cpp
15 15 channels(-1), 16 16 codec(0), 17 17 samplerate(-1), 18 set_initial_vol(false),19 18 use_passthru(false), 20 19 source(AUDIOOUTPUT_UNKNOWN), 21 20 upmixer(0) … … 29 28 channels(other.channels), 30 29 codec(other.codec), 31 30 samplerate(other.samplerate), 32 set_initial_vol(other.set_initial_vol),33 31 use_passthru(other.use_passthru), 34 32 source(other.source), 35 33 upmixer(other.upmixer) … … 44 42 int audio_codec, 45 43 int audio_samplerate, 46 44 AudioOutputSource audio_source, 47 bool audio_set_initial_vol,48 45 bool audio_use_passthru, 49 46 int upmixer_startup) : 50 47 main_device(audio_main_device), … … 53 50 channels(audio_channels), 54 51 codec(audio_codec), 55 52 samplerate(audio_samplerate), 56 set_initial_vol(audio_set_initial_vol),57 53 use_passthru(audio_use_passthru), 58 54 source(audio_source), 59 55 upmixer(upmixer_startup) … … 73 69 channels(audio_channels), 74 70 codec(audio_codec), 75 71 samplerate(audio_samplerate), 76 set_initial_vol(false),77 72 use_passthru(audio_use_passthru), 78 73 source(AUDIOOUTPUT_UNKNOWN), 79 74 upmixer(upmixer_startup) -
libs/libmyth/audiooutputca.cpp
244 244 return false; 245 245 } 246 246 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 254 247 return true; 255 248 } 256 249 … … 399 392 return noErr; 400 393 } 401 394 402 int AudioOutputCA::GetVolumeChannel(int channel) const403 {404 // FIXME: this only returns global volume405 (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 case414 }415 416 void AudioOutputCA::SetVolumeChannel(int channel, int volume)417 {418 // FIXME: this only sets global volume419 (void)channel;420 AudioUnitSetParameter(d->mOutputUnit, kHALOutputParam_Volume,421 kAudioUnitScope_Global, 0, (volume * 0.01), 0);422 }423 424 395 // IOProc style callback for SPDIF audio output 425 396 static OSStatus RenderCallbackSPDIF(AudioDeviceID inDevice, 426 397 const AudioTimeStamp *inNow, -
libs/libmyth/audiooutputwin.h
13 13 AudioOutputWin(const AudioSettings &settings); 14 14 virtual ~AudioOutputWin(); 15 15 16 // Volume control17 virtual int GetVolumeChannel(int channel) const;18 virtual void SetVolumeChannel(int channel, int volume);19 20 16 protected: 21 17 virtual bool OpenDevice(void); 22 18 virtual void CloseDevice(void); -
libs/libmyth/audiooutputjack.cpp
148 148 audio_buffer_unused = JACK_GetBytesFreeSpace(audioid); 149 149 JACK_SetPosition(audioid, BYTES, 0); 150 150 151 // Setup volume control152 if (internal_vol)153 VolumeInit();154 155 151 // Device opened successfully 156 152 return true; 157 153 } … … 206 202 207 203 return space; 208 204 } 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) const220 {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
12 12 AudioOutputOSS(const AudioSettings &settings); 13 13 virtual ~AudioOutputOSS(); 14 14 15 // Volume control16 virtual int GetVolumeChannel(int channel) const;17 virtual void SetVolumeChannel(int channel, int volume);18 19 15 protected: 20 16 // You need to implement the following functions 21 17 virtual bool OpenDevice(void); … … 26 22 vector<int> GetSupportedRates(void); 27 23 28 24 private: 29 void VolumeInit(void);30 void VolumeCleanup(void);31 32 25 void SetFragSize(void); 33 26 34 27 int audiofd; 35 28 mutable int numbadioctls; 36 37 // Volume related38 int mixerfd;39 int control;40 29 }; 41 30 42 31 #endif -
libs/libmyth/audiooutputbase.cpp
37 37 pauseaudio(false), audio_actually_paused(false), 38 38 was_paused(false), 39 39 40 set_initial_vol(settings.set_initial_vol),41 40 buffer_output_data_for_use(false), 42 41 43 42 // private … … 54 53 needs_upmix(false), 55 54 surround_mode(FreeSurround::SurroundModePassive), 56 55 old_audio_stretchfactor(1.0), 57 volume(80),58 56 59 57 blocking(false), 60 58 … … 109 107 110 108 allow_ac3_passthru = (orig_config_channels > 2) ? gContext->GetNumSetting("AC3PassThru", false) : false; 111 109 110 if (gContext->GetSetting("MixerDevice") == "Software:") 111 volume_control = VolumeControlManager::GetControl("Software:"); 112 112 113 // You need to call Reconfigure from your concrete class. 113 114 // Reconfigure(laudio_bits, laudio_channels, 114 115 // laudio_samplerate, laudio_passthru); … … 278 279 killaudio = false; 279 280 pauseaudio = false; 280 281 was_paused = true; 281 internal_vol = gContext->GetNumSetting("MythControlsVolume", 0);282 282 283 283 numlowbuffer = 0; 284 284 … … 359 359 return; 360 360 } 361 361 362 // Only used for software volume363 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 374 362 VERBOSE(VB_AUDIO, LOC + QString("Audio fragment size: %1") 375 363 .arg(fragment_size)); 376 364 … … 664 652 return audbuf_timecode - GetAudiotime(); 665 653 } 666 654 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 683 655 void AudioOutputBase::AdjustVolume(void *buffer, int len, bool music) 684 656 { 685 657 if (audio_bits == 8) … … 691 663 template <class AudioDataType> 692 664 void AudioOutputBase::_AdjustVolume(AudioDataType *buffer, int len, bool music) 693 665 { 666 int volume = volume_control->mute() ? 0 : volume_control->volume(); 667 694 668 float g = volume / 100.0; 695 669 696 670 // Should probably be exponential - this'll do … … 1099 1073 } 1100 1074 } 1101 1075 1102 if ( internal_vol && SWVolume())1076 if (volume_control) 1103 1077 { 1104 1078 int bdiff = kAudioRingBufferSize - waud; 1105 1079 bool music = (timecode < 1); … … 1360 1334 audio_buflock.unlock(); 1361 1335 1362 1336 // Mute individual channels through mono->stereo duplication 1363 MuteState mute_state = GetMuteState();1337 // MuteState mute_state = GetMuteState(); 1364 1338 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 ) 1367 1342 { 1368 1343 int offset_src = 0; 1369 1344 int offset_dst = 0; 1370 1345 1371 if (mute_state == kMuteLeft)1372 offset_src = audio_bits / 8; // copy channel 1 to channel 01373 else if (mute_state == kMuteRight)1374 offset_dst = audio_bits / 8; // copy channel 0 to channel 11346 // 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 1375 1350 1376 1351 for (int i = 0; i < written_size; i += audio_bytes_per_sample) 1377 1352 { -
libs/libmyth/audiooutput.cpp
34 34 int audio_bits, int audio_channels, 35 35 int audio_codec, int audio_samplerate, 36 36 AudioOutputSource source, 37 bool set_initial_vol, boolaudio_passthru,37 bool audio_passthru, 38 38 int upmixer_startup) 39 39 { 40 40 AudioSettings settings( 41 41 main_device, passthru_device, audio_bits, 42 42 audio_channels, audio_codec, audio_samplerate, source, 43 set_initial_vol,audio_passthru, upmixer_startup);43 audio_passthru, upmixer_startup); 44 44 45 45 settings.FixPassThrough(); 46 46 -
libs/libmyth/libmyth.pro
23 23 HEADERS += output.h 24 24 HEADERS += settings.h 25 25 HEADERS += uilistbtntype.h uitypes.h util.h mythuifilebrowser.h 26 HEADERS += volumebase.h visual.h xmlparse.h 26 HEADERS += volumecontrol.h volumecontrolmanager.h volumecontrolsoftware.h 27 HEADERS += visual.h xmlparse.h 27 28 HEADERS += mythhdd.h mythcdrom.h storagegroup.h dbutil.h 28 29 HEADERS += mythcommandlineparser.h mythterminal.h 29 30 HEADERS += mythhttppool.h mythhttphandler.h … … 45 46 SOURCES += output.cpp 46 47 SOURCES += settings.cpp 47 48 SOURCES += uilistbtntype.cpp uitypes.cpp util.cpp mythuifilebrowser.cpp 48 SOURCES += volumebase.cpp xmlparse.cpp 49 SOURCES += volumecontrolmanager.cpp volumecontrolsoftware.cpp 50 SOURCES += xmlparse.cpp 49 51 SOURCES += mythhdd.cpp mythcdrom.cpp storagegroup.cpp dbutil.cpp 50 52 SOURCES += mythcommandlineparser.cpp mythterminal.cpp 51 53 SOURCES += mythhttppool.cpp mythhttphandler.cpp … … 83 85 # Install headers so that plugins can compile independently 84 86 inc.path = $${PREFIX}/include/mythtv/ 85 87 inc.files = dialogbox.h mythcontext.h 86 inc.files += mythwidgets.h remotefile.h oldsettings.h volumecontrol.h88 inc.files += mythwidgets.h remotefile.h oldsettings.h 87 89 inc.files += settings.h uitypes.h xmlparse.h mythplugin.h mythdialogs.h 88 90 inc.files += audiooutput.h audiosettings.h util.h 89 91 inc.files += inetcomms.h mythmedia.h mythwizard.h schemawizard.h dbutil.h 90 92 inc.files += uilistbtntype.h generictree.h managedlist.h mythmediamonitor.h 91 inc.files += visual.h volume base.h output.h langsettings.h93 inc.files += visual.h volumecontrol.h volumecontrolmanager.h output.h langsettings.h 92 94 inc.files += mythexp.h mythpluginapi.h storagegroup.h 93 95 inc.files += mythconfigdialogs.h mythconfiggroups.h 94 96 inc.files += mythterminal.h mythdeque.h mythuifilebrowser.h … … 103 105 104 106 using_oss { 105 107 DEFINES += USING_OSS 106 SOURCES += audiooutputoss.cpp 107 HEADERS += audiooutputoss.h 108 SOURCES += audiooutputoss.cpp volumecontroloss.cpp 109 HEADERS += audiooutputoss.h volumecontroloss.h 108 110 LIBS += $$OSS_LIBS 109 111 } 110 112 … … 132 134 133 135 mingw { 134 136 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 138 142 } 139 143 140 144 macx { 141 HEADERS += audiooutputca.h 142 SOURCES += audiooutputca.cpp 145 DEFINES += USE_COREAUDIO 146 HEADERS += audiooutputca.h volumecontrolcoreaudio.h 147 SOURCES += audiooutputca.cpp volumecontrolcoreaudio.cpp 143 148 HEADERS += mythcdrom-darwin.h 144 149 SOURCES += mythcdrom-darwin.cpp 145 150 … … 179 184 180 185 using_alsa { 181 186 DEFINES += USE_ALSA 182 HEADERS += audiooutputalsa.h 183 SOURCES += audiooutputalsa.cpp 187 HEADERS += audiooutputalsa.h volumecontrolalsa.h 188 SOURCES += audiooutputalsa.cpp volumecontrolalsa.cpp 184 189 LIBS += $$ALSA_LIBS 185 190 } 186 191 -
libs/libmyth/audiosettings.h
32 32 int audio_codec, 33 33 int audio_samplerate, 34 34 AudioOutputSource audio_source, 35 bool audio_set_initial_vol,36 35 bool audio_use_passthru, 37 36 int upmixer_startup = 0); 38 37 … … 58 57 int channels; 59 58 int codec; 60 59 int samplerate; 61 bool set_initial_vol;62 60 bool use_passthru; 63 61 AudioOutputSource source; 64 62 int upmixer; -
libs/libmyth/audiooutputca.h
25 25 bool RenderAudio(unsigned char *aubuf, int size, 26 26 unsigned long long timestamp); 27 27 28 // Volume control29 virtual int GetVolumeChannel(int channel) const;30 virtual void SetVolumeChannel(int channel, int volume);31 32 28 void Debug(QString msg) 33 29 { VERBOSE(VB_AUDIO, "AudioOutputCA::" + msg); } 34 30 … … 37 33 38 34 void Warn(QString msg) 39 35 { VERBOSE(VB_IMPORTANT, "AudioOutputCA Warning: " + msg); } 36 bool internal_vol; 40 37 41 38 protected: 42 39 -
libs/libmyth/audiooutputoss.cpp
30 30 31 31 AudioOutputOSS::AudioOutputOSS(const AudioSettings &settings) : 32 32 AudioOutputBase(settings), 33 audiofd(-1), numbadioctls(0), 34 mixerfd(-1), control(SOUND_MIXER_VOLUME) 33 audiofd(-1), numbadioctls(0) 35 34 { 36 35 // Set everything up 37 36 Reconfigure(settings); … … 194 193 " the error was: %1").arg(strerror(errno))); 195 194 } 196 195 197 // Setup volume control198 if (internal_vol)199 VolumeInit();200 201 196 // Device opened successfully 202 197 return true; 203 198 } … … 242 237 close(audiofd); 243 238 244 239 audiofd = -1; 245 246 VolumeCleanup();247 240 } 248 241 249 242 … … 310 303 311 304 return space; 312 305 } 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 else333 {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) const377 {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; // left394 } else if (channel == 1) {395 volume = (tmpVol >> 8) & 0xff; // right396 } 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 else423 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
369 369 dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ 370 370 | DSBCAPS_GLOBALFOCUS /* Allows background playing */ 371 371 | DSBCAPS_LOCHARDWARE; /* Needed for 5.1 on emu101k */ 372 if (!m_UseSPDIF)373 dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; /* Allow volume control */374 372 dsbdesc.dwBufferBytes = soundcard_buffer_size; /* buffer size */ 375 373 dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf; 376 374 … … 517 515 return buffered; 518 516 } 519 517 520 int AudioOutputDX::GetVolumeChannel(int channel) const521 {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 decibel553 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 565 518 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmyth/audiooutputnull.h
27 27 28 28 virtual void Reset(void); 29 29 30 31 // Volume control32 virtual int GetVolumeChannel(int /* channel */) const { return 100; }33 virtual void SetVolumeChannel(int /* channel */, int /* volume */){return;}34 35 30 virtual int readOutputData(unsigned char *read_buffer, int max_length); 36 31 37 32 protected: -
libs/libmyth/audiooutput.h
5 5 6 6 #include "audiosettings.h" 7 7 #include "mythcontext.h" 8 #include "volumebase.h"9 8 #include "output.h" 10 9 11 class MPUBLIC AudioOutput : public VolumeBase, publicOutputListeners10 class MPUBLIC AudioOutput : public OutputListeners 12 11 { 13 12 public: 14 13 // opens one of the concrete subclasses … … 18 17 int audio_bits, int audio_channels, 19 18 int audio_codec, int audio_samplerate, 20 19 AudioOutputSource source, 21 bool set_initial_vol, boolaudio_passthru,20 bool audio_passthru, 22 21 int upmixer_startup = 0); 23 22 24 23 AudioOutput() : 25 VolumeBase(),OutputListeners(),24 OutputListeners(), 26 25 lastError(QString::null), lastWarn(QString::null) {} 27 26 28 27 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 12 class MPUBLIC VolumeControlManager 13 { 14 public: 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 13 class VolumeControlEndpoint : public VolumeControl, 14 protected IAudioEndpointVolumeCallback 15 { 16 public: 17 static QHash<QString, QString> Enumerate(); 18 19 public: 20 VolumeControlEndpoint(QString device); 21 virtual ~VolumeControlEndpoint(); 22 23 public: 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 32 protected: 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 38 private: 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
13 13 AudioOutputDX(const AudioSettings &settings); 14 14 virtual ~AudioOutputDX(); 15 15 16 virtual int GetVolumeChannel(int channel) const;17 virtual void SetVolumeChannel(int channel, int volume);18 19 16 protected: 20 17 virtual bool OpenDevice(void); 21 18 virtual void CloseDevice(void); -
libs/libmyth/audiooutputalsa.h
9 9 10 10 using namespace std; 11 11 12 class ALSAVolumeInfo13 {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 50 12 class AudioOutputALSA : public AudioOutputBase 51 13 { 52 14 public: 53 15 AudioOutputALSA(const AudioSettings &settings); 54 16 virtual ~AudioOutputALSA(); 55 17 56 // Volume control57 virtual int GetVolumeChannel(int channel) const; // Returns 0-10058 virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol59 60 61 18 protected: 62 19 // You need to implement the following functions 63 20 virtual bool OpenDevice(void); … … 77 34 void ReorderSmpteToAlsa6ch(void *buf, int frames); 78 35 template <class AudioDataType> 79 36 void _ReorderSmpteToAlsa6ch(AudioDataType *buf, int frames); 80 // Volume related81 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;86 37 87 38 private: 88 39 snd_pcm_t *pcm_handle; 89 40 int numbadioctls; 90 41 QMutex killAudioLock; 91 snd_mixer_t *mixer_handle;92 QString mixer_control; // e.g. "PCM"93 42 snd_pcm_sframes_t (*pcm_write_func)(snd_pcm_t*, const void*, 94 43 snd_pcm_uframes_t); 95 44 }; -
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 19 static const unsigned long poll = 250; //< OSS control poll interval (ms) 20 21 QHash<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 78 VolumeControlOSS::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 167 VolumeControlOSS::~VolumeControlOSS() 168 { 169 m_Exit = true; 170 171 if (isRunning()) 172 wait(); 173 174 if (m_Mixer != -1) 175 close(m_Mixer); 176 } 177 178 int 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 235 void 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 274 void VolumeControlOSS::increaseVolume() 275 { 276 setVolume((volume() * m_Range + 100) / m_Range); 277 } 278 279 void VolumeControlOSS::decreaseVolume() 280 { 281 setVolume((volume() * m_Range - 100) / m_Range); 282 } 283 284 bool 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 320 void 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 364 void 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
28 28 #include "iso639.h" 29 29 #include "playbackbox.h" 30 30 #include "globalsettings.h" 31 #include "libmyth/volumecontrolmanager.h" 31 32 #include "recordingprofile.h" 32 33 #include "mythxdisplay.h" 33 34 #include "DisplayRes.h" … … 179 180 return gc; 180 181 } 181 182 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 194 183 static HostComboBox *MixerDevice() 195 184 { 196 185 HostComboBox *gc = new HostComboBox("MixerDevice", true); 197 186 gc->setLabel(QObject::tr("Mixer Device")); 187 gc->addSelection(QObject::tr("Disabled"), QString()); 198 188 199 #ifdef USING_OSS 200 QDir dev("/dev", "mixer*", QDir::Name, QDir::System); 201 gc->fillSelectionsFromDir(dev); 189 QHash<QString, QString> controls = VolumeControlManager::Enumerate(); 202 190 203 dev.setPath("/dev/sound");204 if (dev.exists())191 for (QHash<QString, QString>::const_iterator control = controls.begin(); 192 control != controls.end(); ++control) 205 193 { 206 gc-> fillSelectionsFromDir(dev);194 gc->addSelection(control.value(), control.key()); 207 195 } 208 #endif209 #ifdef USING_ALSA210 gc->addSelection("ALSA:default", "ALSA:default");211 #endif212 #ifdef USING_MINGW213 gc->addSelection("DirectX:", "DirectX:");214 gc->addSelection("Windows:", "Windows:");215 #endif216 #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 #endif221 196 222 197 return gc; 223 198 } 224 199 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 264 200 static HostCheckBox *IndividualMuteControl() 265 201 { 266 202 HostCheckBox *gc = new HostCheckBox("IndividualMuteControl"); … … 3552 3488 group2->addChild(AggressiveBuffer()); 3553 3489 3554 3490 return vcg; 3555 3556 3491 } 3557 3492 3558 class AudioMixerSettingsGroup : public TriggeredConfigurationGroup 3493 static ConfigurationGroup *AudioMixerSettingsGroup() 3559 3494 { 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); 3566 3499 3567 Setting *volumeControl = MythControlsVolume(); 3568 addChild(volumeControl); 3500 vcg->addChild(MixerDevice()); 3569 3501 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 } 3578 3504 3579 ConfigurationGroup *dummy =3580 new VerticalConfigurationGroup(false, true, false, false);3581 3582 // Show Mixer config only if internal volume controls enabled3583 setTrigger(volumeControl);3584 addTarget("0", dummy);3585 addTarget("1", settings);3586 }3587 };3588 3589 3505 static HostComboBox *MythLanguage() 3590 3506 { 3591 3507 HostComboBox *gc = new HostComboBox("Language"); … … 4269 4185 4270 4186 addChild(AudioSystemSettingsGroup()); 4271 4187 4272 addChild( newAudioMixerSettingsGroup());4188 addChild(AudioMixerSettingsGroup()); 4273 4189 4274 4190 VerticalConfigurationGroup *general = 4275 4191 new VerticalConfigurationGroup(false, true, false, false); -
programs/mythtranscode/transcode.cpp
166 166 return last_audiotime; 167 167 } 168 168 169 virtual int GetVolumeChannel(int) const170 {171 // Do nothing172 return 100;173 }174 virtual void SetVolumeChannel(int, int)175 {176 // Do nothing177 }178 virtual void SetVolumeAll(int)179 {180 // Do nothing181 }182 virtual uint GetCurrentVolume(void) const183 {184 // Do nothing185 return 100;186 }187 virtual void SetCurrentVolume(int)188 {189 // Do nothing190 }191 virtual void AdjustCurrentVolume(int)192 {193 // Do nothing194 }195 virtual void SetMute(bool)196 {197 // Do nothing198 }199 virtual void ToggleMute(void)200 {201 // Do nothing202 }203 virtual MuteState GetMuteState(void) const204 {205 // Do nothing206 return kMuteOff;207 }208 virtual MuteState IterateMutedChannels(void)209 {210 // Do nothing211 return kMuteOff;212 }213 169 virtual bool ToggleUpmix(void) 214 170 { 215 171 // Do nothing 216 172 return false; 217 173 } 218 174 219 virtual void SetSWVolume(int new_volume, bool save)220 {221 // Do nothing222 return;223 }224 virtual int GetSWVolume(void)225 {226 // Do nothing227 return 100;228 }229 230 175 // These are pure virtual in AudioOutput, but we don't need them here 231 176 virtual void bufferOutputData(bool){ return; } 232 177 virtual int readOutputData(unsigned char*, int ){ return 0; }
