Skip to content

Commit

Permalink
roc-streaminggh-246 Libsndfile Sink and Source
Browse files Browse the repository at this point in the history
  • Loading branch information
Hrick87 authored and gavv committed Apr 9, 2024
1 parent 1ea1b1b commit 20df3bb
Show file tree
Hide file tree
Showing 41 changed files with 1,917 additions and 513 deletions.
32 changes: 30 additions & 2 deletions 3rdparty/SConscript
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;

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

0 comments on commit 20df3bb

Please sign in to comment.