1 /* 2 * Copyright 2003-2013, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Jérôme Duval 7 * François Revol 8 * Axel Dörfler, axeld@pinc-software.de. 9 * Puck Meerburg, puck@puckipedia.nl 10 * Dario Casalinuovo, b.vitruvio@gmail.com 11 */ 12 13 14 #include "MixerControl.h" 15 16 #include <string.h> 17 18 #include <Debug.h> 19 #include <ParameterWeb.h> 20 21 22 MixerControl::MixerControl(int32 volumeWhich) 23 : 24 fVolumeWhich(volumeWhich), 25 fGainMediaNode(media_node::null), 26 fParameterWeb(NULL), 27 fMixerParameter(NULL), 28 fMuteParameter(NULL), 29 fMin(0.0f), 30 fMax(0.0f), 31 fStep(0.0f) 32 { 33 } 34 35 36 MixerControl::~MixerControl() 37 { 38 _Disconnect(); 39 } 40 41 42 bool 43 MixerControl::Connect(int32 volumeWhich, float* _value, const char** _error) 44 { 45 fVolumeWhich = volumeWhich; 46 47 _Disconnect(); 48 49 status_t status = B_OK; 50 // BMediaRoster::Roster() doesn't set it if all is ok 51 const char* errorString = NULL; 52 BMediaRoster* roster = BMediaRoster::Roster(&status); 53 54 if (BMediaRoster::IsRunning() && roster != NULL 55 && status == B_OK) { 56 switch (volumeWhich) { 57 case VOLUME_USE_MIXER: 58 status = roster->GetAudioMixer(&fGainMediaNode); 59 break; 60 case VOLUME_USE_PHYS_OUTPUT: 61 status = roster->GetAudioOutput(&fGainMediaNode); 62 break; 63 } 64 if (status == B_OK) { 65 status = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb); 66 if (status == B_OK) { 67 // Finding the Mixer slider in the audio output ParameterWeb 68 int32 numParams = fParameterWeb->CountParameters(); 69 BParameter* p = NULL; 70 bool foundMixerLabel = false; 71 for (int i = 0; i < numParams; i++) { 72 p = fParameterWeb->ParameterAt(i); 73 74 // assume the mute preceeding master gain control 75 if (!strcmp(p->Kind(), B_MUTE)) 76 fMuteParameter = p; 77 78 PRINT(("BParameter[%i]: %s\n", i, p->Name())); 79 if (volumeWhich == VOLUME_USE_MIXER) { 80 if (!strcmp(p->Kind(), B_MASTER_GAIN)) 81 break; 82 } else if (volumeWhich == VOLUME_USE_PHYS_OUTPUT) { 83 /* not all cards use the same name, and 84 * they don't seem to use Kind() == B_MASTER_GAIN 85 */ 86 if (!strcmp(p->Kind(), B_MASTER_GAIN)) 87 break; 88 PRINT(("not MASTER_GAIN \n")); 89 90 /* some audio card 91 */ 92 if (!strcmp(p->Name(), "Master")) 93 break; 94 PRINT(("not 'Master' \n")); 95 96 /* some Ensonic card have all controls names 'Volume', so 97 * need to fint the one that has the 'Mixer' text label 98 */ 99 if (foundMixerLabel && !strcmp(p->Name(), "Volume")) 100 break; 101 if (!strcmp(p->Name(), "Mixer")) 102 foundMixerLabel = true; 103 PRINT(("not 'Mixer' \n")); 104 } 105 #if 0 106 //if (!strcmp(p->Name(), "Master")) { 107 if (!strcmp(p->Kind(), B_MASTER_GAIN)) { 108 for (; i < numParams; i++) { 109 p = fParamWeb->ParameterAt(i); 110 if (strcmp(p->Kind(), B_MASTER_GAIN)) 111 p = NULL; 112 else 113 break; 114 } 115 break; 116 } else 117 p = NULL; 118 #endif 119 p = NULL; 120 } 121 if (p == NULL) { 122 errorString = volumeWhich ? "Could not find the soundcard" 123 : "Could not find the mixer"; 124 } else if (p->Type() != BParameter::B_CONTINUOUS_PARAMETER) { 125 errorString = volumeWhich ? "Soundcard control unknown" 126 : "Mixer control unknown"; 127 } else { 128 fMixerParameter = static_cast<BContinuousParameter*>(p); 129 fMin = fMixerParameter->MinValue(); 130 fMax = fMixerParameter->MaxValue(); 131 fStep = fMixerParameter->ValueStep(); 132 133 if (_value != NULL) { 134 float volume; 135 bigtime_t lastChange; 136 size_t size = sizeof(float); 137 fMixerParameter->GetValue(&volume, &size, &lastChange); 138 139 *_value = volume; 140 } 141 } 142 } else { 143 errorString = "No parameter web"; 144 fParameterWeb = NULL; 145 } 146 } else 147 errorString = volumeWhich ? "No Audio output" : "No Mixer"; 148 149 } else 150 errorString = "Media services not running"; 151 152 if (status != B_OK) 153 fGainMediaNode = media_node::null; 154 155 if (errorString) { 156 fprintf(stderr, "MixerControl: %s.\n", errorString); 157 if (_error) 158 *_error = errorString; 159 } 160 if (fMixerParameter == NULL && _value != NULL) 161 *_value = 0; 162 163 return errorString == NULL; 164 } 165 166 167 bool 168 MixerControl::Connected() 169 { 170 return fGainMediaNode != media_node::null; 171 } 172 173 174 int32 175 MixerControl::VolumeWhich() const 176 { 177 return fVolumeWhich; 178 } 179 180 181 void 182 MixerControl::SetMute(bool muted) 183 { 184 if (fMuteParameter == NULL) 185 return; 186 187 int32 mute = muted ? 1 : 0; 188 fMuteParameter->SetValue(&mute, sizeof(int32), system_time()); 189 } 190 191 192 bool 193 MixerControl::Mute() 194 { 195 if (fMuteParameter == NULL) 196 return false; 197 198 int32 mute = 0; 199 bigtime_t lastChange = 0; 200 size_t size = sizeof(int32); 201 fMuteParameter->GetValue(&mute, &size, &lastChange); 202 return mute != 0; 203 } 204 205 206 float 207 MixerControl::Volume() const 208 { 209 if (fMixerParameter == NULL) 210 return 0.0f; 211 212 float volume = 0; 213 bigtime_t lastChange; 214 size_t size = sizeof(float); 215 fMixerParameter->GetValue(&volume, &size, &lastChange); 216 217 return volume; 218 } 219 220 221 void 222 MixerControl::SetVolume(float volume) 223 { 224 if (fMixerParameter == NULL) 225 return; 226 227 if (volume < fMin) 228 volume = fMin; 229 else if (volume > fMax) 230 volume = fMax; 231 232 if (volume != Volume()) 233 fMixerParameter->SetValue(&volume, sizeof(float), system_time()); 234 } 235 236 237 void 238 MixerControl::ChangeVolumeBy(float value) 239 { 240 if (fMixerParameter == NULL || value == 0.0f) 241 return; 242 243 float volume = Volume(); 244 SetVolume(volume + value); 245 } 246 247 248 void 249 MixerControl::_Disconnect() 250 { 251 delete fParameterWeb; 252 fParameterWeb = NULL; 253 fMixerParameter = NULL; 254 255 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 256 if (roster != NULL && fGainMediaNode != media_node::null) 257 roster->ReleaseNode(fGainMediaNode); 258 259 fGainMediaNode = media_node::null; 260 } 261