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