arduino-audio-tools
AudioSync.h
1 
2 #pragma once
3 #include "AudioTools/CoreAudio/AudioStreams.h"
4 #include "AudioTools/CoreAudio/AudioOutput.h"
5 #include "AudioTools/CoreAudio/Buffers.h"
6 #include "AudioTools/AudioCodecs/AudioEncoded.h"
7 
8 
9 namespace audio_tools {
10 
11 
12 enum class RecordType : uint8_t { Undefined, Begin, Send, Receive, End };
13 enum class AudioType : uint8_t { PCM, MP3, AAC, WAV, ADPC };
14 enum class TransmitRole : uint8_t { Sender, Receiver };
15 
17 struct AudioHeader {
18  AudioHeader() = default;
19  uint8_t app = 123;
20  RecordType rec = RecordType::Undefined;
21  uint16_t seq = 0;
22  // record counter
23  void increment() {
24  static uint16_t static_count = 0;
25  seq = static_count++;
26  }
27 };
28 
30 struct AudioDataBegin : public AudioHeader {
31  AudioDataBegin() { rec = RecordType::Begin; }
32  AudioInfo info;
33  AudioType type = AudioType::PCM;
34 };
35 
37 struct AudioSendData : public AudioHeader {
38  AudioSendData() {
39  rec = RecordType::Send;
40  }
41  uint16_t size = 0;
42 };
43 
46  AudioConfirmDataToReceive() { rec = RecordType::Receive; }
47  uint16_t size = 0;
48 };
49 
51 struct AudioDataEnd : public AudioHeader {
52  AudioDataEnd() { rec = RecordType::End; }
53 };
54 
55 
62 class AudioSyncWriter : public AudioOutput {
63  public:
64  AudioSyncWriter(Stream &dest) { p_dest = &dest; }
65 
66  bool begin(AudioInfo &info, AudioType type) {
67  is_sync = true;
68  AudioDataBegin begin;
69  begin.info = info;
70  begin.type = type;
71  begin.increment();
72  int write_len = sizeof(begin);
73  int len = p_dest->write((const uint8_t *)&begin, write_len);
74  return len == write_len;
75  }
76 
77  size_t write(const uint8_t *data, size_t len) override {
78  int written_len = 0;
79  int open_len = len;
80  AudioSendData send;
81  while (written_len < len) {
82  int available_to_write = waitForRequest();
83  size_t to_write_len = DEFAULT_BUFFER_SIZE;
84  to_write_len = min(open_len, available_to_write);
85  send.increment();
86  send.size = to_write_len;
87  p_dest->write((const uint8_t *)&send, sizeof(send));
88  int w = p_dest->write(data + written_len, to_write_len);
89  written_len += w;
90  open_len -= w;
91  }
92  return written_len;
93  }
94 
95  int availableForWrite() override { return available_to_write; }
96 
97  void end() {
98  AudioDataEnd end;
99  end.increment();
100  p_dest->write((const uint8_t *)&end, sizeof(end));
101  }
102 
103  protected:
104  Stream *p_dest;
105  int available_to_write = 1024;
106  bool is_sync;
107 
109  void waitFor(int size) {
110  while (p_dest->available() < size) {
111  delay(10);
112  }
113  }
114 
115  int waitForRequest() {
117  size_t rcv_len = sizeof(rcv);
118  waitFor(rcv_len);
119  p_dest->readBytes((uint8_t *)&rcv, rcv_len);
120  return rcv.size;
121  }
122 };
123 
132 class AudioSyncReader : public AudioStream {
133  public:
135  bool isConfirmer = true) {
136  p_in = &in;
137  p_out = &out;
138  is_confirmer = isConfirmer;
139  }
140 
141  size_t copy() {
142  int processed = 0;
143  int header_size = sizeof(header);
144  waitFor(header_size);
145  readBytes((uint8_t *)&header, header_size);
146 
147  switch (header.rec) {
148  case RecordType::Begin:
149  audioDataBegin();
150  break;
151  case RecordType::End:
152  audioDataEnd();
153  break;
154  case RecordType::Send:
155  processed = receiveData();
156  break;
157  }
158  return processed;
159  }
160 
161  protected:
162  Stream *p_in;
163  EncodedAudioStream *p_out;
165  AudioHeader header;
166  AudioDataBegin begin;
167  size_t available = 0; // initial value
168  bool is_started = false;
169  bool is_confirmer;
170  int last_seq = 0;
171 
173  void audioDataBegin() {
174  readProtocol(&begin, sizeof(begin));
175  p_out->begin();
176  p_out->setAudioInfo(begin.info);
177  requestData();
178  }
179 
181  void audioDataEnd() {
182  AudioDataEnd end;
183  readProtocol(&end, sizeof(end));
184  p_out->end();
185  }
186 
187  // Receives audio data
188  int receiveData() {
189  AudioSendData data;
190  readProtocol(&data, sizeof(data));
191  available = data.size;
192  // receive and process audio data
193  waitFor(available);
194  int max_gap = 10;
195  if (data.seq > last_seq ||
196  (data.seq < max_gap && last_seq >= (32767 - max_gap))) {
197  uint8_t buffer[available];
198  p_in->readBytes((uint8_t *)buffer, available);
199  p_out->write((const uint8_t *)buffer, available);
200  // only one reader should be used as confirmer
201  if (is_confirmer) {
202  requestData();
203  }
204  last_seq = data.seq;
205  }
206  return available;
207  }
208 
210  void waitFor(int size) {
211  while (p_in->available() < size) {
212  delay(10);
213  }
214  }
215 
217  void requestData() {
218  req.size = p_out->availableForWrite();
219  req.increment();
220  p_in->write((const uint8_t *)&req, sizeof(req));
221  p_in->flush();
222  }
223 
225  void readProtocol(AudioHeader *data, int len) {
226  static const int header_size = sizeof(header);
227  memcpy(data, &header, header_size);
228  int read_size = len - header_size;
229  waitFor(read_size);
230  readBytes((uint8_t *)data + header_size, read_size);
231  }
232 };
233 
234 } // namespace audio_tools
Abstract Audio Ouptut class.
Definition: AudioOutput.h:22
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: BaseStream.h:109
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: BaseStream.h:117
Receving Audio Data over the wire and requesting for more data when done to synchronize the processin...
Definition: AudioSync.h:132
void audioDataEnd()
Ends the processing.
Definition: AudioSync.h:181
void audioDataBegin()
Starts the processing.
Definition: AudioSync.h:173
void waitFor(int size)
Waits for the data to be available.
Definition: AudioSync.h:210
void readProtocol(AudioHeader *data, int len)
Reads the protocol record.
Definition: AudioSync.h:225
void requestData()
Request new data from writer.
Definition: AudioSync.h:217
Audio Writer which is synchronizing the amount of data that can be processed with the AudioReceiver.
Definition: AudioSync.h:62
void waitFor(int size)
Waits for the data to be available.
Definition: AudioSync.h:109
A more natural Stream class to process encoded data (aac, wav, mp3...) which also supports the decodi...
Definition: AudioEncoded.h:254
Definition: NoArduino.h:125
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:859
Protocol Record for Request.
Definition: AudioSync.h:45
Protocal Record To Start.
Definition: AudioSync.h:30
Protocol Record for End.
Definition: AudioSync.h:51
Common Header for all records.
Definition: AudioSync.h:17
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
Protocol Record for Data.
Definition: AudioSync.h:37