summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Klotz <uwe_klotz@web.de>2017-10-27 23:29:57 +0200
committerUwe Klotz <uwe_klotz@web.de>2017-11-06 22:27:20 +0100
commit4a445a9aa16f79c549b2784d038a9e61dc449674 (patch)
treec278097e7821d864519584b659d4740e461369af
parent7a52da4867468c6431057bdfa9c6d41d8403f1eb (diff)
More expressive Audio- and MetadataSource interfaces
-rw-r--r--build/depends.py2
-rw-r--r--plugins/soundsourcem4a/SConscript2
-rw-r--r--plugins/soundsourcem4a/soundsourcem4a.cpp8
-rw-r--r--plugins/soundsourcem4a/soundsourcem4a.h4
-rw-r--r--plugins/soundsourcemediafoundation/SConscript2
-rwxr-xr-xplugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp14
-rwxr-xr-xplugins/soundsourcemediafoundation/soundsourcemediafoundation.h4
-rw-r--r--plugins/soundsourcewv/SConscript2
-rw-r--r--plugins/soundsourcewv/soundsourcewv.cpp6
-rw-r--r--plugins/soundsourcewv/soundsourcewv.h2
-rw-r--r--src/analyzer/analyzerqueue.cpp6
-rw-r--r--src/engine/cachingreaderworker.cpp10
-rw-r--r--src/library/browse/browsetablemodel.cpp5
-rw-r--r--src/library/coverartutils.cpp2
-rw-r--r--src/library/dao/trackdao.cpp4
-rw-r--r--src/musicbrainz/chromaprinter.cpp6
-rw-r--r--src/sources/audiosource.cpp23
-rw-r--r--src/sources/audiosource.h186
-rw-r--r--src/sources/audiosourcestereoproxy.h10
-rw-r--r--src/sources/audiosourcetrackproxy.h10
-rw-r--r--src/sources/metadatasource.cpp19
-rw-r--r--src/sources/metadatasource.h68
-rw-r--r--src/sources/metadatasourcetaglib.cpp644
-rw-r--r--src/sources/metadatasourcetaglib.h37
-rw-r--r--src/sources/soundsource.cpp23
-rw-r--r--src/sources/soundsource.h108
-rw-r--r--src/sources/soundsourcecoreaudio.cpp4
-rw-r--r--src/sources/soundsourcecoreaudio.h2
-rw-r--r--src/sources/soundsourceffmpeg.cpp2
-rw-r--r--src/sources/soundsourceffmpeg.h2
-rw-r--r--src/sources/soundsourceflac.cpp4
-rw-r--r--src/sources/soundsourceflac.h2
-rw-r--r--src/sources/soundsourcemodplug.cpp8
-rw-r--r--src/sources/soundsourcemodplug.h4
-rw-r--r--src/sources/soundsourcemp3.cpp4
-rw-r--r--src/sources/soundsourcemp3.h2
-rw-r--r--src/sources/soundsourceoggvorbis.cpp6
-rw-r--r--src/sources/soundsourceoggvorbis.h2
-rw-r--r--src/sources/soundsourceopus.cpp20
-rw-r--r--src/sources/soundsourceopus.h4
-rw-r--r--src/sources/soundsourcepluginlibrary.h2
-rw-r--r--src/sources/soundsourceproxy.cpp36
-rw-r--r--src/sources/soundsourceproxy.h8
-rw-r--r--src/sources/soundsourcesndfile.cpp4
-rw-r--r--src/sources/soundsourcesndfile.h2
-rw-r--r--src/sources/v1/legacyaudiosourceadapter.h12
-rw-r--r--src/test/coverartcache_test.cpp2
-rw-r--r--src/test/metadatatest.cpp6
-rw-r--r--src/test/soundproxy_test.cpp8
-rw-r--r--src/test/taglibtest.cpp12
-rw-r--r--src/track/track.cpp1
-rw-r--r--src/track/track.h10
-rw-r--r--src/track/trackmetadatataglib.cpp1384
-rw-r--r--src/track/trackmetadatataglib.h91
-rw-r--r--src/util/result.h10
55 files changed, 1474 insertions, 1387 deletions
diff --git a/build/depends.py b/build/depends.py
index c2388e1e19..7553dd4f50 100644
--- a/build/depends.py
+++ b/build/depends.py
@@ -816,7 +816,7 @@ class MixxxCore(Feature):
"sources/audiosource.cpp",
"sources/audiosourcestereoproxy.cpp",
- "sources/metadatasource.cpp",
+ "sources/metadatasourcetaglib.cpp",
"sources/soundsource.cpp",
"sources/soundsourceplugin.cpp",
"sources/soundsourcepluginlibrary.cpp",
diff --git a/plugins/soundsourcem4a/SConscript b/plugins/soundsourcem4a/SConscript
index a6cdc375c0..9e1a45f7e8 100644
--- a/plugins/soundsourcem4a/SConscript
+++ b/plugins/soundsourcem4a/SConscript
@@ -13,7 +13,7 @@ Import('build')
m4a_sources = [
"soundsourcem4a.cpp",
"sources/audiosource.cpp",
- "sources/metadatasource.cpp",
+ "sources/metadatasourcetaglib.cpp",
"sources/soundsource.cpp",
"sources/soundsourceplugin.cpp",
"util/audiosignal.cpp",
diff --git a/plugins/soundsourcem4a/soundsourcem4a.cpp b/plugins/soundsourcem4a/soundsourcem4a.cpp
index 7b974f4ab3..49e2c82726 100644
--- a/plugins/soundsourcem4a/soundsourcem4a.cpp
+++ b/plugins/soundsourcem4a/soundsourcem4a.cpp
@@ -176,7 +176,7 @@ SoundSourceM4A::~SoundSourceM4A() {
SoundSource::OpenResult SoundSourceM4A::tryOpen(
OpenMode mode,
- const AudioSourceConfig& audioSrcCfg) {
+ const OpenParams& params) {
DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile);
// open MP4 file, check for >= ver 1.9.1
// From mp4v2/file.h:
@@ -252,7 +252,7 @@ SoundSource::OpenResult SoundSourceM4A::tryOpen(
}
m_inputBuffer.resize(maxSampleBlockInputSize, 0);
- m_audioSrcCfg = audioSrcCfg;
+ m_openParams = params;
if (openDecoder()) {
return OpenResult::Succeeded;
@@ -272,8 +272,8 @@ bool SoundSourceM4A::openDecoder() {
NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration(
m_hDecoder);
pDecoderConfig->outputFormat = FAAD_FMT_FLOAT;
- if (m_audioSrcCfg.channelCount().isMono() ||
- m_audioSrcCfg.channelCount().isStereo()) {
+ if (m_openParams.channelCount().isMono() ||
+ m_openParams.channelCount().isStereo()) {
pDecoderConfig->downMatrix = 1;
} else {
pDecoderConfig->downMatrix = 0;
diff --git a/plugins/soundsourcem4a/soundsourcem4a.h b/plugins/soundsourcem4a/soundsourcem4a.h
index 858257a64b..0ef84a9ac5 100644
--- a/plugins/soundsourcem4a/soundsourcem4a.h
+++ b/plugins/soundsourcem4a/soundsourcem4a.h
@@ -31,7 +31,7 @@ class SoundSourceM4A: public SoundSourcePlugin {
private:
OpenResult tryOpen(
OpenMode mode,
- const AudioSourceConfig& audioSrcCfg) override;
+ const OpenParams& params) override;
bool openDecoder();
void closeDecoder();
@@ -51,7 +51,7 @@ class SoundSourceM4A: public SoundSourcePlugin {
SINT m_inputBufferLength;
SINT m_inputBufferOffset;
- AudioSourceConfig m_audioSrcCfg;
+ OpenParams m_openParams;
NeAACDecHandle m_hDecoder;
SINT m_numberOfPrefetchSampleBlocks;
diff --git a/plugins/soundsourcemediafoundation/SConscript b/plugins/soundsourcemediafoundation/SConscript
index 3edd7a1362..21f9a55736 100644
--- a/plugins/soundsourcemediafoundation/SConscript
+++ b/plugins/soundsourcemediafoundation/SConscript
@@ -21,7 +21,7 @@ if int(build.flags['mediafoundation']):
ssmediafoundation_bin = env.SharedLibrary('soundsourcemediafoundation',
['soundsourcemediafoundation.cpp',
'sources/audiosource.cpp',
- 'sources/metadatasource.cpp',
+ 'sources/metadatasourcetaglib.cpp',
'sources/soundsource.cpp',
'sources/soundsourceplugin.cpp',
'util/audiosignal.cpp',
diff --git a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp
index 637ed85dfa..78c370feed 100755
--- a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp
+++ b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp
@@ -55,7 +55,7 @@ SoundSourceMediaFoundation::~SoundSourceMediaFoundation() {
SoundSource::OpenResult SoundSourceMediaFoundation::tryOpen(
OpenMode /*mode*/,
- const AudioSourceConfig& audioSrcCfg) {
+ const OpenParams& params) {
VERIFY_OR_DEBUG_ASSERT(!SUCCEEDED(m_hrCoInitialize)) {
kLogger.warning()
<< "Cannot reopen file"
@@ -98,7 +98,7 @@ SoundSource::OpenResult SoundSourceMediaFoundation::tryOpen(
return OpenResult::Failed;
}
- if (!configureAudioStream(audioSrcCfg)) {
+ if (!configureAudioStream(config)) {
kLogger.warning()
<< "Failed to configure audio stream";
return OpenResult::Failed;
@@ -485,7 +485,7 @@ ReadableSampleFrames SoundSourceMediaFoundation::readSampleFramesClamped(
If anything in here fails, just bail. I'm not going to decode HRESULTS.
-- Bill
*/
-bool SoundSourceMediaFoundation::configureAudioStream(const AudioSourceConfig& audioSrcCfg) {
+bool SoundSourceMediaFoundation::configureAudioStream(const OpenParams& params) {
HRESULT hr;
// deselect all streams, we only want the first
@@ -591,8 +591,8 @@ bool SoundSourceMediaFoundation::configureAudioStream(const AudioSourceConfig& a
} else {
qDebug() << "Number of channels in input stream" << numChannels;
}
- if (audioSrcCfg.channelCount().valid()) {
- numChannels = audioSrcCfg.channelCount();
+ if (params.channelCount().valid()) {
+ numChannels = params.channelCount();
hr = pAudioType->SetUINT32(
MF_MT_AUDIO_NUM_CHANNELS, numChannels);
if (FAILED(hr)) {
@@ -615,8 +615,8 @@ bool SoundSourceMediaFoundation::configureAudioStream(const AudioSourceConfig& a
} else {
qDebug() << "Samples per second in input stream" << samplesPerSecond;
}
- if (audioSrcCfg.samplingRate().valid()) {
- samplesPerSecond = audioSrcCfg.samplingRate();
+ if (params.samplingRate().valid()) {
+ samplesPerSecond = params.samplingRate();
hr = pAudioType->SetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSecond);
if (FAILED(hr)) {
diff --git a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h
index 19c7a99b3f..27f4f3b41f 100755
--- a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h
+++ b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h
@@ -64,9 +64,9 @@ class SoundSourceMediaFoundation: public mixxx::SoundSourcePlugin {
private:
OpenResult tryOpen(
OpenMode mode,
- const mixxx::AudioSourceConfig& audioSrcCfg) override;
+ const mixxx::AudioSource::OpenParams& params) override;
- bool configureAudioStream(const mixxx::AudioSourceConfig& audioSrcCfg);
+ bool configureAudioStream(const mixxx::AudioSource::OpenParams& params);
bool readProperties();
void seekSampleFrame(SINT frameIndex);
diff --git a/plugins/soundsourcewv/SConscript b/plugins/soundsourcewv/SConscript
index 2f25d23bd5..bf3a712e88 100644
--- a/plugins/soundsourcewv/SConscript
+++ b/plugins/soundsourcewv/SConscript
@@ -13,7 +13,7 @@ Import('build')
wv_sources = [
"soundsourcewv.cpp",
"sources/audiosource.cpp",
- "sources/metadatasource.cpp",
+ "sources/metadatasourcetaglib.cpp",
"sources/soundsource.cpp",
"sources/soundsourceplugin.cpp",
"util/audiosignal.cpp",
diff --git a/plugins/soundsourcewv/soundsourcewv.cpp b/plugins/soundsourcewv/soundsourcewv.cpp
index f1e006fd8e..734b6556a8 100644
--- a/plugins/soundsourcewv/soundsourcewv.cpp
+++ b/plugins/soundsourcewv/soundsourcewv.cpp
@@ -39,12 +39,12 @@ SoundSourceWV::~SoundSourceWV() {
SoundSource::OpenResult SoundSourceWV::tryOpen(
OpenMode /*mode*/,
- const AudioSourceConfig& audioSrcCfg) {
+ const OpenParams& params) {
DEBUG_ASSERT(!m_wpc);
char msg[80]; // hold possible error message
int openFlags = OPEN_WVC | OPEN_NORMALIZE;
- if (audioSrcCfg.channelCount().isMono() ||
- audioSrcCfg.channelCount().isStereo()) {
+ if (params.channelCount().isMono() ||
+ params.channelCount().isStereo()) {
openFlags |= OPEN_2CH_MAX;
}
diff --git a/plugins/soundsourcewv/soundsourcewv.h b/plugins/soundsourcewv/soundsourcewv.h
index 23866b6390..7ce6f340b6 100644
--- a/plugins/soundsourcewv/soundsourcewv.h
+++ b/plugins/soundsourcewv/soundsourcewv.h
@@ -23,7 +23,7 @@ class SoundSourceWV: public SoundSourcePlugin {
private:
OpenResult tryOpen(
OpenMode mode,
- const AudioSourceConfig& audioSrcCfg) override;
+ const OpenParams& params) override;
static int32_t ReadBytesCallback(void* id, void* data, int bcount);
static uint32_t GetPosCallback(void* id);
diff --git a/src/analyzer/analyzerqueue.cpp b/src/analyzer/analyzerqueue.cpp
index 47ac7a0e9d..eea8d5c0e8 100644
--- a/src/analyzer/analyzerqueue.cpp
+++ b/src/analyzer/analyzerqueue.cpp
@@ -342,9 +342,9 @@ void AnalyzerQueue::execThread() {
Trace trace("AnalyzerQueue analyzing track");
// Get the audio
- mixxx::AudioSourceConfig audioSrcCfg;
- audioSrcCfg.setChannelCount(kAnalysisChannels);
- auto pAudioSource = SoundSourceProxy(nextTrack).openAudioSource(audioSrcCfg);
+ mixxx::AudioSource::OpenParams openParams;
+ openParams.setChannelCount(kAnalysisChannels);
+ auto pAudioSource = SoundSourceProxy(nextTrack).openAudioSource(openParams);
if (!pAudioSource) {
kLogger.warning()
<< "Failed to open file for analyzing:"
diff --git a/src/engine/cachingreaderworker.cpp b/src/engine/cachingreaderworker.cpp
index ca98ea82a4..8294be4ccb 100644
--- a/src/engine/cachingreaderworker.cpp
+++ b/src/engine/cachingreaderworker.cpp
@@ -118,8 +118,8 @@ void CachingReaderWorker::run() {
namespace {
-mixxx::AudioSourcePointer openAudioSourceForReading(const TrackPointer& pTrack, const mixxx::AudioSourceConfig& audioSrcCfg) {
- auto pAudioSource = SoundSourceProxy(pTrack).openAudioSource(audioSrcCfg);
+mixxx::AudioSourcePointer openAudioSourceForReading(const TrackPointer& pTrack, const mixxx::AudioSource::OpenParams& params) {
+ auto pAudioSource = SoundSourceProxy(pTrack).openAudioSource(params);
if (!pAudioSource) {
kLogger.warning() << "Failed to open file:" << pTrack->getLocation();
}
@@ -155,9 +155,9 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) {
return;
}
- mixxx::AudioSourceConfig audioSrcCfg;
- audioSrcCfg.setChannelCount(CachingReaderChunk::kChannels);
- m_pAudioSource = openAudioSourceForReading(pTrack, audioSrcCfg);
+ mixxx::AudioSource::OpenParams config;
+ config.setChannelCount(CachingReaderChunk::kChannels);
+ m_pAudioSource = openAudioSourceForReading(pTrack, config);
if (!m_pAudioSource) {
m_readableFrameIndexRange = mixxx::IndexRange();
// Must unlock before emitting to avoid deadlock
diff --git a/src/library/browse/browsetablemodel.cpp b/src/library/browse/browsetablemodel.cpp
index 1ae4f3ffe6..b5f208dbe4 100644
--- a/src/library/browse/browsetablemodel.cpp
+++ b/src/library/browse/browsetablemodel.cpp
@@ -11,7 +11,7 @@
#include "mixer/playerinfo.h"
#include "control/controlobject.h"
#include "library/dao/trackdao.h"
-#include "track/trackmetadatataglib.h"
+#include "sources/metadatasourcetaglib.h"
#include "util/dnd.h"
BrowseTableModel::BrowseTableModel(QObject* parent,
@@ -318,7 +318,8 @@ bool BrowseTableModel::setData(const QModelIndex &index, const QVariant &value,
QStandardItem* item = itemFromIndex(index);
QString track_location(getTrackLocation(index));
- if (OK == mixxx::taglib::writeTrackMetadataIntoFile(trackMetadata, track_location)) {
+ if (mixxx::MetadataSource::ExportResult::Succeeded ==
+ mixxx::MetadataSourceTagLib(track_location).exportTrackMetadata(trackMetadata)) {
// Modify underlying interalPointer object
item->setText(value.toString());
item->setToolTip(item->text());
diff --git a/src/library/coverartutils.cpp b/src/library/coverartutils.cpp
index 654132697f..336aba9a24 100644
--- a/src/library/coverartutils.cpp
+++ b/src/library/coverartutils.cpp
@@ -38,7 +38,7 @@ QImage CoverArtUtils::extractEmbeddedCover(
const QFileInfo& fileInfo,
SecurityTokenPointer pToken) {
auto pTrack = Track::newTemporary(fileInfo, pToken);
- return SoundSourceProxy(pTrack).parseCoverImage();
+ return SoundSourceProxy(pTrack).importCoverImage();
}
//static
diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp
index 673025112c..0df8d5e8d6 100644
--- a/src/library/dao/trackdao.cpp
+++ b/src/library/dao/trackdao.cpp
@@ -281,7 +281,7 @@ void TrackDAO::saveTrack(Track* pTrack) {
// could alternatively store a second copy of TrackMetadata
// in Track.
if (m_pConfig && m_pConfig->getValueString(ConfigKey("[Library]","WriteAudioTags")).toInt() == 1) {
- SoundSourceProxy::saveTrackMetadata(pTrack);
+ SoundSourceProxy::exportTrackMetadata(pTrack);
}
}
}
@@ -1404,7 +1404,7 @@ TrackPointer TrackDAO::getTrackFromDB(TrackId trackId) const {
" to replace the default value introduced with a previous"
" schema upgrade";
mixxx::TrackMetadata trackMetadata;
- if (SoundSourceProxy(pTrack).parseTrackMetadata(&trackMetadata) == OK) {
+ if (SoundSourceProxy(pTrack).importTrackMetadata(&trackMetadata) == mixxx::MetadataSource::ImportResult::Succeeded) {
// Copy the track total from the temporary track object
pTrack->setTrackTotal(trackMetadata.getTrackTotal());
// Also set the track number if it is still empty due
diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp
index 58a465efc7..917ce1e9ca 100644
--- a/src/musicbrainz/chromaprinter.cpp
+++ b/src/musicbrainz/chromaprinter.cpp
@@ -119,9 +119,9 @@ ChromaPrinter::ChromaPrinter(QObject* parent)
}
QString ChromaPrinter::getFingerprint(TrackPointer pTrack) {
- mixxx::AudioSourceConfig audioSrcCfg;
- audioSrcCfg.setChannelCount(kFingerprintChannels);
- auto pAudioSource = SoundSourceProxy(pTrack).openAudioSource(audioSrcCfg);
+ mixxx::AudioSource::OpenParams config;
+ config.setChannelCount(kFingerprintChannels);
+ auto pAudioSource = SoundSourceProxy(pTrack).openAudioSource(config);
if (!pAudioSource || (pAudioSource->channelCount() != kFingerprintChannels)) {
qDebug()
<< "Failed to open file for fingerprinting"
diff --git a/src/sources/audiosource.cpp b/src/sources/audiosource.cpp
index ded3e13950..a21067a586 100644
--- a/src/sources/audiosource.cpp
+++ b/src/sources/audiosource.cpp
@@ -16,9 +16,30 @@ AudioSource::AudioSource(QUrl url)
AudioSignal(kSampleLayout) {
}
+AudioSource::OpenResult AudioSource::open(
+ OpenMode mode,
+ const OpenParams& params) {
+ close(); // reopening is not supported
+
+ OpenResult result;
+ try {
+ result = tryOpen(mode, params);
+ } catch (const std::exception& e) {
+ qWarning() << "Caught unexpected exception from SoundSource::tryOpen():" << e.what();
+ result = OpenResult::Failed;
+ } catch (...) {
+ qWarning() << "Caught unknown exception from SoundSource::tryOpen()";
+ result = OpenResult::Failed;
+ }
+ if (OpenResult::Succeeded != result) {
+ close(); // rollback
+ }
+ return result;
+}
+
bool AudioSource::initFrameIndexRangeOnce(
IndexRange frameIndexRange) {
- VERIFY_OR_DEBUG_ASSERT(frameIndexRange.orientation() != mixxx::IndexRange::Orientation::Backward) {
+ VERIFY_OR_DEBUG_ASSERT(frameIndexRange.orientation() != IndexRange::Orientation::Backward) {
kLogger.warning()
<< "Backward frame index range not supported"
<< frameIndexRange;
diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h
index 59a5673da6..453eea5980 100644
--- a/src/sources/audiosource.h
+++ b/src/sources/audiosource.h
@@ -77,39 +77,6 @@ class WritableSampleFrames: public SampleFrames {
};
-// Interface for reading audio data in sample frames.
-//
-// Each new type of source must implement at least readSampleFramesClamped().
-class /*interface*/ IAudioSource {
- public:
- virtual ~IAudioSource() = default;
-
- protected:
- // Reads as much of the the requested sample frames and writes
- // them into the provided buffer. The capacity of the buffer
- // and the requested range have already been checked and
- // adjusted (= clamped) before if necessary.
- //
- // Returns the number of and decoded sample frames in a readable
- // buffer. The returned buffer is just a view/slice of the provided
- // writable buffer if the result is not empty. If the result is
- // empty the internal memory pointer of the returned buffer might
- // be null.
- virtual ReadableSampleFrames readSampleFramesClamped(
- WritableSampleFrames sampleFrames) = 0;
-
- // The following function is required for accessing the protected
- // read function from siblings implementing this interface, e.g.
- // for proxies and adapters.
- static ReadableSampleFrames readSampleFramesClampedOn(
- IAudioSource& that,
- WritableSampleFrames sampleFrames) {
- return that.readSampleFramesClamped(sampleFrames);
- }
-
-};
-
-
// Common base class for audio sources.
//
// Both the number of channels and the sampling rate must
@@ -120,7 +87,7 @@ class /*interface*/ IAudioSource {
//
// Audio sources are implicitly opened upon creation and
// closed upon destruction.
-class AudioSource: public UrlResource, public AudioSignal, public virtual /*interface*/ IAudioSource {
+class AudioSource: public UrlResource, public AudioSignal {
public:
virtual ~AudioSource() = default;
@@ -135,6 +102,70 @@ class AudioSource: public UrlResource, public AudioSignal, public virtual /*inte
static constexpr SampleLayout kSampleLayout = SampleLayout::Interleaved;
+ enum class OpenMode {
+ // In Strict mode the opening operation should be aborted
+ // as soon as any inconsistencies are detected.
+ Strict,
+ // Opening in Permissive mode is used only after opening
+ // in Strict mode has been aborted by all available
+ // SoundSource implementations.
+ Permissive,
+ };
+
+ enum class OpenResult {
+ Succeeded,
+ // If a SoundSource is not able to open a file because of
+ // internal errors of if the format of the content is not
+ // supported it should return Aborted. This gives SoundSources
+ // with a lower priority the chance to open the same file.
+ // Example: A SoundSourceProvider has been registered for
+ // files with a certain extension, but the corresponding
+ // SoundSource does only support a subset of all possible
+ // data formats that might be stored in files with this
+ // extension.
+ Aborted,
+ // If a SoundSource return Failed while opening a file
+ // the entire operation will fail immediately. No other
+ // sources with lower priority will be given the chance
+ // to open the same file.
+ Failed,
+ };
+
+ // Parameters for opening audio sources
+ class OpenParams : public AudioSignal {
+ public:
+ OpenParams()
+ : AudioSignal(kSampleLayout) {
+ }
+ OpenParams(ChannelCount channelCount, SamplingRate samplingRate)
+ : AudioSignal(kSampleLayout, channelCount, samplingRate) {
+ }
+
+ using AudioSignal::setChannelCount;
+ using AudioSignal::setSamplingRate;
+ };
+
+ // Opens the AudioSource for reading audio data.
+ //
+ // Since reopening is not supported close() will be called
+ // implicitly before the AudioSource is actually opened.
+ //
+ // Optionally the caller may provide the desired properties of
+ // the decoded audio signal. Some decoders are able to reduce
+ // the number of channels or do resampling efficiently on the
+ // fly while decoding the input data.
+ OpenResult open(
+ OpenMode mode,
+ const OpenParams& params = OpenParams());
+
+
+ // Closes the AudioSource and frees all resources.
+ //
+ // Might be called even if the AudioSource has never been
+ // opened, has already been closed, or if opening has failed.
+ virtual void close() = 0;
+
+
// The total length of audio data is bounded and measured in frames.
IndexRange frameIndexRange() const {
return m_frameIndexRange;
@@ -233,6 +264,53 @@ class AudioSource: public UrlResource, public AudioSignal, public virtual /*inte
return initBitrateOnce(Bitrate(bitrate));
}
+ // Tries to open the AudioSource for reading audio data according
+ // to the "Template Method" design pattern.
+ //
+ // The invocation of tryOpen() is enclosed in invocations of close():
+ // - Before: Always
+ // - After: Upon failure
+ // If tryOpen() throws an exception or returns a result other than
+ // OpenResult::Succeeded an invocation of close() will follow.
+ // Implementations do not need to free internal resources twice in
+ // both tryOpen() upon failure and close(). All internal resources
+ // should be freed in close() instead.
+ //
+ // Exceptions s