arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
PortAudioStream.h
1#pragma once
7#include "AudioTools.h"
8#include "portaudio.h"
9
10namespace audio_tools {
11
16class PortAudioConfig : public AudioInfo {
17 public:
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
39 public:
41 TRACED();
42 }
43
45 TRACED();
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();
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:115
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
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
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:885
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