Ticket #7517: volume_control_mythtv_r22850.patch
File volume_control_mythtv_r22850.patch, 128.0 KB (added by , 14 years ago) |
---|
-
configure
595 595 eval "$var=\"\$$var $*\"" 596 596 } 597 597 598 prepend(){ 599 var=$1 600 shift 601 flags_saved && eval "SAVE_$var=\"$* \$SAVE_$var\"" 602 eval "$var=\"$* \$$var\"" 603 } 604 598 605 add_cflags(){ 599 606 append CFLAGS "$@" 600 607 } … … 3325 3332 enable audio_alsa || 3326 3333 disable audio_alsa 3327 3334 3335 # OSS probe 3336 if ! disabled audio_oss ; then 3337 if test -f /usr/"${libdir_name}"/oss/include/sys/soundcard.h && 3338 check_cpp_condition /usr/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then 3339 disable soundcard_h 3340 enable sys_soundcard_h 3341 prepend CONFIG_INCLUDEPATH "/usr/${libdir_name}/oss/include" 3342 elif test -f /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h && 3343 check_cpp_condition /usr/local/"${libdir_name}"/oss/include/sys/soundcard.h "SOUND_VERSION >= 0x040000"; then 3344 disable soundcard_h 3345 enable sys_soundcard_h 3346 prepend CONFIG_INCLUDEPATH "/usr/local/${libdir_name}/oss/include" 3347 else 3348 if enabled soundcard_h ; then 3349 check_cpp_condition soundcard.h "SOUND_VERSION >= 0x040000" && 3350 enable audio_oss || 3351 disable audio_oss 3352 elif enabled sys_soundcard_h ; then 3353 check_cpp_condition sys/soundcard.h "SOUND_VERSION >= 0x040000" && 3354 enable audio_oss || 3355 disable audio_oss 3356 fi 3357 fi 3358 fi 3359 3328 3360 # JACK probe 3329 3361 ! disabled audio_jack && 3330 3362 check_lib jack/jack.h jack_client_new $audio_jack_libs && … … 4022 4054 if enabled audio_oss; then 4023 4055 append CCONFIG "using_oss" 4024 4056 fi 4057 4025 4058 if enabled audio_alsa; then 4026 4059 append CCONFIG "using_alsa" 4027 4060 echo "CONFIG_AUDIO_ALSA_LIBS=$audio_alsa_libs" >> $MYTH_CONFIG_MAK -
libs/libmythtv/NuppelVideoPlayer.cpp
142 142 kDisplayNUVTeletextCaptions, 143 143 }; 144 144 145 NuppelVideoPlayer::NuppelVideoPlayer( bool muted)145 NuppelVideoPlayer::NuppelVideoPlayer() 146 146 : decoder(NULL), decoder_change_lock(QMutex::Recursive), 147 147 videoOutput(NULL), player_ctx(NULL), 148 148 no_hardware_decoders(false), … … 210 210 audio_channels(2), audio_codec(0), 211 211 audio_bits(-1), audio_samplerate(44100), 212 212 audio_stretchfactor(1.0f), audio_lock(QMutex::Recursive), 213 audio_muted_on_creation(muted),214 213 // Picture-in-Picture stuff 215 214 pip_active(false), pip_visible(true), 216 215 // Preview window support … … 403 402 audio_samplerate = (int)samplerate; 404 403 } 405 404 406 uint NuppelVideoPlayer::GetVolume(void)407 {408 QMutexLocker lock(&audio_lock);409 if (audioOutput)410 return audioOutput->GetCurrentVolume();411 return 0;412 }413 414 bool NuppelVideoPlayer::SetMuted(bool mute)415 {416 QMutexLocker lock(&audio_lock);417 bool is_muted = IsMuted();418 419 if (audioOutput && !is_muted && mute &&420 (kMuteAll == SetMuteState(kMuteAll)))421 {422 VERBOSE(VB_AUDIO, "muting sound " <<IsMuted());423 return true;424 }425 else if (audioOutput && is_muted && !mute &&426 (kMuteOff == SetMuteState(kMuteOff)))427 {428 VERBOSE(VB_AUDIO, "unmuting sound "<<IsMuted());429 return true;430 }431 432 VERBOSE(VB_AUDIO, "not changing sound mute state "<<IsMuted());433 434 return false;435 }436 437 MuteState NuppelVideoPlayer::SetMuteState(MuteState mstate)438 {439 QMutexLocker lock(&audio_lock);440 if (audioOutput)441 return audioOutput->SetMuteState(mstate);442 return kMuteAll;443 }444 445 MuteState NuppelVideoPlayer::IncrMuteState(void)446 {447 QMutexLocker lock(&audio_lock);448 MuteState mstate = kMuteAll;449 if (audioOutput)450 mstate = SetMuteState(VolumeBase::NextMuteState(GetMuteState()));451 return mstate;452 }453 454 MuteState NuppelVideoPlayer::GetMuteState(void)455 {456 QMutexLocker lock(&audio_lock);457 if (audioOutput)458 return audioOutput->GetMuteState();459 return kMuteAll;460 }461 462 uint NuppelVideoPlayer::AdjustVolume(int change)463 {464 QMutexLocker lock(&audio_lock);465 if (audioOutput)466 audioOutput->AdjustCurrentVolume(change);467 return GetVolume();468 }469 470 405 void NuppelVideoPlayer::PauseDecoder(void) 471 406 { 472 407 decoder_lock.lock(); … … 902 837 903 838 if (!audioOutput && !using_null_videoout && player_ctx->IsAudioNeeded()) 904 839 { 905 bool setVolume = gContext->GetNumSetting("MythControlsVolume", 1);906 840 audioOutput = AudioOutput::OpenAudio(audio_main_device, 907 841 audio_passthru_device, 908 842 audio_bits, audio_channels, 909 843 audio_codec, audio_samplerate, 910 844 AUDIOOUTPUT_VIDEO, 911 setVolume,audio_passthru);845 audio_passthru); 912 846 if (!audioOutput) 913 847 errMsg = QObject::tr("Unable to create AudioOutput."); 914 848 else … … 930 864 VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio"); 931 865 no_audio_out = false; 932 866 } 933 if (audio_muted_on_creation)934 {935 SetMuteState(kMuteAll);936 audio_muted_on_creation = false;937 }938 867 } 939 868 940 869 if (audioOutput) -
libs/libmythtv/avformatdecoder.cpp
464 464 audioSamples(NULL), audioSamplesResampled(NULL), 465 465 reformat_ctx(NULL), audio_src_fmt(SAMPLE_FMT_NONE), 466 466 allow_ac3_passthru(false), allow_dts_passthru(false), 467 internal_vol(false),468 467 disable_passthru(false), max_channels(2), 469 468 last_ac3_channels(0), dummy_frame(NULL), 470 469 // DVD … … 487 486 max_channels = (uint) gContext->GetNumSetting("MaxChannels", 2); 488 487 allow_ac3_passthru = (max_channels > 2) ? gContext->GetNumSetting("AC3PassThru", false) : false; 489 488 allow_dts_passthru = (max_channels > 2) ? gContext->GetNumSetting("DTSPassThru", false) : false; 490 internal_vol = gContext->GetNumSetting("MythControlsVolume", 0);491 489 492 490 audioIn.sample_size = -32; // force SetupAudioStream to run once 493 491 itv = GetNVP()->GetInteractiveTV(); … … 4370 4368 4371 4369 if (ctx->codec_id == CODEC_ID_AC3) 4372 4370 passthru = allow_ac3_passthru && 4373 ctx->channels >= (int)max_channels && 4374 !internal_vol; 4371 ctx->channels >= (int)max_channels; 4375 4372 else if (ctx->codec_id == CODEC_ID_DTS) 4376 passthru = allow_dts_passthru && !internal_vol;4373 passthru = allow_dts_passthru; 4377 4374 4378 4375 passthru &= !transcoding && !disable_passthru; 4379 4376 // Don't know any cards that support spdif clocked at < 44100 -
libs/libmythtv/tv_play.h
33 33 #include "programlist.h" 34 34 #include "channelutil.h" 35 35 #include "videoouttypes.h" 36 #include "volume base.h"36 #include "volumecontrolmanager.h" 37 37 #include "inputinfo.h" 38 38 #include "channelgroup.h" 39 39 … … 296 296 void AddUDPNotifyEvent(const QString &name, const UDPNotifyOSDSet*); 297 297 void ClearUDPNotifyEvents(void); 298 298 299 void VolumeChanged(int volume); 300 void MuteChanged(bool mute); 301 299 302 protected: 300 303 void TreeMenuEntered(OSDListTreeItemEnteredEvent *e); 301 304 void TreeMenuSelected(OSDListTreeItemSelectedEvent *e); … … 305 308 virtual void run(void); 306 309 void TVEventThreadChecks(void); 307 310 308 void SetMuteTimer(PlayerContext*, int timeout);309 bool MuteChannelChange(PlayerContext *ctx);310 311 311 bool eventFilter(QObject *o, QEvent *e); 312 312 static QStringList lastProgramStringList; 313 313 static EMBEDRETURNPROGRAM RunPlaybackBoxPtr; … … 497 497 498 498 vector<long long> TeardownAllNVPs(PlayerContext*); 499 499 void RestartAllNVPs(PlayerContext *lctx, 500 const vector<long long> &pos, 501 MuteState mctx_mute); 500 const vector<long long> &pos); 502 501 void RestartMainNVP(PlayerContext *mctx); 503 502 504 503 void PxPToggleView( PlayerContext *actx, bool wantPBP); … … 658 657 /// Picture attribute to modify (on arrow left or right) 659 658 PictureAttribute adjustingPictureAttribute; 660 659 660 QSharedPointer<VolumeControl> volumeControl; ///< Volume Control interface 661 661 662 // Ask Allow state 662 663 AskAllowType askAllowType; 663 664 QMap<QString,AskProgramInfo> askAllowPrograms; … … 815 816 TimerContextMap stateChangeTimerId; 816 817 TimerContextMap signalMonitorTimerId; 817 818 TimerContextMap tvchainUpdateTimerId; 818 TimerContextMap unmuteTimerId;819 819 820 820 /// Condition to signal that the Event thread is up and running 821 821 QWaitCondition mainLoopCond; … … 836 836 837 837 ///< Timeout for entry modes in msec 838 838 static const uint kInputModeTimeout; 839 /// Channel changing mute timeout in msec840 static const uint kMuteTimeout;841 839 /// Timeout for updating LCD info in msec 842 840 static const uint kLCDTimeout; 843 841 /// Timeout for browse mode exit in msec -
libs/libmythtv/playercontext.cpp
430 430 431 431 bool PlayerContext::CreateNVP(TV *tv, QWidget *widget, 432 432 TVState desiredState, 433 WId embedwinid, const QRect *embedbounds, 434 bool muted) 433 WId embedwinid, const QRect *embedbounds) 435 434 { 436 435 int exact_seeking = gContext->GetNumSetting("ExactSeeking", 0); 437 436 … … 442 441 return false; 443 442 } 444 443 445 NuppelVideoPlayer *_nvp = new NuppelVideoPlayer( muted);444 NuppelVideoPlayer *_nvp = new NuppelVideoPlayer(); 446 445 447 446 if (nohardwaredecoders) 448 447 _nvp->DisableHardwareDecoders(); … … 492 491 VERBOSE(VB_IMPORTANT, LOC_ERR + errMsg); 493 492 } 494 493 } 495 else if (pipState == kPBPRight)496 nvp->SetMuted(true);497 494 498 495 int maxWait = -1; 499 496 //if (isPIP()) -
libs/libmythtv/NuppelVideoPlayer.h
4 4 #include <sys/time.h> 5 5 6 6 #include "playercontext.h" 7 #include "volumebase.h"8 7 #include "RingBuffer.h" 9 8 #include "osd.h" 10 9 #include "jitterometer.h" … … 104 103 friend class PlayerContext; 105 104 106 105 public: 107 NuppelVideoPlayer( bool muted = false);106 NuppelVideoPlayer(); 108 107 ~NuppelVideoPlayer(); 109 108 110 109 // Initialization … … 127 126 void SetAudioInfo(const QString &main, const QString &passthru, uint rate); 128 127 void SetAudioParams(int bits, int channels, int codec, int samplerate, bool passthru); 129 128 void SetEffDsp(int dsprate); 130 uint AdjustVolume(int change);131 bool SetMuted(bool mute);132 MuteState SetMuteState(MuteState);133 MuteState IncrMuteState(void);134 129 void SetAudioCodec(void *ac); 135 130 136 131 // Sets … … 187 182 float GetVideoAspect(void) const { return video_aspect; } 188 183 float GetFrameRate(void) const { return video_frame_rate; } 189 184 190 uint GetVolume(void);191 185 int GetSecondsBehind(void) const; 192 186 AspectOverrideMode GetAspectOverride(void) const; 193 187 AdjustFillMode GetAdjustFill(void) const; 194 MuteState GetMuteState(void);195 188 CommSkipMode GetAutoCommercialSkip(void) const; 196 189 197 190 int GetFFRewSkip(void) const { return ffrew_skip; } … … 227 220 bool HasAudioOut(void) const { return !no_audio_out; } 228 221 bool IsPIPActive(void) const { return pip_active; } 229 222 bool IsPIPVisible(void) const { return pip_visible; } 230 bool IsMuted(void) { return GetMuteState() == kMuteAll; }231 223 bool UsingNullVideo(void) const { return using_null_videoout; } 232 224 bool HasTVChainNext(void) const; 233 225 … … 719 711 float audio_stretchfactor; 720 712 bool audio_passthru; 721 713 QMutex audio_lock; 722 bool audio_muted_on_creation;723 714 724 715 // Picture-in-Picture 725 716 mutable QMutex pip_players_lock; -
libs/libmythtv/tv_play.cpp
83 83 84 84 85 85 const uint TV::kInputModeTimeout = 5000; 86 const uint TV::kMuteTimeout = 800;87 86 const uint TV::kLCDTimeout = 1000; 88 87 const uint TV::kBrowseTimeout = 30000; 89 88 const uint TV::kKeyRepeatTimeout = 300; … … 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()) … … 8020 7944 8021 7945 void TV::ChangeVolume(PlayerContext *ctx, bool up) 8022 7946 { 8023 ctx->LockDeleteNVP(__FILE__, __LINE__); 8024 if (!ctx->nvp) 7947 if (volumeControl) 8025 7948 { 8026 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8027 return; 7949 if (up) 7950 volumeControl->increaseVolume(); 7951 else 7952 volumeControl->decreaseVolume(); 8028 7953 } 8029 uint curvol = ctx->nvp->AdjustVolume((up) ? +2 : -2);8030 ctx->UnlockDeleteNVP(__FILE__, __LINE__);8031 8032 QString text = tr("Volume %1 %").arg(curvol);8033 8034 OSD *osd = GetOSDLock(ctx);8035 if (osd && !browsemode)8036 {8037 osd->ShowStatus(curvol * 10, true, tr("Adjust Volume"), text, 5,8038 kOSDFunctionalType_PictureAdjust);8039 SetUpdateOSDPosition(false);8040 }8041 ReturnOSDLock(ctx, osd);8042 7954 } 8043 7955 8044 7956 void TV::ToggleTimeStretch(PlayerContext *ctx) … … 8187 8099 8188 8100 void TV::ToggleMute(PlayerContext *ctx) 8189 8101 { 8190 ctx->LockDeleteNVP(__FILE__, __LINE__); 8191 if (!ctx->nvp || !ctx->nvp->HasAudioOut()) 8192 { 8193 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8194 return; 8195 } 8196 8197 MuteState mute_status; 8198 8199 if (!MuteIndividualChannels) 8200 { 8201 ctx->nvp->SetMuted(!ctx->nvp->IsMuted()); 8202 mute_status = (ctx->nvp->IsMuted()) ? kMuteAll : kMuteOff; 8203 } 8204 else 8205 { 8206 mute_status = ctx->nvp->IncrMuteState(); 8207 } 8208 ctx->UnlockDeleteNVP(__FILE__, __LINE__); 8209 8210 QString text; 8211 8212 switch (mute_status) 8213 { 8214 case kMuteOff: text = tr("Mute Off"); break; 8215 case kMuteAll: text = tr("Mute On"); break; 8216 case kMuteLeft: text = tr("Left Channel Muted"); break; 8217 case kMuteRight: text = tr("Right Channel Muted"); break; 8218 } 8219 8220 OSD *osd = GetOSDLock(ctx); 8221 if (osd && !browsemode) 8222 osd->SetSettingsText(text, 5); 8223 ReturnOSDLock(ctx, osd); 8102 if (volumeControl) 8103 volumeControl->setMute(!volumeControl->mute()); 8224 8104 } 8225 8105 8226 8106 void TV::ToggleSleepTimer(const PlayerContext *ctx) … … 8380 8260 ReturnOSDLock(ctx, osd); 8381 8261 } 8382 8262 8383 void TV::SetMuteTimer(PlayerContext *ctx, int timeout)8384 {8385 // message to set the timer will be posted to the main UI thread8386 // where it will be caught in eventFilter and processed as CustomEvent8387 // this will properly set the mute timer8388 // otherwise it never fires on Win328389 QString message = QString("UNMUTE %1 %2").arg((long long)ctx).arg(timeout);8390 qApp->postEvent(gContext->GetMainWindow(), new MythEvent(message));8391 }8392 8393 bool TV::MuteChannelChange(PlayerContext *ctx)8394 {8395 if (!ctx)8396 return false;8397 8398 bool muted = false;8399 ctx->LockDeleteNVP(__FILE__, __LINE__);8400 if (ctx->nvp && !ctx->nvp->IsMuted())8401 muted = ctx->nvp->SetMuted(true);8402 ctx->UnlockDeleteNVP(__FILE__, __LINE__);8403 8404 return muted;8405 }8406 8407 8263 void TV::customEvent(QEvent *e) 8408 8264 { 8409 8265 if ((MythEvent::Type)(e->type()) == kOSDClosedEventType) … … 8679 8535 } 8680 8536 } 8681 8537 8682 if (message.left(6) == "UNMUTE")8683 {8684 if (tokens.size() >= 3)8685 {8686 long long target = tokens[1].toLongLong();8687 PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);8688 for (uint i = 0; i < player.size(); i++)8689 {8690 PlayerContext *ctx = GetPlayer(mctx, i);8691 if (((long long)ctx) == target)8692 {8693 QMutexLocker locker(&timerIdLock);8694 unmuteTimerId[StartTimer(tokens[2].toUInt(), __LINE__)] = ctx;8695 }8696 }8697 ReturnPlayerLock(mctx);8698 }8699 }8700 8701 8538 if (message.left(9) == "START_EPG") 8702 8539 { 8703 8540 int editType = tokens[1].toInt(); … … 9171 9008 { 9172 9009 value = ctx->nvp->getVideoOutput()->GetPictureAttribute(attr); 9173 9010 } 9174 else if (ctx->nvp->HasAudioOut() )9011 else if (ctx->nvp->HasAudioOut() && volumeControl) 9175 9012 { 9176 value = ctx->nvp->GetVolume();9013 value = volumeControl->volume(); 9177 9014 title = tr("Adjust Volume"); 9178 9015 } 9179 9016 } … … 11677 11514 ReturnPlayerLock(mctx); 11678 11515 } 11679 11516 11517 void TV::VolumeChanged(int volume) 11518 { 11519 OSD *osd = GetOSDL(__FILE__, __LINE__); 11520 if (osd && !browsemode) 11521 { 11522 osd->ShowStatus(volume * 10, true, tr("Adjust Volume"), 11523 tr("Volume %1 %").arg(volume), 5, 11524 kOSDFunctionalType_PictureAdjust); 11525 SetUpdateOSDPosition(false); 11526 } 11527 ReturnOSDLock(osd); 11528 } 11529 11530 void TV::MuteChanged(bool mute) 11531 { 11532 OSD *osd = GetOSDL(__FILE__, __LINE__); 11533 if (osd && !browsemode) 11534 osd->SetSettingsText(mute ? tr("Mute On") : tr("Mute Off"), 5); 11535 ReturnOSDLock(osd); 11536 } 11537 11538 11680 11539 OSD *TV::GetOSDL(const char *file, int location) 11681 11540 { 11682 11541 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
263 263 264 264 bool allow_ac3_passthru; 265 265 bool allow_dts_passthru; 266 bool internal_vol;267 266 bool disable_passthru; 268 267 uint max_channels; 269 268 uint last_ac3_channels; -
libs/libmyth/audiooutputwin.cpp
280 280 { 281 281 return m_nPkts * fragment_size; 282 282 } 283 284 int AudioOutputWin::GetVolumeChannel(int channel) const285 {286 DWORD dwVolume = 0xffffffff;287 int Volume = 100;288 if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))289 {290 Volume = (channel == 0) ?291 (LOWORD(dwVolume) / (0xffff / 100)) :292 (HIWORD(dwVolume) / (0xffff / 100));293 }294 295 VERBOSE(VB_AUDIO, "GetVolume(" << channel << ") "296 << Volume << "(" << dwVolume << ")");297 298 return Volume;299 }300 301 void AudioOutputWin::SetVolumeChannel(int channel, int volume)302 {303 if (channel > 1)304 {305 Error(QString("Error setting channel: %1. "306 "Only stereo volume supported").arg(channel));307 return;308 }309 310 DWORD dwVolume = 0xffffffff;311 if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))312 {313 if (channel == 0)314 dwVolume = dwVolume & 0xffff0000 | volume * (0xffff / 100);315 else316 dwVolume = dwVolume & 0xffff | ((volume * (0xffff / 100)) << 16);317 }318 else319 {320 dwVolume = volume * (0xffff / 100);321 dwVolume |= (dwVolume << 16);322 }323 324 VERBOSE(VB_AUDIO, QString("SetVolume(%1) %2(%3)")325 .arg(channel).arg(volume).arg(dwVolume));326 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, dwVolume);327 } -
libs/libmyth/volumecontrolmanager.cpp
1 #include "volumecontrolmanager.h" 2 3 #include "mythverbose.h" 4 #ifdef USE_ALSA 5 #include "volumecontrolalsa.h" 6 #endif 7 #ifdef USE_COREAUDIO 8 #include "volumecontrolcoreaudio.h" 9 #endif 10 #ifdef USING_OSS 11 #include "volumecontroloss.h" 12 #endif 13 #ifdef USING_MINGW 14 #include "volumecontrolendpoint.h" 15 #endif 16 #include "volumecontrolsoftware.h" 17 18 19 QHash<QString, QString> VolumeControlManager::Enumerate() 20 { 21 QHash<QString, QString> result; 22 23 #ifdef USE_ALSA 24 result.unite(VolumeControlALSA::Enumerate()); 25 #endif 26 #ifdef USE_COREAUDIO 27 result.unite(VolumeControlCoreAudio::Enumerate()); 28 #endif 29 #ifdef USING_OSS 30 result.unite(VolumeControlOSS::Enumerate()); 31 #endif 32 #ifdef USING_MINGW 33 result.unite(VolumeControlEndpoint::Enumerate()); 34 #endif 35 result.unite(VolumeControlSoftware::Enumerate()); 36 37 return result; 38 } 39 40 QSharedPointer<VolumeControl> VolumeControlManager::GetControl(QString device) 41 { 42 QSharedPointer<VolumeControl> result; 43 QString api = device.section(':', 0, 0); 44 device = device.remove(0, api.size() + 1); 45 46 if (api == "ALSA") 47 { 48 #ifdef USE_ALSA 49 result = QSharedPointer<VolumeControl>(new VolumeControlALSA(device)); 50 #else 51 VERBOSE(VB_IMPORTANT, 52 QString("Volume control device is set to an ALSA device but " 53 "ALSA support is not compiled in!")); 54 #endif 55 } 56 else if (api == "CoreAudio") 57 { 58 #ifdef USE_COREAUDIO 59 result = QSharedPointer<VolumeControl>(new VolumeControlCoreAudio(device)); 60 #else 61 VERBOSE(VB_IMPORTANT, 62 QString("Volume control device is set to an Core Audio device " 63 "but Core Audio support is not compiled in!")); 64 #endif 65 } 66 else if (api == "OSS" || api.isEmpty()) 67 { 68 #ifdef USING_OSS 69 result = QSharedPointer<VolumeControl>(new VolumeControlOSS(device)); 70 #else 71 VERBOSE(VB_IMPORTANT, 72 QString("Volume control device is set to an OSS device but OSS " 73 "support is not compiled in!")); 74 #endif 75 } 76 else if (api == "Endpoint" || api.isEmpty()) 77 { 78 #ifdef USING_MINGW 79 result = QSharedPointer<VolumeControl>(new VolumeControlEndpoint(device)); 80 #else 81 VERBOSE(VB_IMPORTANT, 82 QString("Volume control device is set to an Endpoint device " 83 "but End Point support is not compiled in!")); 84 #endif 85 } 86 else if (api == "Software" || api.isEmpty()) 87 { 88 result = QSharedPointer<VolumeControl>(new VolumeControlSoftware(device)); 89 } 90 else 91 { 92 VERBOSE(VB_IMPORTANT, 93 QString("Volume control device is set to an unknown API \"%1\"") 94 .arg(api)); 95 } 96 97 return result; 98 } -
libs/libmyth/volumecontrolalsa.cpp
1 #include "volumecontrolalsa.h" 2 3 #include "mythverbose.h" 4 #include <algorithm> 5 6 QHash<QString, QString> VolumeControlALSA::Enumerate() 7 { 8 QHash<QString, QString> result; 9 10 result.insert("ALSA:default", "Default ALSA device"); 11 12 int card = -1; 13 while (snd_card_next(&card) >= 0 && card >= 0) 14 { 15 snd_ctl_t* handle; 16 if (!snd_ctl_open(&handle, 17 QString("hw:%1").arg(card).toAscii().constData(), 0)) 18 { 19 snd_ctl_card_info_t *info; 20 snd_ctl_card_info_alloca(&info); 21 22 if (!snd_ctl_card_info(handle, info)) 23 { 24 result.insert(QString("ALSA:hw:%1") 25 .arg(snd_ctl_card_info_get_id(info)), 26 snd_ctl_card_info_get_name(info)); 27 } 28 snd_ctl_close(handle); 29 } 30 } 31 32 return result; 33 } 34 35 VolumeControlALSA::VolumeControlALSA(QString device) : 36 m_MixerHandle(NULL), 37 m_MixerElement(NULL), 38 m_Range(1) 39 { 40 if (snd_mixer_open(&m_MixerHandle, 0) < 0) 41 { 42 VERBOSE(VB_IMPORTANT, 43 QString("VolumeControlALSA::VolumeControlALSA() - ERROR: " 44 "opening mixer")); 45 return; 46 } 47 48 if (snd_mixer_attach(m_MixerHandle, device.toAscii().constData()) < 0) 49 { 50 VERBOSE(VB_IMPORTANT, 51 QString("VolumeControlALSA::VolumeControlALSA() - ERROR: " 52 "attaching mixer \"%1\"") 53 .arg(device)); 54 return; 55 } 56 57 if (snd_mixer_selem_register(m_MixerHandle, NULL, NULL) < 0) 58 { 59 VERBOSE(VB_IMPORTANT, 60 QString("VolumeControlALSA::VolumeControlALSA() - ERROR: " 61 "registering mixer")); 62 return; 63 } 64 65 if (snd_mixer_load(m_MixerHandle) < 0) 66 { 67 VERBOSE(VB_IMPORTANT, 68 QString("VolumeControlALSA::VolumeControlALSA() - ERROR: " 69 "loading mixer")); 70 return; 71 } 72 73 for (m_MixerElement = snd_mixer_first_elem(m_MixerHandle); 74 m_MixerElement; 75 m_MixerElement = snd_mixer_elem_next(m_MixerElement)) 76 { 77 if (!snd_mixer_selem_is_active(m_MixerElement)) 78 continue; 79 80 if (!snd_mixer_selem_has_playback_volume(m_MixerElement)) 81 continue; 82 83 VERBOSE(VB_AUDIO, 84 QString("VolumeControlALSA::VolumeControlALSA() - " 85 "Using \"%1\"") 86 .arg(snd_mixer_selem_get_name(m_MixerElement))); 87 88 break; 89 } 90 91 if (!m_MixerElement) 92 { 93 VERBOSE(VB_IMPORTANT, 94 QString("VolumeControlALSA::VolumeControlALSA() - ERROR: " 95 "unable to find volume control")); 96 return; 97 } 98 99 long min, max; 100 snd_mixer_selem_get_playback_volume_range(m_MixerElement, &min, &max); 101 m_Range = std::min(std::max(1l, max - min), 100l); 102 103 snd_mixer_selem_set_playback_volume_range(m_MixerElement, 0, 100); 104 105 snd_mixer_elem_set_callback_private(m_MixerElement, this); 106 snd_mixer_elem_set_callback(m_MixerElement, &event); 107 108 if (!pipe(m_Exit)) 109 start(); 110 } 111 112 VolumeControlALSA::~VolumeControlALSA() 113 { 114 if (isRunning()) 115 { 116 write(m_Exit[1], "", 1); 117 118 wait(); 119 120 close(m_Exit[0]); 121 close(m_Exit[1]); 122 } 123 124 if (m_MixerHandle) 125 snd_mixer_close(m_MixerHandle); 126 } 127 128 int VolumeControlALSA::volume() const 129 { 130 long volume = 0; 131 if (m_MixerElement) 132 { 133 if (snd_mixer_selem_has_playback_switch(m_MixerElement) || !mute()) 134 snd_mixer_selem_get_playback_volume(m_MixerElement, 135 SND_MIXER_SCHN_MONO, 136 &volume); 137 else 138 volume = m_Volume; 139 } 140 141 VERBOSE(VB_AUDIO, 142 QString("VolumeControlALSA::volume() = %1") 143 .arg(volume)); 144 145 return volume; 146 } 147 148 void VolumeControlALSA::setVolume(int volume) 149 { 150 VERBOSE(VB_AUDIO, 151 QString("VolumeControlALSA::setVolume(%1)") 152 .arg(volume)); 153 154 volume = std::min(std::max(0, volume), 100); 155 156 if (mute() && volume > VolumeControlALSA::volume()) 157 setMute(false); 158 159 if (m_MixerElement) 160 if (snd_mixer_selem_has_playback_switch(m_MixerElement) || !mute()) 161 snd_mixer_selem_set_playback_volume_all(m_MixerElement, 162 volume); 163 164 if (m_Volume.fetchAndStoreRelaxed(volume) != volume) 165 emit changedVolume(volume); 166 } 167 168 void VolumeControlALSA::increaseVolume() 169 { 170 setVolume((volume() * m_Range + 100) / m_Range); 171 } 172 173 void VolumeControlALSA::decreaseVolume() 174 { 175 setVolume((volume() * m_Range - 100) / m_Range); 176 } 177 178 bool VolumeControlALSA::mute() const 179 { 180 union { 181 int _switch; 182 long int _volume; 183 } playback; 184 185 playback._switch = true; 186 187 if (m_MixerElement) 188 { 189 if (snd_mixer_selem_has_playback_switch(m_MixerElement)) 190 snd_mixer_selem_get_playback_switch(m_MixerElement, 191 SND_MIXER_SCHN_MONO, 192 &playback._switch); 193 else 194 snd_mixer_selem_get_playback_volume(m_MixerElement, 195 SND_MIXER_SCHN_MONO, 196 &playback._volume); 197 } 198 199 VERBOSE(VB_AUDIO, 200 QString("VolumeControlALSA::mute() = %1") 201 .arg(!playback._switch ? "mute" : "unmute")); 202 203 return !playback._switch; 204 } 205 206 void VolumeControlALSA::setMute(bool mute) 207 { 208 VERBOSE(VB_AUDIO, 209 QString("VolumeControlALSA::setMute(%1)") 210 .arg(mute ? "mute" : "unmute")); 211 212 if (m_MixerElement) 213 { 214 if (snd_mixer_selem_has_playback_switch(m_MixerElement)) 215 snd_mixer_selem_set_playback_switch_all(m_MixerElement, 216 !mute); 217 else 218 snd_mixer_selem_set_playback_volume_all(m_MixerElement, 219 mute ? 0 : static_cast<int>(m_Volume)); 220 } 221 222 if (m_Mute.fetchAndStoreRelaxed(mute) != mute) 223 emit changedMute(mute); 224 } 225 226 // static 227 int VolumeControlALSA::event(snd_mixer_elem_t* elem, unsigned int mask) 228 { 229 VERBOSE(VB_AUDIO, 230 QString("VolumeControlALSA::event(%1)") 231 .arg(mask)); 232 233 VolumeControlALSA* that = 234 static_cast<VolumeControlALSA*>(snd_mixer_elem_get_callback_private(elem)); 235 236 if (mask == SND_CTL_EVENT_MASK_REMOVE) 237 { 238 that->m_MixerElement = NULL; 239 return 0; 240 } 241 242 if (mask & SND_CTL_EVENT_MASK_VALUE) 243 { 244 int volume = that->volume(); 245 if (that->m_Volume.fetchAndStoreRelaxed(volume) != volume) 246 emit that->changedVolume(volume); 247 248 bool mute = that->mute(); 249 if (that->m_Mute.fetchAndStoreRelaxed(mute) != mute) 250 emit that->changedMute(mute); 251 } 252 253 return 0; 254 } 255 256 void VolumeControlALSA::run() 257 { 258 VERBOSE(VB_AUDIO, 259 QString("VolumeControlALSA::run() - begin")); 260 261 m_Volume = volume(); 262 m_Mute = mute(); 263 264 int poll_descriptors_count = -1; 265 struct pollfd* poll_descriptors = NULL; 266 267 for(;;) 268 { 269 int poll_descriptors_count_new = 270 snd_mixer_poll_descriptors_count(m_MixerHandle); 271 272 if (poll_descriptors_count_new < 0) 273 { 274 VERBOSE(VB_IMPORTANT, 275 QString("VolumeControlALSA::run() - ERROR: " 276 "snd_mixer_poll_descriptors_count")); 277 break; 278 } 279 280 if (poll_descriptors_count != poll_descriptors_count_new) 281 { 282 delete(poll_descriptors); 283 284 poll_descriptors_count = poll_descriptors_count_new; 285 poll_descriptors = new struct pollfd[poll_descriptors_count + 1]; 286 287 if (!poll_descriptors) 288 { 289 VERBOSE(VB_IMPORTANT, 290 QString("VolumeControlALSA::run() - ERROR: " 291 "malloc")); 292 break; 293 } 294 } 295 296 bzero(poll_descriptors, 297 poll_descriptors_count * sizeof (struct pollfd)); 298 299 poll_descriptors->fd = m_Exit[0]; 300 poll_descriptors->events = POLLIN; 301 302 if (snd_mixer_poll_descriptors(m_MixerHandle, 303 poll_descriptors + 1, 304 poll_descriptors_count) != 305 poll_descriptors_count) 306 { 307 VERBOSE(VB_IMPORTANT, 308 QString("VolumeControlALSA::run() - ERROR: " 309 "snd_mixer_poll_descriptors")); 310 break; 311 } 312 313 if (poll(poll_descriptors, poll_descriptors_count + 1, -1) < 0) 314 { 315 VERBOSE(VB_IMPORTANT, 316 QString("VolumeControlALSA::run() - ERROR: " 317 "poll %1") 318 .arg(errno)); 319 break; 320 } 321 322 if (poll_descriptors->revents & POLLIN) 323 break; 324 325 unsigned short revents; 326 if (snd_mixer_poll_descriptors_revents(m_MixerHandle, 327 poll_descriptors + 1, 328 poll_descriptors_count, 329 &revents) < 0) 330 { 331 VERBOSE(VB_IMPORTANT, 332 QString("VolumeControlALSA::run() - ERROR: " 333 "snd_mixer_poll_descriptors_revents")); 334 break; 335 } 336 337 if (revents & (POLLNVAL | POLLERR)) 338 { 339 VERBOSE(VB_IMPORTANT, 340 QString("VolumeControlALSA::run() - ERROR: " 341 "snd_mixer_poll_descriptors_revents")); 342 break; 343 } 344 345 if (snd_mixer_handle_events(m_MixerHandle) < 0) 346 { 347 VERBOSE(VB_IMPORTANT, 348 QString("VolumeControlALSA::run() - ERROR: " 349 "snd_mixer_handle_events")); 350 break; 351 } 352 } 353 354 delete(poll_descriptors); 355 356 VERBOSE(VB_AUDIO, 357 QString("VolumeControlALSA::run() - end")); 358 } -
libs/libmyth/audiooutputbase.h
18 18 #include "audiooutput.h" 19 19 #include "samplerate.h" 20 20 #include "mythverbose.h" 21 #include "volumecontrolmanager.h" 21 22 22 23 namespace soundtouch { 23 24 class SoundTouch; … … 47 48 48 49 virtual void Reset(void); 49 50 50 void SetSWVolume(int new_volume, bool save);51 int GetSWVolume(void);52 53 51 // timecode is in milliseconds. 54 52 virtual bool AddSamples(char *buffer, int samples, long long timecode); 55 53 virtual bool AddSamples(char *buffers[], int samples, long long timecode); … … 113 111 int audiolen(bool use_lock); // number of valid bytes in audio buffer 114 112 int audiofree(bool use_lock); // number of free bytes in audio buffer 115 113 116 void UpdateVolume(void);117 118 114 void SetStretchFactorLocked(float factor); 119 115 120 116 int GetBaseAudioTime() const { return audiotime; } … … 148 144 bool killaudio; 149 145 150 146 bool pauseaudio, audio_actually_paused, was_paused; 151 bool set_initial_vol;152 147 bool buffer_output_data_for_use; // used by AudioOutputNULL 153 148 154 149 int configured_audio_channels; … … 181 176 int surround_mode; 182 177 bool allow_ac3_passthru; 183 178 float old_audio_stretchfactor; 184 int volume;179 QSharedPointer<VolumeControl> volume_control; ///< Volume Control interface 185 180 186 181 bool blocking; // do AddSamples calls block? 187 182 -
libs/libmyth/audiooutputalsa.cpp
21 21 AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) : 22 22 AudioOutputBase(settings), 23 23 pcm_handle(NULL), 24 numbadioctls(0), 25 mixer_handle(NULL), 26 mixer_control(QString::null) 24 numbadioctls(0) 27 25 { 28 26 // Set everything up 29 27 Reconfigure(settings); … … 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 <cstdio>2 #include <cstdlib>3 4 #include <algorithm>5 using namespace std;6 7 #include <QString>8 9 #include "volumebase.h"10 #include "mythcontext.h"11 12 VolumeBase::VolumeBase() :13 internal_vol(false), volume(80),14 current_mute_state(kMuteOff)15 {16 swvol = swvol_setting =17 (gContext->GetSetting("MixerDevice", "default").toLower() == "software");18 }19 20 bool VolumeBase::SWVolume(void)21 {22 return swvol;23 }24 25 void VolumeBase::SWVolume(bool set)26 {27 if (swvol_setting)28 return;29 swvol = set;30 }31 32 uint VolumeBase::GetCurrentVolume(void) const33 {34 return volume;35 }36 37 void VolumeBase::SetCurrentVolume(int value)38 {39 volume = max(min(value, 100), 0);40 UpdateVolume();41 42 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");43 controlLabel += "MixerVolume";44 gContext->SaveSetting(controlLabel, volume);45 }46 47 void VolumeBase::AdjustCurrentVolume(int change)48 {49 SetCurrentVolume(volume + change);50 }51 52 MuteState VolumeBase::SetMuteState(MuteState mstate)53 {54 current_mute_state = mstate;55 UpdateVolume();56 return current_mute_state;57 }58 59 void VolumeBase::ToggleMute(void)60 {61 bool is_muted = GetMuteState() == kMuteAll;62 SetMuteState((is_muted) ? kMuteOff : kMuteAll);63 }64 65 MuteState VolumeBase::GetMuteState(void) const66 {67 return current_mute_state;68 }69 70 MuteState VolumeBase::NextMuteState(MuteState cur)71 {72 MuteState next = cur;73 74 switch (cur)75 {76 case kMuteOff:77 next = kMuteLeft;78 break;79 case kMuteLeft:80 next = kMuteRight;81 break;82 case kMuteRight:83 next = kMuteAll;84 break;85 case kMuteAll:86 next = kMuteOff;87 break;88 }89 90 return (next);91 }92 93 void VolumeBase::UpdateVolume(void)94 {95 int new_volume = volume;96 bool save = true;97 if (current_mute_state == kMuteAll)98 {99 new_volume = 0;100 save = false;101 }102 103 if (swvol)104 {105 SetSWVolume(new_volume, save);106 return;107 }108 109 // TODO: Avoid assumption that there are 2 channels!110 for (int i = 0; i < 2; i++)111 {112 SetVolumeChannel(i, new_volume);113 }114 115 // Individual channel muting is handled in GetAudioData,116 // this code demonstrates the old method.117 // if (current_mute_state == kMuteLeft)118 // {119 // SetVolumeChannel(0, 0);120 // }121 // else if (current_mute_state == kMuteRight)122 // {123 // SetVolumeChannel(1, 0);124 // }125 }126 127 void VolumeBase::SyncVolume(void)128 {129 // Read the volume from the audio driver and setup our internal state to match130 if (swvol)131 volume = GetSWVolume();132 else133 volume = GetVolumeChannel(0);134 }135 -
libs/libmyth/volumecontrolcoreaudio.h
1 #ifndef VOLUMECONTROLCOREAUDIO 2 #define VOLUMECONTROLCOREAUDIO 3 4 #include "volumecontrol.h" 5 6 #include <QHash> 7 #include <QAtomicInt> 8 #include <CoreAudio/CoreAudio.h> 9 10 11 class VolumeControlCoreAudio : public VolumeControl 12 { 13 public: 14 static QHash<QString, QString> Enumerate(); 15 16 public: 17 VolumeControlCoreAudio(QString device); 18 virtual ~VolumeControlCoreAudio(); 19 20 public: 21 int volume() const; 22 void setVolume(int volume); 23 void increaseVolume(); 24 void decreaseVolume(); 25 26 bool mute() const; 27 void setMute(bool mute); 28 29 protected: 30 static OSStatus event(AudioDeviceID deviceId, UInt32 channel, 31 Boolean input, AudioDevicePropertyID property, 32 void* context); 33 34 private: 35 AudioDeviceID m_DeviceId; //< Core Audio device ID 36 QAtomicInt m_Volume; //< Volume state cache 37 QAtomicInt m_Mute; //< Mute state cache 38 }; 39 40 #endif // VOLUMECONTROLCOREAUDIO -
libs/libmyth/volumecontrolsoftware.h
1 #ifndef VOLUMECONTROLSOFTWARE 2 #define VOLUMECONTROLSOFTWARE 3 4 #include "volumecontrol.h" 5 6 #include <QHash> 7 #include <QAtomicInt> 8 9 10 class VolumeControlSoftware : public VolumeControl 11 { 12 public: 13 static QHash<QString, QString> Enumerate(); 14 15 public: 16 VolumeControlSoftware(QString device); 17 virtual ~VolumeControlSoftware(); 18 19 public: 20 int volume() const; 21 void setVolume(int volume); 22 void increaseVolume(); 23 void decreaseVolume(); 24 25 bool mute() const; 26 void setMute(bool mute); 27 28 private: 29 static QAtomicInt m_Volume; //< Volume state cache 30 static QAtomicInt m_Mute; //< Mute state cache 31 }; 32 33 #endif // VOLUMECONTROLSOFTWARE -
libs/libmyth/volumecontrolcoreaudio.cpp
1 #include "volumecontrolcoreaudio.h" 2 3 #include <CoreServices/CoreServices.h> 4 #include <CoreAudio/CoreAudio.h> 5 6 #include "mythverbose.h" 7 #include <algorithm> 8 9 QHash<QString, QString> VolumeControlCoreAudio::Enumerate() 10 { 11 QHash<QString, QString> result; 12 13 result.insert("CoreAudio:default", "Default Core Audio device"); 14 15 UInt32 size; 16 AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, 17 &size, NULL); 18 UInt32 count = size / sizeof(AudioDeviceID); 19 20 AudioDeviceID* devices = new AudioDeviceID[count]; 21 AudioHardwareGetProperty(kAudioHardwarePropertyDevices, 22 &size, devices); 23 24 for (unsigned int index = 0; index < count; ++index) 25 { 26 bool output = false; 27 28 AudioDeviceGetPropertyInfo(devices[index], 0, 0, 29 kAudioDevicePropertyStreamConfiguration, 30 &size, NULL); 31 if (!size) 32 continue; 33 34 AudioBufferList* buffers = static_cast<AudioBufferList*>(malloc(size)); 35 AudioDeviceGetProperty(devices[index], 0, 0, 36 kAudioDevicePropertyStreamConfiguration, 37 &size, buffers); 38 for (UInt32 buffer = 0; buffer < buffers->mNumberBuffers; ++buffer) 39 { 40 if (buffers->mBuffers[buffer].mNumberChannels) 41 { 42 output = true; 43 break; 44 } 45 } 46 47 free(buffers); 48 49 if (!output) 50 continue; 51 52 QString uid; 53 CFStringRef uidcf; 54 size = sizeof(CFStringRef); 55 AudioDeviceGetProperty(devices[index], 0, 0, 56 kAudioDevicePropertyDeviceUID, 57 &size, &uidcf); 58 if (uidcf) 59 { 60 char buffer[256]; 61 CFStringGetCString(uidcf, buffer, 256, 62 CFStringGetFastestEncoding(uidcf)); 63 uid = QString(buffer); 64 CFRelease(uidcf); 65 } 66 67 AudioDeviceGetPropertyInfo(devices[index], 0, 0, 68 kAudioDevicePropertyDeviceName, 69 &size, NULL); 70 if (!size) 71 continue; 72 73 char* name = static_cast<char*>(malloc(size)); 74 AudioDeviceGetProperty(devices[index], 0, 0, 75 kAudioDevicePropertyDeviceName, 76 &size, name); 77 78 result.insert(QString("CoreAudio:") + uid, name); 79 80 free(name); 81 } 82 83 delete devices; 84 85 return result; 86 } 87 88 VolumeControlCoreAudio::VolumeControlCoreAudio(QString device) : 89 m_DeviceId(kAudioDeviceUnknown) 90 { 91 if (device == QString("default")) 92 { 93 UInt32 size = sizeof(AudioDeviceID); 94 AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, 95 &size, &m_DeviceId); 96 } 97 else 98 { 99 CFStringRef cfString = 100 CFStringCreateWithCharacters(kCFAllocatorDefault, 101 reinterpret_cast<const UniChar*>(device.unicode()), 102 device.length()); 103 104 AudioValueTranslation translateUidToId = { 105 mInputData: &cfString, 106 mInputDataSize: sizeof(CFStringRef), 107 mOutputData: &m_DeviceId, 108 mOutputDataSize: sizeof(AudioDeviceID) 109 }; 110 111 UInt32 translateUidToIdSize = sizeof(AudioValueTranslation); 112 AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, 113 &translateUidToIdSize, 114 &translateUidToId); 115 CFRelease(cfString); 116 } 117 118 AudioDeviceAddPropertyListener(m_DeviceId, 1, false, 119 kAudioDevicePropertyVolumeScalar, 120 &event, 121 this); 122 123 AudioDeviceAddPropertyListener(m_DeviceId, 1, false, 124 kAudioDevicePropertyVolumeDecibels, 125 &event, 126 this); 127 128 AudioDeviceAddPropertyListener(m_DeviceId, 0, false, 129 kAudioDevicePropertyMute, 130 &event, 131 this); 132 133 m_Volume = volume(); 134 m_Mute = mute(); 135 } 136 137 VolumeControlCoreAudio::~VolumeControlCoreAudio() 138 { 139 AudioDeviceRemovePropertyListener(m_DeviceId, 1, false, 140 kAudioDevicePropertyVolumeScalar, 141 &event); 142 143 AudioDeviceRemovePropertyListener(m_DeviceId, 1, false, 144 kAudioDevicePropertyVolumeDecibels, 145 &event); 146 147 AudioDeviceRemovePropertyListener(m_DeviceId, 0, false, 148 kAudioDevicePropertyMute, 149 &event); 150 } 151 152 int VolumeControlCoreAudio::volume() const 153 { 154 Float32 volume = 0; 155 156 if (!mute()) 157 { 158 UInt32 size = sizeof(Float32); 159 AudioDeviceGetProperty(m_DeviceId, 1, false, 160 kAudioDevicePropertyVolumeScalar, 161 &size, &volume); 162 } 163 else 164 volume = static_cast<Float32>(m_Volume) / 100.0f; 165 166 VERBOSE(VB_AUDIO, 167 QString("VolumeControlCoreAudio::volume() = %1") 168 .arg(static_cast<int>(100.0f * volume))); 169 170 return static_cast<int>(100.0f * volume); 171 } 172 173 void VolumeControlCoreAudio::setVolume(int volume) 174 { 175 VERBOSE(VB_AUDIO, 176 QString("VolumeControlCoreAudio::setVolume(%1)") 177 .arg(volume)); 178 179 volume = std::min(std::max(0, volume), 100); 180 181 if (mute() && volume > VolumeControlCoreAudio::volume()) 182 setMute(false); 183 184 if (!mute()) 185 { 186 Float32 value = static_cast<Float32>(volume) / 100.0f; 187 AudioDeviceSetProperty(m_DeviceId, NULL, 1, false, 188 kAudioDevicePropertyVolumeScalar, 189 sizeof(UInt32), &value); 190 } 191 192 if (m_Volume.fetchAndStoreRelaxed(volume) != volume) 193 emit changedVolume(volume); 194 } 195 196 void VolumeControlCoreAudio::increaseVolume() 197 { 198 setVolume(volume() + 10); 199 } 200 201 void VolumeControlCoreAudio::decreaseVolume() 202 { 203 setVolume(volume() - 10); 204 } 205 206 bool VolumeControlCoreAudio::mute() const 207 { 208 UInt32 mute = false; 209 210 UInt32 size = sizeof(UInt32); 211 AudioDeviceGetProperty(m_DeviceId, 0, false, 212 kAudioDevicePropertyMute, &size, &mute); 213 214 VERBOSE(VB_AUDIO, 215 QString("VolumeControlCoreAudio::mute() = %1") 216 .arg(mute ? "mute" : "unmute")); 217 218 return mute; 219 } 220 221 void VolumeControlCoreAudio::setMute(bool mute) 222 { 223 VERBOSE(VB_AUDIO, 224 QString("VolumeControlCoreAudio::setMute(%1)") 225 .arg(mute ? "mute" : "unmute")); 226 227 if (VolumeControlCoreAudio::mute()) 228 { 229 Float32 value = static_cast<Float32>(m_Volume) / 100.0f; 230 AudioDeviceSetProperty(m_DeviceId, NULL, 1, false, 231 kAudioDevicePropertyVolumeScalar, 232 sizeof(UInt32), &value); 233 } 234 235 UInt32 value = mute; 236 AudioDeviceSetProperty(m_DeviceId, NULL, 0, false, 237 kAudioDevicePropertyMute, sizeof(UInt32), &value); 238 239 if (m_Mute.fetchAndStoreRelaxed(mute) != mute) 240 emit changedMute(mute); 241 } 242 243 // static 244 OSStatus VolumeControlCoreAudio::event(AudioDeviceID deviceId, UInt32 channel, 245 Boolean input, 246 AudioDevicePropertyID property, 247 void* context) 248 { 249 VolumeControlCoreAudio* that = 250 static_cast<VolumeControlCoreAudio*>(context); 251 252 if (deviceId == that->m_DeviceId && !input) 253 switch(property) 254 { 255 case kAudioDevicePropertyVolumeScalar: 256 case kAudioDevicePropertyVolumeDecibels: 257 int volume = that->volume(); 258 if (that->m_Volume.fetchAndStoreRelaxed(volume) != volume) 259 emit that->changedVolume(volume); 260 break; 261 262 case kAudioDevicePropertyMute: 263 bool mute = that->mute(); 264 if (that->m_Mute.fetchAndStoreRelaxed(mute) != mute) 265 emit that->changedMute(mute); 266 break; 267 } 268 269 return noErr; 270 } -
libs/libmyth/volumebase.h
1 #ifndef __VOLUME_BASE__2 #define __VOLUME_BASE__3 4 #include "mythexp.h"5 6 typedef enum {7 kMuteOff = 0,8 kMuteLeft,9 kMuteRight,10 kMuteAll,11 } MuteState;12 13 class MPUBLIC VolumeBase14 {15 public:16 VolumeBase();17 virtual ~VolumeBase() {};18 19 void SWVolume(bool set);20 bool SWVolume(void);21 virtual uint GetCurrentVolume(void) const;22 virtual void SetCurrentVolume(int value);23 virtual void AdjustCurrentVolume(int change);24 virtual void ToggleMute(void);25 26 virtual MuteState GetMuteState(void) const;27 virtual MuteState SetMuteState(MuteState);28 29 static MuteState NextMuteState(MuteState);30 31 protected:32 33 virtual int GetVolumeChannel(int channel) const = 0; // Returns 0-10034 virtual void SetVolumeChannel(int channel, int volume) = 0; // range 0-100 for vol35 virtual void SetSWVolume(int new_volume, bool save) = 0;36 virtual int GetSWVolume(void) = 0;37 38 void UpdateVolume(void);39 void SyncVolume(void);40 41 bool internal_vol;42 43 private:44 45 int volume;46 MuteState current_mute_state;47 bool swvol;48 bool swvol_setting;49 50 };51 52 #endif // __VOLUME_BASE__ -
libs/libmyth/volumecontrol.h
1 #ifndef VOLUMECONTROL 2 #define VOLUMECONTROL 3 4 #include <QObject> 5 #include <QString> 6 7 class VolumeControl : public QObject 8 { 9 Q_OBJECT 10 11 public: 12 virtual int volume() const = 0; 13 virtual void setVolume(int volume) = 0; 14 virtual void increaseVolume() = 0; 15 virtual void decreaseVolume() = 0; 16 17 virtual bool mute() const = 0; 18 virtual void setMute(bool mute) = 0; 19 20 signals: 21 void changedVolume(int volume); 22 void changedMute(bool mute); 23 }; 24 25 #endif // VOLUMECONTROL -
libs/libmyth/volumecontrolsoftware.cpp
1 #include "volumecontrolsoftware.h" 2 3 #include "mythcontext.h" 4 #include "mythverbose.h" 5 #include <algorithm> 6 7 QHash<QString, QString> VolumeControlSoftware::Enumerate() 8 { 9 QHash<QString, QString> result; 10 11 result.insert("Software:", "Software Volume Processing"); 12 13 return result; 14 } 15 16 VolumeControlSoftware::VolumeControlSoftware(QString device) 17 { 18 int volume = gContext->GetNumSetting("SoftwareVolume", 80); 19 m_Volume = std::min(std::max(0, volume), 100); 20 m_Mute = gContext->GetNumSetting("SoftwareMute", false) ? true : false; 21 } 22 23 VolumeControlSoftware::~VolumeControlSoftware() 24 { 25 26 } 27 28 int VolumeControlSoftware::volume() const 29 { 30 int volume = m_Volume; 31 32 VERBOSE(VB_AUDIO, 33 QString("VolumeControlSoftware::volume() = %1") 34 .arg(volume)); 35 36 return volume; 37 } 38 39 void VolumeControlSoftware::setVolume(int volume) 40 { 41 VERBOSE(VB_AUDIO, 42 QString("VolumeControlSoftware::setVolume(%1)") 43 .arg(volume)); 44 45 volume = std::min(std::max(0, volume), 100); 46 47 if (m_Volume.fetchAndStoreRelaxed(volume) != volume) 48 { 49 gContext->SaveSetting("SoftwareVolume", volume); 50 emit changedVolume(volume); 51 } 52 } 53 54 void VolumeControlSoftware::increaseVolume() 55 { 56 setVolume(volume() + 1); 57 } 58 59 void VolumeControlSoftware::decreaseVolume() 60 { 61 setVolume(volume() - 1); 62 } 63 64 bool VolumeControlSoftware::mute() const 65 { 66 bool mute = m_Mute ? true : false; 67 68 VERBOSE(VB_AUDIO, 69 QString("VolumeControlSoftware::mute() = %1") 70 .arg(mute ? "mute" : "unmute")); 71 72 return mute; 73 } 74 75 void VolumeControlSoftware::setMute(bool mute) 76 { 77 VERBOSE(VB_AUDIO, 78 QString("VolumeControlSoftware::setMute(%1)") 79 .arg(mute ? "mute" : "unmute")); 80 81 if (m_Mute.fetchAndStoreRelaxed(mute) != mute) 82 { 83 gContext->SaveSetting("SoftwareMute", mute); 84 emit changedMute(mute); 85 } 86 } 87 88 QAtomicInt VolumeControlSoftware::m_Volume; 89 QAtomicInt VolumeControlSoftware::m_Mute; -
libs/libmyth/audiooutputpulse.h
30 30 AudioOutputPulseAudio(const AudioSettings &settings); 31 31 ~AudioOutputPulseAudio(); 32 32 33 int GetVolumeChannel(int channel) const;34 void SetVolumeChannel(int channel, int volume);35 33 void Pause(bool paused); 36 34 void Reset(void); 37 35 void Drain(void); -
libs/libmyth/volumecontroloss.h
1 #ifndef VOLUMECONTROLOSS 2 #define VOLUMECONTROLOSS 3 4 #include "volumecontrol.h" 5 6 #include <QHash> 7 #include <QThread> 8 #include <QAtomicInt> 9 10 11 class VolumeControlOSS : public VolumeControl, protected QThread 12 { 13 public: 14 static QHash<QString, QString> Enumerate(); 15 16 public: 17 VolumeControlOSS(QString device); 18 virtual ~VolumeControlOSS(); 19 20 public: 21 int volume() const; 22 void setVolume(int volume); 23 void increaseVolume(); 24 void decreaseVolume(); 25 26 bool mute() const; 27 void setMute(bool mute); 28 29 protected: 30 virtual void run(); 31 32 private: 33 int m_Mixer; //< OSS mixer file descriptor 34 int m_MixerDev; //< OSS mixer device ID 35 int m_VolumeCtrl; //< OSS control ID for volume 36 int m_VolumeMax; //< OSS maximum for volume 37 int m_VolumeType; //< OSS control type for volume 38 int m_VolumeTimestamp; //< OSS timestamp for volume 39 int m_MuteCtrl; //< OSS control ID for mute 40 int m_MuteTimestamp; //< OSS timestamp for mute 41 int m_Range; //< Range of volume control 42 volatile bool m_Exit; //< Flag to notify thread to exit 43 QAtomicInt m_Volume; //< Volume state cache 44 QAtomicInt m_Mute; //< Mute state cache 45 }; 46 47 #endif // VOLUMECONTROLOSS -
libs/libmyth/volumecontrolalsa.h
1 #ifndef VOLUMECONTROLALSA 2 #define VOLUMECONTROLALSA 3 4 #include "volumecontrol.h" 5 6 #include <QHash> 7 #include <QThread> 8 #include <QAtomicInt> 9 #include <alsa/asoundlib.h> 10 11 12 class VolumeControlALSA : public VolumeControl, protected QThread 13 { 14 public: 15 static QHash<QString, QString> Enumerate(); 16 17 public: 18 VolumeControlALSA(QString device); 19 virtual ~VolumeControlALSA(); 20 21 public: 22 int volume() const; 23 void setVolume(int volume); 24 void increaseVolume(); 25 void decreaseVolume(); 26 27 bool mute() const; 28 void setMute(bool mute); 29 30 protected: 31 virtual void run(); 32 33 static int event(snd_mixer_elem_t* elem, unsigned int mask); 34 35 private: 36 snd_mixer_t* m_MixerHandle; //< ALSA mixer handle 37 snd_mixer_elem_t* m_MixerElement; //< ALSA mixer element handle 38 int m_Range; //< Range of mixer element 39 int m_Exit[2]; //< Pipe file descriptors 40 QAtomicInt m_Volume; //< Volume state cache 41 QAtomicInt m_Mute; //< Mute state cache 42 }; 43 44 #endif // VOLUMECONTROLALSA -
libs/libmyth/audiooutputpulse.cpp
268 268 return writable; 269 269 } 270 270 271 int AudioOutputPulseAudio::GetVolumeChannel(int channel) const272 {273 return (float)volume_control.values[channel]274 / (float)PA_VOLUME_NORM * 100.0f;275 }276 277 void AudioOutputPulseAudio::SetVolumeChannel(int channel, int volume)278 {279 QString fn_log_tag = "SetVolumeChannel, ";280 if (channel < 0 || channel > PULSE_MAX_CHANNELS || volume < 0)281 {282 VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +283 QString("bad volume params, channel %1, volume %2")284 .arg(channel).arg(volume));285 return;286 }287 volume_control.values[channel] =288 (float)volume / 100.0f * (float)PA_VOLUME_NORM;289 volume = min(100, volume);290 volume = max(0, volume);291 uint32_t sink_index = pa_stream_get_device_index(pstream);292 pa_threaded_mainloop_lock(mainloop);293 pa_operation *op =294 pa_context_set_sink_volume_by_index(pcontext, sink_index,295 &volume_control,296 OpCompletionCallback, this);297 pa_threaded_mainloop_unlock(mainloop);298 if (op)299 pa_operation_unref(op);300 else301 VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +302 QString("set sink volume operation failed, sink: %1, "303 "error: %2 ")304 .arg(sink_index)305 .arg(pa_strerror(pa_context_errno(pcontext))));306 }307 308 271 void AudioOutputPulseAudio::Pause(bool paused) 309 272 { 310 273 pa_operation *op; … … 545 508 pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over"); 546 509 pa_stream_set_underflow_callback(pstream, BufferFlowCallback, 547 510 (char*)"under"); 548 if (set_initial_vol) 549 { 550 int volume = gContext->GetNumSetting("MasterMixerVolume", 80); 551 pa_cvolume_set(&volume_control, audio_channels, 552 (float)volume * (float)PA_VOLUME_NORM / 100.0f); 553 } 554 else 555 pa_cvolume_reset(&volume_control, audio_channels); 511 pa_cvolume_reset(&volume_control, audio_channels); 556 512 557 513 // set myth sizes and pa buffer metrics 558 514 fragment_size = (float)sample_rate * 0.020f * // 20msec -
libs/libmyth/volumecontrolendpoint.cpp
1 #include "volumecontrolendpoint.h" 2 3 #include "mythverbose.h" 4 #include <algorithm> 5 #include <math.h> 6 7 typedef struct _BYTE_BLOB 8 { 9 unsigned long clSize; 10 byte abData[ 1 ]; 11 } BYTE_BLOB; 12 13 typedef struct _tagpropertykey 14 { 15 GUID fmtid; 16 DWORD pid; 17 } PROPERTYKEY; 18 19 #define REFPROPVARIANT const PROPVARIANT & 20 21 inline void PropVariantInit ( PROPVARIANT * pvar ) 22 { 23 memset ( pvar, 0, sizeof(PROPVARIANT) ); 24 } 25 WINOLEAPI PropVariantClear ( PROPVARIANT * pvar ); 26 27 EXTERN_C const CLSID CLSID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C,{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}}; 28 EXTERN_C const IID IID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35,{0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}}; 29 EXTERN_C const IID IID_IAudioEndpointVolume = {0x5CDF2C82,0x841E,0x4546,{0x97,0x22,0x0C,0xF7,0x40,0x78,0x22,0x9A}}; 30 EXTERN_C const IID IID_IAudioEndpointVolumeCallback = {0x657804FA,0xD6AD,0x4496,{0x8A,0x60,0x35,0x27,0x52,0xAF,0x4F,0x89}}; 31 EXTERN_C const IID IID_IUnknown = {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}; 32 #define INITGUID 33 #include <Unknwn.h> 34 #include <mmdeviceapi.h> 35 #include <FunctionDiscoveryKeys_devpkey.h> 36 37 38 QHash<QString, QString> VolumeControlEndpoint::Enumerate() 39 { 40 QHash<QString, QString> result; 41 42 HRESULT hr = S_OK; 43 IMMDeviceEnumerator* pEnumerator = NULL; 44 IMMDeviceCollection* pCollection = NULL; 45 46 CoInitialize(NULL); 47 48 // Get enumerator for audio endpoint devices. 49 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, 50 NULL, CLSCTX_INPROC_SERVER, 51 IID_IMMDeviceEnumerator, 52 (void**)&pEnumerator); 53 if (!SUCCEEDED(hr) || !pEnumerator) 54 { 55 CoUninitialize(); 56 return result; 57 } 58 59 result.insert("Endpoint:default", "Default End Point device"); 60 61 hr = pEnumerator->EnumAudioEndpoints(eRender, 62 DEVICE_STATE_ACTIVE, 63 &pCollection); 64 if (!SUCCEEDED(hr) || !pCollection) 65 { 66 pEnumerator->Release(); 67 CoUninitialize(); 68 return result; 69 } 70 71 UINT devices = 0; 72 hr = pCollection->GetCount(&devices); 73 if (!SUCCEEDED(hr)) 74 { 75 pCollection->Release(); 76 pEnumerator->Release(); 77 CoUninitialize(); 78 return result; 79 } 80 81 for (UINT device = 0; device < devices; ++device) 82 { 83 IMMDevice* pDevice = NULL; 84 hr = pCollection->Item(device, &pDevice); 85 if (!SUCCEEDED(hr) || !pDevice) 86 continue; 87 88 LPWSTR pwszID = NULL; 89 hr = pDevice->GetId(&pwszID); 90 if (!SUCCEEDED(hr)) 91 { 92 pDevice->Release(); 93 continue; 94 } 95 QString uid(reinterpret_cast<const QChar*>(pwszID), wcslen(pwszID)); 96 CoTaskMemFree(pwszID); 97 98 IPropertyStore *pProps = NULL; 99 hr = pDevice->OpenPropertyStore(STGM_READ, &pProps); 100 if (!SUCCEEDED(hr) || !pProps) 101 { 102 pDevice->Release(); 103 continue; 104 } 105 106 PROPVARIANT varName; 107 PropVariantInit(&varName); 108 109 hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName); 110 if (!SUCCEEDED(hr)) 111 { 112 PropVariantClear(&varName); 113 pProps->Release(); 114 pDevice->Release(); 115 continue; 116 } 117 QString name(reinterpret_cast<const QChar*>(varName.pwszVal), 118 wcslen(varName.pwszVal)); 119 PropVariantClear(&varName); 120 121 pProps->Release(); 122 pDevice->Release(); 123 124 result.insert(QString("Endpoint:") + uid, name); 125 } 126 127 pCollection->Release(); 128 pEnumerator->Release(); 129 130 CoUninitialize(); 131 132 return result; 133 } 134 135 VolumeControlEndpoint::VolumeControlEndpoint(QString device) : 136 m_EndpointVolume(NULL) 137 { 138 HRESULT hr = S_OK; 139 IMMDeviceEnumerator* pEnumerator = NULL; 140 IMMDevice* pDevice = NULL; 141 142 CoInitialize(NULL); 143 144 // Get enumerator for audio endpoint devices. 145 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, 146 NULL, CLSCTX_INPROC_SERVER, 147 IID_IMMDeviceEnumerator, 148 (void**)&pEnumerator); 149 if (!SUCCEEDED(hr) || !pEnumerator) 150 return; 151 152 if (device == QString("default")) 153 hr = pEnumerator->GetDefaultAudioEndpoint(eRender, 154 eMultimedia, 155 &pDevice); 156 else 157 hr = pEnumerator->GetDevice((LPCWSTR)device.constData(), &pDevice); 158 159 if (!SUCCEEDED(hr) || !pDevice) 160 { 161 pEnumerator->Release(); 162 return; 163 } 164 165 hr = pDevice->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, 166 NULL, (void**)&m_EndpointVolume); 167 if (!SUCCEEDED(hr) || !m_EndpointVolume) 168 { 169 pDevice->Release(); 170 pEnumerator->Release(); 171 return; 172 } 173 174 pDevice->Release(); 175 pEnumerator->Release(); 176 177 hr = m_EndpointVolume->RegisterControlChangeNotify(this); 178 if (!SUCCEEDED(hr)) 179 return; 180 181 UINT step, count; 182 hr = m_EndpointVolume->GetVolumeStepInfo(&step, &count); 183 if (!SUCCEEDED(hr)) 184 return; 185 186 m_Range = std::min(std::max(1U, count - 1), 100U); 187 188 m_Volume = volume(); 189 m_Mute = mute(); 190 } 191 192 VolumeControlEndpoint::~VolumeControlEndpoint() 193 { 194 if (m_EndpointVolume) 195 { 196 m_EndpointVolume->UnregisterControlChangeNotify(this); 197 m_EndpointVolume->Release(); 198 } 199 200 CoUninitialize(); 201 } 202 203 int VolumeControlEndpoint::volume() const 204 { 205 int volume = 0; 206 207 if (!mute()) 208 { 209 if (m_EndpointVolume) 210 { 211 float level; 212 m_EndpointVolume->GetMasterVolumeLevelScalar(&level); 213 volume = static_cast<int>(round(level * 100.0f)); 214 } 215 } 216 else 217 volume = m_Volume; 218 219 VERBOSE(VB_AUDIO, 220 QString("VolumeControlEndpoint::volume() = %1") 221 .arg(volume)); 222 223 return volume; 224 } 225 226 void VolumeControlEndpoint::setVolume(int volume) 227 { 228 VERBOSE(VB_AUDIO, 229 QString("VolumeControlEndpoint::setVolume(%1)") 230 .arg(volume)); 231 232 volume = std::min(std::max(0, volume), 100); 233 234 if (mute() && volume > VolumeControlEndpoint::volume()) 235 setMute(false); 236 237 if (!mute() && m_EndpointVolume) 238 m_EndpointVolume->SetMasterVolumeLevelScalar( 239 round(static_cast<float>(volume * m_Range) / 100.0f) / 240 static_cast<float>(m_Range), NULL); 241 242 if (m_Volume.fetchAndStoreRelaxed(volume) != volume) 243 emit changedVolume(volume); 244 } 245 246 void VolumeControlEndpoint::increaseVolume() 247 { 248 int volume = VolumeControlEndpoint::volume(); 249 float level = (round(static_cast<float>(volume * m_Range) / 100.0f) + 1.0f) 250 / static_cast<float>(m_Range); 251 volume = static_cast<int>(round(level * 100.0f)); 252 setVolume(volume); 253 } 254 255 void VolumeControlEndpoint::decreaseVolume() 256 { 257 int volume = VolumeControlEndpoint::volume(); 258 float level = (round(static_cast<float>(volume * m_Range) / 100.0f) - 1.0f) 259 / static_cast<float>(m_Range); 260 volume = static_cast<int>(round(level * 100.0f)); 261 setVolume(volume); 262 } 263 264 bool VolumeControlEndpoint::mute() const 265 { 266 BOOL mute = FALSE; 267 268 if (m_EndpointVolume) 269 m_EndpointVolume->GetMute(&mute); 270 271 VERBOSE(VB_AUDIO, 272 QString("VolumeControlEndpoint::mute() = %1") 273 .arg(mute ? "mute" : "unmute")); 274 275 return mute; 276 } 277 278 void VolumeControlEndpoint::setMute(bool mute) 279 { 280 VERBOSE(VB_AUDIO, 281 QString("VolumeControlEndpoint::setMute(%1)") 282 .arg(mute ? "mute" : "unmute")); 283 284 if (m_EndpointVolume) 285 { 286 if (VolumeControlEndpoint::mute()) 287 m_EndpointVolume->SetMasterVolumeLevelScalar( 288 static_cast<float>(m_Volume) / 100.0f, NULL); 289 290 m_EndpointVolume->SetMute(mute, NULL); 291 } 292 293 if (m_Mute.fetchAndStoreRelaxed(mute) != mute) 294 emit changedMute(mute); 295 } 296 297 ULONG STDMETHODCALLTYPE VolumeControlEndpoint::AddRef() 298 { 299 return 1; 300 } 301 302 ULONG STDMETHODCALLTYPE VolumeControlEndpoint::Release() 303 { 304 return 0; 305 } 306 307 HRESULT STDMETHODCALLTYPE 308 VolumeControlEndpoint::QueryInterface(REFIID riid, VOID **ppvInterface) 309 { 310 if (IID_IUnknown == riid) 311 { 312 AddRef(); 313 *ppvInterface = (IUnknown*)this; 314 } 315 else if (IID_IAudioEndpointVolumeCallback == riid) 316 { 317 AddRef(); 318 *ppvInterface = (IAudioEndpointVolumeCallback*)this; 319 } 320 else 321 { 322 *ppvInterface = NULL; 323 return E_NOINTERFACE; 324 } 325 return S_OK; 326 } 327 328 HRESULT STDMETHODCALLTYPE 329 VolumeControlEndpoint::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) 330 { 331 HRESULT hr = E_INVALIDARG; 332 333 if (pNotify) 334 { 335 int volume = VolumeControlEndpoint::volume(); 336 if (m_Volume.fetchAndStoreRelaxed(volume) != volume) 337 emit changedVolume(volume); 338 339 bool mute = VolumeControlEndpoint::mute(); 340 if (m_Mute.fetchAndStoreRelaxed(mute) != mute) 341 emit changedMute(mute); 342 343 hr = S_OK; 344 } 345 346 return hr; 347 } -
libs/libmyth/audiooutputjack.h
11 11 AudioOutputJACK(const AudioSettings &settings); 12 12 virtual ~AudioOutputJACK(); 13 13 14 // Volume control15 virtual int GetVolumeChannel(int channel) const; // Returns 0-10016 virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol17 18 14 protected: 19 15 20 16 // You need to implement the following functions … … 27 23 28 24 private: 29 25 30 void VolumeInit(void);31 32 26 int audioid; 33 27 34 28 }; -
libs/libmyth/audiosettings.cpp
15 15 channels(-1), 16 16 codec(0), 17 17 samplerate(-1), 18 set_initial_vol(false),19 18 use_passthru(false), 20 19 source(AUDIOOUTPUT_UNKNOWN), 21 20 upmixer(0) … … 29 28 channels(other.channels), 30 29 codec(other.codec), 31 30 samplerate(other.samplerate), 32 set_initial_vol(other.set_initial_vol),33 31 use_passthru(other.use_passthru), 34 32 source(other.source), 35 33 upmixer(other.upmixer) … … 44 42 int audio_codec, 45 43 int audio_samplerate, 46 44 AudioOutputSource audio_source, 47 bool audio_set_initial_vol,48 45 bool audio_use_passthru, 49 46 int upmixer_startup) : 50 47 main_device(audio_main_device), … … 53 50 channels(audio_channels), 54 51 codec(audio_codec), 55 52 samplerate(audio_samplerate), 56 set_initial_vol(audio_set_initial_vol),57 53 use_passthru(audio_use_passthru), 58 54 source(audio_source), 59 55 upmixer(upmixer_startup) … … 73 69 channels(audio_channels), 74 70 codec(audio_codec), 75 71 samplerate(audio_samplerate), 76 set_initial_vol(false),77 72 use_passthru(audio_use_passthru), 78 73 source(AUDIOOUTPUT_UNKNOWN), 79 74 upmixer(upmixer_startup) -
libs/libmyth/audiooutputca.cpp
244 244 return false; 245 245 } 246 246 247 if (internal_vol && set_initial_vol)248 {249 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");250 controlLabel += "MixerVolume";251 SetCurrentVolume(gContext->GetNumSetting(controlLabel, 80));252 }253 254 247 return true; 255 248 } 256 249 … … 399 392 return noErr; 400 393 } 401 394 402 int AudioOutputCA::GetVolumeChannel(int channel) const403 {404 // FIXME: this only returns global volume405 (void)channel;406 Float32 volume;407 408 if (!AudioUnitGetParameter(d->mOutputUnit,409 kHALOutputParam_Volume,410 kAudioUnitScope_Global, 0, &volume))411 return (int)lroundf(volume * 100.0);412 413 return 0; // error case414 }415 416 void AudioOutputCA::SetVolumeChannel(int channel, int volume)417 {418 // FIXME: this only sets global volume419 (void)channel;420 AudioUnitSetParameter(d->mOutputUnit, kHALOutputParam_Volume,421 kAudioUnitScope_Global, 0, (volume * 0.01), 0);422 }423 424 395 // IOProc style callback for SPDIF audio output 425 396 static OSStatus RenderCallbackSPDIF(AudioDeviceID inDevice, 426 397 const AudioTimeStamp *inNow, -
libs/libmyth/audiooutputwin.h
13 13 AudioOutputWin(const AudioSettings &settings); 14 14 virtual ~AudioOutputWin(); 15 15 16 // Volume control17 virtual int GetVolumeChannel(int channel) const;18 virtual void SetVolumeChannel(int channel, int volume);19 20 16 protected: 21 17 virtual bool OpenDevice(void); 22 18 virtual void CloseDevice(void); -
libs/libmyth/audiooutputjack.cpp
148 148 audio_buffer_unused = JACK_GetBytesFreeSpace(audioid); 149 149 JACK_SetPosition(audioid, BYTES, 0); 150 150 151 // Setup volume control152 if (internal_vol)153 VolumeInit();154 155 151 // Device opened successfully 156 152 return true; 157 153 } … … 206 202 207 203 return space; 208 204 } 209 210 void AudioOutputJACK::VolumeInit(void)211 {212 int volume = 100;213 if (set_initial_vol)214 volume = gContext->GetNumSetting("MasterMixerVolume", 80);215 216 JACK_SetAllVolume(audioid, volume);217 }218 219 int AudioOutputJACK::GetVolumeChannel(int channel) const220 {221 unsigned int vol = 0;222 223 if (!internal_vol)224 return 100;225 226 JACK_GetVolumeForChannel(audioid, channel, &vol);227 return vol;228 }229 230 void AudioOutputJACK::SetVolumeChannel(int channel, int volume)231 {232 if (internal_vol)233 JACK_SetVolumeForChannel(audioid, channel, volume);234 }235 -
libs/libmyth/audiooutputoss.h
12 12 AudioOutputOSS(const AudioSettings &settings); 13 13 virtual ~AudioOutputOSS(); 14 14 15 // Volume control16 virtual int GetVolumeChannel(int channel) const;17 virtual void SetVolumeChannel(int channel, int volume);18 19 15 protected: 20 16 // You need to implement the following functions 21 17 virtual bool OpenDevice(void); … … 26 22 vector<int> GetSupportedRates(void); 27 23 28 24 private: 29 void VolumeInit(void);30 void VolumeCleanup(void);31 32 25 void SetFragSize(void); 33 26 34 27 int audiofd; 35 28 mutable int numbadioctls; 36 37 // Volume related38 int mixerfd;39 int control;40 29 }; 41 30 42 31 #endif -
libs/libmyth/audiooutputbase.cpp
37 37 pauseaudio(false), audio_actually_paused(false), 38 38 was_paused(false), 39 39 40 set_initial_vol(settings.set_initial_vol),41 40 buffer_output_data_for_use(false), 42 41 43 42 // private … … 54 53 needs_upmix(false), 55 54 surround_mode(FreeSurround::SurroundModePassive), 56 55 old_audio_stretchfactor(1.0), 57 volume(80),58 56 59 57 blocking(false), 60 58 … … 109 107 110 108 allow_ac3_passthru = (orig_config_channels > 2) ? gContext->GetNumSetting("AC3PassThru", false) : false; 111 109 110 if (gContext->GetSetting("MixerDevice") == "Software:") 111 volume_control = VolumeControlManager::GetControl("Software:"); 112 112 113 // You need to call Reconfigure from your concrete class. 113 114 // Reconfigure(laudio_bits, laudio_channels, 114 115 // laudio_samplerate, laudio_passthru); … … 278 279 killaudio = false; 279 280 pauseaudio = false; 280 281 was_paused = true; 281 internal_vol = gContext->GetNumSetting("MythControlsVolume", 0);282 282 283 283 numlowbuffer = 0; 284 284 … … 358 358 return; 359 359 } 360 360 361 // Only used for software volume362 if (set_initial_vol && internal_vol)363 volume = gContext->GetNumSetting("PCMMixerVolume", 80);364 {365 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");366 controlLabel += "MixerVolume";367 volume = gContext->GetNumSetting(controlLabel, 80);368 }369 370 SyncVolume();371 VolumeBase::UpdateVolume();372 373 361 VERBOSE(VB_AUDIO, LOC + QString("Audio fragment size: %1") 374 362 .arg(fragment_size)); 375 363 … … 663 651 return audbuf_timecode - GetAudiotime(); 664 652 } 665 653 666 void AudioOutputBase::SetSWVolume(int new_volume, bool save)667 {668 volume = new_volume;669 if (save)670 {671 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");672 controlLabel += "MixerVolume";673 gContext->SaveSetting(controlLabel, volume);674 }675 }676 677 int AudioOutputBase::GetSWVolume()678 {679 return volume;680 }681 682 654 void AudioOutputBase::AdjustVolume(void *buffer, int len, bool music) 683 655 { 684 656 if (audio_bits == 8) … … 690 662 template <class AudioDataType> 691 663 void AudioOutputBase::_AdjustVolume(AudioDataType *buffer, int len, bool music) 692 664 { 665 int volume = volume_control->mute() ? 0 : volume_control->volume(); 666 693 667 float g = volume / 100.0; 694 668 695 669 // Should probably be exponential - this'll do … … 1098 1072 } 1099 1073 } 1100 1074 1101 if ( internal_vol && SWVolume())1075 if (volume_control) 1102 1076 { 1103 1077 int bdiff = kAudioRingBufferSize - waud; 1104 1078 bool music = (timecode < 1); … … 1359 1333 audio_buflock.unlock(); 1360 1334 1361 1335 // Mute individual channels through mono->stereo duplication 1362 MuteState mute_state = GetMuteState();1336 // MuteState mute_state = GetMuteState(); 1363 1337 if (written_size && 1364 audio_channels > 1 && 1365 (mute_state == kMuteLeft || mute_state == kMuteRight)) 1338 audio_channels > 1 //&& 1339 // (mute_state == kMuteLeft || mute_state == kMuteRight) 1340 ) 1366 1341 { 1367 1342 int offset_src = 0; 1368 1343 int offset_dst = 0; 1369 1344 1370 if (mute_state == kMuteLeft)1371 offset_src = audio_bits / 8; // copy channel 1 to channel 01372 else if (mute_state == kMuteRight)1373 offset_dst = audio_bits / 8; // copy channel 0 to channel 11345 // if (mute_state == kMuteLeft) 1346 // offset_src = audio_bits / 8; // copy channel 1 to channel 0 1347 // else if (mute_state == kMuteRight) 1348 // offset_dst = audio_bits / 8; // copy channel 0 to channel 1 1374 1349 1375 1350 for (int i = 0; i < written_size; i += audio_bytes_per_sample) 1376 1351 { -
libs/libmyth/audiooutput.cpp
34 34 int audio_bits, int audio_channels, 35 35 int audio_codec, int audio_samplerate, 36 36 AudioOutputSource source, 37 bool set_initial_vol, boolaudio_passthru,37 bool audio_passthru, 38 38 int upmixer_startup) 39 39 { 40 40 AudioSettings settings( 41 41 main_device, passthru_device, audio_bits, 42 42 audio_channels, audio_codec, audio_samplerate, source, 43 set_initial_vol,audio_passthru, upmixer_startup);43 audio_passthru, upmixer_startup); 44 44 45 45 settings.FixPassThrough(); 46 46 -
libs/libmyth/libmyth.pro
23 23 HEADERS += output.h 24 24 HEADERS += settings.h 25 25 HEADERS += uilistbtntype.h uitypes.h util.h mythuifilebrowser.h 26 HEADERS += volumebase.h visual.h xmlparse.h 26 HEADERS += volumecontrol.h volumecontrolmanager.h volumecontrolsoftware.h 27 HEADERS += visual.h xmlparse.h 27 28 HEADERS += mythhdd.h mythcdrom.h storagegroup.h dbutil.h 28 29 HEADERS += mythcommandlineparser.h mythterminal.h 29 30 HEADERS += mythhttppool.h mythhttphandler.h … … 45 46 SOURCES += output.cpp 46 47 SOURCES += settings.cpp 47 48 SOURCES += uilistbtntype.cpp uitypes.cpp util.cpp mythuifilebrowser.cpp 48 SOURCES += volumebase.cpp xmlparse.cpp 49 SOURCES += volumecontrolmanager.cpp volumecontrolsoftware.cpp 50 SOURCES += xmlparse.cpp 49 51 SOURCES += mythhdd.cpp mythcdrom.cpp storagegroup.cpp dbutil.cpp 50 52 SOURCES += mythcommandlineparser.cpp mythterminal.cpp 51 53 SOURCES += mythhttppool.cpp mythhttphandler.cpp … … 83 85 # Install headers so that plugins can compile independently 84 86 inc.path = $${PREFIX}/include/mythtv/ 85 87 inc.files = dialogbox.h mythcontext.h 86 inc.files += mythwidgets.h remotefile.h oldsettings.h volumecontrol.h88 inc.files += mythwidgets.h remotefile.h oldsettings.h 87 89 inc.files += settings.h uitypes.h xmlparse.h mythplugin.h mythdialogs.h 88 90 inc.files += audiooutput.h audiosettings.h util.h 89 91 inc.files += inetcomms.h mythmedia.h mythwizard.h schemawizard.h dbutil.h 90 92 inc.files += uilistbtntype.h generictree.h managedlist.h mythmediamonitor.h 91 inc.files += visual.h volume base.h output.h langsettings.h93 inc.files += visual.h volumecontrol.h volumecontrolmanager.h output.h langsettings.h 92 94 inc.files += mythexp.h mythpluginapi.h storagegroup.h 93 95 inc.files += mythconfigdialogs.h mythconfiggroups.h 94 96 inc.files += mythterminal.h mythdeque.h mythuifilebrowser.h … … 103 105 104 106 using_oss { 105 107 DEFINES += USING_OSS 106 SOURCES += audiooutputoss.cpp 107 HEADERS += audiooutputoss.h 108 SOURCES += audiooutputoss.cpp volumecontroloss.cpp 109 HEADERS += audiooutputoss.h volumecontroloss.h 108 110 LIBS += $$OSS_LIBS 109 111 } 110 112 … … 132 134 133 135 mingw { 134 136 DEFINES += USING_MINGW 135 SOURCES += mediamonitor-windows.cpp audiooutputwin.cpp audiooutputdx.cpp 136 HEADERS += mediamonitor-windows.h audiooutputwin.h audiooutputdx.h 137 LIBS += -lpthread -lwinmm -lws2_32 137 SOURCES += mediamonitor-windows.cpp 138 HEADERS += mediamonitor-windows.h 139 SOURCES += audiooutputwin.cpp audiooutputdx.cpp volumecontrolendpoint.cpp 140 HEADERS += audiooutputwin.h audiooutputdx.h volumecontrolendpoint.h 141 LIBS += -lpthread -lwinmm -lws2_32 -lole32 138 142 } 139 143 140 144 macx { 141 HEADERS += audiooutputca.h 142 SOURCES += audiooutputca.cpp 145 DEFINES += USE_COREAUDIO 146 HEADERS += audiooutputca.h volumecontrolcoreaudio.h 147 SOURCES += audiooutputca.cpp volumecontrolcoreaudio.cpp 143 148 HEADERS += mythcdrom-darwin.h 144 149 SOURCES += mythcdrom-darwin.cpp 145 150 … … 179 184 180 185 using_alsa { 181 186 DEFINES += USE_ALSA 182 HEADERS += audiooutputalsa.h 183 SOURCES += audiooutputalsa.cpp 187 HEADERS += audiooutputalsa.h volumecontrolalsa.h 188 SOURCES += audiooutputalsa.cpp volumecontrolalsa.cpp 184 189 LIBS += $$ALSA_LIBS 185 190 } 186 191 -
libs/libmyth/audiosettings.h
32 32 int audio_codec, 33 33 int audio_samplerate, 34 34 AudioOutputSource audio_source, 35 bool audio_set_initial_vol,36 35 bool audio_use_passthru, 37 36 int upmixer_startup = 0); 38 37 … … 58 57 int channels; 59 58 int codec; 60 59 int samplerate; 61 bool set_initial_vol;62 60 bool use_passthru; 63 61 AudioOutputSource source; 64 62 int upmixer; -
libs/libmyth/audiooutputca.h
25 25 bool RenderAudio(unsigned char *aubuf, int size, 26 26 unsigned long long timestamp); 27 27 28 // Volume control29 virtual int GetVolumeChannel(int channel) const;30 virtual void SetVolumeChannel(int channel, int volume);31 32 28 void Debug(QString msg) 33 29 { VERBOSE(VB_AUDIO, "AudioOutputCA::" + msg); } 34 30 … … 37 33 38 34 void Warn(QString msg) 39 35 { VERBOSE(VB_IMPORTANT, "AudioOutputCA Warning: " + msg); } 36 bool internal_vol; 40 37 41 38 protected: 42 39 -
libs/libmyth/audiooutputoss.cpp
30 30 31 31 AudioOutputOSS::AudioOutputOSS(const AudioSettings &settings) : 32 32 AudioOutputBase(settings), 33 audiofd(-1), numbadioctls(0), 34 mixerfd(-1), control(SOUND_MIXER_VOLUME) 33 audiofd(-1), numbadioctls(0) 35 34 { 36 35 // Set everything up 37 36 Reconfigure(settings); … … 194 193 " the error was: %1").arg(strerror(errno))); 195 194 } 196 195 197 // Setup volume control198 if (internal_vol)199 VolumeInit();200 201 196 // Device opened successfully 202 197 return true; 203 198 } … … 242 237 close(audiofd); 243 238 244 239 audiofd = -1; 245 246 VolumeCleanup();247 240 } 248 241 249 242 … … 310 303 311 304 return space; 312 305 } 313 314 void AudioOutputOSS::VolumeInit()315 {316 mixerfd = -1;317 int volume = 0;318 319 QString device = gContext->GetSetting("MixerDevice", "/dev/mixer");320 if (device.toLower() == "software")321 return;322 323 QByteArray dev = device.toAscii();324 mixerfd = open(dev.constData(), O_RDONLY);325 326 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");327 328 if (controlLabel == "Master")329 {330 control = SOUND_MIXER_VOLUME;331 }332 else333 {334 control = SOUND_MIXER_PCM;335 }336 337 if (mixerfd < 0)338 {339 VERBOSE(VB_IMPORTANT, LOC +340 QString("Unable to open mixer: '%1'").arg(device));341 return;342 }343 344 if (set_initial_vol)345 {346 int tmpVol;347 volume = gContext->GetNumSetting("MasterMixerVolume", 80);348 tmpVol = (volume << 8) + volume;349 int ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_VOLUME), &tmpVol);350 if (ret < 0)351 {352 VERBOSE(VB_IMPORTANT, LOC_ERR +353 QString("Error Setting initial Master Volume") + ENO);354 }355 356 volume = gContext->GetNumSetting("PCMMixerVolume", 80);357 tmpVol = (volume << 8) + volume;358 ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &tmpVol);359 if (ret < 0)360 {361 VERBOSE(VB_IMPORTANT, LOC_ERR +362 QString("Error setting initial PCM Volume") + ENO);363 }364 }365 }366 367 void AudioOutputOSS::VolumeCleanup()368 {369 if (mixerfd >= 0)370 {371 close(mixerfd);372 mixerfd = -1;373 }374 }375 376 int AudioOutputOSS::GetVolumeChannel(int channel) const377 {378 int volume=0;379 int tmpVol=0;380 381 if (mixerfd <= 0)382 return 100;383 384 int ret = ioctl(mixerfd, MIXER_READ(control), &tmpVol);385 if (ret < 0) {386 VERBOSE(VB_IMPORTANT, QString("Error reading volume for channel %1")387 .arg(channel));388 perror("Reading PCM volume: ");389 return 0;390 }391 392 if (channel == 0) {393 volume = tmpVol & 0xff; // left394 } else if (channel == 1) {395 volume = (tmpVol >> 8) & 0xff; // right396 } else {397 VERBOSE(VB_IMPORTANT, QString("Invalid channel. Only stereo volume supported"));398 }399 400 return volume;401 }402 403 void AudioOutputOSS::SetVolumeChannel(int channel, int volume)404 {405 if (channel > 1) {406 // Don't support more than two channels!407 VERBOSE(VB_IMPORTANT, QString("Error setting channel: %1. Only stereo volume supported")408 .arg(channel));409 return;410 }411 412 if (volume > 100)413 volume = 100;414 if (volume < 0)415 volume = 0;416 417 if (mixerfd >= 0)418 {419 int tmpVol = 0;420 if (channel == 0)421 tmpVol = (GetVolumeChannel(1) << 8) + volume;422 else423 tmpVol = (volume << 8) + GetVolumeChannel(0);424 425 int ret = ioctl(mixerfd, MIXER_WRITE(control), &tmpVol);426 if (ret < 0)427 {428 VERBOSE(VB_IMPORTANT, QString("Error setting volume on channel: %1").arg(channel));429 perror("Setting volume: ");430 }431 }432 }433 -
libs/libmyth/audiooutputdx.cpp
369 369 dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ 370 370 | DSBCAPS_GLOBALFOCUS /* Allows background playing */ 371 371 | DSBCAPS_LOCHARDWARE; /* Needed for 5.1 on emu101k */ 372 if (!m_UseSPDIF)373 dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; /* Allow volume control */374 372 dsbdesc.dwBufferBytes = soundcard_buffer_size; /* buffer size */ 375 373 dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf; 376 374 … … 517 515 return buffered; 518 516 } 519 517 520 int AudioOutputDX::GetVolumeChannel(int channel) const521 {522 HRESULT dsresult;523 long dxVolume = 0;524 int volume;525 526 if (m_UseSPDIF)527 return 100;528 529 dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);530 volume = (int)(pow(10,(float)dxVolume/20)*100);531 532 if (dsresult != DS_OK)533 {534 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to get volume %1")535 .arg(dxVolume));536 return volume;537 }538 539 VERBOSE(VB_AUDIO, LOC + QString("Got volume %1").arg(volume));540 return volume;541 }542 543 void AudioOutputDX::SetVolumeChannel(int channel, int volume)544 {545 HRESULT dsresult;546 float dbAtten = 20 * log10((float)volume/100);547 long dxVolume = (volume == 0) ? DSBVOLUME_MIN : (long)(100.0f * dbAtten);548 549 if (m_UseSPDIF)550 return;551 552 // dxVolume is attenuation in 100ths of a decibel553 dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);554 555 if (dsresult != DS_OK)556 {557 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to set volume %1")558 .arg(dxVolume));559 return;560 }561 562 VERBOSE(VB_AUDIO, LOC + QString("Set volume %1").arg(dxVolume));563 }564 565 518 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmyth/audiooutputnull.h
27 27 28 28 virtual void Reset(void); 29 29 30 31 // Volume control32 virtual int GetVolumeChannel(int /* channel */) const { return 100; }33 virtual void SetVolumeChannel(int /* channel */, int /* volume */){return;}34 35 30 virtual int readOutputData(unsigned char *read_buffer, int max_length); 36 31 37 32 protected: -
libs/libmyth/audiooutput.h
5 5 6 6 #include "audiosettings.h" 7 7 #include "mythcontext.h" 8 #include "volumebase.h"9 8 #include "output.h" 10 9 11 class MPUBLIC AudioOutput : public VolumeBase, publicOutputListeners10 class MPUBLIC AudioOutput : public OutputListeners 12 11 { 13 12 public: 14 13 // opens one of the concrete subclasses … … 18 17 int audio_bits, int audio_channels, 19 18 int audio_codec, int audio_samplerate, 20 19 AudioOutputSource source, 21 bool set_initial_vol, boolaudio_passthru,20 bool audio_passthru, 22 21 int upmixer_startup = 0); 23 22 24 23 AudioOutput() : 25 VolumeBase(),OutputListeners(),24 OutputListeners(), 26 25 lastError(QString::null), lastWarn(QString::null) {} 27 26 28 27 virtual ~AudioOutput() { }; -
libs/libmyth/volumecontrolmanager.h
1 #ifndef VOLUMECONTROLMANAGER 2 #define VOLUMECONTROLMANAGER 3 4 #include "volumecontrol.h" 5 6 #include "mythexp.h" 7 8 #include <QHash> 9 #include <QSharedPointer> 10 #include <QString> 11 12 class MPUBLIC VolumeControlManager 13 { 14 public: 15 static QHash<QString, QString> Enumerate(); 16 static QSharedPointer<VolumeControl> GetControl(QString device); 17 }; 18 19 #endif // VOLUMECONTROLMANAGER -
libs/libmyth/volumecontrolendpoint.h
1 #ifndef VOLUMECONTROLENDPOINT 2 #define VOLUMECONTROLENDPOINT 3 4 #include "volumecontrol.h" 5 6 #include <QHash> 7 #include <QAtomicInt> 8 9 #include <rpcsal.h> 10 #include <endpointvolume.h> 11 12 13 class VolumeControlEndpoint : public VolumeControl, 14 protected IAudioEndpointVolumeCallback 15 { 16 public: 17 static QHash<QString, QString> Enumerate(); 18 19 public: 20 VolumeControlEndpoint(QString device); 21 virtual ~VolumeControlEndpoint(); 22 23 public: 24 int volume() const; 25 void setVolume(int volume); 26 void increaseVolume(); 27 void decreaseVolume(); 28 29 bool mute() const; 30 void setMute(bool mute); 31 32 protected: 33 ULONG STDMETHODCALLTYPE AddRef(); 34 ULONG STDMETHODCALLTYPE Release(); 35 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface); 36 HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify); 37 38 private: 39 IAudioEndpointVolume* m_EndpointVolume; //< Endpoint volume interface 40 int m_Range; //< Range of mixer element 41 QAtomicInt m_Volume; //< Volume state cache 42 QAtomicInt m_Mute; //< Mute state cache 43 }; 44 45 #endif // VOLUMECONTROLWINDOWSENDPOINT -
libs/libmyth/audiooutputdx.h
13 13 AudioOutputDX(const AudioSettings &settings); 14 14 virtual ~AudioOutputDX(); 15 15 16 virtual int GetVolumeChannel(int channel) const;17 virtual void SetVolumeChannel(int channel, int volume);18 19 16 protected: 20 17 virtual bool OpenDevice(void); 21 18 virtual void CloseDevice(void); -
libs/libmyth/audiooutputalsa.h
9 9 10 10 using namespace std; 11 11 12 class ALSAVolumeInfo13 {14 public:15 ALSAVolumeInfo(long playback_vol_min,16 long playback_vol_max) :17 range_multiplier(1.0f),18 volume_min(playback_vol_min), volume_max(playback_vol_max)19 {20 float range = (float) (volume_max - volume_min);21 if (range > 0.0f)22 range_multiplier = 100.0f / range;23 range_multiplier_inv = 1.0f / range_multiplier;24 }25 26 int ToMythRange(long alsa_volume)27 {28 long toz = alsa_volume - volume_min;29 int val = (int) (toz * range_multiplier);30 val = (val < 0) ? 0 : val;31 val = (val > 100) ? 100 : val;32 return val;33 }34 35 long ToALSARange(int myth_volume)36 {37 float tos = myth_volume * range_multiplier_inv;38 long val = (long) (tos + volume_min + 0.5);39 val = (val < volume_min) ? volume_min : val;40 val = (val > volume_max) ? volume_max : val;41 return val;42 }43 44 float range_multiplier;45 float range_multiplier_inv;46 long volume_min;47 long volume_max;48 };49 50 12 class AudioOutputALSA : public AudioOutputBase 51 13 { 52 14 public: 53 15 AudioOutputALSA(const AudioSettings &settings); 54 16 virtual ~AudioOutputALSA(); 55 17 56 // Volume control57 virtual int GetVolumeChannel(int channel) const; // Returns 0-10058 virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol59 60 61 18 protected: 62 19 // You need to implement the following functions 63 20 virtual bool OpenDevice(void); … … 77 34 void ReorderSmpteToAlsa6ch(void *buf, int frames); 78 35 template <class AudioDataType> 79 36 void _ReorderSmpteToAlsa6ch(AudioDataType *buf, int frames); 80 // Volume related81 void SetCurrentVolume(QString control, int channel, int volume);82 void OpenMixer(bool setstartingvolume);83 void CloseMixer(void);84 void SetupMixer(void);85 ALSAVolumeInfo GetVolumeRange(snd_mixer_elem_t *elem) const;86 37 87 38 private: 88 39 snd_pcm_t *pcm_handle; 89 40 int numbadioctls; 90 41 QMutex killAudioLock; 91 snd_mixer_t *mixer_handle;92 QString mixer_control; // e.g. "PCM"93 42 snd_pcm_sframes_t (*pcm_write_func)(snd_pcm_t*, const void*, 94 43 snd_pcm_uframes_t); 95 44 }; -
libs/libmyth/volumecontroloss.cpp
1 #include "volumecontroloss.h" 2 3 #include "mythverbose.h" 4 #include <algorithm> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <sys/ioctl.h> 8 #include <fcntl.h> 9 10 #include <QDir> 11 12 #include "mythconfig.h" 13 #ifdef HAVE_SYS_SOUNDCARD_H 14 #include <sys/soundcard.h> 15 #elif HAVE_SOUNDCARD_H 16 #include <soundcard.h> 17 #endif 18 19 static const unsigned long poll = 250; //< OSS control poll interval (ms) 20 21 QHash<QString, QString> VolumeControlOSS::Enumerate() 22 { 23 QHash<QString, QString> result; 24 #if 1 25 int mixerfd = open("/dev/mixer", O_RDWR, 0); 26 27 if (mixerfd == -1) 28 { 29 VERBOSE(VB_IMPORTANT, 30 QString("VolumeControlOSS::Enumerate() - ERROR: " 31 "opening \"/dev/mixer\"")); 32 return result; 33 } 34 35 oss_sysinfo sysinfo; 36 if (ioctl(mixerfd, SNDCTL_SYSINFO, &sysinfo) == -1) 37 { 38 VERBOSE(VB_IMPORTANT, 39 QString("VolumeControlOSS::Enumerate() - ERROR: " 40 "obtaining system information")); 41 return result; 42 } 43 44 for (int mixer = 0; mixer < sysinfo.nummixers; ++mixer) 45 { 46 oss_mixerinfo info = { 47 dev: mixer 48 }; 49 50 if (ioctl(mixerfd, SNDCTL_MIXERINFO, &info) != -1) 51 result.insert(QString("OSS:%1").arg(info.devnode), info.name); 52 } 53 54 close(mixerfd); 55 56 #else 57 QDir devs("/dev", "mixer*", QDir::Name, QDir::System); 58 59 QFileInfoList files = devs.entryInfoList(); 60 QFileInfoList::Iterator file; 61 for (file = files.begin(); file != files.end(); ++file) 62 { 63 result.insert("OSS:" + file->absoluteFilePath(), 64 file->absoluteFilePath()); 65 } 66 67 devs.setPath("/dev/sound"); 68 files = devs.entryInfoList(); 69 for (file = files.begin(); file != files.end(); ++file) 70 { 71 result.insert("OSS:" + file->absoluteFilePath(), 72 file->absoluteFilePath()); 73 } 74 #endif 75 return result; 76 } 77 78 VolumeControlOSS::VolumeControlOSS(QString device) : 79 m_VolumeCtrl(-1), m_MuteCtrl(-1), m_Exit(false) 80 { 81 m_Mixer = open(device.toAscii().constData(), O_RDWR, 0); 82 83 if (m_Mixer == -1) 84 { 85 VERBOSE(VB_IMPORTANT, 86 QString("VolumeControlOSS::VolumeControlOSS() - ERROR: " 87 "opening \"%1\"").arg(device)); 88 return; 89 } 90 91 oss_sysinfo sysinfo; 92 if (ioctl(m_Mixer, SNDCTL_SYSINFO, &sysinfo) == -1) 93 { 94 VERBOSE(VB_IMPORTANT, 95 QString("VolumeControlOSS::VolumeControlOSS() - ERROR: " 96 "obtaining system information")); 97 return; 98 } 99 100 for (m_MixerDev = 0; m_MixerDev < sysinfo.nummixers; ++m_MixerDev) 101 { 102 oss_mixerinfo info = { 103 dev: m_MixerDev 104 }; 105 106 if (ioctl(m_Mixer, SNDCTL_MIXERINFO, &info) != -1) 107 if (QString(info.devnode) == device) 108 break; 109 } 110 111 int extensions = m_MixerDev; 112 if (ioctl(m_Mixer, SNDCTL_MIX_NREXT, &extensions) == -1) 113 { 114 VERBOSE(VB_IMPORTANT, 115 QString("VolumeControlOSS::VolumeControlOSS() - ERROR: " 116 "obtaining number of extensions")); 117 return; 118 } 119 120 for (int control = 0; control < extensions; ++control) 121 { 122 oss_mixext info = { 123 dev: m_MixerDev, 124 ctrl: control 125 }; 126 127 if (ioctl(m_Mixer, SNDCTL_MIX_EXTINFO, &info) == -1) 128 continue; 129 130 switch (info.type) 131 { 132 case MIXT_MONODB: 133 case MIXT_MONOSLIDER: 134 case MIXT_MONOSLIDER16: 135 case MIXT_SLIDER: 136 case MIXT_STEREOSLIDER: 137 case MIXT_STEREOSLIDER16: 138 if (m_VolumeCtrl == -1) 139 { 140 m_VolumeCtrl = info.ctrl; 141 m_VolumeMax = info.maxvalue; 142 m_VolumeType = info.type; 143 m_VolumeTimestamp = info.timestamp; 144 } 145 break; 146 147 case MIXT_ONOFF: 148 case MIXT_MUTE: 149 if (m_MuteCtrl == -1) 150 { 151 m_MuteCtrl = info.ctrl; 152 m_MuteTimestamp = info.timestamp; 153 } 154 break; 155 } 156 157 if (m_VolumeCtrl != -1 && m_MuteCtrl != -1) 158 break; 159 } 160 161 m_Range = std::min(std::max(1, m_VolumeMax), 100); 162 163 if (m_VolumeCtrl != -1) 164 start(); 165 } 166 167 VolumeControlOSS::~VolumeControlOSS() 168 { 169 m_Exit = true; 170 171 if (isRunning()) 172 wait(); 173 174 if (m_Mixer != -1) 175 close(m_Mixer); 176 } 177 178 int VolumeControlOSS::volume() const 179 { 180 int volume = 0; 181 182 if (m_VolumeCtrl != -1) 183 { 184 if (m_MuteCtrl != -1 || !mute()) 185 { 186 oss_mixer_value value; 187 memset(&value, 0, sizeof(value)); 188 189 value.dev = m_MixerDev; 190 value.ctrl = m_VolumeCtrl; 191 value.timestamp = m_VolumeTimestamp; 192 193 if (ioctl(m_Mixer, SNDCTL_MIX_READ, &value) != -1) 194 { 195 switch (m_VolumeType) 196 { 197 case MIXT_MONODB: 198 case MIXT_MONOSLIDER: 199 volume = value.value & 0xFF; 200 break; 201 202 case MIXT_MONOSLIDER16: 203 volume = value.value & 0xFFFF; 204 break; 205 206 case MIXT_SLIDER: 207 volume = value.value & 0x7FFFFFFF; 208 break; 209 210 case MIXT_STEREOSLIDER: 211 volume = std::max(value.value & 0xFF, 212 (value.value >> 8) & 0xFF); 213 break; 214 215 case MIXT_STEREOSLIDER16: 216 volume = std::max(value.value & 0xFFFF, 217 (value.value >> 16) & 0xFFFF); 218 break; 219 } 220 221 volume = ((200 * volume) + m_VolumeMax) / (2 * m_VolumeMax); 222 } 223 } 224 else 225 volume = m_Volume; 226 } 227 228 VERBOSE(VB_AUDIO, 229 QString("VolumeControlOSS::volume() = %1") 230 .arg(volume)); 231 232 return volume; 233 } 234 235 void VolumeControlOSS::setVolume(int volume) 236 { 237 VERBOSE(VB_AUDIO, 238 QString("VolumeControlOSS::setVolume(%1)") 239 .arg(volume)); 240 241 volume = std::min(std::max(0, volume), 100); 242 243 if (mute() && volume > VolumeControlOSS::volume()) 244 setMute(false); 245 246 if (m_VolumeCtrl != -1 && (m_MuteCtrl != -1 || !mute())) 247 { 248 oss_mixer_value value; 249 memset(&value, 0, sizeof(value)); 250 251 value.dev = m_MixerDev; 252 value.ctrl = m_VolumeCtrl; 253 value.timestamp = m_VolumeTimestamp; 254 value.value = (m_VolumeMax * volume) / 100; 255 256 switch (m_VolumeType) 257 { 258 case MIXT_STEREOSLIDER: 259 value.value = value.value | (value.value << 8); 260 break; 261 262 case MIXT_STEREOSLIDER16: 263 value.value = value.value | (value.value << 16); 264 break; 265 } 266 267 ioctl(m_Mixer, SNDCTL_MIX_WRITE, &value); 268 } 269 270 if (m_Volume.fetchAndStoreRelaxed(volume) != volume) 271 emit changedVolume(volume); 272 } 273 274 void VolumeControlOSS::increaseVolume() 275 { 276 setVolume((volume() * m_Range + 100) / m_Range); 277 } 278 279 void VolumeControlOSS::decreaseVolume() 280 { 281 setVolume((volume() * m_Range - 100) / m_Range); 282 } 283 284 bool VolumeControlOSS::mute() const 285 { 286 bool mute = false; 287 288 if (m_VolumeCtrl != -1) 289 { 290 oss_mixer_value value; 291 memset(&value, 0, sizeof(value)); 292 293 value.dev = m_MixerDev; 294 295 if (m_MuteCtrl != -1) 296 { 297 value.ctrl = m_MuteCtrl; 298 value.timestamp = m_MuteTimestamp; 299 300 if (ioctl(m_Mixer, SNDCTL_MIX_READ, &value) != -1) 301 mute = value.value; 302 } 303 else 304 { 305 value.ctrl = m_VolumeCtrl; 306 value.timestamp = m_VolumeTimestamp; 307 308 if (ioctl(m_Mixer, SNDCTL_MIX_READ, &value) != -1) 309 mute = !value.value; 310 } 311 } 312 313 VERBOSE(VB_AUDIO, 314 QString("VolumeControlOSS::mute() = %1") 315 .arg(mute ? "mute" : "unmute")); 316 317 return mute; 318 } 319 320 void VolumeControlOSS::setMute(bool mute) 321 { 322 VERBOSE(VB_AUDIO, 323 QString("VolumeControlOSS::setMute(%1)") 324 .arg(mute ? "mute" : "unmute")); 325 326 if (m_VolumeCtrl != -1) 327 { 328 oss_mixer_value value; 329 memset(&value, 0, sizeof(value)); 330 331 value.dev = m_MixerDev; 332 333 if (m_MuteCtrl != -1) 334 { 335 value.ctrl = m_MuteCtrl; 336 value.timestamp = m_MuteTimestamp; 337 value.value = mute; 338 } 339 else 340 { 341 value.ctrl = m_VolumeCtrl; 342 value.timestamp = m_VolumeTimestamp; 343 value.value = mute ? 0 : (m_VolumeMax * m_Volume) / 100; 344 345 switch (m_VolumeType) 346 { 347 case MIXT_STEREOSLIDER: 348 value.value = value.value | (value.value << 8); 349 break; 350 351 case MIXT_STEREOSLIDER16: 352 value.value = value.value | (value.value << 16); 353 break; 354 } 355 } 356 357 ioctl(m_Mixer, SNDCTL_MIX_WRITE, &value); 358 } 359 360 if (m_Mute.fetchAndStoreRelaxed(mute) != mute) 361 emit changedMute(mute); 362 } 363 364 void VolumeControlOSS::run() 365 { 366 VERBOSE(VB_AUDIO, 367 QString("VolumeControlOSS::run() - begin")); 368 369 m_Volume = volume(); 370 m_Mute = mute(); 371 372 while(!m_Exit) 373 { 374 msleep(poll); 375 376 int pollvolume = volume(); 377 if (m_Volume.fetchAndStoreRelaxed(pollvolume) != pollvolume) 378 emit changedVolume(pollvolume); 379 380 bool pollmute = mute(); 381 if (m_Mute.fetchAndStoreRelaxed(pollmute) != pollmute) 382 emit changedMute(pollmute); 383 } 384 385 VERBOSE(VB_AUDIO, 386 QString("VolumeControlOSS::run() - end")); 387 } 388 -
programs/mythfrontend/globalsettings.cpp
29 29 #include "iso639.h" 30 30 #include "playbackbox.h" 31 31 #include "globalsettings.h" 32 #include "libmyth/volumecontrolmanager.h" 32 33 #include "recordingprofile.h" 33 34 #include "mythxdisplay.h" 34 35 #include "DisplayRes.h" … … 180 181 return gc; 181 182 } 182 183 183 static HostCheckBox *MythControlsVolume()184 {185 HostCheckBox *gc = new HostCheckBox("MythControlsVolume");186 gc->setLabel(QObject::tr("Use internal volume controls"));187 gc->setValue(true);188 gc->setHelpText(QObject::tr("MythTV can control the PCM and master "189 "mixer volume. If you prefer to control the volume externally "190 "(like your amplifier) or use an external mixer "191 "program, disable this option."));192 return gc;193 }194 195 184 static HostComboBox *MixerDevice() 196 185 { 197 186 HostComboBox *gc = new HostComboBox("MixerDevice", true); 198 187 gc->setLabel(QObject::tr("Mixer Device")); 188 gc->addSelection(QObject::tr("Disabled"), QString()); 199 189 200 #ifdef USING_OSS 201 QDir dev("/dev", "mixer*", QDir::Name, QDir::System); 202 gc->fillSelectionsFromDir(dev); 190 QHash<QString, QString> controls = VolumeControlManager::Enumerate(); 203 191 204 dev.setPath("/dev/sound");205 if (dev.exists())192 for (QHash<QString, QString>::const_iterator control = controls.begin(); 193 control != controls.end(); ++control) 206 194 { 207 gc-> fillSelectionsFromDir(dev);195 gc->addSelection(control.value(), control.key()); 208 196 } 209 #endif210 #ifdef USING_ALSA211 gc->addSelection("ALSA:default", "ALSA:default");212 #endif213 #ifdef USING_MINGW214 gc->addSelection("DirectX:", "DirectX:");215 gc->addSelection("Windows:", "Windows:");216 #endif217 #if !defined(USING_MINGW)218 gc->addSelection("software", "software");219 gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" lets MythTV control "220 "the volume of all audio at the expense of a slight quality loss."));221 #endif222 197 223 198 return gc; 224 199 } 225 200 226 static const char* MixerControlControls[] = { "PCM",227 "Master" };228 229 static HostComboBox *MixerControl()230 {231 HostComboBox *gc = new HostComboBox("MixerControl", true);232 gc->setLabel(QObject::tr("Mixer Controls"));233 for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);234 ++i)235 {236 gc->addSelection(QObject::tr(MixerControlControls[i]),237 MixerControlControls[i]);238 }239 240 gc->setHelpText(QObject::tr("Changing the volume adjusts the selected mixer."));241 return gc;242 }243 244 static HostSlider *MixerVolume()245 {246 HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);247 gs->setLabel(QObject::tr("Master Mixer Volume"));248 gs->setValue(70);249 gs->setHelpText(QObject::tr("Initial volume for the Master Mixer. "250 "This affects all sound created by the sound card. "251 "Note: Do not set this too low."));252 return gs;253 }254 255 static HostSlider *PCMVolume()256 {257 HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);258 gs->setLabel(QObject::tr("PCM Mixer Volume"));259 gs->setValue(70);260 gs->setHelpText(QObject::tr("Initial volume for PCM output. Using the "261 "volume keys in MythTV will adjust this parameter."));262 return gs;263 }264 265 201 static HostCheckBox *IndividualMuteControl() 266 202 { 267 203 HostCheckBox *gc = new HostCheckBox("IndividualMuteControl"); … … 3553 3489 group2->addChild(AggressiveBuffer()); 3554 3490 3555 3491 return vcg; 3556 3557 3492 } 3558 3493 3559 class AudioMixerSettingsGroup : public TriggeredConfigurationGroup 3494 static ConfigurationGroup *AudioMixerSettingsGroup() 3560 3495 { 3561 public: 3562 AudioMixerSettingsGroup() : 3563 TriggeredConfigurationGroup(false, true, false, false) 3564 { 3565 setLabel(QObject::tr("Audio Mixer")); 3566 setUseLabel(false); 3496 ConfigurationGroup *vcg = new VerticalConfigurationGroup(false, true, false, false); 3497 3498 vcg->setLabel(QObject::tr("Audio Mixer")); 3499 vcg->setUseLabel(false); 3567 3500 3568 Setting *volumeControl = MythControlsVolume(); 3569 addChild(volumeControl); 3501 vcg->addChild(MixerDevice()); 3570 3502 3571 // Mixer settings 3572 ConfigurationGroup *settings = 3573 new VerticalConfigurationGroup(false, true, false, false); 3574 settings->addChild(MixerDevice()); 3575 settings->addChild(MixerControl()); 3576 settings->addChild(MixerVolume()); 3577 settings->addChild(PCMVolume()); 3578 settings->addChild(IndividualMuteControl()); 3503 return vcg; 3504 } 3579 3505 3580 ConfigurationGroup *dummy =3581 new VerticalConfigurationGroup(false, true, false, false);3582 3583 // Show Mixer config only if internal volume controls enabled3584 setTrigger(volumeControl);3585 addTarget("0", dummy);3586 addTarget("1", settings);3587 }3588 };3589 3590 3506 static HostComboBox *MythLanguage() 3591 3507 { 3592 3508 HostComboBox *gc = new HostComboBox("Language"); … … 4270 4186 4271 4187 addChild(AudioSystemSettingsGroup()); 4272 4188 4273 addChild( newAudioMixerSettingsGroup());4189 addChild(AudioMixerSettingsGroup()); 4274 4190 4275 4191 VerticalConfigurationGroup *general = 4276 4192 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; }