diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 0091143..fd3cd30 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -31,6 +31,7 @@ jobs: libogg-dev \ libpipewire-0.3-dev \ libsndfile1-dev \ + libopusenc-dev \ libvorbis-dev \ portaudio19-dev - uses: actions/checkout@v5 @@ -49,6 +50,7 @@ jobs: ${{ matrix.audio-backend }} -DENABLE_MP3LAME=ON -DENABLE_SNDFILE=ON + -DENABLE_OPUS=ON -DENABLE_VORBIS=ON - name: Build working-directory: ${{ github.workspace }}/build diff --git a/.github/workflows/code-scanning.yaml b/.github/workflows/code-scanning.yaml index c404792..d8b695f 100644 --- a/.github/workflows/code-scanning.yaml +++ b/.github/workflows/code-scanning.yaml @@ -32,11 +32,12 @@ jobs: libogg-dev \ libpipewire-0.3-dev \ libsndfile1-dev \ + libopusenc-dev \ libvorbis-dev \ portaudio19-dev - uses: actions/checkout@v5 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: cpp queries: security-and-quality @@ -56,9 +57,10 @@ jobs: -DENABLE_PORTAUDIO=ON -DENABLE_MP3LAME=ON -DENABLE_SNDFILE=ON + -DENABLE_OPUS=ON -DENABLE_VORBIS=ON - name: Build working-directory: ${{ github.workspace }}/build run: cmake --build . --config ${{ matrix.build-type }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 14dba65..3224159 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.11) project(svar - VERSION 2.0.0 + VERSION 2.1.0 DESCRIPTION "Simple Voice Activated Recorder" LANGUAGES C) @@ -27,7 +27,8 @@ endif() option(ENABLE_MP3LAME "Enable MP3 support.") option(ENABLE_SNDFILE "Enable WAV support.") -option(ENABLE_VORBIS "Enable OGG support.") +option(ENABLE_OPUS "Enable OPUS support.") +option(ENABLE_VORBIS "Enable VORBIS support.") configure_file( ${PROJECT_SOURCE_DIR}/config.h.in @@ -77,10 +78,16 @@ if(ENABLE_MP3LAME) target_link_libraries(svarcore Mp3Lame::Mp3Lame) endif() +if(ENABLE_OPUS) + pkg_check_modules(OggOpus REQUIRED IMPORTED_TARGET libopusenc) + target_sources(svarcore PRIVATE src/writer-opus.c) + target_link_libraries(svarcore PkgConfig::OggOpus) +endif() + if(ENABLE_VORBIS) - pkg_check_modules(VorbisOgg REQUIRED IMPORTED_TARGET vorbis vorbisenc ogg) - target_sources(svarcore PRIVATE src/writer-ogg.c) - target_link_libraries(svarcore PkgConfig::VorbisOgg) + pkg_check_modules(OggVorbis REQUIRED IMPORTED_TARGET vorbis vorbisenc ogg) + target_sources(svarcore PRIVATE src/writer-vorbis.c) + target_link_libraries(svarcore PkgConfig::OggVorbis) endif() if(BUILD_TESTING) diff --git a/README.md b/README.md index caadaf1..ba2c030 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ Supported output formats: - RAW (PCM 16bit interleaved) - WAV, RF64 ([libsndfile](http://www.mega-nerd.com/libsndfile/)) - MP3 ([mp3lame](http://lame.sourceforge.net/)) -- OGG ([libvorbis](http://www.xiph.org/vorbis/)) +- OGG/OPUS ([libopusenc](https://opus-codec.org/)) +- OGG/VORBIS ([libvorbis](http://www.xiph.org/vorbis/)) For low CPU consumption WAV is recommended - it is the default selection. @@ -39,6 +40,6 @@ from the last 100 ms of captured audio. mkdir build && cd build cmake .. \ -DENABLE_ALSA=ON -DENABLE_PIPEWIRE=ON -DENABLE_PORTAUDIO=ON \ - -DENABLE_SNDFILE=ON -DENABLE_MP3LAME=ON -DENABLE_VORBIS=ON + -DENABLE_SNDFILE=ON -DENABLE_MP3LAME=ON -DENABLE_OPUS=ON -DENABLE_VORBIS=ON make && make install ``` diff --git a/config.h.in b/config.h.in index c2813d1..21e8a53 100644 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,9 @@ /* Define to 1 if SNDFile is enabled. */ #cmakedefine ENABLE_SNDFILE 1 +/* Define to 1 if Ogg Opus is enabled. */ +#cmakedefine ENABLE_OPUS 1 + /* Define to 1 if Ogg Vorbis is enabled. */ #cmakedefine ENABLE_VORBIS 1 diff --git a/src/main.c b/src/main.c index a661daa..c4429d5 100644 --- a/src/main.c +++ b/src/main.c @@ -39,8 +39,11 @@ #if ENABLE_SNDFILE # include "writer-wav.h" #endif +#if ENABLE_OPUS +# include "writer-opus.h" +#endif #if ENABLE_VORBIS -# include "writer-ogg.h" +# include "writer-vorbis.h" #endif /* Application banner used for output file comment string. */ @@ -97,8 +100,13 @@ static void print_audio_info(void) { printf("Output bit rate [kbit/s]: min=%d max=%d\n", bitrate_min / 1000, bitrate_max / 1000); #endif +#if ENABLE_OPUS + if (writer->type == WRITER_TYPE_OPUS) + printf("Output bit rate [kbit/s]: %d\n", + bitrate_nom / 1000); +#endif #if ENABLE_VORBIS - if (writer->type == WRITER_TYPE_OGG) + if (writer->type == WRITER_TYPE_VORBIS) printf("Output bit rate [kbit/s]: min=%d nominal=%d max=%d\n", bitrate_min / 1000, bitrate_nom / 1000, bitrate_max / 1000); #endif @@ -142,8 +150,10 @@ int main(int argc, char *argv[]) { /* Select default output format based on available libraries. */ #if ENABLE_SNDFILE enum writer_type writer_type = WRITER_TYPE_WAV; +#elif ENABLE_OPUS + enum writer_type writer_type = WRITER_TYPE_OPUS; #elif ENABLE_VORBIS - enum writer_type writer_type = WRITER_TYPE_OGG; + enum writer_type writer_type = WRITER_TYPE_VORBIS; #elif ENABLE_MP3LAME enum writer_type writer_type = WRITER_TYPE_MP3; #else @@ -250,8 +260,11 @@ int main(int argc, char *argv[]) { WRITER_TYPE_WAV, WRITER_TYPE_RF64, #endif +#if ENABLE_OPUS + WRITER_TYPE_OPUS, +#endif #if ENABLE_VORBIS - WRITER_TYPE_OGG, + WRITER_TYPE_VORBIS, #endif }; @@ -379,9 +392,15 @@ int main(int argc, char *argv[]) { writer_mp3_print_internals(writer); break; #endif +#if ENABLE_OPUS + case WRITER_TYPE_OPUS: + writer = writer_opus_new(pcm_format, pcm_channels, pcm_rate, + bitrate_nom, banner); + break; +#endif #if ENABLE_VORBIS - case WRITER_TYPE_OGG: - writer = writer_ogg_new(pcm_format, pcm_channels, pcm_rate, + case WRITER_TYPE_VORBIS: + writer = writer_vorbis_new(pcm_format, pcm_channels, pcm_rate, bitrate_min, bitrate_nom, bitrate_max, banner); break; #endif diff --git a/src/writer-mp3.c b/src/writer-mp3.c index 8604feb..2afb0a1 100644 --- a/src/writer-mp3.c +++ b/src/writer-mp3.c @@ -77,7 +77,7 @@ struct writer * writer_mp3_new( int bitrate_min, int bitrate_max, const char * comment) { if (format != PCM_FORMAT_S16LE) { - error("MP3 unsupported PCM format: %s", pcm_format_name(format)); + error("LAME: Unsupported PCM format: %s", pcm_format_name(format)); return NULL; } diff --git a/src/writer-opus.c b/src/writer-opus.c new file mode 100644 index 0000000..118b1e0 --- /dev/null +++ b/src/writer-opus.c @@ -0,0 +1,127 @@ +/* + * SVAR - writer-opus.c + * SPDX-FileCopyrightText: 2025 Arkadiusz Bokowy and contributors + * SPDX-License-Identifier: MIT + */ + +#include "writer-opus.h" + +#include +#include +#include +#include + +#include + +#include "log.h" +#include "pcm.h" +#include "writer.h" + +struct writer_opus { + OggOpusEnc * enc; + OggOpusComments * comments; + unsigned int channels; + unsigned int sampling; + int bitrate; +}; + +static int writer_opus_open(struct writer * writer, const char * pathname) { + struct writer_opus * w = writer->w; + + writer->close(writer); + + int err; + const int family = w->channels <= 2 ? 0 : 1; + if ((w->enc = ope_encoder_create_file(pathname, w->comments, w->sampling, + w->channels, family, &err)) == NULL) { + error("OPUS: Couldn't create encoder: %s", ope_strerror(err)); + errno = EINVAL; + return -1; + } + + if ((err = ope_encoder_ctl(w->enc, OPUS_SET_BITRATE(w->bitrate))) != OPE_OK) + warn("OPUS: Couldn't set bitrate: %s", ope_strerror(err)); + + writer->opened = true; + return 0; +} + +static void writer_opus_close(struct writer * writer) { + struct writer_opus * w = writer->w; + writer->opened = false; + + if (w->enc == NULL) + return; + + ope_encoder_drain(w->enc); + ope_encoder_destroy(w->enc); + w->enc = NULL; +} + +static ssize_t writer_opus_write(struct writer * writer, const void * buffer, size_t frames) { + struct writer_opus * w = writer->w; + + int err; + /* Write 16-bit PCM samples to the encoder. */ + if ((err = ope_encoder_write(w->enc, (const opus_int16 *)buffer, frames)) != OPE_OK) { + error("OPUS: Encoding error: %s", ope_strerror(err)); + return -1; + } + + return frames; +} + +static void writer_opus_free(struct writer * writer) { + if (writer == NULL) + return; + struct writer_opus * w = writer->w; + writer->close(writer); + if (w->comments != NULL) + ope_comments_destroy(w->comments); + free(writer->w); + free(writer); +} + +struct writer * writer_opus_new( + enum pcm_format format, unsigned int channels, unsigned int sampling, + int bitrate, const char * comment) { + + if (format != PCM_FORMAT_S16LE) { + error("OPUS: Unsupported PCM format: %s", pcm_format_name(format)); + return NULL; + } + + struct writer * writer; + if ((writer = malloc(sizeof(*writer))) == NULL) + return NULL; + + writer->type = WRITER_TYPE_OPUS; + writer->opened = false; + writer->open = writer_opus_open; + writer->write = writer_opus_write; + writer->close = writer_opus_close; + writer->free = writer_opus_free; + + struct writer_opus * w; + if ((writer->w = w = calloc(1, sizeof(*w))) == NULL) { + free(writer); + return NULL; + } + + if ((w->comments = ope_comments_create()) == NULL) { + writer_opus_free(writer); + return NULL; + } + + w->channels = channels; + w->sampling = sampling; + w->bitrate = bitrate; + + if (comment != NULL) { + char tag[8 + strlen(comment) + 1]; + snprintf(tag, sizeof(tag), "ENCODER=%s", comment); + ope_comments_add_string(w->comments, tag); + } + + return writer; +} diff --git a/src/writer-opus.h b/src/writer-opus.h new file mode 100644 index 0000000..fa537c2 --- /dev/null +++ b/src/writer-opus.h @@ -0,0 +1,18 @@ +/* + * SVAR - writer-opus.h + * SPDX-FileCopyrightText: 2025 Arkadiusz Bokowy and contributors + * SPDX-License-Identifier: MIT + */ + +#pragma once +#ifndef SVAR_WRITER_OPUS_H_ +#define SVAR_WRITER_OPUS_H_ + +#include "pcm.h" +#include "writer.h" + +struct writer * writer_opus_new( + enum pcm_format format, unsigned int channels, unsigned int sampling, + int bitrate, const char * comment); + +#endif diff --git a/src/writer-ogg.c b/src/writer-vorbis.c similarity index 77% rename from src/writer-ogg.c rename to src/writer-vorbis.c index 1a683be..ab765ca 100644 --- a/src/writer-ogg.c +++ b/src/writer-vorbis.c @@ -1,10 +1,10 @@ /* - * SVAR - writer-ogg.c + * SVAR - writer-vorbis.c * SPDX-FileCopyrightText: 2010-2025 Arkadiusz Bokowy and contributors * SPDX-License-Identifier: MIT */ -#include "writer-ogg.h" +#include "writer-vorbis.h" #include #include @@ -22,7 +22,7 @@ #include "pcm.h" #include "writer.h" -struct writer_ogg { +struct writer_vorbis { ogg_stream_state ogg_s; ogg_packet ogg_p_main; ogg_packet ogg_p_comm; @@ -34,7 +34,7 @@ struct writer_ogg { FILE * fp; }; -static size_t do_analysis_and_write_ogg(struct writer_ogg * w) { +static size_t do_analysis_and_write_ogg(struct writer_vorbis * w) { ogg_packet o_pack; ogg_page o_page; @@ -59,8 +59,8 @@ static size_t do_analysis_and_write_ogg(struct writer_ogg * w) { return len; } -static int writer_ogg_open(struct writer * writer, const char * pathname) { - struct writer_ogg * w = writer->w; +static int writer_vorbis_open(struct writer * writer, const char * pathname) { + struct writer_vorbis * w = writer->w; writer->close(writer); if ((w->fp = fopen(pathname, "w")) == NULL) @@ -81,8 +81,8 @@ static int writer_ogg_open(struct writer * writer, const char * pathname) { return 0; } -static void writer_ogg_close(struct writer * writer) { - struct writer_ogg * w = writer->w; +static void writer_vorbis_close(struct writer * writer) { + struct writer_vorbis * w = writer->w; writer->opened = false; ogg_page o_page; @@ -92,7 +92,7 @@ static void writer_ogg_close(struct writer * writer) { return; vorbis_analysis_wrote(&w->vbs_d, 0); do_analysis_and_write_ogg(w); - /* Flush any un-written partial ogg page. */ + /* Flush any un-written partial OGG page. */ while (ogg_stream_flush(&w->ogg_s, &o_page)) { len += fwrite(o_page.header, 1, o_page.header_len, w->fp); len += fwrite(o_page.body, 1, o_page.body_len, w->fp); @@ -104,11 +104,11 @@ static void writer_ogg_close(struct writer * writer) { w->fp = NULL; } -static ssize_t writer_ogg_write(struct writer * writer, const void * buffer, size_t frames) { - struct writer_ogg * w = writer->w; +static ssize_t writer_vorbis_write(struct writer * writer, const void * buffer, size_t frames) { + struct writer_vorbis * w = writer->w; /* Convert interleaved 16-bit buffer into vorbis buffer. */ - float **vbs_buffer = vorbis_analysis_buffer(&w->vbs_d, frames); + float ** vbs_buffer = vorbis_analysis_buffer(&w->vbs_d, frames); for (size_t fi = 0; fi < frames; fi++) for (int ci = 0; ci < w->vbs_i.channels; ci++) vbs_buffer[ci][fi] = (float)(((int16_t *)buffer)[fi * w->vbs_i.channels + ci]) / 0x7ffe; @@ -117,10 +117,10 @@ static ssize_t writer_ogg_write(struct writer * writer, const void * buffer, siz return do_analysis_and_write_ogg(w); } -static void writer_ogg_free(struct writer * writer) { +static void writer_vorbis_free(struct writer * writer) { if (writer == NULL) return; - struct writer_ogg * w = writer->w; + struct writer_vorbis * w = writer->w; writer->close(writer); vorbis_comment_clear(&w->vbs_c); vorbis_info_clear(&w->vbs_i); @@ -128,12 +128,12 @@ static void writer_ogg_free(struct writer * writer) { free(writer); } -struct writer * writer_ogg_new( +struct writer * writer_vorbis_new( enum pcm_format format, unsigned int channels, unsigned int sampling, int bitrate_min, int bitrate_nom, int bitrate_max, const char * comment) { if (format != PCM_FORMAT_S16LE) { - error("OGG unsupported PCM format: %s", pcm_format_name(format)); + error("VORBIS: Unsupported PCM format: %s", pcm_format_name(format)); return NULL; } @@ -141,14 +141,14 @@ struct writer * writer_ogg_new( if ((writer = malloc(sizeof(*writer))) == NULL) return NULL; - writer->type = WRITER_TYPE_OGG; + writer->type = WRITER_TYPE_VORBIS; writer->opened = false; - writer->open = writer_ogg_open; - writer->write = writer_ogg_write; - writer->close = writer_ogg_close; - writer->free = writer_ogg_free; + writer->open = writer_vorbis_open; + writer->write = writer_vorbis_write; + writer->close = writer_vorbis_close; + writer->free = writer_vorbis_free; - struct writer_ogg * w; + struct writer_vorbis * w; if ((writer->w = w = calloc(1, sizeof(*w))) == NULL) { free(writer); return NULL; @@ -181,6 +181,6 @@ struct writer * writer_ogg_new( return writer; fail: - writer_ogg_free(writer); + writer_vorbis_free(writer); return NULL; } diff --git a/src/writer-ogg.h b/src/writer-vorbis.h similarity index 72% rename from src/writer-ogg.h rename to src/writer-vorbis.h index c6dc3ac..d17974b 100644 --- a/src/writer-ogg.h +++ b/src/writer-vorbis.h @@ -1,17 +1,17 @@ /* - * SVAR - writer-ogg.h + * SVAR - writer-vorbis.h * SPDX-FileCopyrightText: 2010-2025 Arkadiusz Bokowy and contributors * SPDX-License-Identifier: MIT */ #pragma once -#ifndef SVAR_WRITER_OGG_H_ -#define SVAR_WRITER_OGG_H_ +#ifndef SVAR_WRITER_VORBIS_H_ +#define SVAR_WRITER_VORBIS_H_ #include "pcm.h" #include "writer.h" -struct writer * writer_ogg_new( +struct writer * writer_vorbis_new( enum pcm_format format, unsigned int channels, unsigned int sampling, int bitrate_min, int bitrate_nom, int bitrate_max, const char * comment); diff --git a/src/writer-wav.c b/src/writer-wav.c index 50c4376..bf8ce3b 100644 --- a/src/writer-wav.c +++ b/src/writer-wav.c @@ -25,7 +25,7 @@ static int writer_open(struct writer * writer, const char * pathname) { writer->close(writer); if ((w->sf = sf_open(pathname, SFM_WRITE, &w->sfinfo)) == NULL) { - error("Couldn't create output file: %s", sf_strerror(NULL)); + error("SF: Couldn't create output file: %s", sf_strerror(NULL)); return -1; } diff --git a/src/writer.c b/src/writer.c index 0d15293..02c550b 100644 --- a/src/writer.c +++ b/src/writer.c @@ -86,8 +86,12 @@ const char * writer_type_to_extension(enum writer_type type) { case WRITER_TYPE_MP3: return "mp3"; #endif +#if ENABLE_OPUS + case WRITER_TYPE_OPUS: + return "opus"; +#endif #if ENABLE_VORBIS - case WRITER_TYPE_OGG: + case WRITER_TYPE_VORBIS: return "ogg"; #endif } @@ -108,9 +112,13 @@ const char * writer_type_to_string(enum writer_type type) { case WRITER_TYPE_MP3: return "mp3"; #endif +#if ENABLE_OPUS + case WRITER_TYPE_OPUS: + return "opus"; +#endif #if ENABLE_VORBIS - case WRITER_TYPE_OGG: - return "ogg"; + case WRITER_TYPE_VORBIS: + return "vorbis"; #endif } return "unknown"; diff --git a/src/writer.h b/src/writer.h index dbd0fb3..fb8e1a3 100644 --- a/src/writer.h +++ b/src/writer.h @@ -27,8 +27,11 @@ enum writer_type { #if ENABLE_MP3LAME WRITER_TYPE_MP3, #endif +#if ENABLE_OPUS + WRITER_TYPE_OPUS, +#endif #if ENABLE_VORBIS - WRITER_TYPE_OGG, + WRITER_TYPE_VORBIS, #endif }; diff --git a/test/tc-writer.c b/test/tc-writer.c index dcefc2e..26a2ebe 100644 --- a/test/tc-writer.c +++ b/test/tc-writer.c @@ -17,7 +17,8 @@ #include "writer.h" #include "writer-mp3.h" #include "writer-wav.h" -#include "writer-ogg.h" +#include "writer-opus.h" +#include "writer-vorbis.h" static const uint8_t pcm_u8[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; static const int16_t pcm_s16[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -97,16 +98,54 @@ START_TEST(test_writer_mp3_write) { } END_TEST #endif +#if ENABLE_OPUS +START_TEST(test_writer_opus) { + + struct writer * w; + /* For now, the U8 format is not supported in OPUS writer. */ + ck_assert_ptr_eq(w = writer_opus_new(PCM_FORMAT_U8, 1, 16000, + 64000, NULL), NULL); + ck_assert_ptr_ne(w = writer_opus_new(PCM_FORMAT_S16LE, 1, 16000, + 64000, NULL), NULL); + ck_assert_uint_eq(w->type, WRITER_TYPE_OPUS); + ck_assert_uint_eq(w->opened, false); + + w->close(w); + w->free(w); + +} END_TEST +#endif + +#if ENABLE_OPUS +START_TEST(test_writer_opus_write) { + + struct writer * w; + const char * filename = "tc-writer.opus"; + ck_assert_ptr_ne(w = writer_opus_new(PCM_FORMAT_S16LE, 1, 16000, + 64000, "SVAR - test"), NULL); + ck_assert_int_ne(w->open(w, filename), -1); + ck_assert_uint_eq(w->opened, true); + + w->write(w, &pcm_s16[0], 5); + w->write(w, &pcm_s16[5], 5); + w->close(w); + + unlink(filename); + w->free(w); + +} END_TEST +#endif + #if ENABLE_VORBIS -START_TEST(test_writer_ogg) { +START_TEST(test_writer_vorbis) { struct writer * w; - /* For now, the U8 format is not supported in OGG writer. */ - ck_assert_ptr_eq(w = writer_ogg_new(PCM_FORMAT_U8, 1, 16000, + /* For now, the U8 format is not supported in VORBIS writer. */ + ck_assert_ptr_eq(w = writer_vorbis_new(PCM_FORMAT_U8, 1, 16000, 32000, 64000, 96000, NULL), NULL); - ck_assert_ptr_ne(w = writer_ogg_new(PCM_FORMAT_S16LE, 1, 16000, + ck_assert_ptr_ne(w = writer_vorbis_new(PCM_FORMAT_S16LE, 1, 16000, 32000, 64000, 96000, NULL), NULL); - ck_assert_uint_eq(w->type, WRITER_TYPE_OGG); + ck_assert_uint_eq(w->type, WRITER_TYPE_VORBIS); ck_assert_uint_eq(w->opened, false); w->close(w); @@ -116,11 +155,11 @@ START_TEST(test_writer_ogg) { #endif #if ENABLE_VORBIS -START_TEST(test_writer_ogg_write) { +START_TEST(test_writer_vorbis_write) { struct writer * w; const char * filename = "tc-writer.ogg"; - ck_assert_ptr_ne(w = writer_ogg_new(PCM_FORMAT_S16LE, 1, 16000, + ck_assert_ptr_ne(w = writer_vorbis_new(PCM_FORMAT_S16LE, 1, 16000, 32000, 64000, 96000, "SVAR - test"), NULL); ck_assert_int_ne(w->open(w, filename), -1); ck_assert_uint_eq(w->opened, true); @@ -205,9 +244,14 @@ void tcase_init(Suite * s) { tcase_add_test(tc, test_writer_mp3_write); #endif +#if ENABLE_OPUS + tcase_add_test(tc, test_writer_opus); + tcase_add_test(tc, test_writer_opus_write); +#endif + #if ENABLE_VORBIS - tcase_add_test(tc, test_writer_ogg); - tcase_add_test(tc, test_writer_ogg_write); + tcase_add_test(tc, test_writer_vorbis); + tcase_add_test(tc, test_writer_vorbis_write); #endif #if ENABLE_SNDFILE