1
+ /* *
2
+ * @file ContainerOSC.h
3
+ * @author Phil Schatzmann
4
+ * @brief A simple container format which uses OSC messages to
5
+ * tramsmit Header records with audio info and Audio records with the audio
6
+ * data.
7
+ *
8
+ * @version 0.1
9
+ * @date 2025-05-20
10
+ *
11
+ * @copyright Copyright (c) 2022
12
+ *
13
+ */
14
+ #pragma once
15
+ #include < string.h>
16
+
17
+ #include " AudioTools/AudioCodecs/AudioCodecsBase.h"
18
+ #include " AudioTools/AudioCodecs/MultiDecoder.h"
19
+ #include " AudioTools/Communication/OSCData.h"
20
+ #include " AudioTools/CoreAudio/AudioBasic/StrView.h"
21
+
22
+ namespace audio_tools {
23
+
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();
28
+ * @ingroup codecs
29
+ * @ingroup encoder
30
+ * @author Phil Schatzmann
31
+ * @copyright GPLv3
32
+ */
33
+ class OSCContainerEncoder : public AudioEncoder {
34
+ public:
35
+ OSCContainerEncoder () = default ;
36
+ OSCContainerEncoder (AudioEncoder &encoder) { p_codec = &encoder; }
37
+
38
+ void setEncoder (AudioEncoder *encoder) { p_codec = encoder; }
39
+
40
+ void setOutput (Print &outStream) {
41
+ LOGD (" OSCContainerEncoder::setOutput" );
42
+ p_out = &outStream;
43
+ }
44
+
45
+ bool begin () override {
46
+ TRACED ();
47
+ // target.begin();
48
+ bool rc = p_codec->begin ();
49
+ p_codec->setAudioInfo (audioInfo ());
50
+ is_beginning = true ;
51
+ writeAudioInfo ();
52
+ return rc;
53
+ }
54
+
55
+ void setAudioInfo (AudioInfo info) override {
56
+ TRACED ();
57
+ writeAudioInfo ();
58
+ AudioWriter::setAudioInfo (info);
59
+ }
60
+
61
+ // / Add data segment. On first write we also add a AudioInfo header
62
+ size_t write (const uint8_t *data, size_t len) {
63
+ LOGD (" OSCContainerEncoder::write: %d" , (int )len);
64
+ if (packet_count % repeat_info == 0 ) {
65
+ writeAudioInfo ();
66
+ }
67
+ writeAudio (data, len);
68
+ return len;
69
+ }
70
+
71
+ void end () { p_codec->end (); }
72
+
73
+ operator bool () { return true ; };
74
+
75
+ virtual const char *mime () { return " audio/OSC" ; };
76
+
77
+ void setRepeatInfoEvery (int packet_count) {
78
+ this ->repeat_info = packet_count;
79
+ }
80
+
81
+ protected:
82
+ uint64_t packet_count = 0 ;
83
+ int repeat_info = 0 ;
84
+ bool is_beginning = true ;
85
+ AudioEncoder *p_codec = nullptr ;
86
+ Print *p_out = nullptr ;
87
+
88
+ void writeAudio (const uint8_t *data, size_t len) {
89
+ LOGD (" writeAudio: %d" , (int )len);
90
+ uint8_t osc_data[len + 20 ]; // 20 is guess to cover address & fmt
91
+ OSCData osc{osc_data, sizeof (osc_data)};
92
+ osc.setAddress (" /audio/data" );
93
+ osc.setFormat (" b" );
94
+ osc.write (data, len);
95
+ p_out->write (osc_data, osc.size ());
96
+ }
97
+
98
+ void writeAudioInfo () {
99
+ LOGD (" writeAudioInfo" );
100
+ uint8_t osc_data[100 ];
101
+ OSCData osc{osc_data, sizeof (osc_data)};
102
+ osc.setAddress (" /audio/info" );
103
+ osc.setFormat (" iiis" );
104
+ osc.write ((int32_t )audioInfo ().sample_rate );
105
+ osc.write ((int32_t )audioInfo ().channels );
106
+ osc.write ((int32_t )audioInfo ().bits_per_sample );
107
+ osc.write (p_codec->mime ());
108
+ p_out->write (osc_data, osc.size ());
109
+ }
110
+ };
111
+
112
+ /* *
113
+ * @brief Decodes the provided data from the OSC segments. I recommend to assign
114
+ * a MultiDecoder so that we can support muiltiple audio types.
115
+ * @ingroup codecs
116
+ * @ingroup decoder
117
+ * @author Phil Schatzmann
118
+ * @copyright GPLv3
119
+ */
120
+ class OSCContainerDecoder : public ContainerDecoder {
121
+ public:
122
+ OSCContainerDecoder () = default ;
123
+ OSCContainerDecoder (AudioDecoder &decoder) { setDecoder (decoder); }
124
+ OSCContainerDecoder (MultiDecoder &decoder) { setDecoder (decoder); }
125
+
126
+ void setDecoder (AudioDecoder &decoder) { p_codec = &decoder; }
127
+
128
+ void setDecoder (MultiDecoder &decoder) {
129
+ p_codec = &decoder;
130
+ p_multi_decoder = &decoder;
131
+ }
132
+
133
+ void setOutput (Print &outStream) {
134
+ LOGD (" OSCContainerDecoder::setOutput" )
135
+ p_out = &outStream;
136
+ }
137
+
138
+ bool begin () {
139
+ TRACED ();
140
+ is_first = true ;
141
+ osc.setReference (this );
142
+ osc.addCallback (" /audio/info" , parseInfo, OSCCompare::StartsWith);
143
+ osc.addCallback (" /audio/data" , parseData, OSCCompare::StartsWith);
144
+ return true ;
145
+ }
146
+
147
+ void end () { TRACED (); }
148
+
149
+ size_t write (const uint8_t *data, size_t len) {
150
+ LOGD (" write: %d" , (int )len);
151
+ if (!osc.parse ((uint8_t *)data, len)) {
152
+ return 0 ;
153
+ }
154
+ return len;
155
+ }
156
+
157
+ operator bool () { return true ; };
158
+
159
+ // / Provides the mime type from the encoder
160
+ const char *mime () { return mime_str.c_str (); };
161
+
162
+ protected:
163
+ bool is_first = true ;
164
+ AudioDecoder *p_codec = nullptr ;
165
+ MultiDecoder *p_multi_decoder = nullptr ;
166
+ SingleBuffer<uint8_t > buffer{0 };
167
+ Print *p_out = nullptr ;
168
+ OSCData osc;
169
+ Str mime_str;
170
+
171
+ static bool parseData (OSCData &osc, void *ref) {
172
+ OSCBinaryData data = osc.readData ();
173
+ OSCContainerDecoder *decoder = static_cast <OSCContainerDecoder *>(ref);
174
+ if (decoder->p_codec != nullptr ) {
175
+ decoder->p_codec ->write (data.data , data.len );
176
+ }
177
+ return true ;
178
+ }
179
+
180
+ static bool parseInfo (OSCData &osc, void *ref) {
181
+ AudioInfo info;
182
+ info.sample_rate = osc.readInt32 ();
183
+ info.channels = osc.readInt32 ();
184
+ info.bits_per_sample = osc.readInt32 ();
185
+ const char *mime = osc.readString ();
186
+
187
+ OSCContainerDecoder *decoder = static_cast <OSCContainerDecoder *>(ref);
188
+ if (decoder != nullptr ) {
189
+ decoder->setAudioInfo (info);
190
+ decoder->mime_str = mime;
191
+ // select the right decoder based on the mime type
192
+ if (decoder->p_multi_decoder )
193
+ decoder->p_multi_decoder ->selectDecoder (mime);
194
+ }
195
+
196
+ return true ;
197
+ }
198
+ };
199
+
200
+ } // namespace audio_tools
0 commit comments