diff --git a/src/internal_modules/roc_audio/pcm_format.cpp b/src/internal_modules/roc_audio/pcm_subformat.cpp similarity index 100% rename from src/internal_modules/roc_audio/pcm_format.cpp rename to src/internal_modules/roc_audio/pcm_subformat.cpp diff --git a/src/internal_modules/roc_sndio/io_pump.cpp b/src/internal_modules/roc_sndio/io_pump.cpp index 64793ae09..6ae8a527c 100644 --- a/src/internal_modules/roc_sndio/io_pump.cpp +++ b/src/internal_modules/roc_sndio/io_pump.cpp @@ -40,8 +40,8 @@ IoPump::IoPump(core::IPool& frame_pool, , stop_(0) , transferred_bytes_(0) , init_status_(status::NoStatus) { - if (!io_config.sample_spec.is_complete()) { - roc_panic("io pump: expected complete sample spec: spec=%s", + if (!io_config.sample_spec.is_complete() || !io_config.sample_spec.is_pcm()) { + roc_panic("io pump: required complete sample spec with pcm format: spec=%s", audio::sample_spec_to_str(io_config.sample_spec).c_str()); } @@ -83,7 +83,7 @@ status::StatusCode IoPump::run() { // EOF is fine code = status::StatusOK; roc_log(LogDebug, "io pump: transferred %.3f MB", - (double)transferred_bytes_ / 1024 * 1024); + (double)transferred_bytes_ / 1024 / 1024); } if (code == status::StatusOK) { diff --git a/src/tests/roc_sndio/test_helpers/mock_source.h b/src/tests/roc_sndio/test_helpers/mock_source.h index 465cbec2e..69dbb4714 100644 --- a/src/tests/roc_sndio/test_helpers/mock_source.h +++ b/src/tests/roc_sndio/test_helpers/mock_source.h @@ -22,8 +22,8 @@ namespace test { class MockSource : public ISource { public: - MockSource(audio::FrameFactory& frame_factory, - const audio::SampleSpec& sample_spec, + MockSource(const audio::SampleSpec& sample_spec, + audio::FrameFactory& frame_factory, core::IArena& arena) : IDevice(arena) , ISource(arena) diff --git a/src/tests/roc_sndio/test_io_pump.cpp b/src/tests/roc_sndio/test_io_pump.cpp index cb04bb640..52aa22cdf 100644 --- a/src/tests/roc_sndio/test_io_pump.cpp +++ b/src/tests/roc_sndio/test_io_pump.cpp @@ -25,16 +25,16 @@ namespace sndio { namespace { -enum { FrameSize = 512, SampleRate = 48000 }; +enum { FrameSize = 512, ManySamples = FrameSize * 10 }; -const audio::SampleSpec sample_spec(SampleRate, - audio::PcmSubformat_Raw, - audio::ChanLayout_Surround, - audio::ChanOrder_Smpte, - audio::ChanMask_Surround_Stereo); +const audio::SampleSpec frame_spec(48000, + audio::PcmSubformat_Raw, + audio::ChanLayout_Surround, + audio::ChanOrder_Smpte, + audio::ChanMask_Surround_Stereo); const core::nanoseconds_t frame_duration = FrameSize * core::Second - / core::nanoseconds_t(sample_spec.sample_rate() * sample_spec.num_channels()); + / core::nanoseconds_t(frame_spec.sample_rate() * frame_spec.num_channels()); core::HeapArena arena; @@ -51,19 +51,27 @@ audio::FrameFactory frame_factory(frame_pool, frame_buffer_pool); TEST_GROUP(io_pump) { IoConfig source_config; IoConfig sink_config; + IoConfig pump_config; void setup() { + audio::SampleSpec file_spec; + file_spec.set_format(audio::Format_Wav); + file_spec.set_pcm_subformat(audio::PcmSubformat_Raw); + file_spec.set_sample_rate(frame_spec.sample_rate()); + file_spec.set_channel_set(frame_spec.channel_set()); + source_config.sample_spec = audio::SampleSpec(); source_config.frame_length = frame_duration; - sink_config.sample_spec = sample_spec; + sink_config.sample_spec = file_spec; sink_config.frame_length = frame_duration; + + pump_config.sample_spec = frame_spec; + pump_config.frame_length = frame_duration; } }; -IGNORE_TEST(io_pump, write_read) { - enum { NumSamples = FrameSize * 10 }; - +TEST(io_pump, write_read) { for (size_t n_backend = 0; n_backend < BackendMap::instance().num_backends(); n_backend++) { IBackend& backend = BackendMap::instance().nth_backend(n_backend); @@ -73,8 +81,8 @@ IGNORE_TEST(io_pump, write_read) { dbgio::TempFile file("test.wav"); - test::MockSource mock_source(frame_factory, sink_config.sample_spec, arena); - mock_source.add(NumSamples); + test::MockSource mock_source(pump_config.sample_spec, frame_factory, arena); + mock_source.add(ManySamples); { // open file sink @@ -84,11 +92,11 @@ IGNORE_TEST(io_pump, write_read) { // copy from mock source to file sink IoPump pump(frame_pool, frame_buffer_pool, mock_source, NULL, *file_sink, - sink_config, IoPump::ModeOneshot); + pump_config, IoPump::ModeOneshot); LONGS_EQUAL(status::StatusOK, pump.init_status()); LONGS_EQUAL(status::StatusOK, pump.run()); - CHECK(mock_source.num_returned() >= NumSamples - FrameSize); + CHECK(mock_source.num_returned() >= ManySamples - FrameSize); } // open file source @@ -99,7 +107,7 @@ IGNORE_TEST(io_pump, write_read) { // copy from file source to mock sink test::MockSink mock_sink(arena); IoPump pump(frame_pool, frame_buffer_pool, *file_source, NULL, mock_sink, - sink_config, IoPump::ModePermanent); + pump_config, IoPump::ModePermanent); LONGS_EQUAL(status::StatusOK, pump.init_status()); LONGS_EQUAL(status::StatusOK, pump.run()); @@ -108,9 +116,7 @@ IGNORE_TEST(io_pump, write_read) { } } -IGNORE_TEST(io_pump, write_overwrite_read) { - enum { NumSamples = FrameSize * 10 }; - +TEST(io_pump, write_overwrite_read) { for (size_t n_backend = 0; n_backend < BackendMap::instance().num_backends(); n_backend++) { IBackend& backend = BackendMap::instance().nth_backend(n_backend); @@ -120,53 +126,53 @@ IGNORE_TEST(io_pump, write_overwrite_read) { dbgio::TempFile file("test.wav"); - test::MockSource mock_source(frame_factory, sink_config.sample_spec, arena); - mock_source.add(NumSamples); + test::MockSource mock_source(pump_config.sample_spec, frame_factory, arena); + mock_source.add(ManySamples); { // open file sink core::ScopedPtr file_sink; - test::expect_open_sink(status::StatusOK, backend, frame_factory, arena, "wav", - file.path(), sink_config, file_sink); + test::expect_open_sink(status::StatusOK, backend, frame_factory, arena, + "file", file.path(), sink_config, file_sink); // copy from mock source to file sink IoPump pump(frame_pool, frame_buffer_pool, mock_source, NULL, *file_sink, - sink_config, IoPump::ModeOneshot); + pump_config, IoPump::ModeOneshot); LONGS_EQUAL(status::StatusOK, pump.init_status()); LONGS_EQUAL(status::StatusOK, pump.run()); } // add more samples to mock source - mock_source.add(NumSamples); + mock_source.add(ManySamples); size_t num_returned1 = mock_source.num_returned(); - CHECK(num_returned1 >= NumSamples - FrameSize); + CHECK(num_returned1 >= ManySamples - FrameSize); { // open file sink core::ScopedPtr file_sink; - test::expect_open_sink(status::StatusOK, backend, frame_factory, arena, "wav", - file.path(), sink_config, file_sink); + test::expect_open_sink(status::StatusOK, backend, frame_factory, arena, + "file", file.path(), sink_config, file_sink); // copy next samples from mock source to file sink, overwriting file IoPump pump(frame_pool, frame_buffer_pool, mock_source, NULL, *file_sink, - sink_config, IoPump::ModeOneshot); + pump_config, IoPump::ModeOneshot); LONGS_EQUAL(status::StatusOK, pump.init_status()); LONGS_EQUAL(status::StatusOK, pump.run()); } size_t num_returned2 = mock_source.num_returned() - num_returned1; - CHECK(num_returned1 >= NumSamples - FrameSize); + CHECK(num_returned1 >= ManySamples - FrameSize); // open file source core::ScopedPtr file_source; - test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "wav", + test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "file", file.path(), source_config, file_source); // copy from file source to mock sink test::MockSink mock_sink(arena); IoPump pump(frame_pool, frame_buffer_pool, *file_source, NULL, mock_sink, - sink_config, IoPump::ModePermanent); + pump_config, IoPump::ModePermanent); LONGS_EQUAL(status::StatusOK, pump.init_status()); LONGS_EQUAL(status::StatusOK, pump.run()); diff --git a/src/tests/roc_sndio/test_sinks.cpp b/src/tests/roc_sndio/test_sinks.cpp index c2034e972..959afaafe 100644 --- a/src/tests/roc_sndio/test_sinks.cpp +++ b/src/tests/roc_sndio/test_sinks.cpp @@ -9,8 +9,11 @@ #include #include "test_helpers/mock_sink.h" +#include "test_helpers/mock_source.h" #include "test_helpers/utils.h" +#include "roc_audio/pcm_mapper_reader.h" +#include "roc_audio/pcm_mapper_writer.h" #include "roc_core/heap_arena.h" #include "roc_core/macro_helpers.h" #include "roc_core/scoped_ptr.h" @@ -18,17 +21,72 @@ #include "roc_sndio/backend_map.h" #include "roc_sndio/isource.h" +// This file contains tests for ISink implementations provided by different backends +// in roc_sndio. +// +// Every test iterates through all available backends, and for each one it opens a sink +// and writes frames to it. Then it checks that the sink successfully wrote output file. +// +// Test usually defines two sample specs: +// - file spec: tells ISink format/rate/channels to use for output file +// (if some parts are omitted, sink will use defaults) +// - frame spec: defines which format/rate/channels ISink expects to be +// used for frames written to it +// +// In some backends, ISink always expects raw frames and performs conversions to +// file format by itself. In other backends, ISink may expect frames to have the +// same format as requested output format. This is defined by ISink::sample_spec(). + namespace roc { namespace sndio { namespace { -enum { FrameSize = 500 }; +enum { FrameSize = 500, MaxFrameSize = FrameSize * 10, ManySamples = MaxFrameSize * 10 }; core::HeapArena arena; -audio::FrameFactory frame_factory(arena, FrameSize * sizeof(audio::sample_t)); +audio::FrameFactory frame_factory(arena, MaxFrameSize * sizeof(audio::sample_t)); + +void write_samples(ISink& sink, const audio::SampleSpec& frame_spec, size_t num_samples) { + CHECK(frame_spec.is_complete()); + CHECK(frame_spec.is_raw()); + + const core::nanoseconds_t frame_len = FrameSize * core::Second + / core::nanoseconds_t(frame_spec.sample_rate() * frame_spec.num_channels()); + + // sink may consume non-raw frames, so use pcm mapper + audio::PcmMapperWriter sink_mapper(sink, frame_factory, frame_spec, + sink.sample_spec()); + LONGS_EQUAL(status::StatusOK, sink_mapper.init_status()); + + test::MockSource mock_source(frame_spec, frame_factory, arena); + mock_source.add(num_samples * frame_spec.num_channels()); + + for (;;) { + audio::FramePtr frame = + frame_factory.allocate_frame(frame_spec.ns_2_bytes(frame_len)); + + const status::StatusCode code = mock_source.read( + *frame, frame_spec.ns_2_stream_timestamp(frame_len), audio::ModeHard); + + CHECK(code == status::StatusOK || code == status::StatusPart + || code == status::StatusFinish); + + if (code == status::StatusFinish) { + break; + } + + LONGS_EQUAL(status::StatusOK, sink_mapper.write(*frame)); + } +} + +void read_wav(IBackend& backend, + const audio::SampleSpec& frame_spec, + const char* path, + size_t num_samples) { + CHECK(frame_spec.is_complete()); + CHECK(frame_spec.is_raw()); -void read_wav(IBackend& backend, const audio::SampleSpec& frame_spec, const char* path) { const core::nanoseconds_t frame_len = FrameSize * core::Second / core::nanoseconds_t(frame_spec.sample_rate() * frame_spec.num_channels()); @@ -38,20 +96,23 @@ void read_wav(IBackend& backend, const audio::SampleSpec& frame_spec, const char source_config.sample_spec = audio::SampleSpec(); source_config.frame_length = frame_len; - IDevice* source_device = NULL; - LONGS_EQUAL(status::StatusOK, - backend.open_device(DeviceType_Source, "file", path, source_config, - frame_factory, arena, &source_device)); - CHECK(source_device != NULL); + core::ScopedPtr source; + test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "file", + path, source_config, source); - core::ScopedPtr source(source_device->to_source()); - CHECK(source != NULL); + LONGS_EQUAL(frame_spec.sample_rate(), source->sample_spec().sample_rate()); + CHECK(frame_spec.channel_set() == source->sample_spec().channel_set()); + + // source may produce non-raw frames, so use pcm mapper + audio::PcmMapperReader source_mapper(*source, frame_factory, frame_spec, + source->sample_spec()); + LONGS_EQUAL(status::StatusOK, source_mapper.init_status()); for (;;) { audio::FramePtr frame = frame_factory.allocate_frame(frame_spec.ns_2_bytes(frame_len)); - const status::StatusCode code = source->read( + const status::StatusCode code = source_mapper.read( *frame, frame_spec.ns_2_stream_timestamp(frame_len), audio::ModeHard); CHECK(code == status::StatusOK || code == status::StatusPart @@ -63,6 +124,8 @@ void read_wav(IBackend& backend, const audio::SampleSpec& frame_spec, const char LONGS_EQUAL(status::StatusOK, mock_sink.write(*frame)); } + + mock_sink.check(0, num_samples * frame_spec.num_channels()); } audio::ChannelSet make_channel_set(audio::ChannelMask chans) { @@ -88,8 +151,8 @@ IoConfig make_config(const audio::SampleSpec& file_spec, TEST_GROUP(sinks) {}; -// Don't specify output spec. -TEST(sinks, empty_spec) { +// Don't specify output spec (sink will use default). +TEST(sinks, spec_empty) { audio::SampleSpec file_spec; file_spec.clear(); @@ -121,15 +184,19 @@ TEST(sinks, empty_spec) { CHECK(!sink->has_state()); CHECK(!sink->has_latency()); CHECK(!sink->has_clock()); + + write_samples(*sink, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, sink->close()); + + read_wav(backend, frame_spec, file.path(), ManySamples); } } -// Specify complete spec. -TEST(sinks, complete_spec) { +// Specify complete output spec. +TEST(sinks, spec_complete) { audio::SampleSpec file_spec; file_spec.set_format(audio::Format_Wav); - file_spec.set_pcm_subformat(audio::PcmSubformat_SInt16); + file_spec.set_pcm_subformat(audio::PcmSubformat_SInt24); file_spec.set_sample_rate(48000); file_spec.set_channel_set(make_channel_set(audio::ChanMask_Surround_Mono)); @@ -154,7 +221,8 @@ TEST(sinks, complete_spec) { audio::SampleSpec actual_spec = sink->sample_spec(); CHECK(actual_spec.pcm_subformat() != audio::PcmSubformat_Invalid); - if (actual_spec.pcm_subformat() == audio::PcmSubformat_SInt16_Le) { + if (actual_spec.pcm_subformat() == audio::PcmSubformat_SInt24_Le) { + // Sink may request either raw samples or specified output spec. actual_spec.set_pcm_subformat(audio::PcmSubformat_Raw); } @@ -163,12 +231,16 @@ TEST(sinks, complete_spec) { CHECK(!sink->has_state()); CHECK(!sink->has_latency()); CHECK(!sink->has_clock()); + + write_samples(*sink, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, sink->close()); + + read_wav(backend, frame_spec, file.path(), ManySamples); } } // Specify only format. -TEST(sinks, explicit_format) { +TEST(sinks, spec_only_format) { audio::SampleSpec file_spec; file_spec.set_format(audio::Format_Wav); @@ -200,15 +272,19 @@ TEST(sinks, explicit_format) { CHECK(!sink->has_state()); CHECK(!sink->has_latency()); CHECK(!sink->has_clock()); + + write_samples(*sink, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, sink->close()); + + read_wav(backend, frame_spec, file.path(), ManySamples); } } // Specify only format and sub-format. -TEST(sinks, explicit_format_and_subformat) { +TEST(sinks, spec_only_format_and_subformat) { audio::SampleSpec file_spec; file_spec.set_format(audio::Format_Wav); - file_spec.set_pcm_subformat(audio::PcmSubformat_SInt16); + file_spec.set_pcm_subformat(audio::PcmSubformat_SInt24); audio::SampleSpec frame_spec; frame_spec.set_format(audio::Format_Pcm); @@ -231,7 +307,8 @@ TEST(sinks, explicit_format_and_subformat) { audio::SampleSpec actual_spec = sink->sample_spec(); CHECK(actual_spec.pcm_subformat() != audio::PcmSubformat_Invalid); - if (actual_spec.pcm_subformat() == audio::PcmSubformat_SInt16_Le) { + if (actual_spec.pcm_subformat() == audio::PcmSubformat_SInt24_Le) { + // Sink may request either raw samples or specified sub-format. actual_spec.set_pcm_subformat(audio::PcmSubformat_Raw); } @@ -240,12 +317,16 @@ TEST(sinks, explicit_format_and_subformat) { CHECK(!sink->has_state()); CHECK(!sink->has_latency()); CHECK(!sink->has_clock()); + + write_samples(*sink, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, sink->close()); + + read_wav(backend, frame_spec, file.path(), ManySamples); } } // Specify only sample rate. -TEST(sinks, explicit_rate) { +TEST(sinks, spec_only_rate) { audio::SampleSpec file_spec; file_spec.set_sample_rate(48000); @@ -277,12 +358,16 @@ TEST(sinks, explicit_rate) { CHECK(!sink->has_state()); CHECK(!sink->has_latency()); CHECK(!sink->has_clock()); + + write_samples(*sink, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, sink->close()); + + read_wav(backend, frame_spec, file.path(), ManySamples); } } // Specify only channel set. -TEST(sinks, explicit_channels) { +TEST(sinks, spec_only_channels) { audio::SampleSpec file_spec; file_spec.set_channel_set(make_channel_set(audio::ChanMask_Surround_Mono)); @@ -314,7 +399,11 @@ TEST(sinks, explicit_channels) { CHECK(!sink->has_state()); CHECK(!sink->has_latency()); CHECK(!sink->has_clock()); + + write_samples(*sink, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, sink->close()); + + read_wav(backend, frame_spec, file.path(), ManySamples); } } diff --git a/src/tests/roc_sndio/test_sources.cpp b/src/tests/roc_sndio/test_sources.cpp index 20fadd538..064c819ec 100644 --- a/src/tests/roc_sndio/test_sources.cpp +++ b/src/tests/roc_sndio/test_sources.cpp @@ -8,57 +8,73 @@ #include +#include "test_helpers/mock_sink.h" #include "test_helpers/mock_source.h" #include "test_helpers/utils.h" +#include "roc_audio/pcm_mapper_reader.h" +#include "roc_audio/pcm_mapper_writer.h" #include "roc_core/heap_arena.h" #include "roc_core/macro_helpers.h" #include "roc_core/scoped_ptr.h" -#include "roc_core/slab_pool.h" #include "roc_dbgio/temp_file.h" #include "roc_sndio/backend_map.h" #include "roc_sndio/isink.h" +// This file contains tests for ISource implementations provided by different backends +// in roc_sndio. +// +// Every test iterates through all available backends, and for each one it prepares an +// input file, opens a source, reads frames from it, and retrieved samples. +// +// Test usually defines three sample specs: +// - file write spec: defines which format/rate/channels to use for prepared +// input file +// - file read spec: tells ISource format/rate/channels to use for input file +// (usually only format or format+subformat can be specified) +// - frame spec: defines which format/rate/channels ISource uses for produced +// audio frames +// +// In some backends, ISource always produces raw frames and performs conversions from +// file format by itself. In other backends, ISource may produce frames with the +// same format as input file format. This is defined by ISource::sample_spec(). + namespace roc { namespace sndio { namespace { -enum { MaxBufSize = 8192, FrameSize = 500 }; +enum { FrameSize = 500, MaxFrameSize = FrameSize * 10, ManySamples = MaxFrameSize * 10 }; core::HeapArena arena; - -core::SlabPool frame_pool("frame_pool", arena); -core::SlabPool - frame_buffer_pool("frame_buffer_pool", - arena, - sizeof(core::Buffer) + MaxBufSize * sizeof(audio::sample_t)); - -audio::FrameFactory frame_factory(frame_pool, frame_buffer_pool); +audio::FrameFactory frame_factory(arena, MaxFrameSize * sizeof(audio::sample_t)); void write_wav(IBackend& backend, const audio::SampleSpec& file_write_spec, const audio::SampleSpec& frame_spec, const char* path, size_t num_samples) { + CHECK(frame_spec.is_complete()); + CHECK(frame_spec.is_raw()); + const core::nanoseconds_t frame_len = FrameSize * core::Second / core::nanoseconds_t(frame_spec.sample_rate() * frame_spec.num_channels()); - test::MockSource mock_source(frame_factory, frame_spec, arena); + test::MockSource mock_source(frame_spec, frame_factory, arena); mock_source.add(num_samples * file_write_spec.num_channels()); IoConfig sink_config; sink_config.sample_spec = file_write_spec; sink_config.frame_length = frame_len; - IDevice* sink_device = NULL; - LONGS_EQUAL(status::StatusOK, - backend.open_device(DeviceType_Sink, "file", path, sink_config, - frame_factory, arena, &sink_device)); - CHECK(sink_device != NULL); + core::ScopedPtr sink; + test::expect_open_sink(status::StatusOK, backend, frame_factory, arena, "file", path, + sink_config, sink); - core::ScopedPtr sink(sink_device->to_sink()); - CHECK(sink != NULL); + // sink may consume non-raw frames, so use pcm mapper + audio::PcmMapperWriter sink_mapper(*sink, frame_factory, frame_spec, + sink->sample_spec()); + LONGS_EQUAL(status::StatusOK, sink_mapper.init_status()); for (;;) { audio::FramePtr frame = @@ -74,10 +90,46 @@ void write_wav(IBackend& backend, break; } - LONGS_EQUAL(status::StatusOK, sink->write(*frame)); + LONGS_EQUAL(status::StatusOK, sink_mapper.write(*frame)); } } +void read_samples(ISource& source, + const audio::SampleSpec& frame_spec, + size_t num_samples) { + CHECK(frame_spec.is_complete()); + CHECK(frame_spec.is_raw()); + + const core::nanoseconds_t frame_len = FrameSize * core::Second + / core::nanoseconds_t(frame_spec.sample_rate() * frame_spec.num_channels()); + + // source may produce non-raw frames, so use pcm mapper + audio::PcmMapperReader source_mapper(source, frame_factory, frame_spec, + source.sample_spec()); + LONGS_EQUAL(status::StatusOK, source_mapper.init_status()); + + test::MockSink mock_sink(arena); + + for (;;) { + audio::FramePtr frame = + frame_factory.allocate_frame(frame_spec.ns_2_bytes(frame_len)); + + const status::StatusCode code = source_mapper.read( + *frame, frame_spec.ns_2_stream_timestamp(frame_len), audio::ModeHard); + + CHECK(code == status::StatusOK || code == status::StatusPart + || code == status::StatusFinish); + + if (code == status::StatusFinish) { + break; + } + + mock_sink.write(*frame); + } + + mock_sink.check(0, num_samples * frame_spec.num_channels()); +} + void expect_read(status::StatusCode expected_code, ISource& source, audio::Frame& frame, @@ -111,8 +163,8 @@ IoConfig make_config(const audio::SampleSpec& file_read_spec, TEST_GROUP(sources) {}; -// Don't specify input spec. -TEST(sources, empty_spec) { +// Don't specify input spec (source will detect everything from file). +TEST(sources, spec_empty) { audio::SampleSpec file_read_spec; file_read_spec.clear(); @@ -136,7 +188,7 @@ TEST(sources, empty_spec) { } dbgio::TempFile file("test.wav"); - write_wav(backend, file_write_spec, frame_spec, file.path(), MaxBufSize * 10); + write_wav(backend, file_write_spec, frame_spec, file.path(), ManySamples); core::ScopedPtr source; test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "file", @@ -149,12 +201,14 @@ TEST(sources, empty_spec) { CHECK(!source->has_state()); CHECK(!source->has_latency()); CHECK(!source->has_clock()); + + read_samples(*source, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, source->close()); } } -// Specify only format. -TEST(sources, explicit_format) { +// Specify only format (force source to use specific format). +TEST(sources, spec_only_format) { audio::SampleSpec file_read_spec; file_read_spec.set_format(audio::Format_Wav); @@ -178,7 +232,7 @@ TEST(sources, explicit_format) { } dbgio::TempFile file("test.wav"); - write_wav(backend, file_write_spec, frame_spec, file.path(), MaxBufSize * 10); + write_wav(backend, file_write_spec, frame_spec, file.path(), ManySamples); core::ScopedPtr source; test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "file", @@ -191,18 +245,20 @@ TEST(sources, explicit_format) { CHECK(!source->has_state()); CHECK(!source->has_latency()); CHECK(!source->has_clock()); + + read_samples(*source, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, source->close()); } } -// File with non-default rate and channels. -TEST(sources, non_default_file) { +// File with non-default sub-format, rate and channels. +TEST(sources, non_default_input_file) { audio::SampleSpec file_read_spec; file_read_spec.clear(); audio::SampleSpec file_write_spec; file_write_spec.set_format(audio::Format_Wav); - file_write_spec.set_pcm_subformat(audio::PcmSubformat_Raw); + file_write_spec.set_pcm_subformat(audio::PcmSubformat_SInt24); file_write_spec.set_sample_rate(48000); file_write_spec.set_channel_set(make_channel_set(audio::ChanMask_Surround_Mono)); @@ -220,7 +276,7 @@ TEST(sources, non_default_file) { } dbgio::TempFile file("test.wav"); - write_wav(backend, file_write_spec, frame_spec, file.path(), MaxBufSize * 10); + write_wav(backend, file_write_spec, frame_spec, file.path(), ManySamples); core::ScopedPtr source; test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "file", @@ -233,6 +289,8 @@ TEST(sources, non_default_file) { CHECK(!source->has_state()); CHECK(!source->has_latency()); CHECK(!source->has_clock()); + + read_samples(*source, frame_spec, ManySamples); LONGS_EQUAL(status::StatusOK, source->close()); } } @@ -341,7 +399,7 @@ TEST(sources, bad_format) { } dbgio::TempFile file("test.wav"); - write_wav(backend, file_write_spec, frame_spec, file.path(), MaxBufSize * 10); + write_wav(backend, file_write_spec, frame_spec, file.path(), ManySamples); core::ScopedPtr source; test::expect_open_source(status::StatusNoFormat, backend, frame_factory, arena, @@ -382,7 +440,7 @@ TEST(sources, bad_config) { } dbgio::TempFile file("test.wav"); - write_wav(backend, file_write_spec, frame_spec, file.path(), MaxBufSize * 10); + write_wav(backend, file_write_spec, frame_spec, file.path(), ManySamples); core::ScopedPtr source; test::expect_open_source( @@ -392,7 +450,7 @@ TEST(sources, bad_config) { } } -// Rewind and read same frame again. +// Rewind and read same frames again. TEST(sources, rewind) { audio::SampleSpec file_read_spec; file_read_spec.clear(); @@ -417,7 +475,7 @@ TEST(sources, rewind) { } dbgio::TempFile file("test.wav"); - write_wav(backend, file_write_spec, frame_spec, file.path(), MaxBufSize * 10); + write_wav(backend, file_write_spec, frame_spec, file.path(), ManySamples); core::ScopedPtr source; test::expect_open_source(status::StatusOK, backend, frame_factory, arena, "file",