arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
MimeDetector.h
1#pragma once
2
3#include "AudioTools/AudioCodecs/HeaderParserAAC.h"
4#include "AudioTools/AudioCodecs/HeaderParserMP3.h"
5#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
6
7namespace audio_tools {
8
24 public:
25 MimeDetector() {
26 setCheck("audio/vnd.wave", checkWAV);
27 setCheck("audio/ogg", checkOGG);
28 setCheck("video/MP2T", checkMP2T);
29 setCheck("audio/prs.sid", checkSID);
30 setCheck("audio/m4a", checkM4A);
31 setCheck("audio/mpeg", checkMP3Ext);
32 setCheck("audio/aac", checkAACExt);
33 }
34
35 bool begin() {
36 is_first = true;
37 return true;
38 }
39
41 size_t write(uint8_t* data, size_t len) {
42 actual_mime = default_mime;
43 determineMime(data, len);
44 return len;
45 }
46
48 void setCheck(const char* mime, bool (*check)(uint8_t* start, size_t len)) {
49 StrView mime_str{mime};
50 for (int j = 0; j < checks.size(); j++) {
51 Check l_check = checks[j];
52 if (mime_str.equals(l_check.mime)) {
53 l_check.check = check;
54 return;
55 }
56 }
57 Check check_to_add{mime, check};
58 checks.push_back(check_to_add);
59 }
60
61 // /// Define the callback that will notify about mime changes
62 void setMimeCallback(void (*callback)(const char*)) {
63 TRACED();
64 this->notifyMimeCallback = callback;
65 }
66
69 const char* mime() { return actual_mime; }
70
71 static bool checkAAC(uint8_t* start, size_t len) {
72 return start[0] == 0xFF &&
73 (start[1] == 0xF0 || start[1] == 0xF1 || start[1] == 0xF9);
74 }
75
76 static bool checkAACExt(uint8_t* start, size_t len) {
77 // checking logic for files
78 if (memcmp(start + 4, "ftypM4A", 7) == 0) {
79 return true;
80 }
81 // check for streaming
82 HeaderParserAAC aac;
83 // it should start with a synch word
84 int pos = aac.findSyncWord((const uint8_t*)start, len);
85 if (pos == -1) {
86 return false;
87 }
88 // make sure that it is not an mp3
89 if (aac.isValid(start + pos, len - pos)) {
90 return false;
91 }
92 return true;
93 }
94
95 static bool checkMP3(uint8_t* start, size_t len) {
96 return memcmp(start, "ID3", 3) == 0 ||
97 (start[0] == 0xFF && ((start[1] & 0xE0) == 0xE0));
98 }
99
100 static bool checkMP3Ext(uint8_t* start, size_t len) {
101 HeaderParserMP3 mp3;
102 return mp3.isValid(start, len);
103 }
104
105 static bool checkWAV(uint8_t* start, size_t len) {
106 return memcmp(start, "RIFF", 4) == 0;
107 }
108
109 static bool checkOGG(uint8_t* start, size_t len) {
110 return memcmp(start, "OggS", 4) == 0;
111 }
112
114 static bool checkMP2T(uint8_t* start, size_t len) {
115 if (len < 189) return start[0] == 0x47;
116
117 return start[0] == 0x47 && start[188] == 0x47;
118 }
119
121 static bool checkSID(uint8_t* start, size_t len) {
122 return memcmp(start, "PSID", 4) == 0 || memcmp(start, "RSID", 4) == 0;
123 }
124
125 static bool checkM4A(uint8_t* header, size_t len) {
126 if (len < 12) return false;
127
128 // prevent false detecton by mp3 files
129 if (memcmp(header, "ID3", 3) == 0) return false;
130
131 // Special hack when we position to start of mdat box
132 if (memcmp(header + 4, "mdat", 4) != 0) return true;
133
134 // Check for "ftyp" at offset 4
135 if (memcmp(header + 4, "ftyp", 4) != 0) return false;
136
137 // Check for "M4A " or similar major brand
138 if (memcmp(header + 8, "M4A ", 4) == 0 ||
139 memcmp(header + 8, "mp42", 4) == 0 ||
140 memcmp(header + 8, "isom", 4) == 0)
141 return true;
142
143 return false;
144 }
145
147 void setDefaultMime(const char* mime) { default_mime = mime; }
148
149 protected:
150 struct Check {
151 const char* mime = nullptr;
152 bool (*check)(uint8_t* data, size_t len) = nullptr;
153 Check(const char* mime, bool (*check)(uint8_t* data, size_t len)) {
154 this->mime = mime;
155 this->check = check;
156 }
157 Check() = default;
158 };
159 Vector<Check> checks{0};
160 bool is_first = false;
161 const char* actual_mime = nullptr;
162 const char* default_mime = nullptr;
163 void (*notifyMimeCallback)(const char* mime) = nullptr;
164
166 void determineMime(void* data, size_t len) {
167 if (is_first) {
168 actual_mime = lookupMime((uint8_t*)data, len);
169 if (notifyMimeCallback != nullptr && actual_mime != nullptr) {
170 notifyMimeCallback(actual_mime);
171 }
172 is_first = false;
173 }
174 }
175
177 const char* lookupMime(uint8_t* data, size_t len) {
178 for (int j = 0; j < checks.size(); j++) {
179 Check l_check = checks[j];
180 if (l_check.check(data, len)) {
181 return l_check.mime;
182 }
183 }
184 return default_mime;
185 }
186};
187
188} // namespace audio_tools
Logic to detemine the mime type from the content. By default the following mime types are supported (...
Definition MimeDetector.h:23
static bool checkSID(uint8_t *start, size_t len)
Commodore 64 SID File.
Definition MimeDetector.h:121
void determineMime(void *data, size_t len)
Update the mime type.
Definition MimeDetector.h:166
void setCheck(const char *mime, bool(*check)(uint8_t *start, size_t len))
adds/updates the checking logic for the indicated mime
Definition MimeDetector.h:48
const char * lookupMime(uint8_t *data, size_t len)
Default logic which supports aac, mp3, wav and ogg.
Definition MimeDetector.h:177
size_t write(uint8_t *data, size_t len)
write the header to determine the mime
Definition MimeDetector.h:41
const char * mime()
Definition MimeDetector.h:69
void setDefaultMime(const char *mime)
Provides the default mime type if no mime could be determined.
Definition MimeDetector.h:147
static bool checkMP2T(uint8_t *start, size_t len)
MPEG-2 TS Byte Stream Format.
Definition MimeDetector.h:114
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Definition MimeDetector.h:150