this repo has no description
1/*
2This file is part of Darling.
3
4Copyright (C) 2020 Lubos Dolezel
5
6Darling is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11Darling is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with Darling. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "AudioFileFormatManager.h"
21
22AudioFileFormatManager::AudioFileFormatManager()
23{
24
25}
26
27void AudioFileFormatManager::buildDatabase()
28{
29 AudioComponentDescription acd = { 0 };
30 acd.componentType = 'afil';
31
32 AudioComponent component = nullptr;
33
34 while ((component = ::AudioComponentFindNext(component, &acd)) != nullptr)
35 {
36 AudioComponentInstance inst;
37 OSStatus status = ::AudioComponentInstanceNew(component, &inst);
38
39 if (status != noErr)
40 continue;
41
42 analyzeAudioFileComponent(inst);
43 ::AudioComponentInstanceDispose(inst);
44 }
45}
46
47static std::vector<std::string> cfArrayToVector(CFArrayRef array)
48{
49 std::vector<std::string> rv;
50 const CFIndex count = CFArrayGetCount(array);
51
52 rv.reserve(count);
53
54 for (CFIndex i = 0; i < count; i++)
55 {
56 CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(array, i);
57 rv.push_back(CFStringGetCStringPtr(str, kCFStringEncodingUTF8));
58 }
59
60 return rv;
61}
62
63void AudioFileFormatManager::analyzeAudioFileComponent(AudioFileComponent component)
64{
65 ComponentInfo ci;
66 UInt32 propSize;
67
68 ::AudioComponentGetDescription(AudioComponent(component), &ci.acd);
69
70 ci.fileType = ci.acd.componentSubType; // TODO: Is this correct?
71
72 {
73 CFStringRef name = nullptr;
74 propSize = sizeof(name);
75
76 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_FileTypeName, 0, nullptr, &propSize, &name) == noErr && name)
77 {
78 ci.name = CFStringGetCStringPtr(name, kCFStringEncodingUTF8);
79 CFRelease(name);
80 }
81 }
82 {
83 UInt32 can;
84
85 propSize = sizeof(can);
86 ci.canRead = ci.canWrite = false;
87
88 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_CanRead, 0, nullptr, &propSize, &can) == noErr && can)
89 ci.canRead = true;
90 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_CanWrite, 0, nullptr, &propSize, &can) == noErr && can)
91 ci.canWrite = true;
92 }
93
94 CFArrayRef array = nullptr;
95 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_UTIsForType, 0, nullptr, &propSize, &array) == noErr && array)
96 {
97 ci.utis = cfArrayToVector(array);
98 CFRelease(array);
99 }
100
101 array = nullptr;
102 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_MIMETypesForType, 0, nullptr, &propSize, &array) == noErr && array)
103 {
104 ci.mimeTypes = cfArrayToVector(array);
105 CFRelease(array);
106 }
107
108 array = nullptr;
109 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_ExtensionsForType, 0, nullptr, &propSize, &array) == noErr && array)
110 {
111 ci.extensions = cfArrayToVector(array);
112 CFRelease(array);
113 }
114
115 if (::AudioFileComponentGetGlobalInfoSize(component, kAudioFileComponent_AvailableFormatIDs, 0, nullptr, &propSize) == noErr)
116 {
117 const size_t formatCount = propSize / sizeof(UInt32);
118 std::unique_ptr<UInt32[]> formatIds(new UInt32[formatCount]);
119
120 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_AvailableFormatIDs, 0, nullptr, &propSize, formatIds.get()) == noErr)
121 {
122 for (size_t i = 0; i < formatCount; i++)
123 {
124 UInt32 format = formatIds[i];
125 std::vector<AudioStreamBasicDescription> asbds;
126
127 if (::AudioFileComponentGetGlobalInfoSize(component, kAudioFileComponent_AvailableStreamDescriptionsForFormat, sizeof(UInt32), &format, &propSize) == noErr)
128 {
129 asbds.resize(propSize / sizeof(AudioStreamBasicDescription));
130
131 if (::AudioFileComponentGetGlobalInfo(component, kAudioFileComponent_AvailableStreamDescriptionsForFormat, sizeof(UInt32), &format, &propSize, asbds.data()) != noErr)
132 asbds.resize(0);
133
134 ci.formatDescriptions.emplace(format, std::move(asbds));
135 }
136 else
137 ci.formatDescriptions.emplace(format, asbds);
138 }
139 }
140 }
141
142 registerComponent(ci);
143}
144
145void AudioFileFormatManager::addToMap(std::unordered_map<std::string, std::vector<ComponentInfo*>>& map, const std::string& key, ComponentInfo* ci)
146{
147 auto it = map.find(key);
148 if (it == map.end())
149 it = map.emplace(key, std::vector<ComponentInfo*>()).first;
150 it->second.push_back(ci);
151}
152
153void AudioFileFormatManager::registerComponent(const ComponentInfo& ci)
154{
155 m_components.push_back(ci);
156
157 // Add format into various maps
158 ComponentInfo* pci = &m_components.back();
159 m_fileTypeMap.emplace(ci.fileType, pci);
160
161 for (const std::string& uti : ci.utis)
162 addToMap(m_utiMap, uti, pci);
163 for (const std::string& mime : ci.mimeTypes)
164 addToMap(m_mimeMap, mime, pci);
165 for (const std::string& ext : ci.extensions)
166 addToMap(m_extensionMap, ext, pci);
167}
168
169AudioFileFormatManager* AudioFileFormatManager::instance()
170{
171 static AudioFileFormatManager inst;
172 return &inst;
173}
174
175std::set<UInt32> AudioFileFormatManager::availableFormatIDs(UInt32 fileType) const
176{
177 std::set<UInt32> rv;
178
179 auto it = m_fileTypeMap.find(fileType);
180 if (it == m_fileTypeMap.end())
181 return rv;
182
183 const ComponentInfo* ci = it->second;
184
185 for (auto const& [key, value] : ci->formatDescriptions)
186 rv.insert(key);
187 return rv;
188}
189
190const AudioFileFormatManager::ComponentInfo* AudioFileFormatManager::fileType(UInt32 fileType) const
191{
192 auto it = m_fileTypeMap.find(fileType);
193 if (it == m_fileTypeMap.end())
194 return nullptr;
195 return it->second;
196}
197
198std::set<UInt32> AudioFileFormatManager::types(bool writableTypes) const
199{
200 std::set<UInt32> rv;
201
202 for (const ComponentInfo& ci : m_components)
203 {
204 if (writableTypes && ci.canWrite)
205 rv.insert(ci.fileType);
206 else if (!writableTypes && ci.canRead)
207 rv.insert(ci.fileType);
208 }
209
210 return rv;
211}
212
213std::set<UInt32> AudioFileFormatManager::findTypes(const std::unordered_map<std::string, std::vector<ComponentInfo*>>& map, const char* key)
214{
215 std::set<UInt32> rv;
216
217 auto it = map.find(key);
218 if (it == map.end())
219 return rv;
220
221 for (const ComponentInfo* ci : it->second)
222 rv.insert(ci->fileType);
223
224 return rv;
225}
226
227std::set<UInt32> AudioFileFormatManager::typesForMIME(const char* mime) const
228{
229 return findTypes(m_mimeMap, mime);
230}
231
232std::set<UInt32> AudioFileFormatManager::typesForUTI(const char* uti) const
233{
234 return findTypes(m_utiMap, uti);
235}
236
237std::set<UInt32> AudioFileFormatManager::typesForExtension(const char* ext) const
238{
239 return findTypes(m_extensionMap, ext);
240}
241
242std::set<std::string> AudioFileFormatManager::allMIMEs() const
243{
244 return allKeys(m_mimeMap);
245}
246
247std::set<std::string> AudioFileFormatManager::allUTIs() const
248{
249 return allKeys(m_utiMap);
250}
251
252std::set<std::string> AudioFileFormatManager::allExtensions() const
253{
254 return allKeys(m_extensionMap);
255}