/[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 1305 - (hide annotations) (download)
Mon Aug 27 07:51:28 2007 UTC (16 years, 8 months ago) by iliev
File size: 32439 byte(s)
* added default min and max values to restrict the number of allowed
  audio output channels and MIDI input ports
* the connection to the PCM interface is now closed when destroying
  an audio output device

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 iliev 1305 uint channels = 1;
229     if (!Parameters.count("CARD")) return channels;
230 schoenebeck 1049
231     // obtain information from given sound card
232     ParameterCard card(Parameters["CARD"]);
233     String pcm_name = "hw:" + card.ValueAsString();
234     snd_pcm_t* pcm_handle = NULL;
235 iliev 1305 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return channels;
236 schoenebeck 1049 snd_pcm_hw_params_t* hwparams;
237     snd_pcm_hw_params_alloca(&hwparams);
238     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
239     snd_pcm_close(pcm_handle);
240 iliev 1305 return channels;
241 schoenebeck 1049 }
242 iliev 1305
243 schoenebeck 1049 if (snd_pcm_hw_params_get_channels_min(hwparams, &channels) < 0) {
244     snd_pcm_close(pcm_handle);
245 iliev 1305 return channels;
246 schoenebeck 1049 }
247     snd_pcm_close(pcm_handle);
248     return channels;
249     }
250    
251     optional<int> AudioOutputDeviceAlsa::ParameterChannels::RangeMaxAsInt(std::map<String,String> Parameters) {
252 iliev 1305 uint channels = 100;
253     if (!Parameters.count("CARD")) return channels;
254 schoenebeck 1049
255     // obtain information from given sound card
256     String pcm_name = "hw:" + Parameters["CARD"];
257     snd_pcm_t* pcm_handle = NULL;
258 iliev 1305 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return channels;
259 schoenebeck 1049 snd_pcm_hw_params_t* hwparams;
260     snd_pcm_hw_params_alloca(&hwparams);
261     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
262     snd_pcm_close(pcm_handle);
263 iliev 1305 return channels;
264 schoenebeck 1049 }
265 iliev 1305
266 schoenebeck 1049 if (snd_pcm_hw_params_get_channels_max(hwparams, &channels) < 0) {
267     snd_pcm_close(pcm_handle);
268 iliev 1305 return channels;
269 schoenebeck 1049 }
270     snd_pcm_close(pcm_handle);
271     return channels;
272     }
273    
274    
275    
276 schoenebeck 212 // *************** ParameterFragments ***************
277     // *
278    
279     AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments() : DeviceCreationParameterInt() {
280     InitWithDefault();
281     }
282    
283 schoenebeck 880 AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments(String s) throw (Exception) : DeviceCreationParameterInt(s) {
284 schoenebeck 212 }
285    
286     String AudioOutputDeviceAlsa::ParameterFragments::Description() {
287     return "Number of buffer fragments";
288     }
289    
290     bool AudioOutputDeviceAlsa::ParameterFragments::Fix() {
291     return true;
292     }
293    
294     bool AudioOutputDeviceAlsa::ParameterFragments::Mandatory() {
295     return false;
296     }
297    
298     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragments::DependsAsParameters() {
299     static ParameterCard card;
300     std::map<String,DeviceCreationParameter*> dependencies;
301     dependencies[card.Name()] = &card;
302     return dependencies;
303     }
304    
305     optional<int> AudioOutputDeviceAlsa::ParameterFragments::DefaultAsInt(std::map<String,String> Parameters) {
306 schoenebeck 1049 if (!Parameters.count("CARD")) return optional<int>::nothing;
307    
308     // obtain information from given sound card
309     ParameterCard card(Parameters["CARD"]);
310     String pcm_name = "hw:" + card.ValueAsString();
311     snd_pcm_t* pcm_handle = NULL;
312     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
313     snd_pcm_hw_params_t* hwparams;
314     snd_pcm_hw_params_alloca(&hwparams);
315     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
316     snd_pcm_close(pcm_handle);
317     return optional<int>::nothing;
318     }
319     uint segs = 2;
320     if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &segs, NULL) < 0) {
321     snd_pcm_close(pcm_handle);
322     return optional<int>::nothing;
323     }
324     snd_pcm_close(pcm_handle);
325     return segs;
326 schoenebeck 212 }
327    
328     optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMinAsInt(std::map<String,String> Parameters) {
329 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
330    
331     // obtain information from given sound card
332 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
333     String pcm_name = "hw:" + card.ValueAsString();
334 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
335 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
336 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
337     snd_pcm_hw_params_alloca(&hwparams);
338     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
339     snd_pcm_close(pcm_handle);
340     return optional<int>::nothing;
341     }
342     int dir = 0;
343     uint periods_min;
344     if (snd_pcm_hw_params_get_periods_min(hwparams, &periods_min, &dir) < 0) {
345     snd_pcm_close(pcm_handle);
346     return optional<int>::nothing;
347     }
348     snd_pcm_close(pcm_handle);
349     return (int) periods_min;
350 schoenebeck 212 }
351    
352     optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMaxAsInt(std::map<String,String> Parameters) {
353 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
354    
355     // obtain information from given sound card
356 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
357     String pcm_name = "hw:" + card.ValueAsString();
358 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
359 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
360 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
361     snd_pcm_hw_params_alloca(&hwparams);
362     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
363     snd_pcm_close(pcm_handle);
364     return optional<int>::nothing;
365     }
366     int dir = 0;
367     uint periods_max;
368     if (snd_pcm_hw_params_get_periods_max(hwparams, &periods_max, &dir) < 0) {
369     snd_pcm_close(pcm_handle);
370     return optional<int>::nothing;
371     }
372     snd_pcm_close(pcm_handle);
373     return (int) periods_max;
374 schoenebeck 212 }
375    
376     std::vector<int> AudioOutputDeviceAlsa::ParameterFragments::PossibilitiesAsInt(std::map<String,String> Parameters) {
377     return std::vector<int>();
378     }
379    
380 schoenebeck 880 void AudioOutputDeviceAlsa::ParameterFragments::OnSetValue(int i) throw (Exception) {
381 schoenebeck 212 // not posssible, as parameter is fix
382     }
383    
384     String AudioOutputDeviceAlsa::ParameterFragments::Name() {
385 schoenebeck 221 return "FRAGMENTS";
386 schoenebeck 212 }
387    
388    
389    
390     // *************** ParameterFragmentSize ***************
391     // *
392    
393     AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize() : DeviceCreationParameterInt() {
394     InitWithDefault();
395     }
396    
397 schoenebeck 880 AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize(String s) throw (Exception) : DeviceCreationParameterInt(s) {
398 schoenebeck 212 }
399    
400     String AudioOutputDeviceAlsa::ParameterFragmentSize::Description() {
401     return "Size of each buffer fragment";
402     }
403    
404     bool AudioOutputDeviceAlsa::ParameterFragmentSize::Fix() {
405     return true;
406     }
407    
408     bool AudioOutputDeviceAlsa::ParameterFragmentSize::Mandatory() {
409     return false;
410     }
411    
412     std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragmentSize::DependsAsParameters() {
413     static ParameterCard card;
414     std::map<String,DeviceCreationParameter*> dependencies;
415     dependencies[card.Name()] = &card;
416     return dependencies;
417     }
418    
419     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::DefaultAsInt(std::map<String,String> Parameters) {
420 schoenebeck 1049 if (!Parameters.count("CARD")) return optional<int>::nothing;
421    
422     // obtain information from given sound card
423     ParameterCard card(Parameters["CARD"]);
424     String pcm_name = "hw:" + card.ValueAsString();
425     snd_pcm_t* pcm_handle = NULL;
426     if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
427     snd_pcm_hw_params_t* hwparams;
428     snd_pcm_hw_params_alloca(&hwparams);
429     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
430     snd_pcm_close(pcm_handle);
431     return optional<int>::nothing;
432     }
433     snd_pcm_uframes_t size = 128;
434     if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &size, NULL) < 0) {
435     snd_pcm_close(pcm_handle);
436     return optional<int>::nothing;
437     }
438     snd_pcm_close(pcm_handle);
439     return size;
440 schoenebeck 212 }
441    
442     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMinAsInt(std::map<String,String> Parameters) {
443 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
444    
445     // obtain information from given sound card
446 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
447     String pcm_name = "hw:" + card.ValueAsString();
448 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
449 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
450 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
451     snd_pcm_hw_params_alloca(&hwparams);
452     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
453     snd_pcm_close(pcm_handle);
454     return optional<int>::nothing;
455     }
456     int dir = 0;
457     unsigned long period_size_min;
458     if (snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, &dir) < 0) {
459     snd_pcm_close(pcm_handle);
460     return optional<int>::nothing;
461     }
462     snd_pcm_close(pcm_handle);
463     return (int) period_size_min;
464 schoenebeck 212 }
465    
466     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
467 schoenebeck 226 if (!Parameters.count("CARD")) return optional<int>::nothing;
468    
469     // obtain information from given sound card
470 schoenebeck 1049 ParameterCard card(Parameters["CARD"]);
471     String pcm_name = "hw:" + card.ValueAsString();
472 schoenebeck 226 snd_pcm_t* pcm_handle = NULL;
473 schoenebeck 485 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
474 schoenebeck 226 snd_pcm_hw_params_t* hwparams;
475     snd_pcm_hw_params_alloca(&hwparams);
476     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
477     snd_pcm_close(pcm_handle);
478     return optional<int>::nothing;
479     }
480     int dir = 0;
481     unsigned long period_size_max;
482     if (snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, &dir) < 0) {
483     snd_pcm_close(pcm_handle);
484     return optional<int>::nothing;
485     }
486     snd_pcm_close(pcm_handle);
487     return (int) period_size_max; //FIXME: might overflow int limit
488 schoenebeck 212 }
489    
490     std::vector<int> AudioOutputDeviceAlsa::ParameterFragmentSize::PossibilitiesAsInt(std::map<String,String> Parameters) {
491     return std::vector<int>();
492     }
493    
494 schoenebeck 880 void AudioOutputDeviceAlsa::ParameterFragmentSize::OnSetValue(int i) throw (Exception) {
495 schoenebeck 212 // not posssible, as parameter is fix
496     }
497    
498     String AudioOutputDeviceAlsa::ParameterFragmentSize::Name() {
499 schoenebeck 221 return "FRAGMENTSIZE";
500 schoenebeck 212 }
501    
502    
503    
504     // *************** AudioOutputDeviceAlsa ***************
505     // *
506    
507 schoenebeck 200 /**
508     * Create and initialize Alsa audio output device with given parameters.
509     *
510     * @param Parameters - optional parameters
511     * @throws AudioOutputException if output device cannot be opened
512     */
513 schoenebeck 392 AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) {
514 schoenebeck 200 pcm_handle = NULL;
515     stream = SND_PCM_STREAM_PLAYBACK;
516 schoenebeck 221 this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
517     this->uiSamplerate = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
518     this->FragmentSize = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt();
519     uint Fragments = ((DeviceCreationParameterInt*)Parameters["FRAGMENTS"])->ValueAsInt();
520     String Card = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString();
521 schoenebeck 200
522 schoenebeck 513 dmsg(2,("Checking if hw parameters supported...\n"));
523 schoenebeck 200 if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) {
524     pcm_name = "hw:" + Card;
525     }
526     else {
527 schoenebeck 513 fprintf(stderr, "Warning: your soundcard doesn't support chosen hardware parameters; ");
528     fprintf(stderr, "trying to compensate support lack with plughw...");
529 schoenebeck 200 fflush(stdout);
530     pcm_name = "plughw:" + Card;
531     }
532 schoenebeck 513 dmsg(2,("HW check completed.\n"));
533 schoenebeck 200
534     int err;
535    
536     snd_pcm_hw_params_alloca(&hwparams); // Allocate the snd_pcm_hw_params_t structure on the stack.
537    
538     /* Open PCM. The last parameter of this function is the mode. */
539     /* If this is set to 0, the standard mode is used. Possible */
540     /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
541     /* If SND_PCM_NONBLOCK is used, read / write access to the */
542     /* PCM device will return immediately. If SND_PCM_ASYNC is */
543     /* specified, SIGIO will be emitted whenever a period has */
544     /* been completely processed by the soundcard. */
545 schoenebeck 531 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
546 schoenebeck 200 throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
547     }
548    
549     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
550     throw AudioOutputException(String("Error, cannot initialize hardware parameter structure: ") + snd_strerror(err));
551     }
552    
553     /* Set access type. This can be either */
554     /* SND_PCM_ACCESS_RW_INTERLEAVED or */
555     /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
556     if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
557     throw AudioOutputException(String("Error snd_pcm_hw_params_set_access: ") + snd_strerror(err));
558     }
559    
560     /* Set sample format */
561     #if WORDS_BIGENDIAN
562     if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0)
563     #else // little endian
564     if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
565     #endif
566     {
567     throw AudioOutputException(String("Error setting sample format: ") + snd_strerror(err));
568     }
569    
570     int dir = 0;
571    
572     /* Set sample rate. If the exact rate is not supported */
573     /* by the hardware, use nearest possible rate. */
574     #if ALSA_MAJOR > 0
575     if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &uiSamplerate, &dir)) < 0)
576     #else
577     if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, uiSamplerate, &dir)) < 0)
578     #endif
579     {
580     throw AudioOutputException(String("Error setting sample rate: ") + snd_strerror(err));
581     }
582    
583     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, uiAlsaChannels)) < 0) {
584     throw AudioOutputException(String("Error setting number of channels: ") + snd_strerror(err));
585     }
586    
587     /* Set number of periods. Periods used to be called fragments. */
588     if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
589 schoenebeck 1049 throw AudioOutputException(String("Error setting number of ") + ToString(Fragments) + " periods: " + snd_strerror(err));
590 schoenebeck 200 }
591    
592     /* Set buffer size (in frames). The resulting latency is given by */
593     /* latency = periodsize * periods / (rate * bytes_per_frame) */
594     if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
595     throw AudioOutputException(String("Error setting buffersize: ") + snd_strerror(err));
596     }
597    
598     /* Apply HW parameter settings to */
599     /* PCM device and prepare device */
600     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
601     throw AudioOutputException(String("Error setting HW params: ") + snd_strerror(err));
602     }
603    
604     if (snd_pcm_sw_params_malloc(&swparams) != 0) {
605     throw AudioOutputException(String("Error in snd_pcm_sw_params_malloc: ") + snd_strerror(err));
606     }
607    
608     if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
609     throw AudioOutputException(String("Error in snd_pcm_sw_params_current: ") + snd_strerror(err));
610     }
611    
612     if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
613     throw AudioOutputException(String("Error in snd_pcm_sw_params_set_stop_threshold: ") + snd_strerror(err));
614     }
615    
616     if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
617     throw AudioOutputException(String("Error in snd_pcm_sw_params: ") + snd_strerror(err));
618     }
619    
620     if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
621     throw AudioOutputException(String("Error snd_pcm_prepare: ") + snd_strerror(err));
622     }
623    
624     // allocate Alsa output buffer
625     pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize];
626    
627     // create audio channels for this audio device to which the sampler engines can write to
628 schoenebeck 226 for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
629 schoenebeck 200
630 schoenebeck 221 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
631 schoenebeck 200 Play();
632     }
633     }
634    
635     AudioOutputDeviceAlsa::~AudioOutputDeviceAlsa() {
636     //dmsg(0,("Stopping Alsa Thread..."));
637     //StopThread(); //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
638     //dmsg(0,("OK\n"));
639    
640 iliev 1305 snd_pcm_close(pcm_handle);
641 schoenebeck 200
642     if (pAlsaOutputBuffer) {
643     //FIXME: currently commented out due to segfault
644     //delete[] pOutputBuffer;
645     }
646     }
647    
648     /**
649     * Checks if sound card supports the chosen parameters.
650     *
651     * @returns true if hardware supports it
652 schoenebeck 485 * @throws AudioOutputException - if device cannot be accessed
653 schoenebeck 200 */
654 schoenebeck 485 bool AudioOutputDeviceAlsa::HardwareParametersSupported(String card, uint channels, int samplerate, uint numfragments, uint fragmentsize) throw (AudioOutputException) {
655 schoenebeck 200 pcm_name = "hw:" + card;
656 schoenebeck 485 int err;
657 schoenebeck 513 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, SND_PCM_NONBLOCK)) < 0) {
658 schoenebeck 485 throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
659     }
660 schoenebeck 200 snd_pcm_hw_params_alloca(&hwparams);
661     if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
662     snd_pcm_close(pcm_handle);
663     return false;
664     }
665     if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
666     snd_pcm_close(pcm_handle);
667     return false;
668     }
669     #if WORDS_BIGENDIAN
670     if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0)
671     #else // little endian
672     if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0)
673     #endif
674     {
675     snd_pcm_close(pcm_handle);
676     return false;
677     }
678     int dir = 0;
679     if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
680     snd_pcm_close(pcm_handle);
681     return false;
682     }
683     if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
684     snd_pcm_close(pcm_handle);
685     return false;
686     }
687     if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
688     snd_pcm_close(pcm_handle);
689     return false;
690     }
691     if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
692     snd_pcm_close(pcm_handle);
693     return false;
694     }
695    
696     snd_pcm_close(pcm_handle);
697     return true;
698     }
699    
700     void AudioOutputDeviceAlsa::Play() {
701     StartThread();
702     }
703    
704     bool AudioOutputDeviceAlsa::IsPlaying() {
705     return IsRunning(); // if Thread is running
706     }
707    
708     void AudioOutputDeviceAlsa::Stop() {
709     StopThread();
710     }
711    
712 schoenebeck 226 AudioChannel* AudioOutputDeviceAlsa::CreateChannel(uint ChannelNr) {
713     // just create a mix channel
714     return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAlsaChannels));
715 schoenebeck 200 }
716    
717     uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {
718     return FragmentSize;
719     }
720    
721     uint AudioOutputDeviceAlsa::SampleRate() {
722     return uiSamplerate;
723     }
724    
725     String AudioOutputDeviceAlsa::Name() {
726 schoenebeck 221 return "ALSA";
727 schoenebeck 200 }
728    
729     String AudioOutputDeviceAlsa::Driver() {
730     return Name();
731     }
732    
733     String AudioOutputDeviceAlsa::Description() {
734     return "Advanced Linux Sound Architecture";
735     }
736    
737     String AudioOutputDeviceAlsa::Version() {
738 iliev 1305 String s = "$Revision: 1.23 $";
739 schoenebeck 200 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
740     }
741    
742     /**
743     * Entry point for the thread.
744     */
745     int AudioOutputDeviceAlsa::Main() {
746     while (true) {
747    
748     // let all connected engines render 'FragmentSize' sample points
749     RenderAudio(FragmentSize);
750    
751     // convert from DSP value range (-1.0..+1.0) to 16 bit integer value
752     // range (-32768..+32767), check clipping and copy to Alsa output buffer
753     // (note: we use interleaved output method to Alsa)
754     for (int c = 0; c < uiAlsaChannels; c++) {
755     float* in = Channels[c]->Buffer();
756     for (int i = 0, o = c; i < FragmentSize; i++ , o += uiAlsaChannels) {
757     float sample_point = in[i] * 32768.0f;
758     if (sample_point < -32768.0) sample_point = -32768.0;
759     if (sample_point > 32767.0) sample_point = 32767.0;
760     pAlsaOutputBuffer[o] = (int16_t) sample_point;
761     }
762     }
763    
764     // output sound
765     int res = Output();
766     if (res < 0) {
767     fprintf(stderr, "Alsa: Audio output error, exiting.\n");
768     exit(EXIT_FAILURE);
769     }
770     }
771     }
772    
773     /**
774     * Will be called after every audio fragment cycle, to output the audio data
775     * of the current fragment to the soundcard.
776     *
777     * @returns 0 on success, a value < 0 on error
778     */
779     int AudioOutputDeviceAlsa::Output() {
780     int err = snd_pcm_writei(pcm_handle, pAlsaOutputBuffer, FragmentSize);
781     if (err < 0) {
782     fprintf(stderr, "Error snd_pcm_writei failed: %s\n", snd_strerror(err));
783     return -1;
784     }
785     return 0;
786     }
787    
788     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC