/[svn]/linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceAlsa.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceAlsa.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1049 - (hide annotations) (download)
Wed Feb 28 06:53:42 2007 UTC (17 years, 2 months ago) by schoenebeck
File size: 32598 byte(s)
* the ALSA audio output driver parameters now reflect the correct
  parameter value ranges for the respective selected sound card
  (patch by Till Wimmer, a bit fixed and extended)
* bumped version to 0.4.0.4cvs

1 schoenebeck 200 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1049 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 schoenebeck 200 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "AudioOutputDeviceAlsa.h"
25     #include "AudioOutputDeviceFactory.h"
26    
27     namespace LinuxSampler {
28    
29 schoenebeck 212 // *************** ParameterCard ***************
30     // *
31    
32     AudioOutputDeviceAlsa::ParameterCard::ParameterCard() : DeviceCreationParameterString() {
33     InitWithDefault(); // use default card
34     }
35    
36 schoenebeck 880 AudioOutputDeviceAlsa::ParameterCard::ParameterCard(String s) throw (Exception) : DeviceCreationParameterString(s) {
37 schoenebeck 212 }
38    
39     String AudioOutputDeviceAlsa::ParameterCard::Description() {
40     return "Sound card to be used";
41     }
42    
43     bool AudioOutputDeviceAlsa::ParameterCard::Fix() {
44     return true;
45     }
46    
47     bool AudioOutputDeviceAlsa::ParameterCard::Mandatory() {
48     return false;
49     }
50    
51     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterCard::DependsAsParameters() {
52     return std::map<String,DeviceCreationParameter*>(); // no dependencies
53     }
54    
55     optional<String> AudioOutputDeviceAlsa::ParameterCard::DefaultAsString(std::map<String,String> Parameters) {
56     std::vector<String> cards = PossibilitiesAsString(Parameters);
57 schoenebeck 880 if (cards.empty()) throw Exception("AudioOutputDeviceAlsa: Can't find any card");
58 schoenebeck 212 return cards[0]; // first card by default
59     }
60    
61     std::vector<String> AudioOutputDeviceAlsa::ParameterCard::PossibilitiesAsString(std::map<String,String> Parameters) {
62     int err;
63     std::vector<String> CardNames;
64    
65     // iterate through all cards
66     int card_index = -1;
67     while (snd_card_next(&card_index) >= 0 && card_index >= 0) {
68     String hw_name = "hw:" + ToString(card_index);
69     snd_ctl_t* hCardCtrl;
70     if ((err = snd_ctl_open(&hCardCtrl, hw_name.c_str(), 0)) < 0) {
71     std::cerr << "AudioOutputDeviceAlsa: Cannot open sound control for card " << card_index << " - " << snd_strerror(err) << std::endl;
72     continue;
73     }
74    
75     // iterate through all devices of that card
76     int device_index = -1;
77     while (!snd_ctl_pcm_next_device(hCardCtrl, &device_index) && device_index >= 0) {
78     String name = ToString(card_index) + "," + ToString(device_index);
79     //dmsg(1,("[possibility:%s]", name.c_str()));
80     CardNames.push_back(name);
81     }
82    
83     snd_ctl_close(hCardCtrl);
84     }
85    
86     return CardNames;
87     }
88    
89 schoenebeck 880 void AudioOutputDeviceAlsa::ParameterCard::OnSetValue(String s) throw (Exception) {
90 schoenebeck 212 // not posssible, as parameter is fix
91     }
92    
93     String AudioOutputDeviceAlsa::ParameterCard::Name() {
94 schoenebeck 221 return "CARD";
95 schoenebeck 212 }
96    
97    
98    
99 schoenebeck 1049 // *************** ParameterSampleRate ***************
100     // *
101    
102     AudioOutputDeviceAlsa::ParameterSampleRate::ParameterSampleRate() : AudioOutputDevice::ParameterSampleRate::ParameterSampleRate() {
103     }
104    
105     AudioOutputDeviceAlsa::ParameterSampleRate::ParameterSampleRate(String s) : AudioOutputDevice::ParameterSampleRate::ParameterSampleRate(s) {
106     }
107    
108     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterSampleRate::DependsAsParameters() {
109     static ParameterCard card;
110     std::map<String,DeviceCreationParameter*> dependencies;
111     dependencies[card.Name()] = &card;
112     return dependencies;
113     }
114    
115     optional<int> AudioOutputDeviceAlsa::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {
116     if (!Parameters.count("CARD")) return optional<int>::nothing;
117    
118     // obtain information from given sound card
119     ParameterCard card(Parameters["CARD"]);
120     String pcm_name = "hw:" + card.ValueAsString();
121     snd_pcm_t* pcm_handle = NULL;
122     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
123     snd_pcm_hw_params_t* hwparams;
124     snd_pcm_hw_params_alloca(&hwparams);
125     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
126     snd_pcm_close(pcm_handle);
127     return optional<int>::nothing;
128     }
129     uint rate = 44100;
130     if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, NULL) < 0) {
131     snd_pcm_close(pcm_handle);
132     return optional<int>::nothing;
133     }
134     snd_pcm_close(pcm_handle);
135     return rate;
136     }
137    
138     optional<int> AudioOutputDeviceAlsa::ParameterSampleRate::RangeMinAsInt(std::map<String,String> Parameters) {
139     if (!Parameters.count("CARD")) return optional<int>::nothing;
140    
141     // obtain information from given sound card
142     ParameterCard card(Parameters["CARD"]);
143     String pcm_name = "hw:" + card.ValueAsString();
144     snd_pcm_t* pcm_handle = NULL;
145     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
146     snd_pcm_hw_params_t* hwparams;
147     snd_pcm_hw_params_alloca(&hwparams);
148     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
149     snd_pcm_close(pcm_handle);
150     return optional<int>::nothing;
151     }
152     uint rate;
153     if (snd_pcm_hw_params_get_rate_min(hwparams, &rate, NULL) < 0) {
154     snd_pcm_close(pcm_handle);
155     return optional<int>::nothing;
156     }
157     snd_pcm_close(pcm_handle);
158     return rate;
159     }
160    
161     optional<int> AudioOutputDeviceAlsa::ParameterSampleRate::RangeMaxAsInt(std::map<String,String> Parameters) {
162     if (!Parameters.count("CARD")) return optional<int>::nothing;
163    
164     // obtain information from given sound card
165     String pcm_name = "hw:" + Parameters["CARD"];
166     snd_pcm_t* pcm_handle = NULL;
167     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
168     snd_pcm_hw_params_t* hwparams;
169     snd_pcm_hw_params_alloca(&hwparams);
170     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
171     snd_pcm_close(pcm_handle);
172     return optional<int>::nothing;
173     }
174     uint rate;
175     if (snd_pcm_hw_params_get_rate_max(hwparams, &rate, NULL) < 0) {
176     snd_pcm_close(pcm_handle);
177     return optional<int>::nothing;
178     }
179     snd_pcm_close(pcm_handle);
180     return rate;
181     }
182    
183    
184    
185     // *************** ParameterChannels ***************
186     // *
187    
188     AudioOutputDeviceAlsa::ParameterChannels::ParameterChannels() : AudioOutputDevice::ParameterChannels::ParameterChannels() {
189     //InitWithDefault();
190     // could not determine default value? ...
191     //if (ValueAsInt() == 0) SetValue(2); // ... then (try) a common value
192     }
193    
194     AudioOutputDeviceAlsa::ParameterChannels::ParameterChannels(String s) : AudioOutputDevice::ParameterChannels::ParameterChannels(s) {
195     }
196    
197     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterChannels::DependsAsParameters() {
198     static ParameterCard card;
199     std::map<String,DeviceCreationParameter*> dependencies;
200     dependencies[card.Name()] = &card;
201     return dependencies;
202     }
203    
204     optional<int> AudioOutputDeviceAlsa::ParameterChannels::DefaultAsInt(std::map<String,String> Parameters) {
205     if (!Parameters.count("CARD")) return optional<int>::nothing;
206    
207     // obtain information from given sound card
208     ParameterCard card(Parameters["CARD"]);
209     String pcm_name = "hw:" + card.ValueAsString();
210     snd_pcm_t* pcm_handle = NULL;
211     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
212     snd_pcm_hw_params_t* hwparams;
213     snd_pcm_hw_params_alloca(&hwparams);
214     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
215     snd_pcm_close(pcm_handle);
216     return optional<int>::nothing;
217     }
218     uint channels = 2;
219     if (snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &channels) < 0) {
220     snd_pcm_close(pcm_handle);
221     return optional<int>::nothing;
222     }
223     snd_pcm_close(pcm_handle);
224     return channels;
225     }
226    
227     optional<int> AudioOutputDeviceAlsa::ParameterChannels::RangeMinAsInt(std::map<String,String> Parameters) {
228     if (!Parameters.count("CARD")) return optional<int>::nothing;
229    
230     // obtain information from given sound card
231     ParameterCard card(Parameters["CARD"]);
232     String pcm_name = "hw:" + card.ValueAsString();
233     snd_pcm_t* pcm_handle = NULL;
234     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
235     snd_pcm_hw_params_t* hwparams;
236     snd_pcm_hw_params_alloca(&hwparams);
237     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
238     snd_pcm_close(pcm_handle);
239     return optional<int>::nothing;
240     }
241     uint channels;
242     if (snd_pcm_hw_params_get_channels_min(hwparams, &channels) < 0) {
243     snd_pcm_close(pcm_handle);
244     return optional<int>::nothing;
245     }
246     snd_pcm_close(pcm_handle);
247     return channels;
248     }
249    
250     optional<int> AudioOutputDeviceAlsa::ParameterChannels::RangeMaxAsInt(std::map<String,String> Parameters) {
251     if (!Parameters.count("CARD")) return optional<int>::nothing;
252    
253     // obtain information from given sound card
254     String pcm_name = "hw:" + Parameters["CARD"];
255     snd_pcm_t* pcm_handle = NULL;
256     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
257     snd_pcm_hw_params_t* hwparams;
258     snd_pcm_hw_params_alloca(&hwparams);
259     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
260     snd_pcm_close(pcm_handle);
261     return optional<int>::nothing;
262     }
263     uint channels;
264     if (snd_pcm_hw_params_get_channels_max(hwparams, &channels) < 0) {
265     snd_pcm_close(pcm_handle);
266     return optional<int>::nothing;
267     }
268     snd_pcm_close(pcm_handle);
269     return channels;
270     }
271    
272    
273    
274 schoenebeck 212 // *************** ParameterFragments ***************
275     // *
276    
277     AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments() : DeviceCreationParameterInt() {
278     InitWithDefault();
279     }
280    
281 schoenebeck 880 AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments(String s) throw (Exception) : DeviceCreationParameterInt(s) {
282 schoenebeck 212 }
283    
284     String AudioOutputDeviceAlsa::ParameterFragments::Description() {
285     return "Number of buffer fragments";
286     }
287    
288     bool AudioOutputDeviceAlsa::ParameterFragments::Fix() {
289     return true;
290     }
291    
292     bool AudioOutputDeviceAlsa::ParameterFragments::Mandatory() {
293     return false;
294     }
295    
296     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragments::DependsAsParameters() {
297     static ParameterCard card;
298     std::map<String,DeviceCreationParameter*> dependencies;
299     dependencies[card.Name()] = &card;
300     return dependencies;
301     }
302    
303     optional<int> AudioOutputDeviceAlsa::ParameterFragments::DefaultAsInt(std::map<String,String> Parameters) {
304 schoenebeck 1049 if (!Parameters.count("CARD")) return optional<int>::nothing;
305    
306     // obtain information from given sound card
307     ParameterCard card(Parameters["CARD"]);
308     String pcm_name = "hw:" + card.ValueAsString();
309     snd_pcm_t* pcm_handle = NULL;
310     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
311     snd_pcm_hw_params_t* hwparams;
312     snd_pcm_hw_params_alloca(&hwparams);
313     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
314     snd_pcm_close(pcm_handle);
315     return optional<int>::nothing;
316     }
317     uint segs = 2;
318     if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &segs, NULL) < 0) {
319     snd_pcm_close(pcm_handle);
320     return optional<int>::nothing;
321     }
322     snd_pcm_close(pcm_handle);
323     return segs;
324 schoenebeck 212 }
325    
326     optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMinAsInt(std::map<String,String> Parameters) {
327 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
328    
329     // obtain information from given sound card
330 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
331     String pcm_name = "hw:" + card.ValueAsString();
332 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
333 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
334 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
335     snd_pcm_hw_params_alloca(&hwparams);
336     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
337     snd_pcm_close(pcm_handle);
338     return optional<int>::nothing;
339     }
340     int dir = 0;
341     uint periods_min;
342     if (snd_pcm_hw_params_get_periods_min(hwparams, &periods_min, &dir) < 0) {
343     snd_pcm_close(pcm_handle);
344     return optional<int>::nothing;
345     }
346     snd_pcm_close(pcm_handle);
347     return (int) periods_min;
348 schoenebeck 212 }
349    
350     optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMaxAsInt(std::map<String,String> Parameters) {
351 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
352    
353     // obtain information from given sound card
354 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
355     String pcm_name = "hw:" + card.ValueAsString();
356 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
357 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
358 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
359     snd_pcm_hw_params_alloca(&hwparams);
360     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
361     snd_pcm_close(pcm_handle);
362     return optional<int>::nothing;
363     }
364     int dir = 0;
365     uint periods_max;
366     if (snd_pcm_hw_params_get_periods_max(hwparams, &periods_max, &dir) < 0) {
367     snd_pcm_close(pcm_handle);
368     return optional<int>::nothing;
369     }
370     snd_pcm_close(pcm_handle);
371     return (int) periods_max;
372 schoenebeck 212 }
373    
374     std::vector<int> AudioOutputDeviceAlsa::ParameterFragments::PossibilitiesAsInt(std::map<String,String> Parameters) {
375     return std::vector<int>();
376     }
377    
378 schoenebeck 880 void AudioOutputDeviceAlsa::ParameterFragments::OnSetValue(int i) throw (Exception) {
379 schoenebeck 212 // not posssible, as parameter is fix
380     }
381    
382     String AudioOutputDeviceAlsa::ParameterFragments::Name() {
383 schoenebeck 221 return "FRAGMENTS";
384 schoenebeck 212 }
385    
386    
387    
388     // *************** ParameterFragmentSize ***************
389     // *
390    
391     AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize() : DeviceCreationParameterInt() {
392     InitWithDefault();
393     }
394    
395 schoenebeck 880 AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize(String s) throw (Exception) : DeviceCreationParameterInt(s) {
396 schoenebeck 212 }
397    
398     String AudioOutputDeviceAlsa::ParameterFragmentSize::Description() {
399     return "Size of each buffer fragment";
400     }
401    
402     bool AudioOutputDeviceAlsa::ParameterFragmentSize::Fix() {
403     return true;
404     }
405    
406     bool AudioOutputDeviceAlsa::ParameterFragmentSize::Mandatory() {
407     return false;
408     }
409    
410     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragmentSize::DependsAsParameters() {
411     static ParameterCard card;
412     std::map<String,DeviceCreationParameter*> dependencies;
413     dependencies[card.Name()] = &card;
414     return dependencies;
415     }
416    
417     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::DefaultAsInt(std::map<String,String> Parameters) {
418 schoenebeck 1049 if (!Parameters.count("CARD")) return optional<int>::nothing;
419    
420     // obtain information from given sound card
421     ParameterCard card(Parameters["CARD"]);
422     String pcm_name = "hw:" + card.ValueAsString();
423     snd_pcm_t* pcm_handle = NULL;
424     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
425     snd_pcm_hw_params_t* hwparams;
426     snd_pcm_hw_params_alloca(&hwparams);
427     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
428     snd_pcm_close(pcm_handle);
429     return optional<int>::nothing;
430     }
431     snd_pcm_uframes_t size = 128;
432     if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &size, NULL) < 0) {
433     snd_pcm_close(pcm_handle);
434     return optional<int>::nothing;
435     }
436     snd_pcm_close(pcm_handle);
437     return size;
438 schoenebeck 212 }
439    
440     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMinAsInt(std::map<String,String> Parameters) {
441 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
442    
443     // obtain information from given sound card
444 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
445     String pcm_name = "hw:" + card.ValueAsString();
446 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
447 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
448 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
449     snd_pcm_hw_params_alloca(&hwparams);
450     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
451     snd_pcm_close(pcm_handle);
452     return optional<int>::nothing;
453     }
454     int dir = 0;
455     unsigned long period_size_min;
456     if (snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, &dir) < 0) {
457     snd_pcm_close(pcm_handle);
458     return optional<int>::nothing;
459     }
460     snd_pcm_close(pcm_handle);
461     return (int) period_size_min;
462 schoenebeck 212 }
463    
464     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
465 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
466    
467     // obtain information from given sound card
468 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
469     String pcm_name = "hw:" + card.ValueAsString();
470 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
471 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
472 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
473     snd_pcm_hw_params_alloca(&hwparams);
474     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
475     snd_pcm_close(pcm_handle);
476     return optional<int>::nothing;
477     }
478     int dir = 0;
479     unsigned long period_size_max;
480     if (snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, &dir) < 0) {
481     snd_pcm_close(pcm_handle);
482     return optional<int>::nothing;
483     }
484     snd_pcm_close(pcm_handle);
485     return (int) period_size_max; //FIXME: might overflow int limit
486 schoenebeck 212 }
487    
488     std::vector<int> AudioOutputDeviceAlsa::ParameterFragmentSize::PossibilitiesAsInt(std::map<String,String> Parameters) {
489     return std::vector<int>();
490     }
491    
492 schoenebeck 880 void AudioOutputDeviceAlsa::ParameterFragmentSize::OnSetValue(int i) throw (Exception) {
493 schoenebeck 212 // not posssible, as parameter is fix
494     }
495    
496     String AudioOutputDeviceAlsa::ParameterFragmentSize::Name() {
497 schoenebeck 221 return "FRAGMENTSIZE";
498 schoenebeck 212 }
499    
500    
501    
502     // *************** AudioOutputDeviceAlsa ***************
503     // *
504    
505 schoenebeck 200 /**
506     * Create and initialize Alsa audio output device with given parameters.
507     *
508     * @param Parameters - optional parameters
509     * @throws AudioOutputException if output device cannot be opened
510     */
511 schoenebeck 392 AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) {
512 schoenebeck 200 pcm_handle = NULL;
513     stream = SND_PCM_STREAM_PLAYBACK;
514 schoenebeck 221 this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
515     this->uiSamplerate = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
516     this->FragmentSize = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt();
517     uint Fragments = ((DeviceCreationParameterInt*)Parameters["FRAGMENTS"])->ValueAsInt();
518     String Card = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString();
519 schoenebeck 200
520 schoenebeck 513 dmsg(2,("Checking if hw parameters supported...\n"));
521 schoenebeck 200 if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) {
522     pcm_name = "hw:" + Card;
523     }
524     else {
525 schoenebeck 513 fprintf(stderr, "Warning: your soundcard doesn't support chosen hardware parameters; ");
526     fprintf(stderr, "trying to compensate support lack with plughw...");
527 schoenebeck 200 fflush(stdout);
528     pcm_name = "plughw:" + Card;
529     }
530 schoenebeck 513 dmsg(2,("HW check completed.\n"));
531 schoenebeck 200
532     int err;
533    
534     snd_pcm_hw_params_alloca(&hwparams); // Allocate the snd_pcm_hw_params_t structure on the stack.
535    
536     /* Open PCM. The last parameter of this function is the mode. */
537     /* If this is set to 0, the standard mode is used. Possible */
538     /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
539     /* If SND_PCM_NONBLOCK is used, read / write access to the */
540     /* PCM device will return immediately. If SND_PCM_ASYNC is */
541     /* specified, SIGIO will be emitted whenever a period has */
542     /* been completely processed by the soundcard. */
543 schoenebeck 531 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
544 schoenebeck 200 throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
545     }
546    
547     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
548     throw AudioOutputException(String("Error, cannot initialize hardware parameter structure: ") + snd_strerror(err));
549     }
550    
551     /* Set access type. This can be either */
552     /* SND_PCM_ACCESS_RW_INTERLEAVED or */
553     /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
554     if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
555     throw AudioOutputException(String("Error snd_pcm_hw_params_set_access: ") + snd_strerror(err));
556     }
557    
558     /* Set sample format */
559     #if WORDS_BIGENDIAN
560     if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0)
561     #else // little endian
562     if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
563     #endif
564     {
565     throw AudioOutputException(String("Error setting sample format: ") + snd_strerror(err));
566     }
567    
568     int dir = 0;
569    
570     /* Set sample rate. If the exact rate is not supported */
571     /* by the hardware, use nearest possible rate. */
572     #if ALSA_MAJOR > 0
573     if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &uiSamplerate, &dir)) < 0)
574     #else
575     if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, uiSamplerate, &dir)) < 0)
576     #endif
577     {
578     throw AudioOutputException(String("Error setting sample rate: ") + snd_strerror(err));
579     }
580    
581     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, uiAlsaChannels)) < 0) {
582     throw AudioOutputException(String("Error setting number of channels: ") + snd_strerror(err));
583     }
584    
585     /* Set number of periods. Periods used to be called fragments. */
586     if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
587 schoenebeck 1049 throw AudioOutputException(String("Error setting number of ") + ToString(Fragments) + " periods: " + snd_strerror(err));
588 schoenebeck 200 }
589    
590     /* Set buffer size (in frames). The resulting latency is given by */
591     /* latency = periodsize * periods / (rate * bytes_per_frame) */
592     if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
593     throw AudioOutputException(String("Error setting buffersize: ") + snd_strerror(err));
594     }
595    
596     /* Apply HW parameter settings to */
597     /* PCM device and prepare device */
598     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
599     throw AudioOutputException(String("Error setting HW params: ") + snd_strerror(err));
600     }
601    
602     if (snd_pcm_sw_params_malloc(&swparams) != 0) {
603     throw AudioOutputException(String("Error in snd_pcm_sw_params_malloc: ") + snd_strerror(err));
604     }
605    
606     if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
607     throw AudioOutputException(String("Error in snd_pcm_sw_params_current: ") + snd_strerror(err));
608     }
609    
610     if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
611     throw AudioOutputException(String("Error in snd_pcm_sw_params_set_stop_threshold: ") + snd_strerror(err));
612     }
613    
614     if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
615     throw AudioOutputException(String("Error in snd_pcm_sw_params: ") + snd_strerror(err));
616     }
617    
618     if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
619     throw AudioOutputException(String("Error snd_pcm_prepare: ") + snd_strerror(err));
620     }
621    
622     // allocate Alsa output buffer
623     pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize];
624    
625     // create audio channels for this audio device to which the sampler engines can write to
626 schoenebeck 226 for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
627 schoenebeck 200
628 schoenebeck 221 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
629 schoenebeck 200 Play();
630     }
631     }
632    
633     AudioOutputDeviceAlsa::~AudioOutputDeviceAlsa() {
634     //dmsg(0,("Stopping Alsa Thread..."));
635     //StopThread(); //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
636     //dmsg(0,("OK\n"));
637    
638     //FIXME: currently commented out due to segfault
639     //snd_pcm_close(pcm_handle);
640    
641     if (pAlsaOutputBuffer) {
642     //FIXME: currently commented out due to segfault
643     //delete[] pOutputBuffer;
644     }
645     }
646    
647     /**
648     * Checks if sound card supports the chosen parameters.
649     *
650     * @returns true if hardware supports it
651 schoenebeck 485 * @throws AudioOutputException - if device cannot be accessed
652 schoenebeck 200 */
653 schoenebeck 485 bool AudioOutputDeviceAlsa::HardwareParametersSupported(String card, uint channels, int samplerate, uint numfragments, uint fragmentsize) throw (AudioOutputException) {
654 schoenebeck 200 pcm_name = "hw:" + card;
655 schoenebeck 485 int err;
656 schoenebeck 513 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, SND_PCM_NONBLOCK)) < 0) {
657 schoenebeck 485 throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
658     }
659 schoenebeck 200 snd_pcm_hw_params_alloca(&hwparams);
660     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
661     snd_pcm_close(pcm_handle);
662     return false;
663     }
664     if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
665     snd_pcm_close(pcm_handle);
666     return false;
667     }
668     #if WORDS_BIGENDIAN
669     if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0)
670     #else // little endian
671     if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0)
672     #endif
673     {
674     snd_pcm_close(pcm_handle);
675     return false;
676     }
677     int dir = 0;
678     if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
679     snd_pcm_close(pcm_handle);
680     return false;
681     }
682     if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
683     snd_pcm_close(pcm_handle);
684     return false;
685     }
686     if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
687     snd_pcm_close(pcm_handle);
688     return false;
689     }
690     if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
691     snd_pcm_close(pcm_handle);
692     return false;
693     }
694    
695     snd_pcm_close(pcm_handle);
696     return true;
697     }
698    
699     void AudioOutputDeviceAlsa::Play() {
700     StartThread();
701     }
702    
703     bool AudioOutputDeviceAlsa::IsPlaying() {
704     return IsRunning(); // if Thread is running
705     }
706    
707     void AudioOutputDeviceAlsa::Stop() {
708     StopThread();
709     }
710    
711 schoenebeck 226 AudioChannel* AudioOutputDeviceAlsa::CreateChannel(uint ChannelNr) {
712     // just create a mix channel
713     return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAlsaChannels));
714 schoenebeck 200 }
715    
716     uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {
717     return FragmentSize;
718     }
719    
720     uint AudioOutputDeviceAlsa::SampleRate() {
721     return uiSamplerate;
722     }
723    
724     String AudioOutputDeviceAlsa::Name() {
725 schoenebeck 221 return "ALSA";
726 schoenebeck 200 }
727    
728     String AudioOutputDeviceAlsa::Driver() {
729     return Name();
730     }
731    
732     String AudioOutputDeviceAlsa::Description() {
733     return "Advanced Linux Sound Architecture";
734     }
735    
736     String AudioOutputDeviceAlsa::Version() {
737 schoenebeck 1049 String s = "$Revision: 1.22 $";
738 schoenebeck 200 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
739     }
740    
741     /**
742     * Entry point for the thread.
743     */
744     int AudioOutputDeviceAlsa::Main() {
745     while (true) {
746    
747     // let all connected engines render 'FragmentSize' sample points
748     RenderAudio(FragmentSize);
749    
750     // convert from DSP value range (-1.0..+1.0) to 16 bit integer value
751     // range (-32768..+32767), check clipping and copy to Alsa output buffer
752     // (note: we use interleaved output method to Alsa)
753     for (int c = 0; c < uiAlsaChannels; c++) {
754     float* in = Channels[c]->Buffer();
755     for (int i = 0, o = c; i < FragmentSize; i++ , o += uiAlsaChannels) {
756     float sample_point = in[i] * 32768.0f;
757     if (sample_point < -32768.0) sample_point = -32768.0;
758     if (sample_point > 32767.0) sample_point = 32767.0;
759     pAlsaOutputBuffer[o] = (int16_t) sample_point;
760     }
761     }
762    
763     // output sound
764     int res = Output();
765     if (res < 0) {
766     fprintf(stderr, "Alsa: Audio output error, exiting.\n");
767     exit(EXIT_FAILURE);
768     }
769     }
770     }
771    
772     /**
773     * Will be called after every audio fragment cycle, to output the audio data
774     * of the current fragment to the soundcard.
775     *
776     * @returns 0 on success, a value < 0 on error
777     */
778     int AudioOutputDeviceAlsa::Output() {
779     int err = snd_pcm_writei(pcm_handle, pAlsaOutputBuffer, FragmentSize);
780     if (err < 0) {
781     fprintf(stderr, "Error snd_pcm_writei failed: %s\n", snd_strerror(err));
782     return -1;
783     }
784     return 0;
785     }
786    
787     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC