libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
audiodesc.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
13#include <promeki/namespace.h>
14#include <promeki/sharedptr.h>
15#include <promeki/audioformat.h>
17#include <promeki/metadata.h>
18#include <promeki/string.h>
19#include <promeki/json.h>
20
21PROMEKI_NAMESPACE_BEGIN
22
23class SdpMediaDescription;
24
49class AudioDesc {
50 PROMEKI_SHARED_FINAL(AudioDesc)
51 public:
53 using Ptr = SharedPtr<AudioDesc>;
54
56 using List = ::promeki::List<AudioDesc>;
57
59 using PtrList = ::promeki::List<Ptr>;
60
70 static AudioDesc fromJson(const JsonObject &json, Error *err = nullptr);
71
90 static AudioDesc fromSdp(const SdpMediaDescription &md);
91
93 AudioDesc() = default;
94
106 AudioDesc(float sr, unsigned int ch)
107 : _format(AudioFormat::NativeFloat), _sampleRate(sr), _channels(ch),
108 _channelMap(AudioChannelMap::defaultForChannels(ch)) {
109 if (!validParams()) reset();
110 }
111
123 AudioDesc(const AudioFormat &fmt, float sr, unsigned int ch)
124 : _format(fmt), _sampleRate(sr), _channels(ch),
125 _channelMap(AudioChannelMap::defaultForChannels(ch)) {
126 if (!validParams()) reset();
127 }
128
139 AudioDesc(const AudioFormat &fmt, float sr, AudioChannelMap map)
140 : _format(fmt), _sampleRate(sr), _channels(static_cast<unsigned int>(map.channels())),
141 _channelMap(std::move(map)) {
142 if (!validParams()) reset();
143 }
144
162 SdpMediaDescription toSdp(uint8_t payloadType) const;
163
169 bool formatEquals(const AudioDesc &other) const {
170 return _format == other._format && _sampleRate == other._sampleRate &&
171 _channels == other._channels && _channelMap == other._channelMap;
172 }
173
179 bool operator==(const AudioDesc &other) const {
180 return formatEquals(other) && _metadata == other._metadata;
181 }
182
184 bool isValid() const { return _format.isValid() && _sampleRate > 0.0f && _channels > 0; }
185
187 bool isCompressed() const { return _format.isCompressed(); }
188
193 bool isNative() const { return _format.id() == AudioFormat::NativeFloat; }
194
200 AudioDesc workingDesc() const {
201 return AudioDesc(AudioFormat(AudioFormat::NativeFloat), _sampleRate, _channels);
202 }
203
205 String toString() const {
206 return String::sprintf("[%s %fHz %uc]", _format.name().cstr(), _sampleRate, _channels);
207 }
208
217 JsonObject toJson() const {
218 JsonObject ret;
219 ret.set("Format", _format.name());
220 ret.set("SampleRate", _sampleRate);
221 ret.set("Channels", _channels);
222 // Only emit the channel map when it differs from the default
223 // mapping for this channel count — keeps simple descriptors clean.
224 if (_channelMap != AudioChannelMap::defaultForChannels(_channels)) {
225 ret.set("ChannelMap", _channelMap.toString());
226 }
227 if (!_metadata.isEmpty()) ret.set("Metadata", _metadata.toJson());
228 return ret;
229 }
230
232 const AudioFormat &format() const { return _format; }
233
235 void setFormat(const AudioFormat &val) { _format = val; }
236
238 float sampleRate() const { return _sampleRate; }
239
241 void setSampleRate(float val) { _sampleRate = val; }
242
244 unsigned int channels() const { return _channels; }
245
253 void setChannels(unsigned int val) {
254 _channels = val;
255 _channelMap = AudioChannelMap::defaultForChannels(val);
256 }
257
259 const AudioChannelMap &channelMap() const { return _channelMap; }
260
269 void setChannelMap(const AudioChannelMap &map) {
270 if (map.channels() == _channels) _channelMap = map;
271 }
272
274 const Metadata &metadata() const { return _metadata; }
275
277 Metadata &metadata() { return _metadata; }
278
280 size_t bytesPerSample() const { return _format.bytesPerSample(); }
281
290 size_t bytesPerSampleStride() const {
291 return _format.isPlanar() ? _format.bytesPerSample() : _format.bytesPerSample() * _channels;
292 }
293
305 size_t channelBufferOffset(unsigned int chan, size_t bufferSamples) const {
306 return _format.isPlanar() ? _format.bytesPerSample() * bufferSamples * chan
307 : _format.bytesPerSample() * chan;
308 }
309
315 size_t bufferSize(size_t samples) const { return _format.bytesPerSample() * _channels * samples; }
316
323 void samplesToFloat(float *out, const uint8_t *in, size_t samples) const {
324 _format.samplesToFloat(out, in, samples * _channels);
325 }
326
333 void floatToSamples(uint8_t *out, const float *in, size_t samples) const {
334 _format.floatToSamples(out, in, samples * _channels);
335 }
336
337 private:
338 AudioFormat _format;
339 float _sampleRate = 0.0f;
340 unsigned int _channels = 0;
341 AudioChannelMap _channelMap;
342 Metadata _metadata;
343
344 bool validParams() const { return _format.isValid() && _sampleRate > 0.0f && _channels > 0; }
345
346 void reset() {
347 _format = AudioFormat();
348 _sampleRate = 0.0f;
349 _channels = 0;
350 _channelMap = AudioChannelMap();
351 }
352};
353
357inline DataStream &operator<<(DataStream &stream, const AudioDesc &desc) {
358 stream.beginFrame(DataTypeAudioDesc, 1);
359 stream << desc.format();
360 stream << desc.sampleRate();
361 stream << static_cast<uint32_t>(desc.channels());
362 stream << desc.channelMap();
363 stream << desc.metadata();
364 stream.endFrame();
365 return stream;
366}
367
371inline DataStream &operator>>(DataStream &stream, AudioDesc &desc) {
372 if (!stream.readFrame(DataTypeAudioDesc)) {
373 desc = AudioDesc();
374 return stream;
375 }
376 AudioFormat fmt;
377 float sr = 0.0f;
378 uint32_t ch = 0;
379 AudioChannelMap map;
380 Metadata meta;
381 stream >> fmt >> sr >> ch >> map >> meta;
382 if (stream.status() != DataStream::Ok) {
383 desc = AudioDesc();
384 return stream;
385 }
386 desc = AudioDesc(fmt, sr, ch);
387 // Restore the explicit channel map if it parsed validly; otherwise keep
388 // the default that the (fmt, sr, ch) constructor installs.
389 if (map.channels() == ch) desc.setChannelMap(map);
390 desc.metadata() = std::move(meta);
391 return stream;
392}
393
394PROMEKI_NAMESPACE_END
395
396PROMEKI_FORMAT_VIA_TOSTRING(promeki::AudioDesc);
397
398#endif // PROMEKI_ENABLE_PROAV