Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Libsndfile Sink and Source #660

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions 3rdparty/SConscript
gavv marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ thirdparty_versions = {
'openfec': '1.4.2.7',
'openssl': '3.0.8',
'pulseaudio': '12.2',
'sndfile': '1.0.28',
'sndfile': '1.0.26',
'sox': '14.4.2',
'speexdsp': '1.2.0',

Expand All @@ -44,6 +44,10 @@ external_dependencies = set(thirdparty_versions.keys()) \
# ragel is always needed
external_dependencies.add('ragel')

# ensures we don't build sndfile twice
if 'pulseaudio' in external_dependencies:
external_dependencies.add('sndfile')

# on Linux, PulseAudio needs ALSA
if meta.platform in ['linux'] and 'pulseaudio' in external_dependencies:
external_dependencies.add('alsa')
Expand Down Expand Up @@ -230,6 +234,31 @@ elif 'speexdsp' in system_dependencies:

env = conf.Finish()

# dep: sndfile
if 'sndfile' in autobuild_dependencies:

env.BuildThirdParty(thirdparty_versions, 'sndfile')

conf = Configure(env, custom_tests=env.CustomTests)

env = conf.Finish()

elif 'sndfile' in system_dependencies:
conf = Configure(env, custom_tests=env.CustomTests)

if not conf.AddPkgConfigDependency('sndfile', '--cflags --libs', exclude_from_pc=True):
conf.env.AddManualDependency(libs=['sndfile'], exclude_from_pc=True)

if not is_crosscompiling:
if not conf.CheckLibWithHeaderExt(
'sndfile', 'sndfile.h', 'C'):
env.Die("libsndfile >= 1.0.26 not found (see 'config.log' for details)")
else:
if not conf.CheckLibWithHeaderExt('sndfile', 'sndfile.h', 'C', run=False):
env.Die("libsndfile not found (see 'config.log' for details)")

env = conf.Finish()

# dep: alsa
if 'alsa' in autobuild_dependencies:
env.BuildThirdParty(thirdparty_versions, 'alsa')
Expand All @@ -252,7 +281,6 @@ if 'pulseaudio' in autobuild_dependencies:

env.BuildThirdParty(thirdparty_versions, 'ltdl')
env.BuildThirdParty(thirdparty_versions, 'json-c')
env.BuildThirdParty(thirdparty_versions, 'sndfile')
env.BuildThirdParty(thirdparty_versions, 'pulseaudio',
deps=pa_deps, libs=['pulse', 'pulse-simple'])

Expand Down
9 changes: 9 additions & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ AddOption('--disable-sox',
action='store_true',
help='disable SoX support in tools')

AddOption('--disable-sndfile',
dest='disable_sndfile',
action='store_true',
help='disable sndfile support in tools')

AddOption('--disable-openssl',
dest='disable_openssl',
action='store_true',
Expand Down Expand Up @@ -825,6 +830,10 @@ else:
env.Append(ROC_TARGETS=[
'target_sox',
])
if not GetOption('disable_sndfile'):
env.Append(ROC_TARGETS=[
'target_sndfile',
])
if not GetOption('disable_alsa') and meta.platform in ['linux']:
env.Append(ROC_TARGETS=[
'target_alsa',
Expand Down
6 changes: 6 additions & 0 deletions debian/copyright
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,10 @@ Copyright:
ForeverASilver <https://github.com/ForeverASilver>
JJ <https://github.com/computerscienceiscool>
Hunter Rick <hunter.ellis.rick@gmail.com>
Pekureda <angelthorns@proton.me>
Anurag Soni <anuragsoni39@yahoo.com>
Samad Khan <khan.samad47@gmail.com>
Alyssa Ross <hi@alyssa.is>
Arseniy136 <zakhvatkinars@gmail.com>
Amandeep Singh <as4456@columbia.edu>
License: MPL-2.0
2 changes: 1 addition & 1 deletion scripts/ci_checks/linux-arm/aarch64-linux-gnu-gcc-7.4.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain="aarch64-linux-gnu"
compiler="gcc-7.4.1-release"
cpu="cortex-a53" # armv8

third_party="libuv,libunwind,openfec,alsa,speexdsp,sox,openssl,cpputest"
third_party="libuv,libunwind,openfec,alsa,speexdsp,sox,openssl,cpputest,sndfile"

for pulse_ver in 8.0 15.99.1
do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain="arm-bcm2708hardfp-linux-gnueabi"
compiler="gcc-4.7.1-release"
cpu="arm1176" # armv6

third_party="libuv,libunwind,libatomic_ops,openfec,alsa,pulseaudio:5.0,speexdsp,sox,openssl,cpputest"
third_party="libuv,libunwind,libatomic_ops,openfec,alsa,pulseaudio:5.0,speexdsp,sox,openssl,cpputest,sndfile"

scons -Q \
--enable-werror \
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci_checks/linux-arm/arm-linux-gnueabihf-gcc-4.9.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain="arm-linux-gnueabihf"
compiler="gcc-4.9.4-release"
cpu="cortex-a15" # armv7

third_party="libuv,libunwind,openfec,alsa,pulseaudio:10.0,speexdsp,sox,openssl,cpputest"
third_party="libuv,libunwind,openfec,alsa,pulseaudio:10.0,speexdsp,sox,openssl,cpputest,sndfile"

scons -Q \
--enable-werror \
Expand Down
4 changes: 3 additions & 1 deletion scripts/ci_checks/linux-checks/conditional-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ scons -Q --enable-werror --build-3rdparty=all \
--disable-openssl \
--disable-speex \
--disable-sox \
--disable-pulseaudio
--disable-pulseaudio \
--disable-sndfile

# optional dependencies: none, optional targets: all
scons -Q --enable-werror --build-3rdparty=all \
Expand All @@ -26,6 +27,7 @@ scons -Q --enable-werror --build-3rdparty=all \
--disable-speex \
--disable-sox \
--disable-pulseaudio \
--disable-sndfile \
test

# optional dependencies: all, optional targets: all
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci_checks/linux-checks/pulseaudio-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ do
--enable-werror \
--enable-tests \
--enable-examples \
--build-3rdparty=openfec,pulseaudio:$pulse_ver \
--build-3rdparty=openfec,pulseaudio:$pulse_ver,sndfile \
test
done
2 changes: 1 addition & 1 deletion scripts/ci_checks/macos/standard-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set -euxo pipefail
brew install --force --overwrite \
automake scons ragel gengetopt \
libuv speexdsp sox openssl@3 \
cpputest google-benchmark
cpputest google-benchmark libsndfile

# debug build
scons -Q \
Expand Down
2 changes: 1 addition & 1 deletion src/internal_modules/roc_audio/frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Frame : public core::NonCopyable<> {
FlagNotComplete = (1 << 2),

//! Set if some late packets were dropped while the frame was being built.
//! It's not necessarty that the frame itself is blank or incomplete.
//! It's not necessarily that the frame itself is blank or incomplete.
FlagPacketDrops = (1 << 3)
};

Expand Down
6 changes: 6 additions & 0 deletions src/internal_modules/roc_audio/sample_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "roc_core/macro_helpers.h"
#include "roc_core/panic.h"
#include "roc_packet/units.h"
#include "sample_spec.h"

namespace roc {
namespace audio {
Expand Down Expand Up @@ -136,6 +137,11 @@ bool SampleSpec::is_valid() const {
&& sample_rate_ != 0 && channel_set_.is_valid();
}

bool SampleSpec::is_empty() const {
return sample_fmt_ == SampleFormat_Invalid && pcm_fmt_ == PcmFormat_Invalid
&& sample_rate_ == 0 && channel_set_.num_channels() == 0;
}

bool SampleSpec::is_raw() const {
return sample_fmt_ == SampleFormat_Pcm && pcm_fmt_ == Sample_RawFormat;
}
Expand Down
3 changes: 3 additions & 0 deletions src/internal_modules/roc_audio/sample_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class SampleSpec {
//! Check if sample spec has non-zero rate and valid channel set.
bool is_valid() const;

//! Check if sample spec has a zero rate, empty channel set, and invalid_format.
bool is_empty() const;

//! Check if samples are in raw format.
//! @returns
//! true if sample_format() is SampleFormat_Pcm and pcm_format()
Expand Down
5 changes: 4 additions & 1 deletion src/internal_modules/roc_sndio/backend_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ void BackendMap::register_backends_() {
pulseaudio_backend_.reset(new (pulseaudio_backend_) PulseaudioBackend);
add_backend_(pulseaudio_backend_.get());
#endif // ROC_TARGET_PULSEAUDIO

#ifdef ROC_TARGET_SNDFILE
sndfile_backend_.reset(new (sndfile_backend_) SndfileBackend);
add_backend_(sndfile_backend_.get());
#endif // ROC_TARGET_SNDFILE
#ifdef ROC_TARGET_SOX
sox_backend_.reset(new (sox_backend_) SoxBackend);
add_backend_(sox_backend_.get());
Expand Down
8 changes: 8 additions & 0 deletions src/internal_modules/roc_sndio/backend_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include "roc_sndio/pulseaudio_backend.h"
#endif // ROC_TARGET_PULSEAUDIO

#ifdef ROC_TARGET_SNDFILE
#include "roc_sndio/sndfile_backend.h"
#endif // ROC_TARGET_SNDFILE

#ifdef ROC_TARGET_SOX
#include "roc_sndio/sox_backend.h"
#endif // ROC_TARGET_SOX
Expand Down Expand Up @@ -69,6 +73,10 @@ class BackendMap : public core::NonCopyable<> {
core::Optional<PulseaudioBackend> pulseaudio_backend_;
#endif // ROC_TARGET_PULSEAUDIO

#ifdef ROC_TARGET_SNDFILE
core::Optional<SndfileBackend> sndfile_backend_;
#endif // ROC_TARGET_SNDFILE

#ifdef ROC_TARGET_SOX
core::Optional<SoxBackend> sox_backend_;
#endif // ROC_TARGET_SOX
Expand Down
2 changes: 2 additions & 0 deletions src/internal_modules/roc_sndio/ibackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class IBackend {
const char* path,
const Config& config,
core::IArena& arena) = 0;
//! Returns name of backend.
virtual const char* name() const = 0;
};

} // namespace sndio
Expand Down
2 changes: 1 addition & 1 deletion src/internal_modules/roc_sndio/isource.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ISource : virtual public IDevice, public audio::IFrameReader {

//! Adjust source clock to match consumer clock.
//! @remarks
//! Invoked regularly after reading every or a several frames.
//! Invoked regularly after reading every or several frames.
//! @p timestamp defines the time in Unix domain when the last sample of the last
//! frame read from source is going to be actually processed by consumer.
virtual void reclock(core::nanoseconds_t timestamp) = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/internal_modules/roc_sndio/print_supported.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ bool print_supported(BackendDispatcher& backend_dispatcher, core::IArena& arena)
}

prn.writef("\nsupported formats for audio files:\n");
print_string_list(prn, list, ".", "");
print_string_list(prn, list, "", "");

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,9 @@ IDevice* PulseaudioBackend::open_device(DeviceType device_type,
return device.release();
}

const char* PulseaudioBackend::name() const {
return "PulseAudio";
}

} // namespace sndio
} // namespace roc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class PulseaudioBackend : public IBackend, core::NonCopyable<> {
const char* path,
const Config& config,
core::IArena& arena);

virtual const char* name() const;
};

} // namespace sndio
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright (c) 2023 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_sndio/sndfile_backend.h"
#include "roc_core/log.h"
#include "roc_core/scoped_ptr.h"
#include "roc_sndio/sndfile_extension_table.h"
#include "roc_sndio/sndfile_sink.h"
#include "roc_sndio/sndfile_source.h"

namespace roc {
namespace sndio {

SndfileBackend::SndfileBackend() {
roc_log(LogDebug, "sndfile backend: initializing");
}

void SndfileBackend::discover_drivers(core::Array<DriverInfo, MaxDrivers>& driver_list) {
SF_FORMAT_INFO format_info;
int total_number_of_drivers;

if (int errnum = sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT,
&total_number_of_drivers, sizeof(int))) {
roc_panic("sndfile backend: sf_command(SFC_GET_FORMAT_MAJOR_COUNT) failed %s",
sf_error_number(errnum));
}

for (int format_index = 0; format_index < total_number_of_drivers; format_index++) {
format_info.format = format_index;
if (int errnum = sf_command(NULL, SFC_GET_FORMAT_MAJOR, &format_info,
sizeof(format_info))) {
roc_panic("sndfile backend: sf_command(SFC_GET_FORMAT_MAJOR) failed %s",
sf_error_number(errnum));
}

const char* driver = format_info.extension;
gavv marked this conversation as resolved.
Show resolved Hide resolved

for (size_t map_index = 0; map_index < ROC_ARRAY_SIZE(file_type_map);
map_index++) {
if (file_type_map[map_index].format_id == format_info.format) {
driver = file_type_map[map_index].driver_name;
}
}

if (!driver_list.push_back(
DriverInfo(driver, DriverType_File,
DriverFlag_SupportsSource | DriverFlag_SupportsSink, this))) {
roc_panic("sndfile backend: driver_list.push_back(DriverInfo) failed to add "
"driver");
}
}
}

IDevice* SndfileBackend::open_device(DeviceType device_type,
DriverType driver_type,
const char* driver,
const char* path,
const Config& config,
core::IArena& arena) {
if (driver_type != DriverType_File) {
roc_log(LogDebug, "sndfile backend: driver=%s is not a file type", driver);
return NULL;
}

switch (device_type) {
case DeviceType_Sink: {
core::ScopedPtr<SndfileSink> sink(new (arena) SndfileSink(arena, config), arena);
if (!sink || !sink->is_valid()) {
roc_log(LogDebug, "sndfile backend: can't construct sink: driver=%s path=%s",
driver, path);
return NULL;
}

if (!sink->open(driver, path)) {
roc_log(LogDebug, "sndfile backend: open failed: driver=%s path=%s", driver,
path);
return NULL;
}

return sink.release();
} break;

case DeviceType_Source: {
core::ScopedPtr<SndfileSource> source(new (arena) SndfileSource(arena, config),
arena);
if (!source || !source->is_valid()) {
roc_log(LogDebug,
"sndfile backend: can't construct source: driver=%s path=%s", driver,
path);
return NULL;
}

if (!source->open(driver, path)) {
roc_log(LogDebug, "sndfile backend: open failed: driver=%s path=%s", driver,
path);
return NULL;
}

return source.release();
} break;

default:
break;
}

roc_panic("sndfile backend: invalid device type");
}

const char* SndfileBackend::name() const {
return "sndfile";
}
} // namespace sndio
} // namespace roc
Loading
Loading