Ticket #7517: volume_control_mythtv_r22764.patch
| File volume_control_mythtv_r22764.patch, 128.7 KB (added by , 16 years ago) |
|---|
-
configure
596 596 eval "$var=\"\$$var $*\"" 597 597 } 598 598 599 prepend(){ 600 var=$1 601 shift 602 flags_saved && eval "SAVE_$var=\"$* \$SAVE_$var\"" 603 eval "$var=\"$* \$$var\"" 604 } 605 599 606 add_cflags(){ 600 607 append CFLAGS "$@" 601 608 } … … 3329 3336 enable audio_alsa || 3330 3337 disable audio_alsa 3331 3338 3339 # OSS probe 3340 if ! disabled audio_oss ; then 3341 if test -f /usr/"${libdir_name}"/oss/include/sys/soundcard.h && 3342 check_cpp_condition /usr/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then 3343 disable soundcard_h 3344 enable sys_soundcard_h 3345 prepend CONFIG_INCLUDEPATH "/usr/${libdir_name}/oss/include" 3346 elif test -f /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h && 3347 check_cpp_condition /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then 3348 disable soundcard_h 3349 enable sys_soundcard_h 3350 prepend CONFIG_INCLUDEPATH "/usr/local/${libdir_name}/oss/include" 3351 else 3352 if enabled soundcard_h ; then 3353 check_cpp_condition soundcard.h "SOUND_VERSION >= 0x040000" && 3354 enable audio_oss || 3355 disable audio_oss 3356 elif enabled sys_soundcard_h ; then 3357 check_cpp_condition sys/soundcard.h "SOUND_VERSION >= 0x040000" && 3358 enable audio_oss || 3359 disable audio_oss 3360 fi 3361 fi 3362 fi 3363 3332 3364 # JACK probe 3333 3365 ! disabled audio_jack && 3334 3366 check_lib jack/jack.h jack_client_new $audio_jack_libs && … … 4027 4059 if enabled audio_oss; then 4028 4060 append CCONFIG "using_oss" 4029 4061 fi 4062 4030 4063 if enabled audio_alsa; then 4031 4064 append CCONFIG "using_alsa" 4032 4065 echo "CONFIG_AUDIO_ALSA_LIBS=$audio_alsa_libs" >> $MYTH_CONFIG_MAK -
libs/libmythtv/NuppelVideoPlayer.cpp
147 147 kDisplayNUVTeletextCaptions, 148 148 }; 149 149 150 NuppelVideoPlayer::NuppelVideoPlayer( bool muted)150 NuppelVideoPlayer::NuppelVideoPlayer() 151 151 : decoder(NULL), decoder_change_lock(QMutex::Recursive), 152 152 videoOutput(NULL), player_ctx(NULL), 153 153 no_hardware_decoders(false), … … 215 215 audio_channels(2), audio_codec(0), 216 216 audio_bits(-1), audio_samplerate(44100), 217 217 audio_stretchfactor(1.0f), audio_lock(QMutex::Recursive), 218 audio_muted_on_creation(muted),219 218 // Picture-in-Picture stuff 220 219 pip_active(false), pip_visible(true), 221 220 // Preview window support … … 408 407 audio_samplerate = (int)samplerate; 409 408 } 410 409 411 uint NuppelVideoPlayer::GetVolume(void)412 {413 QMutexLocker lock(&audio_lock);414 if (audioOutput)415 return audioOutput->GetCurrentVolume();416 return 0;417 }418 419 bool NuppelVideoPlayer::SetMuted(bool mute)420 {421 QMutexLocker lock(&audio_lock);422 bool is_muted = IsMuted();423 424 if (audioOutput && !is_muted && mute &&425 (kMuteAll == SetMuteState(kMuteAll)))426 {427 VERBOSE(VB_AUDIO, "muting sound " <<IsMuted());428 return true;429 }430 else if (audioOutput && is_muted && !mute &&431 (kMuteOff == SetMuteState(kMuteOff)))432 {433 VERBOSE(VB_AUDIO, "unmuting sound "<<IsMuted());434 return true;435 }436 437 VERBOSE(VB_AUDIO, "not changing sound mute state "<<IsMuted());438 439 return false;440 }441 442 MuteState NuppelVideoPlayer::SetMuteState(MuteState mstate)443 {444 QMutexLocker lock(&audio_lock);445 if (audioOutput)446 return audioOutput->SetMuteState(mstate);447 return kMuteAll;448 }449 450 MuteState NuppelVideoPlayer::IncrMuteState(void)451 {452 QMutexLocker lock(&audio_lock);453 MuteState mstate = kMuteAll;454 if (audioOutput)455 mstate = SetMuteState(VolumeBase::NextMuteState(GetMuteState()));456 return mstate;457 }458 459 MuteState NuppelVideoPlayer::GetMuteState(void)460 {461 QMutexLocker lock(&audio_lock);462 if (audioOutput)463 return audioOutput->GetMuteState();464 return kMuteAll;465 }466 467 uint NuppelVideoPlayer::AdjustVolume(int change)468 {469 QMutexLocker lock(&audio_lock);470 if (audioOutput)471 audioOutput->AdjustCurrentVolume(change);472 return GetVolume();473 }474 475 410 void NuppelVideoPlayer::PauseDecoder(void) 476 411 { 477 412 decoder_lock.lock(); … … 907 842 908 843 if (!audioOutput && !using_null_videoout && player_ctx->IsAudioNeeded()) 909 844 { 910 bool setVolume = gContext->GetNumSetting("MythControlsVolume", 1);911 845 audioOutput = AudioOutput::OpenAudio(audio_main_device, 912 846 audio_passthru_device, 913 847 audio_bits, audio_channels, 914 848 audio_codec, audio_samplerate, 915 849 AUDIOOUTPUT_VIDEO, 916 setVolume,audio_passthru);850 audio_passthru); 917 851 if (!audioOutput) 918 852 errMsg = QObject::tr("Unable to create AudioOutput."); 919 853 else … … 935 869 VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio"); 936 870 no_audio_out = false; 937 871 } 938 if (audio_muted_on_creation)939 {940 SetMuteState(kMuteAll);941 audio_muted_on_creation = false;942 }943 872 } 944 873 945 874 if (audioOutput) -
libs/libmythtv/DetectLetterbox.cpp
8 8 #include "DetectLetterbox.h" 9 9 #include "NuppelVideoPlayer.h" 10 10 #include "videoouttypes.h" 11 #include "mythcontext.h" 11 12 12 13 DetectLetterbox::DetectLetterbox(NuppelVideoPlayer* const nvp) 13 14 { -
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(); … … 4365 4363 4366 4364 if (ctx->codec_id == CODEC_ID_AC3) 4367 4365 passthru = allow_ac3_passthru && 4368 ctx->channels >= (int)max_channels && 4369 !internal_vol; 4366 ctx->channels >= (int)max_channels; 4370 4367 else if (ctx->codec_id == CODEC_ID_DTS) 4371 passthru = allow_dts_passthru && !internal_vol;4368 passthru = allow_dts_passthru; 4372 4369 4373 4370 passthru &= !transcoding && !disable_passthru; 4374 4371 // Don't know any cards that support spdif clocked at < 44100 -
libs/libmythtv/tv_play.h
24 24 #include "programlist.h" 25 25 #include "channelutil.h" 26 26 #include "videoouttypes.h" 27 #include "volume base.h"27 #include "volumecontrolmanager.h" 28 28 #include "inputinfo.h" 29 29 #include "channelgroup.h" 30 30 … … 292 292 void AddUDPNotifyEvent(const QString &name, const UDPNotifyOSDSet*); 293 293 void ClearUDPNotifyEvents(void); 294 294 295 void VolumeChanged(int volume); 296 void MuteChanged(bool mute); 297 295 298 protected: 296 299 void TreeMenuEntered(OSDListTreeItemEnteredEvent *e); 297 300 void TreeMenuSelected(OSDListTreeItemSelectedEvent *e); … … 301 304 virtual void run(void); 302 305 void TVEventThreadChecks(void); 303 306 304 void SetMuteTimer(PlayerContext*, int timeout);305 bool MuteChannelChange(PlayerContext *ctx);306 307 307 bool eventFilter(QObject *o, QEvent *e); 308 308 static QStringList lastProgramStringList; 309 309 static EMBEDRETURNPROGRAM RunPlaybackBoxPtr; … … 493 493 494 494 vector<long long> TeardownAllNVPs(PlayerContext*); 495 495 void RestartAllNVPs(PlayerContext *lctx, 496 const vector<long long> &pos, 497 MuteState mctx_mute); 496 const vector<long long> &pos); 498 497 void RestartMainNVP(PlayerContext *mctx); 499 498 500 499 void PxPToggleView( PlayerContext *actx, bool wantPBP); … … 654 653 /// Picture attribute to modify (on arrow left or right) 655 654 PictureAttribute adjustingPictureAttribute; 656 655 656 QSharedPointer<VolumeControl> volumeControl; ///< Volume Control interface 657 657 658 // Ask Allow state 658 659 AskAllowType askAllowType; 659 660 QMap<QString,AskProgramInfo> askAllowPrograms; … … 811 812 TimerContextMap stateChangeTimerId; 812 813 TimerContextMap signalMonitorTimerId; 813 814 TimerContextMap tvchainUpdateTimerId; 814 TimerContextMap unmuteTimerId;815 815 816 816 /// Condition to signal that the Event thread is up and running 817 817 QWaitCondition mainLoopCond; … … 832 832 833 833 ///< Timeout for entry modes in msec 834 834 static const uint kInputModeTimeout; 835 /// Channel changing mute timeout in msec836 static const uint kMuteTimeout;837 835 /// Timeout for updating LCD info in msec 838 836 static const uint kLCDTimeout; 839 837 /// Timeout for browse mode exit in msec -
libs/libmythtv/playercontext.cpp
11 11 #include "util-osx-cocoa.h" 12 12 #include "videoouttypes.h" 13 13 #include "storagegroup.h" 14 #include "mythcontext.h" 14 15 15 16 #define LOC QString("playCtx: ") 16 17 #define LOC_ERR QString("playCtx, Error: ") … … 429 430 430 431 bool PlayerContext::CreateNVP(TV *tv, QWidget *widget, 431 432 TVState desiredState, 432 WId embedwinid, const QRect *embedbounds, 433 bool muted) 433 WId embedwinid, const QRect *embedbounds) 434 434 { 435 435 int exact_seeking = gContext->GetNumSetting("ExactSeeking", 0); 436 436 … … 441 441 return false; 442 442 } 443 443 444 NuppelVideoPlayer *_nvp = new NuppelVideoPlayer( muted);444 NuppelVideoPlayer *_nvp = new NuppelVideoPlayer(); 445 445 446 446 if (nohardwaredecoders) 447 447 _nvp->DisableHardwareDecoders(); … … 491 491 QString errMsg = nvp->ReinitAudio(); 492 492 } 493 493 } 494 else if (pipState == kPBPRight)495 nvp->SetMuted(true);496 494 497 495 int maxWait = -1; 498 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 IsIVTVDecoder(void) const; 232 224 bool UsingNullVideo(void) const { return using_null_videoout; } 233 225 bool HasTVChainNext(void) const; … … 721 713 float audio_stretchfactor; 722 714 bool audio_passthru; 723 715 QMutex audio_lock; 724 bool audio_muted_on_creation;725 716 726 717 // Picture-in-Picture 727 718 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; … … 894 893 player.push_back(new PlayerContext("player")); 895 894 playerActive = 0; 896 895 playerLock.unlock(); 896 897 volumeControl = VolumeControlManager::GetControl(gContext->GetSetting("MixerDevice")); 898 if (volumeControl) 899 { 900 connect(volumeControl.data(), SIGNAL(changedVolume(int)), 901 this, SLOT(VolumeChanged(int)), Qt::QueuedConnection); 902 connect(volumeControl.data(), SIGNAL(changedMute(bool)), 903 this, SLOT(MuteChanged(bool)), Qt::QueuedConnection); 904 } 897 905 } 898 906 899 907 /** \fn TV::Init(bool) … … 2787 2795 if (handled) 2788 2796 return; 2789 2797 2790 // Check unmute..2791 ctx = NULL;2792 {2793 QMutexLocker locker(&timerIdLock);2794 TimerContextMap::iterator it = unmuteTimerId.find(timer_id);2795 if (it != unmuteTimerId.end())2796 {2797 KillTimer(timer_id);2798 ctx = *it;2799 unmuteTimerId.erase(it);2800 }2801 }2802 2803 if (ctx)2804 {2805 PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);2806 if (find_player_index(ctx) >= 0)2807 {2808 ctx->LockDeleteNVP(__FILE__, __LINE__);2809 if (ctx->nvp && ctx->nvp->IsMuted())2810 ctx->nvp->SetMuted(false);2811 ctx->UnlockDeleteNVP(__FILE__, __LINE__);2812 }2813 ReturnPlayerLock(mctx);2814 handled = true;2815 }2816 2817 2798 if (handled) 2818 2799 return; 2819 2800 … … 5375 5356 } 5376 5357 } 5377 5358 5378 MuteState mctx_mute = kMuteOff;5379 mctx->LockDeleteNVP(__FILE__, __LINE__);5380 if (mctx->nvp)5381 mctx_mute = mctx->nvp->GetMuteState();5382 mctx->UnlockDeleteNVP(__FILE__, __LINE__);5383 5384 5359 vector<long long> pos = TeardownAllNVPs(mctx); 5385 5360 5386 5361 if (wantPBP) … … 5398 5373 } 5399 5374 } 5400 5375 5401 RestartAllNVPs(mctx, pos , mctx_mute);5376 RestartAllNVPs(mctx, pos); 5402 5377 5403 5378 VERBOSE(VB_PLAYBACK, LOC + 5404 5379 QString("PxPToggleType() converting from %1 to %2 -- end") … … 5542 5517 * \brief Recreate Main and PIP windows. Could be either PIP or PBP views. 5543 5518 */ 5544 5519 void TV::RestartAllNVPs(PlayerContext *lctx, 5545 const vector<long long> &pos, 5546 MuteState mctx_mute) 5520 const vector<long long> &pos) 5547 5521 { 5548 5522 QString loc = LOC + QString("RestartAllNVPs(): "); 5549 5523 … … 5590 5564 pipctx->LockDeleteNVP(__FILE__, __LINE__); 5591 5565 if (pipctx->nvp) 5592 5566 { 5593 pipctx->nvp->SetMuted(true);5594 5567 pipctx->nvp->JumpToFrame(pos[i]); 5595 5568 } 5596 5569 pipctx->UnlockDeleteNVP(__FILE__, __LINE__); … … 5602 5575 ForceNextStateNone(pipctx); 5603 5576 } 5604 5577 } 5605 5606 // If old main player had a kMuteAll | kMuteOff setting,5607 // apply old main player's mute setting to new main player.5608 mctx->LockDeleteNVP(__FILE__, __LINE__);5609 if (mctx->nvp && ((kMuteAll == mctx_mute) || (kMuteOff == mctx_mute)))5610 mctx->nvp->SetMuteState(mctx_mute);5611 mctx->UnlockDeleteNVP(__FILE__, __LINE__);5612 5578 } 5613 5579 5614 5580 void TV::PxPSwap(PlayerContext *mctx, PlayerContext *pipctx) … … 5636 5602 return; 5637 5603 } 5638 5604 5639 MuteState mctx_mute = mctx->nvp->GetMuteState();5640 5605 mctx->deleteNVPLock.unlock(); 5641 5606 pipctx->deleteNVPLock.unlock(); 5642 5607 … … 5650 5615 playerActive = (ctx_index == playerActive) ? 5651 5616 0 : ((ctx_index == 0) ? ctx_index : playerActive); 5652 5617 5653 RestartAllNVPs(mctx, pos , mctx_mute);5618 RestartAllNVPs(mctx, pos); 5654 5619 5655 5620 SetActive(mctx, playerActive, false); 5656 5621 … … 5671 5636 mctx->deleteNVPLock.unlock(); 5672 5637 return; 5673 5638 } 5674 5675 MuteState mctx_mute = mctx->nvp->GetMuteState();5676 5677 // HACK - FIXME5678 // workaround muted audio when NVP is re-created5679 mctx_mute = kMuteOff;5680 // FIXME - end5681 5639 mctx->deleteNVPLock.unlock(); 5682 5640 5683 5641 vector<long long> pos = TeardownAllNVPs(mctx); 5684 RestartAllNVPs(mctx, pos , mctx_mute);5642 RestartAllNVPs(mctx, pos); 5685 5643 SetActive(mctx, playerActive, false); 5686 5644 5687 5645 VERBOSE(VB_PLAYBACK, LOC + "Restart main player -- end"); … … 5806 5764 5807 5765 VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- begin"); 5808 5766 5809 bool muted = false;5810 5811 5767 ctx->LockDeleteNVP(__FILE__, __LINE__); 5812 5768 if (!ctx->nvp) 5813 5769 { … … 5815 5771 return false; 5816 5772 } 5817 5773 5818 if (ctx == GetPlayer(ctx, 0))5819 muted = MuteChannelChange(ctx);5820 5821 5774 bool res = false; 5822 5775 5823 5776 if (LONG_LONG_MIN != audiosyncBaseline) … … 5838 5791 } 5839 5792 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 5840 5793 5841 if (muted)5842 SetMuteTimer(ctx, kMuteTimeout);5843 5844 5794 VERBOSE(VB_PLAYBACK, LOC + "DoNVPSeek() -- end"); 5845 5795 5846 5796 return res; … … 6121 6071 if (StateIsLiveTV(GetState(ctx))) 6122 6072 return; 6123 6073 6124 ctx->LockDeleteNVP(__FILE__, __LINE__);6125 bool muted = MuteChannelChange(ctx);6126 ctx->UnlockDeleteNVP(__FILE__, __LINE__);6127 6128 6074 struct StatusPosInfo posInfo; 6129 6075 ctx->CalcNVPSliderPosition(posInfo); 6130 6076 … … 6143 6089 if (ctx->nvp) 6144 6090 ctx->nvp->SkipCommercials(direction); 6145 6091 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 6146 6147 if (muted)6148 SetMuteTimer(ctx, kMuteTimeout);6149 6092 } 6150 6093 6151 6094 void TV::SwitchSource(uint source_direction) … … 6315 6258 if (mctx != ctx) 6316 6259 PIPRemovePlayer(mctx, ctx); 6317 6260 6318 bool muted = false;6319 ctx->LockDeleteNVP(__FILE__, __LINE__);6320 if (ctx->nvp && ctx->nvp->IsMuted())6321 muted = true;6322 ctx->UnlockDeleteNVP(__FILE__, __LINE__);6323 6324 6261 // pause the decoder first, so we're not reading too close to the end. 6325 6262 ctx->buffer->IgnoreLiveEOF(true); 6326 6263 ctx->buffer->StopReads(); … … 6372 6309 6373 6310 if (ctx->CreateNVP( 6374 6311 this, gContext->GetMainWindow(), ctx->GetState(), 6375 mctx->embedWinID, &mctx->embedBounds , muted))6312 mctx->embedWinID, &mctx->embedBounds)) 6376 6313 { 6377 6314 ScheduleStateChange(ctx); 6378 6315 ok = true; … … 6729 6666 6730 6667 void TV::ChangeChannel(PlayerContext *ctx, int direction) 6731 6668 { 6732 bool muted = false;6733 6734 6669 if ((browse_changrp || (direction == CHANNEL_DIRECTION_FAVORITE)) && 6735 6670 (channel_group_id > -1)) 6736 6671 { … … 6761 6696 6762 6697 QString oldinputname = ctx->recorder->GetInput(); 6763 6698 6764 muted = MuteChannelChange(ctx);6765 6766 6699 if (ctx->paused) 6767 6700 { 6768 6701 OSD *osd = GetOSDLock(ctx); … … 6790 6723 ctx->recorder->ChangeChannel(direction); 6791 6724 ClearInputQueues(ctx, false); 6792 6725 6793 if (muted)6794 SetMuteTimer(ctx, kMuteTimeout * 2);6795 6796 6726 UnpauseLiveTV(ctx); 6797 6727 6798 6728 if (oldinputname != ctx->recorder->GetInput()) … … 6809 6739 6810 6740 QString channum = chan; 6811 6741 QStringList reclist; 6812 bool muted = false;6813 6742 6814 6743 QString oldinputname = ctx->recorder->GetInput(); 6815 6744 … … 6879 6808 if (getit || !ctx->recorder || !ctx->recorder->CheckChannel(channum)) 6880 6809 return; 6881 6810 6882 muted = MuteChannelChange(ctx);6883 6884 6811 OSD *osd = GetOSDLock(ctx); 6885 6812 if (osd && ctx->paused) 6886 6813 { … … 6906 6833 6907 6834 ctx->recorder->SetChannel(channum); 6908 6835 6909 if (muted)6910 SetMuteTimer(ctx, kMuteTimeout * 2);6911 6912 6836 UnpauseLiveTV(ctx); 6913 6837 6914 6838 if (oldinputname != ctx->recorder->GetInput()) … … 8019 7943 8020 7944 void TV::ChangeVolume(PlayerContext *ctx, bool up) 8021 7945 { 8022 ctx->LockDeleteNVP(__FILE__, __LINE__); 8023 if (!ctx->nvp) 7946 if (volumeControl) 8024 7947 { 8025 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8026 return; 7948 if (up) 7949 volumeControl->increaseVolume(); 7950 else 7951 volumeControl->decreaseVolume(); 8027 7952 } 8028 uint curvol = ctx->nvp->AdjustVolume((up) ? +2 : -2);8029 ctx->UnlockDeleteNVP(__FILE__, __LINE__);8030 8031 QString text = tr("Volume %1 %").arg(curvol);8032 8033 OSD *osd = GetOSDLock(ctx);8034 if (osd && !browsemode)8035 {8036 osd->ShowStatus(curvol * 10, true, tr("Adjust Volume"), text, 5,8037 kOSDFunctionalType_PictureAdjust);8038 SetUpdateOSDPosition(false);8039 }8040 ReturnOSDLock(ctx, osd);8041 7953 } 8042 7954 8043 7955 void TV::ToggleTimeStretch(PlayerContext *ctx) … … 8186 8098 8187 8099 void TV::ToggleMute(PlayerContext *ctx) 8188 8100 { 8189 ctx->LockDeleteNVP(__FILE__, __LINE__); 8190 if (!ctx->nvp || !ctx->nvp->HasAudioOut()) 8191 { 8192 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8193 return; 8194 } 8195 8196 MuteState mute_status; 8197 8198 if (!MuteIndividualChannels) 8199 { 8200 ctx->nvp->SetMuted(!ctx->nvp->IsMuted()); 8201 mute_status = (ctx->nvp->IsMuted()) ? kMuteAll : kMuteOff; 8202 } 8203 else 8204 { 8205 mute_status = ctx->nvp->IncrMuteState(); 8206 } 8207 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8208 8209 QString text; 8210 8211 switch (mute_status) 8212 { 8213 case kMuteOff: text = tr("Mute Off"); break; 8214 case kMuteAll: text = tr("Mute On"); break; 8215 case kMuteLeft: text = tr("Left Channel Muted"); break; 8216 case kMuteRight: text = tr("Right Channel Muted"); break; 8217 } 8218 8219 OSD *osd = GetOSDLock(ctx); 8220 if (osd && !browsemode) 8221 osd->SetSettingsText(text, 5); 8222 ReturnOSDLock(ctx, osd); 8101 if (volumeControl) 8102 volumeControl->setMute(!volumeControl->mute()); 8223 8103 } 8224 8104 8225 8105 void TV::ToggleSleepTimer(const PlayerContext *ctx) … … 8379 8259 ReturnOSDLock(ctx, osd); 8380 8260 } 8381 8261 8382 void TV::SetMuteTimer(PlayerContext *ctx, int timeout)8383 {8384 // message to set the timer will be posted to the main UI thread8385 // where it will be caught in eventFilter and processed as CustomEvent8386 // this will properly set the mute timer8387 // otherwise it never fires on Win328388 QString message = QString("UNMUTE %1 %2").arg((long long)ctx).arg(timeout);8389 qApp->postEvent(gContext->GetMainWindow(), new MythEvent(message));8390 }8391 8392 bool TV::MuteChannelChange(PlayerContext *ctx)8393 {8394 if (!ctx)8395 return false;8396 8397 bool muted = false;8398 ctx->LockDeleteNVP(__FILE__, __LINE__);8399 if (ctx->nvp && !ctx->nvp->IsMuted())8400 muted = ctx->nvp->SetMuted(true);8401 ctx->UnlockDeleteNVP(__FILE__, __LINE__);8402 8403 return muted;8404 }8405 8406 8262 void TV::customEvent(QEvent *e) 8407 8263 { 8408 8264 if ((MythEvent::Type)(e->type()) == kOSDClosedEventType) … … 8678 8534 } 8679 8535 } 8680 8536 8681 if (message.left(6) == "UNMUTE")8682 {8683 if (tokens.size() >= 3)8684 {8685 long long target = tokens[1].toLongLong();8686 PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);8687 for (uint i = 0; i < player.size(); i++)8688 {8689 PlayerContext *ctx = GetPlayer(mctx, i);8690 if (((long long)ctx) == target)8691 {8692 QMutexLocker locker(&timerIdLock);8693 unmuteTimerId[StartTimer(tokens[2].toUInt(), __LINE__)] = ctx;8694 }8695 }8696 ReturnPlayerLock(mctx);8697 }8698 }8699 8700 8537 if (message.left(9) == "START_EPG") 8701 8538 { 8702 8539 int editType = tokens[1].toInt(); … … 9170 9007 { 9171 9008 value = ctx->nvp->getVideoOutput()->GetPictureAttribute(attr); 9172 9009 } 9173 else if (ctx->nvp->HasAudioOut() )9010 else if (ctx->nvp->HasAudioOut() && volumeControl) 9174 9011 { 9175 value = ctx->nvp->GetVolume();9012 value = volumeControl->volume(); 9176 9013 title = tr("Adjust Volume"); 9177 9014 } 9178 9015 } … … 11676 11513 ReturnPlayerLock(mctx); 11677 11514 } 11678 11515 11516 void TV::VolumeChanged(int volume) 11517 { 11518 OSD *osd = GetOSDL(__FILE__, __LINE__); 11519 if (osd && !browsemode) 11520 { 11521 osd->ShowStatus(volume * 10, true, tr("Adjust Volume"), 11522 tr("Volume %1 %").arg(volume), 5, 11523 kOSDFunctionalType_PictureAdjust); 11524 SetUpdateOSDPosition(false); 11525 } 11526 ReturnOSDLock(osd); 11527 } 11528 11529 void TV::MuteChanged(bool mute) 11530 { 11531 OSD *osd = GetOSDL(__FILE__, __LINE__); 11532 if (osd && !browsemode) 11533 osd->SetSettingsText(mute ? tr("Mute On") : tr("Mute Off"), 5); 11534 ReturnOSDLock(osd); 11535 } 11536 11537 11679 11538 OSD *TV::GetOSDL(const char *file, int location) 11680 11539 { 11681 11540 PlayerContext *actx = GetPlayerReadLock(-1, file, location); -
libs/libmythtv/playercontext.h
48 48 // Actions 49 49 bool CreateNVP(TV *tv, QWidget *widget, 50 50 TVState desiredState, 51 WId embedwinid, const QRect *embedBounds, 52 bool muted = false); 51 WId embedwinid, const QRect *embedBounds); 53 52 void TeardownPlayer(void); 54 53 bool StartDecoderThread(int maxWait = -1); 55 54 bool StartOSD(TV *tv); -
libs/libmythtv/avformatdecoder.h
264 264 265 265 bool allow_ac3_passthru; 266 266 bool allow_dts_passthru; 267 bool internal_vol;268 267 bool disable_passthru; 269 268 uint max_channels; 270 269 uint last_ac3_channels; -
libs/libmyth/audiooutputwin.cpp
270 270 { 271 271 return m_nPkts * fragment_size; 272 272 } 273 274 int AudioOutputWin::GetVolumeChannel(int channel) const275 {276 DWORD dwVolume = 0xffffffff;277 int Volume = 100;278 if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))279 {280 Volume = (channel == 0) ?281 (LOWORD(dwVolume) / (0xffff / 100)) :282 (HIWORD(dwVolume) / (0xffff / 100));283 }284 285 VERBOSE(VB_AUDIO, "GetVolume(" << channel << ") "286 << Volume << "(" << dwVolume << ")");287 288 return Volume;289 }290 291 void AudioOutputWin::SetVolumeChannel(int channel, int volume)292 {293 if (channel > 1)294 {295 Error(QString("Error setting channel: %1. "296 "Only stereo volume supported").arg(channel));297 return;298 }299 300 DWORD dwVolume = 0xffffffff;301 if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))302 {303 if (channel == 0)304 dwVolume = dwVolume & 0xffff0000 | volume * (0xffff / 100);305 else306 dwVolume = dwVolume & 0xffff | ((volume * (0xffff / 100)) << 16);307 }308 else309 {310 dwVolume = volume * (0xffff / 100);311 dwVolume |= (dwVolume << 16);312 }313 314 VERBOSE(VB_AUDIO, QString("SetVolume(%1) %2(%3)")315 .arg(channel).arg(volume).arg(dwVolume));316 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, dwVolume);317 } -
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); … … 249 247 // it really is 250 248 audio_buffer_unused = soundcard_buffer_size - (fragment_size * 4); 251 249 252 if (internal_vol)253 OpenMixer(set_initial_vol);254 255 250 // Device opened successfully 256 251 return true; 257 252 } 258 253 259 254 void AudioOutputALSA::CloseDevice() 260 255 { 261 CloseMixer();262 256 if (pcm_handle != NULL) 263 257 { 264 258 snd_pcm_close(pcm_handle); … … 617 611 618 612 return 0; 619 613 } 620 621 622 int AudioOutputALSA::GetVolumeChannel(int channel) const623 {624 long actual_volume;625 626 if (mixer_handle == NULL)627 return 100;628 629 QByteArray mix_ctl = mixer_control.toAscii();630 snd_mixer_selem_id_t *sid;631 snd_mixer_selem_id_alloca(&sid);632 snd_mixer_selem_id_set_index(sid, 0);633 snd_mixer_selem_id_set_name(sid, mix_ctl.constData());634 635 snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);636 if (!elem)637 {638 VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")639 .arg(mixer_control));640 return 100;641 }642 643 snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;644 if (!snd_mixer_selem_has_playback_channel(elem, chan))645 {646 snd_mixer_selem_id_set_index(sid, channel);647 if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)648 {649 VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1 %2")650 .arg(mixer_control).arg(channel));651 return 100;652 }653 }654 655 ALSAVolumeInfo vinfo = GetVolumeRange(elem);656 657 snd_mixer_selem_get_playback_volume(658 elem, (snd_mixer_selem_channel_id_t)channel, &actual_volume);659 660 return vinfo.ToMythRange(actual_volume);661 }662 663 void AudioOutputALSA::SetVolumeChannel(int channel, int volume)664 {665 SetCurrentVolume(mixer_control, channel, volume);666 }667 668 void AudioOutputALSA::SetCurrentVolume(QString control, int channel, int volume)669 {670 VERBOSE(VB_AUDIO, QString("Setting %1 volume to %2")671 .arg(control).arg(volume));672 673 if (!mixer_handle)674 return; // no mixer, nothing to do675 676 QByteArray ctl = control.toAscii();677 snd_mixer_selem_id_t *sid;678 snd_mixer_selem_id_alloca(&sid);679 snd_mixer_selem_id_set_index(sid, 0);680 snd_mixer_selem_id_set_name(sid, ctl.constData());681 682 snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);683 if (!elem)684 {685 VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")686 .arg(control));687 return;688 }689 690 snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;691 if (!snd_mixer_selem_has_playback_channel(elem, chan))692 {693 snd_mixer_selem_id_set_index(sid, channel);694 if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)695 {696 VERBOSE(VB_IMPORTANT,697 QString("mixer unable to find control %1 %2")698 .arg(control).arg(channel));699 return;700 }701 }702 703 ALSAVolumeInfo vinfo = GetVolumeRange(elem);704 705 long set_vol = vinfo.ToALSARange(volume);706 707 int err = snd_mixer_selem_set_playback_volume(elem, chan, set_vol);708 if (err < 0)709 {710 VERBOSE(VB_IMPORTANT, QString("mixer set channel %1 err %2: %3")711 .arg(channel).arg(err).arg(snd_strerror(err)));712 }713 else714 {715 VERBOSE(VB_AUDIO, QString("channel %1 vol set to %2")716 .arg(channel).arg(set_vol));717 }718 719 if (snd_mixer_selem_has_playback_switch(elem))720 {721 int unmute = (0 != set_vol);722 if (snd_mixer_selem_has_playback_switch_joined(elem))723 {724 // Only mute if all the channels should be muted.725 for (int i = 0; i < audio_channels; i++)726 {727 if (0 != GetVolumeChannel(i))728 unmute = 1;729 }730 }731 732 err = snd_mixer_selem_set_playback_switch(elem, chan, unmute);733 if (err < 0)734 {735 VERBOSE(VB_IMPORTANT, LOC_ERR +736 QString("Mixer set playback switch %1 err %2: %3")737 .arg(channel).arg(err).arg(snd_strerror(err)));738 }739 else740 {741 VERBOSE(VB_AUDIO, LOC +742 QString("channel %1 playback switch set to %2")743 .arg(channel).arg(unmute));744 }745 }746 }747 748 void AudioOutputALSA::OpenMixer(bool setstartingvolume)749 {750 int volume;751 752 mixer_control = gContext->GetSetting("MixerControl", "PCM");753 754 SetupMixer();755 756 if (mixer_handle != NULL && setstartingvolume)757 {758 volume = gContext->GetNumSetting("MasterMixerVolume", 80);759 SetCurrentVolume("Master", 0, volume);760 SetCurrentVolume("Master", 1, volume);761 762 volume = gContext->GetNumSetting("PCMMixerVolume", 80);763 SetCurrentVolume("PCM", 0, volume);764 SetCurrentVolume("PCM", 1, volume);765 }766 }767 768 void AudioOutputALSA::CloseMixer(void)769 {770 if (mixer_handle != NULL)771 snd_mixer_close(mixer_handle);772 mixer_handle = NULL;773 }774 775 void AudioOutputALSA::SetupMixer(void)776 {777 int err;778 779 QString alsadevice = gContext->GetSetting("MixerDevice", "default");780 QString device = alsadevice.remove(QString("ALSA:"));781 782 if (mixer_handle != NULL)783 CloseMixer();784 785 if (alsadevice.toLower() == "software")786 return;787 788 VERBOSE(VB_AUDIO, QString("Opening mixer %1").arg(device));789 790 // TODO: This is opening card 0. Fix for case of multiple soundcards791 if ((err = snd_mixer_open(&mixer_handle, 0)) < 0)792 {793 Warn(QString("Mixer device open error %1: %2")794 .arg(err).arg(snd_strerror(err)));795 mixer_handle = NULL;796 return;797 }798 799 QByteArray dev = device.toAscii();800 if ((err = snd_mixer_attach(mixer_handle, dev.constData())) < 0)801 {802 Warn(QString("Mixer attach error %1: %2"803 "\n\t\t\tCheck Mixer Name in Setup: '%3'")804 .arg(err).arg(snd_strerror(err)).arg(device));805 CloseMixer();806 return;807 }808 809 if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0)810 {811 Warn(QString("Mixer register error %1: %2")812 .arg(err).arg(snd_strerror(err)));813 CloseMixer();814 return;815 }816 817 if ((err = snd_mixer_load(mixer_handle)) < 0)818 {819 Warn(QString("Mixer load error %1: %2")820 .arg(err).arg(snd_strerror(err)));821 CloseMixer();822 return;823 }824 }825 826 ALSAVolumeInfo AudioOutputALSA::GetVolumeRange(snd_mixer_elem_t *elem) const827 {828 long volume_min, volume_max;829 830 int err = snd_mixer_selem_get_playback_volume_range(831 elem, &volume_min, &volume_max);832 833 if (err < 0)834 {835 static bool first_time = true;836 if (first_time)837 {838 VERBOSE(VB_IMPORTANT,839 "snd_mixer_selem_get_playback_volume_range()" + ENO);840 first_time = false;841 }842 }843 844 ALSAVolumeInfo vinfo(volume_min, volume_max);845 846 VERBOSE(VB_AUDIO, QString("Volume range is %1 to %2, mult=%3")847 .arg(vinfo.volume_min).arg(vinfo.volume_max)848 .arg(vinfo.range_multiplier));849 850 return vinfo;851 } -
libs/libmyth/volumebase.cpp
1 #include <qstring.h>2 #include <cstdio>3 #include <cstdlib>4 5 #include <algorithm>6 using namespace std;7 #include "volumebase.h"8 9 VolumeBase::VolumeBase() :10 internal_vol(false), volume(80),11 current_mute_state(kMuteOff)12 {13 swvol = swvol_setting =14 (gContext->GetSetting("MixerDevice", "default").toLower() == "software");15 }16 17 bool VolumeBase::SWVolume(void)18 {19 return swvol;20 }21 22 void VolumeBase::SWVolume(bool set)23 {24 if (swvol_setting)25 return;26 swvol = set;27 }28 29 uint VolumeBase::GetCurrentVolume(void) const30 {31 return volume;32 }33 34 void VolumeBase::SetCurrentVolume(int value)35 {36 volume = max(min(value, 100), 0);37 UpdateVolume();38 39 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");40 controlLabel += "MixerVolume";41 gContext->SaveSetting(controlLabel, volume);42 }43 44 void VolumeBase::AdjustCurrentVolume(int change)45 {46 SetCurrentVolume(volume + change);47 }48 49 MuteState VolumeBase::SetMuteState(MuteState mstate)50 {51 current_mute_state = mstate;52 UpdateVolume();53 return current_mute_state;54 }55 56 void VolumeBase::ToggleMute(void)57 {58 bool is_muted = GetMuteState() == kMuteAll;59 SetMuteState((is_muted) ? kMuteOff : kMuteAll);60 }61 62 MuteState VolumeBase::GetMuteState(void) const63 {64 return current_mute_state;65 }66 67 MuteState VolumeBase::NextMuteState(MuteState cur)68 {69 MuteState next = cur;70 71 switch (cur)72 {73 case kMuteOff:74 next = kMuteLeft;75 break;76 case kMuteLeft:77 next = kMuteRight;78 break;79 case kMuteRight:80 next = kMuteAll;81 break;82 case kMuteAll:83 next = kMuteOff;84 break;85 }86 87 return (next);88 }89 90 void VolumeBase::UpdateVolume(void)91 {92 int new_volume = volume;93 bool save = true;94 if (current_mute_state == kMuteAll)95 {96 new_volume = 0;97 save = false;98 }99 100 if (swvol)101 {102 SetSWVolume(new_volume, save);103 return;104 }105 106 // TODO: Avoid assumption that there are 2 channels!107 for (int i = 0; i < 2; i++)108 {109 SetVolumeChannel(i, new_volume);110 }111 112 // Individual channel muting is handled in GetAudioData,113 // this code demonstrates the old method.114 // if (current_mute_state == kMuteLeft)115 // {116 // SetVolumeChannel(0, 0);117 // }118 // else if (current_mute_state == kMuteRight)119 // {120 // SetVolumeChannel(1, 0);121 // }122 }123 124 void VolumeBase::SyncVolume(void)125 {126 // Read the volume from the audio driver and setup our internal state to match127 if (swvol)128 volume = GetSWVolume();129 else130 volume = GetVolumeChannel(0);131 }132 -
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 VOLUMEBASE2 #define VOLUMEBASE3 4 #include <iostream>5 using namespace std;6 7 #include <qstring.h>8 #include "mythcontext.h"9 10 typedef enum {11 kMuteOff = 0,12 kMuteLeft,13 kMuteRight,14 kMuteAll,15 } MuteState;16 17 class MPUBLIC VolumeBase18 {19 public:20 VolumeBase();21 virtual ~VolumeBase() {};22 23 void SWVolume(bool set);24 bool SWVolume(void);25 virtual uint GetCurrentVolume(void) const;26 virtual void SetCurrentVolume(int value);27 virtual void AdjustCurrentVolume(int change);28 virtual void ToggleMute(void);29 30 virtual MuteState GetMuteState(void) const;31 virtual MuteState SetMuteState(MuteState);32 33 static MuteState NextMuteState(MuteState);34 35 protected:36 37 virtual int GetVolumeChannel(int channel) const = 0; // Returns 0-10038 virtual void SetVolumeChannel(int channel, int volume) = 0; // range 0-100 for vol39 virtual void SetSWVolume(int new_volume, bool save) = 0;40 virtual int GetSWVolume(void) = 0;41 42 void UpdateVolume(void);43 void SyncVolume(void);44 45 bool internal_vol;46 47 private:48 49 int volume;50 MuteState current_mute_state;51 bool swvol;52 bool swvol_setting;53 54 };55 56 #endif57 -
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
33 33 AudioOutputPulseAudio(const AudioSettings &settings); 34 34 ~AudioOutputPulseAudio(); 35 35 36 int GetVolumeChannel(int channel) const;37 void SetVolumeChannel(int channel, int volume);38 36 void Pause(bool paused); 39 37 void Reset(void); 40 38 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
266 266 return writable; 267 267 } 268 268 269 int AudioOutputPulseAudio::GetVolumeChannel(int channel) const270 {271 return (float)volume_control.values[channel]272 / (float)PA_VOLUME_NORM * 100.0f;273 }274 275 void AudioOutputPulseAudio::SetVolumeChannel(int channel, int volume)276 {277 QString fn_log_tag = "SetVolumeChannel, ";278 if (channel < 0 || channel > PULSE_MAX_CHANNELS || volume < 0)279 {280 VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +281 QString("bad volume params, channel %1, volume %2")282 .arg(channel).arg(volume));283 return;284 }285 volume_control.values[channel] =286 (float)volume / 100.0f * (float)PA_VOLUME_NORM;287 volume = min(100, volume);288 volume = max(0, volume);289 uint32_t sink_index = pa_stream_get_device_index(pstream);290 pa_threaded_mainloop_lock(mainloop);291 pa_operation *op =292 pa_context_set_sink_volume_by_index(pcontext, sink_index,293 &volume_control,294 OpCompletionCallback, this);295 pa_threaded_mainloop_unlock(mainloop);296 if (op)297 pa_operation_unref(op);298 else299 VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +300 QString("set sink volume operation failed, sink: %1, "301 "error: %2 ")302 .arg(sink_index)303 .arg(pa_strerror(pa_context_errno(pcontext))));304 }305 306 269 void AudioOutputPulseAudio::Pause(bool paused) 307 270 { 308 271 pa_operation *op; … … 543 506 pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over"); 544 507 pa_stream_set_underflow_callback(pstream, BufferFlowCallback, 545 508 (char*)"under"); 546 if (set_initial_vol) 547 { 548 int volume = gContext->GetNumSetting("MasterMixerVolume", 80); 549 pa_cvolume_set(&volume_control, audio_channels, 550 (float)volume * (float)PA_VOLUME_NORM / 100.0f); 551 } 552 else 553 pa_cvolume_reset(&volume_control, audio_channels); 509 pa_cvolume_reset(&volume_control, audio_channels); 554 510 555 511 // set myth sizes and pa buffer metrics 556 512 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
38 38 pauseaudio(false), audio_actually_paused(false), 39 39 was_paused(false), 40 40 41 set_initial_vol(settings.set_initial_vol),42 41 buffer_output_data_for_use(false), 43 42 44 43 // private … … 55 54 needs_upmix(false), 56 55 surround_mode(FreeSurround::SurroundModePassive), 57 56 old_audio_stretchfactor(1.0), 58 volume(80),59 57 60 58 blocking(false), 61 59 … … 110 108 111 109 allow_ac3_passthru = (orig_config_channels > 2) ? gContext->GetNumSetting("AC3PassThru", false) : false; 112 110 111 if (gContext->GetSetting("MixerDevice") == "Software:") 112 volume_control = VolumeControlManager::GetControl("Software:"); 113 113 114 // You need to call Reconfigure from your concrete class. 114 115 // Reconfigure(laudio_bits, laudio_channels, 115 116 // laudio_samplerate, laudio_passthru); … … 279 280 killaudio = false; 280 281 pauseaudio = false; 281 282 was_paused = true; 282 internal_vol = gContext->GetNumSetting("MythControlsVolume", 0);283 283 284 284 numlowbuffer = 0; 285 285 … … 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 … … 669 657 return audbuf_timecode - GetAudiotime(); 670 658 } 671 659 672 void AudioOutputBase::SetSWVolume(int new_volume, bool save)673 {674 volume = new_volume;675 if (save)676 {677 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");678 controlLabel += "MixerVolume";679 gContext->SaveSetting(controlLabel, volume);680 }681 }682 683 int AudioOutputBase::GetSWVolume()684 {685 return volume;686 }687 688 660 void AudioOutputBase::AdjustVolume(void *buffer, int len, bool music) 689 661 { 690 662 if (audio_bits == 8) … … 696 668 template <class AudioDataType> 697 669 void AudioOutputBase::_AdjustVolume(AudioDataType *buffer, int len, bool music) 698 670 { 671 int volume = volume_control->mute() ? 0 : volume_control->volume(); 672 699 673 float g = volume / 100.0; 700 674 701 675 // Should probably be exponential - this'll do … … 1104 1078 } 1105 1079 } 1106 1080 1107 if ( internal_vol && SWVolume())1081 if (volume_control) 1108 1082 { 1109 1083 int bdiff = kAudioRingBufferSize - waud; 1110 1084 bool music = (timecode < 1); … … 1365 1339 audio_buflock.unlock(); 1366 1340 1367 1341 // Mute individual channels through mono->stereo duplication 1368 MuteState mute_state = GetMuteState();1342 // MuteState mute_state = GetMuteState(); 1369 1343 if (written_size && 1370 audio_channels > 1 && 1371 (mute_state == kMuteLeft || mute_state == kMuteRight)) 1344 audio_channels > 1 //&& 1345 // (mute_state == kMuteLeft || mute_state == kMuteRight) 1346 ) 1372 1347 { 1373 1348 int offset_src = 0; 1374 1349 int offset_dst = 0; 1375 1350 1376 if (mute_state == kMuteLeft)1377 offset_src = audio_bits / 8; // copy channel 1 to channel 01378 else if (mute_state == kMuteRight)1379 offset_dst = audio_bits / 8; // copy channel 0 to channel 11351 // if (mute_state == kMuteLeft) 1352 // offset_src = audio_bits / 8; // copy channel 1 to channel 0 1353 // else if (mute_state == kMuteRight) 1354 // offset_dst = audio_bits / 8; // copy channel 0 to channel 1 1380 1355 1381 1356 for (int i = 0; i < written_size; i += audio_bytes_per_sample) 1382 1357 { -
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
337 337 dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ 338 338 | DSBCAPS_GLOBALFOCUS /* Allows background playing */ 339 339 | DSBCAPS_LOCHARDWARE; /* Needed for 5.1 on emu101k */ 340 if (!m_UseSPDIF)341 dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; /* Allow volume control */342 340 dsbdesc.dwBufferBytes = soundcard_buffer_size; /* buffer size */ 343 341 dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf; 344 342 … … 485 483 return buffered; 486 484 } 487 485 488 int AudioOutputDX::GetVolumeChannel(int channel) const489 {490 HRESULT dsresult;491 long dxVolume = 0;492 int volume;493 494 if (m_UseSPDIF)495 return 100;496 497 dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);498 volume = (int)(pow(10,(float)dxVolume/20)*100);499 500 if (dsresult != DS_OK)501 {502 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to get volume %1")503 .arg(dxVolume));504 return volume;505 }506 507 VERBOSE(VB_AUDIO, LOC + QString("Got volume %1").arg(volume));508 return volume;509 }510 511 void AudioOutputDX::SetVolumeChannel(int channel, int volume)512 {513 HRESULT dsresult;514 float dbAtten = 20 * log10((float)volume/100);515 long dxVolume = (volume == 0) ? DSBVOLUME_MIN : (long)(100.0f * dbAtten);516 517 if (m_UseSPDIF)518 return;519 520 // dxVolume is attenuation in 100ths of a decibel521 dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);522 523 if (dsresult != DS_OK)524 {525 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to set volume %1")526 .arg(dxVolume));527 return;528 }529 530 VERBOSE(VB_AUDIO, LOC + QString("Set volume %1").arg(dxVolume));531 }532 533 486 /* 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 "libmythtv/mpeg/iso639.h" 29 29 #include "playbackbox.h" 30 30 #include "globalsettings.h" 31 #include "libmyth/volumecontrolmanager.h" 31 32 #include "libmythtv/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"); … … 4485 4401 4486 4402 addChild(AudioSystemSettingsGroup()); 4487 4403 4488 addChild( newAudioMixerSettingsGroup());4404 addChild(AudioMixerSettingsGroup()); 4489 4405 4490 4406 VerticalConfigurationGroup *general = 4491 4407 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; }
