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