arduino-audio-tools
PortAudioStream.h
1 #pragma once
7 #include "AudioTools.h"
8 #include "portaudio.h"
9 
10 namespace audio_tools {
11 
16 class PortAudioConfig : public AudioInfo {
17  public:
18  PortAudioConfig() {
19  sample_rate = 44100;
20  channels = 2;
21  bits_per_sample = 16;
22  };
23  PortAudioConfig(const PortAudioConfig&) = default;
24  PortAudioConfig(const AudioInfo& in) {
26  channels = in.channels;
28  }
29 
30  bool is_input = false;
31  bool is_output = true;
32 };
33 
38 class PortAudioStream : public AudioStream {
39  public:
40  PortAudioStream() {
41  TRACED();
42  }
43 
44  ~PortAudioStream(){
45  TRACED();
46  Pa_Terminate();
47  }
48 
49  PortAudioConfig defaultConfig(RxTxMode mode) {
50  TRACED();
51  PortAudioConfig result;
52  switch(mode){
53  case RX_MODE:
54  result.is_input = true;
55  result.is_output = false;
56  break;
57  case TX_MODE:
58  result.is_input = false;
59  result.is_output = true;
60  break;
61  case RXTX_MODE:
62  result.is_input = true;
63  result.is_output = true;
64  break;
65  default:
66  LOGE("Unsupported Mode")
67  break;
68  }
69 
70  return result;
71  }
72 
73  PortAudioConfig defaultConfig() {
74  TRACED();
75  PortAudioConfig default_info;
76  return default_info;
77  }
78 
80  void setAudioInfo(AudioInfo in) override {
81  TRACEI();
82  info.channels = in.channels;
83  info.sample_rate = in.sample_rate;
85  info.logInfo();
86  begin(info);
87  };
88 
89  // start with default configuration
90  bool begin() override {
91  return begin(defaultConfig());
92  }
93 
94  // start with the indicated configuration
95  bool begin(PortAudioConfig info) {
96  TRACED();
97  this->info = info;
98 
99  if (info.channels>0 && info.sample_rate && info.bits_per_sample>0){
100  LOGD("Pa_Initialize");
101  err = Pa_Initialize();
102  LOGD("Pa_Initialize - done");
103  if( err != paNoError ) {
104  LOGE( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
105  return false;
106  }
107 
108  // calculate frames
109  int buffer_frames = paFramesPerBufferUnspecified; //buffer_size / bytes / info.channels;
110 
111  // Open an audio I/O stream.
112  LOGD("Pa_OpenDefaultStream");
113  err = Pa_OpenDefaultStream( &stream,
114  info.is_input ? info.channels : 0, // no input channels
115  info.is_output ? info.channels : 0, // no output
116  getFormat(), // format
117  info.sample_rate, // sample rate
118  buffer_frames, // frames per buffer
119  nullptr,
120  nullptr );
121  LOGD("Pa_OpenDefaultStream - done");
122  if( err != paNoError && err!= paOutputUnderflow ) {
123  LOGE( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
124  return false;
125  }
126  } else {
127  LOGI("basic audio information is missing...");
128  return false;
129  }
130  return true;
131  }
132 
133  void end() override {
134  TRACED();
135  err = Pa_StopStream( stream );
136  if( err != paNoError ) {
137  LOGE( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
138  }
139 
140  err = Pa_CloseStream( stream );
141  if( err != paNoError ) {
142  LOGE( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
143  }
144  stream_started = false;
145  }
146 
147  operator bool() {
148  return err == paNoError;
149  }
150 
151  size_t write(const uint8_t* data, size_t len) override {
152  LOGD("write: %zu", len);
153 
154  startStream();
155 
156  size_t result = 0;
157  if (stream!=nullptr){
158  int frames = len / bytesPerSample() / info.channels;
159  err = Pa_WriteStream( stream, data, frames);
160  if( err == paNoError ) {
161  LOGD("Pa_WriteStream: %zu", len);
162  result = len;
163  } else {
164  LOGE("PortAudio error: %s", Pa_GetErrorText( err ) );
165  }
166  } else {
167  LOGW("stream is null")
168  }
169  return result;
170  }
171 
172  size_t readBytes( uint8_t *data, size_t len) override {
173  LOGD("readBytes: %zu", len);
174  size_t result = 0;
175  if (stream!=nullptr){
176  int frames = len / bytesPerSample() / info.channels;
177  err = Pa_ReadStream( stream, data, frames );
178  if( err == paNoError ) {
179  result = len;
180  } else {
181  LOGE( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
182  }
183  } else {
184  LOGW("stream is null")
185  }
186  return len;
187  }
188 
189 
190  protected:
191  PaStream *stream = nullptr;
192  PaError err = paNoError;
193  PortAudioConfig info;
194  bool stream_started = false;
195  int buffer_size = 10*1024;
196 
197  int bytesPerSample(){
198  //return info.bits_per_sample / 8;
199  return info.bits_per_sample==24 ? sizeof(int24_t): info.bits_per_sample / 8;
200  }
201 
202 
203  PaSampleFormat getFormat(){
204  switch(bytesPerSample()){
205  case 1:
206  return paInt8;
207  case 2:
208  return paInt16;
209  case 3:
210  return paInt24;
211  case 4:
212  return paInt32;
213  }
214  // make sure that we return a valid value
215  return paInt16;
216  }
217 
219  void startStream() {
220  if (!stream_started && stream != nullptr) {
221  TRACED();
222  err = Pa_StartStream( stream );
223  if( err == paNoError ) {
224  stream_started = true;
225  } else {
226  stream_started = false;
227  LOGE( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
228  }
229  }
230  }
231 };
232 
233 } // namespace
234 
235 
236 
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: BaseStream.h:109
PortAudio information.
Definition: PortAudioStream.h:16
Arduino Audio Stream using PortAudio.
Definition: PortAudioStream.h:38
void startStream()
automatically start the stream when we start to get data
Definition: PortAudioStream.h:219
void setAudioInfo(AudioInfo in) override
notification of audio info change
Definition: PortAudioStream.h:80
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition: AudioTypes.h:28
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:823
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:59