diff --git a/CHANGES.rst b/CHANGES.rst index 43ab399..ea6b835 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,9 @@ Saraswati changelog in progress =========== +- Add capability for storing audio without putting it into container. Thanks, @MKO1640. +- Add audio formats "wav" and "WavPack". Thanks, @MKO1640. + 2021-07-21 0.6.0 ================ @@ -22,7 +25,7 @@ in progress - Run recorder service task (checking for free disk space) each 10 seconds - Improve production setup documentation -- Remove ``recording_`` prefix from recorded file name. Thanks, Weef. +- Remove ``recording_`` prefix from recorded file name. Thanks, @msweef. - Improve spool subdirectory hierarchy to reduce the number of files per directory. Thanks, Michael. The new scheme is ``/var/spool/saraswati/{year}/{month:02d}/{day:02d}/{channel}/{timestamp}_{channel}_{fragment:04d}.mka``. - Use more ISO-like timestamp format, separating each datetime's fragments. diff --git a/saraswati/cli.py b/saraswati/cli.py index b0e44e0..6a8762f 100644 --- a/saraswati/cli.py +++ b/saraswati/cli.py @@ -85,9 +85,18 @@ def validate_channel(ctx, param, value): "-cf", "container_format", envvar="CONTAINER_FORMAT", - type=click.Choice(["matroska", "ogg"]), + type=click.Choice(["matroska", "ogg", "none"]), default="matroska", - help="""Set container format. Use either "matroska" (default) or "ogg".""", + help="""Set container format. Use either "matroska" (default) or "ogg" or "none" for no container.""", +) +audio_format_opt = click.option( + "--audio-format", + "-af", + "audio_format", + envvar="AUDIO_FORMAT", + type=click.Choice(["flac", "wav", "wavpack"]), + default="flac", + help="""Set audio format. Use either "flac" (default), "wav" or "wavpack".""", ) spool_opt = click.option( "--spool", @@ -182,6 +191,7 @@ def cli(ctx): ) @channels_opt @container_opt +@audio_format_opt @spool_opt @click.option( "--chunk-duration", @@ -205,6 +215,7 @@ def record( chunk_duration: int, chunk_max_files: int, container_format: str, + audio_format: str, spool_path: str, upload_target: str, upload_interval: int, @@ -228,6 +239,7 @@ def record( chunk_duration=chunk_duration, chunk_max_files=chunk_max_files, container_format=container_format, + audio_format=audio_format, spool_path=spool_path, upload_target=upload_target, upload_interval=upload_interval, diff --git a/saraswati/model.py b/saraswati/model.py index 00c9e60..d591525 100644 --- a/saraswati/model.py +++ b/saraswati/model.py @@ -24,7 +24,7 @@ class SaraswatiSettings: # How to encode the audio. container_format: str = "matroska" # ogg, matroska - + audio_format: str = "flac" # flac,wav,wavpack # Where to store the recordings. spool_path: Optional[str] = None spool_filename_pattern: Optional[ diff --git a/saraswati/recorder.py b/saraswati/recorder.py index cc53b37..572c9a7 100644 --- a/saraswati/recorder.py +++ b/saraswati/recorder.py @@ -162,14 +162,36 @@ def add_channel(self, name: str, source: str): # TODO: Add WavPack (wavpackenc) # https://gstreamer.freedesktop.org/documentation/wavpack/wavpackenc.html - muxer = None - if self.settings.container_format == "matroska": - muxer = "matroskamux" - elif self.settings.container_format == "ogg": - muxer = "oggmux" + muxer = None + encoder = None + if self.settings.container_format == "none": + if self.settings.audio_format == "flac": + muxer = "flacenc" + encoder = "" + elif self.settings.audio_format == "wav": + muxer = "wavenc" + encoder = "" + elif self.settings.audio_format == "wavpack": + muxer = "wavpackenc" + encoder = "" + + else: + if self.settings.audio_format == "flac": + encoder = "flacenc ! flactag ! flacparse !" + elif self.settings.audio_format == "wav": + encoder = "wavenc ! wavparse !" + if self.settings.audio_format == "wavpack": + encoder = "wavpackenc !" + + if self.settings.container_format == "matroska": + muxer = "matroskamux" + + elif self.settings.container_format == "ogg": + muxer = "oggmux" + pipeline_expression = ( - f"{source} ! audioconvert ! queue ! flacenc ! flactag ! flacparse ! " + f"{source} ! audioconvert ! queue ! {encoder} " f"muxer.audio_%u splitmuxsink name=muxer muxer={muxer} " f"max-size-time={chunk_duration_ns:.0f} max-files={self.settings.chunk_max_files}" ) @@ -286,10 +308,18 @@ def on_format_location_real(self, splitmux, fragment_id, user_data): # Compute container file suffix. suffix = None + if self.settings.container_format == "matroska": suffix = "mka" elif self.settings.container_format == "ogg": suffix = "ogg" + elif self.settings.container_format == "none": + if self.settings.audio_format == "wav": + suffix = "wav" + elif self.settings.audio_format == "flac": + suffix = "flac" + elif self.settings.audio_format == "wavpack": + suffix = "wv" # Compute output location. location = str(self.output_location).format( diff --git a/saraswati/setup/systemd/saraswati.default b/saraswati/setup/systemd/saraswati.default index 3e0a1b0..db723f3 100644 --- a/saraswati/setup/systemd/saraswati.default +++ b/saraswati/setup/systemd/saraswati.default @@ -21,9 +21,15 @@ # SARASWATI_CHANNEL_12="testdrive3 source=audiotestsrc wave=3 freq=600" # SARASWATI_CHANNEL_13="testdrive4 source=audiotestsrc wave=3 freq=800" -# Configure audio recording container +# Configure audio recording container default=matroska # SARASWATI_CONTAINER_FORMAT=matroska # SARASWATI_CONTAINER_FORMAT=ogg +# SARASWATI_CONTAINER_FORMAT=none + +# Configure audio recording format. default=flac +# SARASWATI_AUDIO_FORMAT=flac +# SARASWATI_AUDIO_FORMAT=wav +# SARASWATI_AUDIO_FORMAT=wavpack # Configure spool directory SARASWATI_SPOOL_PATH=/var/spool/saraswati