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