22
22
namespace audio_tools {
23
23
24
24
/* *
25
- * @brief Wraps the encoded data into OSC info and daata segments so that we
26
- * can recover the audio configuration and orignial segments. We assume that a
27
- * full segment is written with each call of write();
25
+ * @brief Wraps the encoded data into OSC info and data segments so that the
26
+ * receiver can recover the audio configuration and orignial segments.
28
27
* @ingroup codecs
29
28
* @ingroup encoder
30
29
* @author Phil Schatzmann
@@ -37,17 +36,15 @@ class OSCContainerEncoder : public AudioEncoder {
37
36
38
37
void setEncoder (AudioEncoder *encoder) { p_codec = encoder; }
39
38
40
- void setOutput (Print &outStream) {
41
- LOGD (" OSCContainerEncoder::setOutput" );
42
- p_out = &outStream;
43
- }
39
+ void setOutput (Print &outStream) { p_out = &outStream; }
44
40
45
41
bool begin () override {
46
42
TRACED ();
47
43
if (p_codec == nullptr ) return false ;
48
- // target.begin( );
49
- is_active = p_codec->begin ( );
44
+ osc_out. setOutput (*p_out );
45
+ p_codec->setOutput (osc_out );
50
46
p_codec->setAudioInfo (audioInfo ());
47
+ is_active = p_codec->begin ();
51
48
writeAudioInfo (audioInfo (), p_codec->mime ());
52
49
return is_active;
53
50
}
@@ -64,7 +61,7 @@ class OSCContainerEncoder : public AudioEncoder {
64
61
if ((repeat_info > 0 ) && (packet_count % repeat_info == 0 )) {
65
62
writeAudioInfo (audioInfo (), p_codec->mime ());
66
63
}
67
- writeAudio (data, len, packet_count );
64
+ p_codec-> write (data, len);
68
65
packet_count++;
69
66
return len;
70
67
}
@@ -78,53 +75,98 @@ class OSCContainerEncoder : public AudioEncoder {
78
75
79
76
virtual const char *mime () { return " audio/OSC" ; };
80
77
78
+ // / Activate/deactivate the sending of the audio info
79
+ void setInfoActive (bool flag) { is_send_info_active = flag; }
80
+ // / Automatically resend audio info ever nth write.
81
81
void setRepeatInfoEvery (int packet_count) {
82
82
this ->repeat_info = packet_count;
83
83
}
84
84
85
85
// / Returns the sequence number of the next packet
86
- uint64_t getSequenceNumber () { return packet_count ; }
87
-
88
- // / Writes the audio with the indicated sequence number to the output.
89
- // / To be called to resend missing data
90
- void writeAudio ( const uint8_t *data, size_t len, uint64_t sequenceNumber) {
91
- LOGD ( " writeAudio: %d " , ( int )len);
92
- uint8_t osc_data[len + 20 ]; // 20 is guess to cover address & fmt
93
- OSCData osc{osc_data, sizeof (osc_data)};
94
- osc. setAddress ( " /audio/data " );
95
- osc. setFormat ( " ttb " );
96
- osc. write (( uint64_t ) millis ());
97
- // we use a uint64_t for a sequence number
98
- osc. write (sequenceNumber);
99
- osc. write ( data, len);
100
- p_out-> write (osc_data, osc. size () );
86
+ uint64_t getSequenceNumber () { return osc_out. getSequenceNumber () ; }
87
+
88
+ // / Define a reference object to be provided by the callback
89
+ void setReference ( void *ref) { osc_out. setReference (ref); }
90
+
91
+ // / Get informed about the encoded packages
92
+ void setEncodedWriteCallback ( void (*write_callback)( uint8_t *data, size_t len,
93
+ uint64_t seq,
94
+ void *ref)) {
95
+ osc_out. setEncodedWriteCallback (write_callback );
96
+ }
97
+
98
+ // / Resend the encoded data
99
+ size_t resendEncodedData ( uint8_t * data, size_t len, uint64_t seq) {
100
+ return osc_out. write (data, len, seq );
101
101
}
102
102
103
103
protected:
104
104
uint64_t packet_count = 0 ;
105
105
int repeat_info = 0 ;
106
106
bool is_active = false ;
107
+ bool is_send_info_active = true ;
107
108
AudioEncoder *p_codec = nullptr ;
108
109
Print *p_out = nullptr ;
109
110
111
+ // / Output Encoded Audio via OSC
112
+ class OSCOutput : public AudioOutput {
113
+ public:
114
+ void setReference (void *ref) { this ->ref = ref; }
115
+ void setOutput (Print &outStream) { p_out = &outStream; }
116
+ void setEncodedWriteCallback (void (*write_callback)(
117
+ uint8_t *data, size_t len, uint64_t seq, void *ref)) {
118
+ this ->encoded_write_callback = write_callback;
119
+ }
120
+ uint64_t getSequenceNumber () { return sequence_number; }
121
+ size_t write (const uint8_t *data, size_t len) override {
122
+ size_t result = write (data, len);
123
+ sequence_number++;
124
+ return result;
125
+ }
126
+ size_t write (const uint8_t *data, size_t len, uint64_t seq) {
127
+ LOGD (" writeAudio: %d" , (int )len);
128
+ if (encoded_write_callback != nullptr ) {
129
+ encoded_write_callback ((uint8_t *)data, len, sequence_number, ref);
130
+ }
131
+ uint8_t osc_data[len + 20 ]; // 20 is guess to cover address & fmt
132
+ OSCData osc{osc_data, sizeof (osc_data)};
133
+ osc.setAddress (" /audio/data" );
134
+ osc.setFormat (" ttb" );
135
+ osc.write ((uint64_t )millis ());
136
+ // we use a uint64_t for a sequence number
137
+ osc.write (sequence_number);
138
+ osc.write (data, len);
139
+ p_out->write (osc_data, osc.size ());
140
+ return len;
141
+ }
142
+
143
+ protected:
144
+ void (*encoded_write_callback)(uint8_t *data, size_t len, uint64_t seq,
145
+ void *ref) = nullptr ;
146
+ Print *p_out = nullptr ;
147
+ uint64_t sequence_number = 0 ;
148
+ void *ref = nullptr ;
149
+ } osc_out;
110
150
111
151
void writeAudioInfo (AudioInfo info, const char *mime) {
112
- LOGD (" writeAudioInfo" );
113
- uint8_t osc_data[100 ];
114
- OSCData osc{osc_data, sizeof (osc_data)};
115
- osc.setAddress (" /audio/info" );
116
- osc.setFormat (" iiis" );
117
- osc.write ((int32_t )info.sample_rate );
118
- osc.write ((int32_t )info.channels );
119
- osc.write ((int32_t )info.bits_per_sample );
120
- osc.write (mime);
121
- p_out->write (osc_data, osc.size ());
152
+ if (is_send_info_active) {
153
+ LOGD (" writeAudioInfo" );
154
+ uint8_t osc_data[100 ];
155
+ OSCData osc{osc_data, sizeof (osc_data)};
156
+ osc.setAddress (" /audio/info" );
157
+ osc.setFormat (" iiis" );
158
+ osc.write ((int32_t )info.sample_rate );
159
+ osc.write ((int32_t )info.channels );
160
+ osc.write ((int32_t )info.bits_per_sample );
161
+ osc.write (mime);
162
+ p_out->write (osc_data, osc.size ());
163
+ }
122
164
}
123
165
};
124
166
125
167
/* *
126
- * @brief Decodes the provided data from the OSC segments. I recommend to assign
127
- * a MultiDecoder so that we can support muiltiple audio types.
168
+ * @brief Decodes the provided data from the OSC segments. I recommend to
169
+ * assign a MultiDecoder so that we can support muiltiple audio types.
128
170
* @ingroup codecs
129
171
* @ingroup decoder
130
172
* @author Phil Schatzmann
@@ -192,7 +234,8 @@ class OSCContainerDecoder : public ContainerDecoder {
192
234
193
235
// / Callback to be called when data is missing
194
236
void setMissingDataCallback (void (*missing_data_callback)(uint64_t from_seq,
195
- uint64_t to_seq, void * ref)) {
237
+ uint64_t to_seq,
238
+ void *ref)) {
196
239
this ->missing_data_callback = missing_data_callback;
197
240
}
198
241
@@ -216,7 +259,8 @@ class OSCContainerDecoder : public ContainerDecoder {
216
259
void *ref = nullptr ;
217
260
218
261
// / Default callback for missing data: just log the missing range
219
- static void missingDataCallback (uint64_t from_seq, uint64_t to_seq, void * ref) {
262
+ static void missingDataCallback (uint64_t from_seq, uint64_t to_seq,
263
+ void *ref) {
220
264
LOGW (" Missing sequence numbers %d - %d" , from_seq, to_seq);
221
265
}
222
266
0 commit comments