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