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