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 fParameterWeb = NULL; 162 } 163 } else { 164 if (!retrying) { 165 retrying = true; 166 goto retry; 167 } 168 errorString = volumeWhich ? "No Audio output" : "No Mixer"; 169 } 170 } else { 171 if (!retrying) { 172 retrying = true; 173 goto retry; 174 } 175 errorString = "No Media Roster"; 176 } 177 178 if (status != B_OK) 179 fGainMediaNode = media_node::null; 180 181 if (errorString) { 182 fprintf(stderr, "MixerControl: %s.\n", errorString); 183 if (_error) 184 *_error = errorString; 185 } 186 if (fMixerParameter == NULL && _value != NULL) 187 *_value = 0; 188 189 return errorString == NULL; 190 } 191 192 193 bool 194 MixerControl::Connected() 195 { 196 return fGainMediaNode != media_node::null; 197 } 198 199 200 int32 201 MixerControl::VolumeWhich() const 202 { 203 return fVolumeWhich; 204 } 205 206 207 void 208 MixerControl::SetMute(bool muted) 209 { 210 if (fMuteParameter == NULL) 211 return; 212 213 int32 mute = muted ? 1 : 0; 214 fMuteParameter->SetValue(&mute, sizeof(int32), system_time()); 215 } 216 217 218 bool 219 MixerControl::Mute() 220 { 221 if (fMuteParameter == NULL) 222 return false; 223 224 int32 mute = 0; 225 bigtime_t lastChange = 0; 226 size_t size = sizeof(int32); 227 fMuteParameter->GetValue(&mute, &size, &lastChange); 228 return mute != 0; 229 } 230 231 232 float 233 MixerControl::Volume() const 234 { 235 if (fMixerParameter == NULL) 236 return 0.0f; 237 238 float volume = 0; 239 bigtime_t lastChange; 240 size_t size = sizeof(float); 241 fMixerParameter->GetValue(&volume, &size, &lastChange); 242 243 return volume; 244 } 245 246 247 void 248 MixerControl::SetVolume(float volume) 249 { 250 if (fMixerParameter == NULL) 251 return; 252 253 if (volume < fMin) 254 volume = fMin; 255 else if (volume > fMax) 256 volume = fMax; 257 258 if (volume != Volume()) 259 fMixerParameter->SetValue(&volume, sizeof(float), system_time()); 260 } 261 262 263 void 264 MixerControl::ChangeVolumeBy(float value) 265 { 266 if (fMixerParameter == NULL || value == 0.0f) 267 return; 268 269 float volume = Volume(); 270 SetVolume(volume + value); 271 } 272 273 274 void 275 MixerControl::_Disconnect() 276 { 277 delete fParameterWeb; 278 fParameterWeb = NULL; 279 fMixerParameter = NULL; 280 281 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 282 if (roster != NULL && fGainMediaNode != media_node::null) 283 roster->ReleaseNode(fGainMediaNode); 284 285 fGainMediaNode = media_node::null; 286 } 287