/[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 3766 - (hide annotations) (download)
Mon Apr 6 12:41:49 2020 UTC (4 years ago) by schoenebeck
File size: 32974 byte(s)
Fixed deadlocks (e.g. when restarting engines).

* Individual thread implementations (e.g. disk thread, etc.):
  Disable thread cancellation on critical sections, e.g. when holding
  mutex locks, to prevent deadlocks if thread is stopped and/or
  restarted.

* Added TestCancel() calls to thread implementations if missing.

* No need to wrap Thread::TestCancel() calls into
  CONFIG_PTHREAD_TESTCANCEL macro conditions (since TestCancel() is
  already a stub on systems which don't have pthread_testcancel()
  available).

* If compiled for debugging: give each thread a human readable name
  to simplify debugging of multi-threading issues.

* DiskThreadBase: TestCancel() and pthread_testcancel() calls are
  per-se redundant, so only call TestCancel().

* Added missing override keywords to silent compiler warnings.

* Bumped version (2.1.1.svn54).

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

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC