SoDaRadio-5.0.3-master:8901fb5
AudioALSA.hxx
Go to the documentation of this file.
1 #ifndef ALSA_PCM_HDR
2 #define ALSA_PCM_HDR
3 /*
4  Copyright (c) 2012, Matthew H. Reilly (kb1vc)
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions are
9  met:
10 
11  Redistributions of source code must retain the above copyright
12  notice, this list of conditions and the following disclaimer.
13  Redistributions in binary form must reproduce the above copyright
14  notice, this list of conditions and the following disclaimer in
15  the documentation and/or other materials provided with the
16  distribution.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 
31 #include "SoDaBase.hxx"
32 #include "AudioIfc.hxx"
33 #include <string>
34 #if HAVE_LIBASOUND
35 # include <alsa/asoundlib.h>
36 # define ALSA_DEF
37 #else
38 # define ALSA_DEF { throw SoDa::SoDaException("ALSA Sound Library is not enabled in this build version."); }
39 #endif
40 #include <boost/format.hpp>
41 #include <iostream>
42 #include <stdexcept>
43 
44 namespace SoDa {
63  class AudioALSA : public AudioIfc {
64  public:
73  AudioALSA(unsigned int _sample_rate,
75  unsigned int _sample_count_hint = 1024,
76  std::string audio_port_name = std::string("default"));
77 
79 #if HAVE_LIBASOUND
80  snd_pcm_close(pcm_out);
81 #endif
82  }
83 
90  int send(void * buf, unsigned int len) ALSA_DEF ;
91 
98  bool sendBufferReady(unsigned int len) ALSA_DEF ;
99 
107  int recv(void * buf, unsigned int len, bool block = true) ALSA_DEF ;
108 
115  bool recvBufferReady(unsigned int len) ALSA_DEF ;
116 
121  void sleepOut() {
122 #if HAVE_LIBASOUND
123  snd_pcm_drain(pcm_out);
124 #endif
125  }
129  void wakeOut() {
130 #if HAVE_LIBASOUND
131  int err;
132  if((err = snd_pcm_prepare(pcm_out)) < 0) {
133  throw
134  SoDaException((boost::format("AudioALSA::wakeOut() Failed to wake after sleepOut() pcm_prepare -- %s")
135  % snd_strerror(err)).str(), this);
136  }
137  if((err = snd_pcm_start(pcm_out)) < 0) {
138  throw
139  SoDaException((boost::format("AudioALSA::wakeOut() Failed to wake after sleepOut() pcm_start -- %s")
140  % snd_strerror(err)).str(), this);
141  }
142 #endif
143  }
144 
149  void sleepIn() {
150 #if HAVE_LIBASOUND
151  snd_pcm_drop(pcm_in);
152 
153  // now read the input buffers until they're empty
154  int buf[1000];
155  int len = 1000;
156  int stat = 1;
157  while(stat > 0) {
158  stat = snd_pcm_readi(pcm_in, buf, len);
159  if(stat == 0) break;
160  else if(stat == -EAGAIN) continue;
161  else break;
162  }
163 #endif
164  }
165 
169  void wakeIn() {
170 #if HAVE_LIBASOUND
171  int err;
172  if((err = snd_pcm_prepare(pcm_in)) < 0) {
173  throw
174  SoDaException((boost::format("AudioALSA::wakeIn() Failed to wake after sleepIn() -- %s")
175  % snd_strerror(err)).str(), this);
176  }
177  if((err = snd_pcm_start(pcm_in)) < 0) {
178  throw
179  SoDaException((boost::format("AudioALSA::wakeIn() Failed to wake after sleepIn() -- %s")
180  % snd_strerror(err)).str(), this);
181  }
182 #endif
183  }
184 #if HAVE_LIBASOUND
185  std::string currentPlaybackState() {
186  std::string cs = currentState(pcm_out);
187  return (boost::format("%s ready_frames = %d") % cs % snd_pcm_avail(pcm_out)).str();
188  }
189 
190  std::string currentCaptureState() {
191  return currentState(pcm_in);
192  }
193 #endif
194  protected:
195 #if HAVE_LIBASOUND
196  snd_pcm_t * pcm_out;
197  snd_pcm_t * pcm_in;
198  snd_pcm_hw_params_t * hw_in_params;
199  snd_pcm_hw_params_t * hw_out_params;
200 
204  std::string currentState(snd_pcm_t * dev) {
205  snd_pcm_state_t st = snd_pcm_state(dev);
206 
207  switch (st) {
208  case SND_PCM_STATE_OPEN:
209  return std::string("SND_PCM_STATE_OPEN");
210  break;
211  case SND_PCM_STATE_SETUP:
212  return std::string("SND_PCM_STATE_SETUP");
213  break;
214  case SND_PCM_STATE_PREPARED:
215  return std::string("SND_PCM_STATE_PREPARED");
216  break;
217  case SND_PCM_STATE_RUNNING:
218  return std::string("SND_PCM_STATE_RUNNING");
219  break;
220  case SND_PCM_STATE_XRUN:
221  return std::string("SND_PCM_STATE_XRUN");
222  break;
223  case SND_PCM_STATE_DRAINING:
224  return std::string("SND_PCM_STATE_DRAINING");
225  break;
226  case SND_PCM_STATE_PAUSED:
227  return std::string("SND_PCM_STATE_PAUSED");
228  break;
229  case SND_PCM_STATE_SUSPENDED:
230  return std::string("SND_PCM_STATE_SUSPENDED");
231  break;
232  case SND_PCM_STATE_DISCONNECTED:
233  return std::string("SND_PCM_STATE_DISCONNECTED");
234  break;
235  default:
236  return std::string("BADSTATE-UNKNOWN");
237  }
238  }
239 
243  void setupPlayback(std::string audio_port_name);
244 
248  void setupCapture(std::string audio_port_name);
249 
255  void setupParams(snd_pcm_t * dev, snd_pcm_hw_params_t * & hw_params);
256 
262  snd_pcm_format_t translateFormat(AudioIfc::DataFormat fmt);
263 
270  void checkStatus(int err, const std::string & exp, bool fatal = false) {
271 
272  if (err < 0) {
273  if(fatal) throw SoDaException((boost::format("%s %s") % exp % snd_strerror(err)).str(), this);
274  else std::cerr << boost::format("%s %s %s\n") % getObjName() % exp % snd_strerror(err);
275  }
276  }
277 #endif // HAVE_LIBASOUND
278  };
279 }
280 
281 
282 #endif
The Baseclass for all SoDa objects, and useful commonly used classes.
int send(void *buf, unsigned int len)
send – send a buffer to the audio output
Definition: AudioALSA.hxx:90
std::string & getObjName()
get the name of this object
Definition: SoDaBase.hxx:182
bool sendBufferReady(unsigned int len)
sendBufferReady – is there enough space in the audio device send buffer for a call from send...
Definition: AudioALSA.hxx:98
virtual std::string currentCaptureState()
Definition: AudioIfc.hxx:166
The SoDa Exception class.
Definition: SoDaBase.hxx:217
void wakeOut()
start the output stream
Definition: AudioALSA.hxx:129
virtual std::string currentPlaybackState()
Definition: AudioIfc.hxx:165
void sleepOut()
stop the output stream so that we don&#39;t encounter a buffer underflow while the reciever is muted...
Definition: AudioALSA.hxx:121
void sleepIn()
stop the input stream so that we don&#39;t encounter a buffer overflow while the transmitter is inactive...
Definition: AudioALSA.hxx:149
ALSA audio interface class.
Definition: AudioALSA.hxx:63
bool recvBufferReady(unsigned int len)
recvBufferReady – are there samples waiting in the audio device?
Definition: AudioALSA.hxx:115
Generic Audio Interface Class.
Definition: AudioIfc.hxx:44
int recv(void *buf, unsigned int len, bool block=true)
recv – get a buffer of data from the audio input
Definition: AudioALSA.hxx:107
void wakeIn()
start the input stream
Definition: AudioALSA.hxx:169
#define ALSA_DEF
Definition: AudioALSA.hxx:38
AudioALSA(unsigned int _sample_rate, AudioIfc::DataFormat _fmt, unsigned int _sample_count_hint=1024, std::string audio_port_name=std::string("default"))
constructor
Definition: AudioALSA.cxx:254