diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile.am | 42 | ||||
| -rw-r--r-- | src/AlsaInput.h | 18 | ||||
| -rw-r--r-- | src/FileInput.cpp | 108 | ||||
| -rw-r--r-- | src/FileInput.h | 61 | ||||
| -rw-r--r-- | src/dabplus-enc-file-zmq.c | 620 | ||||
| -rw-r--r-- | src/dabplus-enc.cpp (renamed from src/dabplus-enc-alsa-zmq.cpp) | 197 | 
7 files changed, 333 insertions, 714 deletions
@@ -30,3 +30,4 @@ mot-encoder  dabplus-enc-file  dabplus-enc-file-zmq  dabplus-enc-alsa-zmq +dabplus-enc-zmq diff --git a/Makefile.am b/Makefile.am index 7801cc1..8662153 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,31 +43,22 @@ libfdk_aac_la_LDFLAGS = -version-info @FDK_AAC_VERSION@ -no-undefined \  #aac_enc_SOURCES = src/aac-enc.c \  #				  src/wavreader.c -dabplus_enc_file_zmq_LDADD     = libfdk-aac.la -lfec -lzmq -dabplus_enc_file_zmq_CFLAGS    = $(AM_CPPFLAGS) $(GITVERSION_FLAGS) -dabplus_enc_file_zmq_SOURCES   = src/dabplus-enc-file-zmq.c \ -								 src/wavreader.c \ -								 src/encryption.c \ -								 src/encryption.h \ -								 src/utils.c \ -								 src/utils.h \ -								 contrib/lib_crc.h \ -								 contrib/lib_crc.c - -dabplus_enc_alsa_zmq_LDFLAGS     = -no-install -dabplus_enc_alsa_zmq_LDADD       = libfdk-aac.la -lfec -lzmq -lasound \ +dabplus_enc_LDFLAGS     = -no-install +dabplus_enc_LDADD       = libfdk-aac.la -lfec -lzmq -lasound \  								   -lrt -lboost_thread -dabplus_enc_alsa_zmq_CPPFLAGS    = $(AM_CPPFLAGS) $(GITVERSION_FLAGS) -dabplus_enc_alsa_zmq_SOURCES     = src/dabplus-enc-alsa-zmq.cpp \ -								   src/AlsaInput.cpp \ -								   src/AlsaInput.h \ -								   src/SampleQueue.h \ -								   src/encryption.c \ -								   src/encryption.h \ -								   src/zmq.hpp \ -								   src/utils.c \ -								   src/utils.h - +dabplus_enc_CPPFLAGS    = $(AM_CPPFLAGS) $(GITVERSION_FLAGS) +dabplus_enc_SOURCES     = src/dabplus-enc.cpp \ +						  src/FileInput.cpp \ +						  src/FileInput.h \ +						  src/AlsaInput.cpp \ +						  src/AlsaInput.h \ +						  src/SampleQueue.h \ +						  src/encryption.c \ +						  src/encryption.h \ +						  src/zmq.hpp \ +						  src/utils.c \ +						  src/utils.h \ +						  src/wavreader.c  mot_encoder_CFLAGS   = $(GITVERSION_FLAGS) @MAGICKWAND_CFLAGS@ -Icontrib  mot_encoder_LDADD    = @MAGICKWAND_LDADD@ @@ -75,8 +66,7 @@ mot_encoder_SOURCES  = src/mot-encoder.c \  					   contrib/lib_crc.h \  					   contrib/lib_crc.c -bin_PROGRAMS =  dabplus-enc-file-zmq$(EXEEXT) \ -				dabplus-enc-alsa-zmq$(EXEEXT) \ +bin_PROGRAMS =  dabplus-enc$(EXEEXT) \  				mot-encoder$(EXEEXT)  noinst_HEADERS = src/wavreader.h diff --git a/src/AlsaInput.h b/src/AlsaInput.h index 0d454a3..bd3a800 100644 --- a/src/AlsaInput.h +++ b/src/AlsaInput.h @@ -27,18 +27,19 @@  #include "SampleQueue.h" -using namespace std; -  // 16 bits per sample is fine for now  #define BYTES_PER_SAMPLE 2  // How many samples we insert into the queue each call  #define NUM_SAMPLES_PER_CALL 10 // 10 samples @ 32kHz = 3.125ms +/* Common functionality for the direct alsa input and the + * threaded alsa input + */  class AlsaInput  {      public: -        AlsaInput(const string& alsa_dev, +        AlsaInput(const std::string& alsa_dev,                  unsigned int channels,                  unsigned int rate) :              m_alsa_dev(alsa_dev), @@ -57,12 +58,10 @@ class AlsaInput          /* Prepare the audio input */          int prepare(); -        virtual void start() = 0; -      protected:          ssize_t m_read(uint8_t* buf, snd_pcm_uframes_t length); -        string m_alsa_dev; +        std::string m_alsa_dev;          unsigned int m_channels;          unsigned int m_rate; @@ -75,13 +74,11 @@ class AlsaInput  class AlsaInputDirect : public AlsaInput  {      public: -        AlsaInputDirect(const string& alsa_dev, +        AlsaInputDirect(const std::string& alsa_dev,                  unsigned int channels,                  unsigned int rate) :              AlsaInput(alsa_dev, channels, rate) { } -        virtual void start() { }; -          /* Read length Bytes from from the alsa device.           * length must be a multiple of channels * bytes_per_sample.           * @@ -97,7 +94,7 @@ class AlsaInputDirect : public AlsaInput  class AlsaInputThreaded : public AlsaInput  {      public: -        AlsaInputThreaded(const string& alsa_dev, +        AlsaInputThreaded(const std::string& alsa_dev,                  unsigned int channels,                  unsigned int rate,                  SampleQueue<uint8_t>& queue) : @@ -115,6 +112,7 @@ class AlsaInputThreaded : public AlsaInput              }          } +        /* Start the ALSA thread that fills the queue */          virtual void start();          bool fault_detected() { return m_fault; }; diff --git a/src/FileInput.cpp b/src/FileInput.cpp new file mode 100644 index 0000000..c8023dd --- /dev/null +++ b/src/FileInput.cpp @@ -0,0 +1,108 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2014 Matthias P. Braendli + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *    http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#include "FileInput.h" +#include "wavreader.h" +#include <cstring> +#include <cstdio> + +#include <stdint.h> + +int FileInput::prepare(void) +{ +    if (m_raw_input) { +        if (m_filename && strcmp(m_filename, "-")) { +            m_in_fh = fopen(m_filename, "rb"); +            if (!m_in_fh) { +                fprintf(stderr, "Can't open input file!\n"); +                return 1; +            } +        } +        else { +            m_in_fh = stdin; +        } +    } +    else { +        int bits_per_sample = 0; +        int channels = 0; +        int wav_format = 0; +        int sample_rate = 0; + +        m_wav = wav_read_open(m_filename); +        if (!m_wav) { +            fprintf(stderr, "Unable to open wav file %s\n", m_filename); +            return 1; +        } +        if (!wav_get_header(m_wav, &wav_format, &channels, &sample_rate, +                    &bits_per_sample, NULL)) { +            fprintf(stderr, "Bad wav file %s\n", m_filename); +            return 1; +        } +        if (wav_format != 1) { +            fprintf(stderr, "Unsupported WAV format %d\n", wav_format); +            return 1; +        } +        if (bits_per_sample != 16) { +            fprintf(stderr, "Unsupported WAV sample depth %d\n", bits_per_sample); +            return 1; +        } +        if (channels != 2) { +            fprintf(stderr, "Unsupported WAV channels %d\n", channels); +            return 1; +        } +        if (m_sample_rate != sample_rate) { +            fprintf(stderr, +                    "WAV sample rate %d doesn't correspond to desired sample rate %d\n", +                    sample_rate, m_sample_rate); +            return 1; +        } +    } + +    return 0; +} + +ssize_t FileInput::read(uint8_t* buf, size_t length) +{ +    ssize_t pcmread; + +    if (m_raw_input) { +        if (fread(buf, length, 1, m_in_fh) == 1) { +            pcmread = length; +        } +        else { +            fprintf(stderr, "Unable to read from input!\n"); +            return 0; +        } +    } +    else { +        pcmread = wav_read_data(m_wav, buf, length); +    } + +    return pcmread; +} + +FileInput::~FileInput() +{ +    if (m_raw_input && m_in_fh) { +        fclose(m_in_fh); +    } +    else if (m_wav) { +        wav_read_close(m_wav); +    } +} + diff --git a/src/FileInput.h b/src/FileInput.h new file mode 100644 index 0000000..9330577 --- /dev/null +++ b/src/FileInput.h @@ -0,0 +1,61 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2014 Matthias P. Braendli + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *    http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef _FILE_INPUT_H_ +#define _FILE_INPUT_H_ + +#include <stdint.h> +#include <stdio.h> + +class FileInput +{ +    public: +        FileInput(const char* filename, +                bool raw_input, +                int sample_rate) : +            m_filename(filename), +            m_raw_input(raw_input), +            m_sample_rate(sample_rate) { } + +        ~FileInput(); + +        /* Open the file and prepare the wav decoder. +         * +         * Returns nonzero on error +         */ +        int prepare(void); + +        /* Read length bytes into buf. +         * +         * Returns the number of bytes read. +         */ +        ssize_t read(uint8_t* buf, size_t length); + +    protected: +        const char* m_filename; +        bool m_raw_input; +        int m_sample_rate; + +        /* handle to the wav reader */ +        void *m_wav; + +        FILE* m_in_fh; +}; + +#endif + diff --git a/src/dabplus-enc-file-zmq.c b/src/dabplus-enc-file-zmq.c deleted file mode 100644 index 1bfae12..0000000 --- a/src/dabplus-enc-file-zmq.c +++ /dev/null @@ -1,620 +0,0 @@ -/* ------------------------------------------------------------------ - * Copyright (C) 2011 Martin Storsjo - * Copyright (C) 2013,2014 Matthias P. Braendli - * Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. - *      http://rd.csp.it/ - * - * http://opendigitalradio.org - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program  If not, see <http://www.gnu.org/licenses/>. - * ------------------------------------------------------------------- - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <getopt.h> -#include <zmq.h> -#include <assert.h> -#include "libAACenc/include/aacenc_lib.h" -#include "wavreader.h" -#include "encryption.h" -#include "utils.h" - -#include <fec.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> - -#include "contrib/lib_crc.h" - -void usage(const char* name) { -    fprintf(stderr, -    "dabplus-enc-file-zmq %s is a HE-AACv2 encoder for DAB+\n" -    "based on fdk-aac-dabplus that can read from a file\n" -    "or pipe source and encode to a ZeroMQ output for ODR-DabMux,\n" -    "a file or standard output.\n" -    "\n" -    "It includes PAD (DLS and MOT Slideshow) support by http://rd.csp.it\n" -    "to be used with mot-encoder\n" -    "\n" -    "  http://opendigitalradio.org\n" -    "\nUsage:\n" -    "%s [OPTION...]\n", -#if defined(GITVERSION) -    GITVERSION -#else -    PACKAGE_VERSION -#endif -    , name); - -    fprintf(stderr, -    "     -b, --bitrate={ 8, 16, ..., 192 }    Output bitrate in kbps. Must be 8 multiple.\n" -    "     -i, --input=FILENAME                 Input filename (default: stdin).\n" -    "     -o, --output=URI                     Output zmq uri or filename.\n" -    "                                          Use '-' for standard output,\n" -    "                                          'tcp://odr-dabmux-host:9000' for ZeroMQ.\n" -    "                                          Protocols supported: tcp, pgm, epgm\n" -    "     -a, --afterburner                    Turn on AAC encoder quality increaser.\n" -    "     -p, --pad=BYTES                      Set PAD size in bytes.\n" -    "     -P, --pad-fifo=FILENAME              Set PAD data input fifo name (default: /tmp/pad.fifo).\n" -    "     -f, --format={ wav, raw }            Set input file format (default: wav).\n" -    "     -c, --channels={ 1, 2 }              Nb of input channels for raw input (default: 2).\n" -    "     -r, --rate={ 32000, 48000 }          Sample rate for raw input (default: 48000).\n" -    "     -k, --secret-key=FILE                Set the secret key for encryption.\n" -    "     -l, --level                          Show level indication.\n" -    //"   -v, --verbose=LEVEL                  Set verbosity level.\n" -    "\n" -    "Only the tcp:// zeromq transport has been tested until now.\n" - -    ); - -} - - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -int main(int argc, char *argv[]) { -    int subchannel_index = 8; //64kbps subchannel -    int ch=0; -    const char *infile = NULL; -    const char *outuri = NULL; -    FILE *in_fh; -    FILE *out_fh; -    void *wav; -    int wav_format, bits_per_sample, sample_rate=48000, channels=2; -    uint8_t* input_buf; -    int16_t* convert_buf; - -    /* Keep track of peaks */ -    int peak_left  = 0; -    int peak_right = 0; - -    void *rs_handler = NULL; -    int aot = AOT_DABPLUS_AAC_LC; -    int afterburner = 0, raw_input=0; -    HANDLE_AACENCODER handle; -    CHANNEL_MODE mode; -    AACENC_InfoStruct info = { 0 }; - -    char* pad_fifo = "/tmp/pad.fifo"; -    int pad_fd; -    unsigned char pad_buf[128]; -    int padlen; - -    void *zmq_context = zmq_ctx_new(); -    void *zmq_sock = NULL; - -    int show_level = 0; - -    /* Data for ZMQ CURVE authentication */ -    char* keyfile = NULL; -    char secretkey[CURVE_KEYLEN+1]; - -    const struct option longopts[] = { -        {"bitrate",       required_argument,  0, 'b'}, -        {"input",         required_argument,  0, 'i'}, -        {"output",        required_argument,  0, 'o'}, -        {"format",        required_argument,  0, 'f'}, -        {"rate",          required_argument,  0, 'r'}, -        {"channels",      required_argument,  0, 'c'}, -        {"pad",           required_argument,  0, 'p'}, -        {"pad-fifo",      required_argument,  0, 'P'}, -        {"secret-key",    required_argument,  0, 'k'}, -        {"afterburner",   no_argument,        0, 'a'}, -        {"help",          no_argument,        0, 'h'}, -        {"level",         no_argument,        0, 'l'}, -        {0,0,0,0}, -    }; - -    if (argc == 1) { -        usage(argv[0]); -        return 0; -    } - -    int index; -    while(ch != -1) { -        ch = getopt_long(argc, argv, "tlhab:c:i:k:o:r:f:p:P:", longopts, &index); -        switch (ch) { -        case 'f': -            if(strcmp(optarg, "raw")==0) { -                raw_input = 1; -            } else if(strcmp(optarg, "wav")!=0) -                usage(argv[0]); -            break; -        case 'a': -            afterburner = 1; -            break; -        case 'b': -            subchannel_index = atoi(optarg) / 8; -            break; -        case 'c': -            channels = atoi(optarg); -            break; -        case 'r': -            sample_rate = atoi(optarg); -            break; -        case 'i': -            infile = optarg; -            break; -        case 'k': -            keyfile = optarg; -            break; -        case 'o': -            outuri = optarg; -            break; -        case 'p': -            padlen = atoi(optarg); -            break; -        case 'P': -            pad_fifo = optarg; -            break; -        case 'l': -            show_level = 1; -            break; -        case '?': -        case 'h': -            usage(argv[0]); -            return 1; -        } -    } - -    if(subchannel_index < 1 || subchannel_index > 24) { -        fprintf(stderr, "Bad subchannels number: %d, try other bitrate.\n", -                subchannel_index); -        return 1; -    } -    if(padlen != 0) { -        int flags; -        if (mkfifo(pad_fifo, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) != 0) { -            if (errno != EEXIST) { -                fprintf(stderr, "Can't create pad file: %d!\n", errno); -                return 1; -            } -        } -        pad_fd = open(pad_fifo, O_RDONLY | O_NONBLOCK); -        if (pad_fd == -1) { -            fprintf(stderr, "Can't open pad file!\n"); -            return 1; -        } -        flags = fcntl(pad_fd, F_GETFL, 0); -        if (fcntl(pad_fd, F_SETFL, flags | O_NONBLOCK)) { -            fprintf(stderr, "Can't set non-blocking mode in pad file!\n"); -            return 1; -        } -    } - -    if(raw_input) { -        if(infile && strcmp(infile, "-")) { -            in_fh = fopen(infile, "rb"); -            if(!in_fh) { -                fprintf(stderr, "Can't open input file!\n"); -                return 1; -            } -        } else { -            in_fh = stdin; -        } -    } else { -        wav = wav_read_open(infile); -        if (!wav) { -            fprintf(stderr, "Unable to open wav file %s\n", infile); -            return 1; -        } -        if (!wav_get_header(wav, &wav_format, &channels, &sample_rate, &bits_per_sample, NULL)) { -            fprintf(stderr, "Bad wav file %s\n", infile); -            return 1; -        } -        if (wav_format != 1) { -            fprintf(stderr, "Unsupported WAV format %d\n", wav_format); -            return 1; -        } -        if (bits_per_sample != 16) { -            fprintf(stderr, "Unsupported WAV sample depth %d\n", bits_per_sample); -            return 1; -        } -        if (channels > 2) { -            fprintf(stderr, "Unsupported WAV channels %d\n", channels); -            return 1; -        } -    } - -    if (outuri) { -        if (strcmp(outuri, "-") == 0) { -            out_fh = stdout; -        } -        else if (strncmp(outuri, "file://", 7) == 0) { -            out_fh = fopen(&outuri[7], "wb"); - -            if(!out_fh) { -                fprintf(stderr, "Can't open output file!\n"); -                return 1; -            } -        } -        else if ((strncmp(outuri, "tcp://", 6) == 0) || -                (strncmp(outuri, "pgm://", 6) == 0) || -                (strncmp(outuri, "epgm://", 7) == 0)) { -            zmq_sock = zmq_socket(zmq_context, ZMQ_PUB); -            if (zmq_sock == NULL) { -                fprintf(stderr, "Error occurred during zmq_socket: %s\n", -                        zmq_strerror(errno)); -                return 2; -            } -            if (keyfile) { -                fprintf(stderr, "Enabling encryption\n"); - -                int rc = readkey(keyfile, secretkey); -                if (rc) { -                    fprintf(stderr, "Error reading secret key\n"); -                    return 2; -                } - -                const int yes = 1; -                rc = zmq_setsockopt(zmq_sock, ZMQ_CURVE_SERVER, -                        &yes, sizeof(yes)); -                if (rc) { -                    fprintf(stderr, "Error: %s\n", zmq_strerror(errno)); -                    return 2; -                } - -                rc = zmq_setsockopt(zmq_sock, ZMQ_CURVE_SECRETKEY, -                        secretkey, CURVE_KEYLEN); -                if (rc) { -                    fprintf(stderr, "Error: %s\n", zmq_strerror(errno)); -                    return 2; -                } -            } -            if (zmq_connect(zmq_sock, outuri) != 0) { -                fprintf(stderr, "Error occurred during zmq_connect: %s\n", -                        zmq_strerror(errno)); -                return 2; -            } -        } -        else { -            out_fh = fopen(outuri, "wb"); - -            if(!out_fh) { -                fprintf(stderr, "Can't open output file!\n"); -                return 1; -            } -        } -    } else { -        fprintf(stderr, "Output URI not defined\n"); -        return 1; -    } - - -    switch (channels) { -    case 1: mode = MODE_1;       break; -    case 2: mode = MODE_2;       break; -    default: -        fprintf(stderr, "Unsupported channels number %d\n", channels); -        return 1; -    } - - -    if (aacEncOpen(&handle, 0x01|0x02|0x04, channels) != AACENC_OK) { -        fprintf(stderr, "Unable to open encoder\n"); -        return 1; -    } - - -    if(channels == 2 && subchannel_index <= 6) -        aot = AOT_DABPLUS_PS; -    else if((channels == 1 && subchannel_index <= 8) || subchannel_index <= 10) -        aot = AOT_DABPLUS_SBR; - -    fprintf(stderr, "Using %d subchannels. AAC type: %s%s%s. channels=%d, sample_rate=%d\n", -            subchannel_index, -            aot == AOT_DABPLUS_PS ? "HE-AAC v2" : "", -            aot == AOT_DABPLUS_SBR ? "HE-AAC" : "", -            aot == AOT_DABPLUS_AAC_LC ? "AAC-LC" : "", -            channels, sample_rate); - -    if (aacEncoder_SetParam(handle, AACENC_AOT, aot) != AACENC_OK) { -        fprintf(stderr, "Unable to set the AOT\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_SAMPLERATE, sample_rate) != AACENC_OK) { -        fprintf(stderr, "Unable to set the samplerate\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_CHANNELMODE, mode) != AACENC_OK) { -        fprintf(stderr, "Unable to set the channel mode\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_CHANNELORDER, 1) != AACENC_OK) { -        fprintf(stderr, "Unable to set the wav channel order\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_GRANULE_LENGTH, 960) != AACENC_OK) { -        fprintf(stderr, "Unable to set the granule length\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_TRANSMUX, TT_DABPLUS) != AACENC_OK) { -        fprintf(stderr, "Unable to set the RAW transmux\n"); -        return 1; -    } - -    /*if (aacEncoder_SetParam(handle, AACENC_BITRATEMODE, 7 *AACENC_BR_MODE_SFR*) != AACENC_OK) { -        fprintf(stderr, "Unable to set the bitrate mode\n"); -        return 1; -    }*/ - - -    fprintf(stderr, "AAC bitrate set to: %d\n", subchannel_index*8000); -    if (aacEncoder_SetParam(handle, AACENC_BITRATE, subchannel_index*8000) != AACENC_OK) { -        fprintf(stderr, "Unable to set the bitrate\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_AFTERBURNER, afterburner) != AACENC_OK) { -        fprintf(stderr, "Unable to set the afterburner mode\n"); -        return 1; -    } -    if (aacEncoder_SetParam(handle, AACENC_ANCILLARY_BITRATE, 0) != AACENC_OK) { -        fprintf(stderr, "Unable to set the ancillary bitrate\n"); -        return 1; -    } -    if (aacEncEncode(handle, NULL, NULL, NULL, NULL) != AACENC_OK) { -        fprintf(stderr, "Unable to initialize the encoder\n"); -        return 1; -    } -    if (aacEncInfo(handle, &info) != AACENC_OK) { -        fprintf(stderr, "Unable to get the encoder info\n"); -        return 1; -    } - -    fprintf(stderr, "DAB+ Encoding: framelen=%d\n", info.frameLength); - -    int input_size = channels*2*info.frameLength; -    input_buf = (uint8_t*) malloc(input_size); -    convert_buf = (int16_t*) malloc(input_size); - -    /* symsize=8, gfpoly=0x11d, fcr=0, prim=1, nroots=10, pad=135 */ -    rs_handler = init_rs_char(8, 0x11d, 0, 1, 10, 135); -    if (rs_handler == NULL) { -        perror("init_rs_char failed"); -        return 0; -    } - -    int outbuf_size = subchannel_index*120; -    uint8_t zmqframebuf[2048]; -    struct zmq_frame_header_t *zmq_frame_header = -        (struct zmq_frame_header_t*)zmqframebuf; - -    uint8_t outbuf[2048]; - -    if(outbuf_size % 5 != 0) { -        fprintf(stderr, "(outbuf_size mod 5) = %d\n", outbuf_size % 5); -    } - -    fprintf(stderr, "outbuf_size: %d\n", outbuf_size); -    //outbuf_size += (4 * subchannel_index * (8*8)/8) - outbuf_size/5; -    fprintf(stderr, "outbuf_size: %d\n", outbuf_size); - -    int frame=0; -    int send_error_count = 0; -    while (1) { -        memset(outbuf, 0x00, outbuf_size); - -        AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 }; -        AACENC_InArgs in_args = { 0 }; -        AACENC_OutArgs out_args = { 0 }; -        int in_identifier[] = {IN_AUDIO_DATA, IN_ANCILLRY_DATA}; -        int in_size[2], in_elem_size[2]; -        int out_identifier = OUT_BITSTREAM_DATA; -        int out_size, out_elem_size; -        int pcmread=0, i, ret; -        int send_error; -        void *in_ptr[2], *out_ptr; -        AACENC_ERROR err; - -        // Read data from the PAD fifo -        if (padlen != 0) { -            ret = read(pad_fd, pad_buf, padlen); -        } -        else { -            ret = 0; -        } - - -        if(ret < 0 && errno == EAGAIN) { -            // If this condition passes, there is no data to be read -            in_buf.numBufs = 1;    // Samples; -        } -        else if(ret >= 0) { -            // Otherwise, you're good to go and buffer should contain "count" bytes. -            in_buf.numBufs = 2;    // Samples + Data; -            if (ret > 0) -                fprintf(stderr, "p"); -        } -        else { -            // Some other error occurred during read. -            fprintf(stderr, "Unable to read from PAD!\n"); -                        break; -        } - -        if(raw_input) { -            if(fread(input_buf, input_size, 1, in_fh) == 1) { -                pcmread = input_size; -            } else { -                fprintf(stderr, "Unable to read from input!\n"); -                break; -            } -        } else { -            pcmread = wav_read_data(wav, input_buf, input_size); -        } - -        for (i = 0; i < pcmread/2; i++) { -            const uint8_t* in = &input_buf[2*i]; -            convert_buf[i] = in[0] | (in[1] << 8); -        } - -        for (i = 0; i < pcmread/2; i+=2) { -            peak_left  = MAX(peak_left,  convert_buf[i]); -            peak_right = MAX(peak_right, convert_buf[i+1]); -        } - -        if (pcmread <= 0) { -            in_args.numInSamples = -1; -        } else { -            in_ptr[0] = convert_buf; -            in_ptr[1] = pad_buf; -            in_size[0] = pcmread; -            in_size[1] = padlen; - -            in_elem_size[0] = 2; -            in_elem_size[1] = sizeof(UCHAR); - -            in_args.numInSamples = pcmread/2; -            in_args.numAncBytes = padlen; - -            //in_buf.numBufs = 2;    // Samples + Data - -            in_buf.bufs = (void**)&in_ptr; -            in_buf.bufferIdentifiers = in_identifier; -            in_buf.bufSizes = in_size; -            in_buf.bufElSizes = in_elem_size; - -        } -        out_ptr = outbuf; -        out_size = sizeof(outbuf); -        out_elem_size = 1; -        out_buf.numBufs = 1; -        out_buf.bufs = &out_ptr; -        out_buf.bufferIdentifiers = &out_identifier; -        out_buf.bufSizes = &out_size; -        out_buf.bufElSizes = &out_elem_size; - -        if ((err = aacEncEncode(handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) { -            if (err == AACENC_ENCODE_EOF) -                break; -            fprintf(stderr, "Encoding failed\n"); -            return 1; -        } -        if (out_args.numOutBytes == 0) -            continue; -#if 0 -        unsigned char au_start[6]; -        unsigned char* sfbuf = outbuf; -        au_start[0] = 6; -        au_start[1] = (*(sfbuf + 3) << 4) + ((*(sfbuf + 4)) >> 4); -        au_start[2] = ((*(sfbuf + 4) & 0x0f) << 8) + *(sfbuf + 5); -        fprintf (stderr, "au_start[0] = %d\n", au_start[0]); -        fprintf (stderr, "au_start[1] = %d\n", au_start[1]); -        fprintf (stderr, "au_start[2] = %d\n", au_start[2]); -#endif - -        int row, col; -        unsigned char buf_to_rs_enc[110]; -        unsigned char rs_enc[10]; -        for(row=0; row < subchannel_index; row++) { -            for(col=0;col < 110; col++) { -                buf_to_rs_enc[col] = outbuf[subchannel_index * col + row]; -            } - -            encode_rs_char(rs_handler, buf_to_rs_enc, rs_enc); - -            for(col=110; col<120; col++) { -                outbuf[subchannel_index * col + row] = rs_enc[col-110]; -                assert(subchannel_index * col + row < outbuf_size); -            } -        } - -        if (zmq_sock) { -            zmq_frame_header->version = 1; -            zmq_frame_header->encoder = ZMQ_ENCODER_FDK; -            zmq_frame_header->datasize = outbuf_size; -            zmq_frame_header->audiolevel_left = peak_left; -            zmq_frame_header->audiolevel_right = peak_right; - -            memcpy(ZMQ_FRAME_DATA(zmq_frame_header), -                    outbuf, outbuf_size); - -            send_error = zmq_send(zmq_sock, zmqframebuf, -                    ZMQ_FRAME_SIZE(zmq_frame_header), ZMQ_DONTWAIT); -            if (send_error < 0) { -                fprintf(stderr, "ZeroMQ send failed! %s\n", zmq_strerror(errno)); -                send_error_count ++; -            } -        } -        else { -            fwrite(outbuf, 1, /*out_args.numOutBytes*/ outbuf_size, out_fh); -        } - -        if (send_error_count > 10) -        { -            fprintf(stderr, "ZeroMQ send failed ten times, aborting!\n"); -            break; -        } -        //fwrite(outbuf, 1, /*out_args.numOutBytes*/ outbuf_size, out_fh); -        //fprintf(stderr, "Written %d/%d bytes!\n", out_args.numOutBytes + row*10, outbuf_size); - -        if (show_level && out_args.numOutBytes + row*10 == outbuf_size) { -            fprintf(stderr, "\rIn: [%6s|%-6s]", -                    level(0, &peak_left), -                    level(1, &peak_right)); -        } - -        frame++; -    } -    fprintf(stderr, "\n"); - -    free(input_buf); -    free(convert_buf); -    if(raw_input) { -        fclose(in_fh); -    } else { -        wav_read_close(wav); -    } - -    if (zmq_sock) { -        zmq_close(zmq_sock); -        zmq_ctx_term(zmq_context); -    } -    else { -        fclose(out_fh); -    } - -    free_rs_char(rs_handler); - -    aacEncClose(&handle); - -    return 0; -} - diff --git a/src/dabplus-enc-alsa-zmq.cpp b/src/dabplus-enc.cpp index 699a256..82780d5 100644 --- a/src/dabplus-enc-alsa-zmq.cpp +++ b/src/dabplus-enc.cpp @@ -18,15 +18,16 @@   */  #include "AlsaInput.h" +#include "FileInput.h"  #include "SampleQueue.h"  #include "zmq.hpp"  extern "C" {  #include "encryption.h"  #include "utils.h" +#include "wavreader.h"  } -  #include <string>  #include <getopt.h>  #include <cstdio> @@ -47,8 +48,8 @@ using namespace std;  void usage(const char* name) {      fprintf(stderr, -    "dabplus-enc-alsa-zmq %s is a HE-AACv2 encoder for DAB+\n" -    "based on fdk-aac-dabplus that can read from a ALSA source\n" +    "dabplus-enc %s is a HE-AACv2 encoder for DAB+\n" +    "based on fdk-aac-dabplus that can read from a ALSA or file source\n"      "and encode to a ZeroMQ output for ODR-DabMux.\n"      "\n"      "The -D option enables experimental sound card clock drift compensation.\n" @@ -69,7 +70,7 @@ void usage(const char* name) {      "\n"      "  http://opendigitalradio.org\n"      "\nUsage:\n" -    "%s [OPTION...]\n", +    "%s (-i file|-d alsa_device) [OPTION...]\n",  #if defined(GITVERSION)      GITVERSION  #else @@ -77,21 +78,27 @@ void usage(const char* name) {  #endif      , name);      fprintf(stderr, -    "     -b, --bitrate={ 8, 16, ..., 192 }    Output bitrate in kbps. Must be 8 multiple.\n" +    "   For the alsa input:\n" +    "     -d, --device=alsa_device             Set ALSA input device (default: \"default\").\n"      "     -D, --drift-comp                     Enable ALSA sound card drift compensation.\n" -    //"   -i, --input=FILENAME                 Input filename (default: stdin).\n" +    "   For the file input:\n" +    "     -i, --input=FILENAME                 Input filename (default: stdin).\n" +    "     -f, --format={ wav, raw }            Set input file format (default: wav).\n" +    "   Encoder parameters:\n" +    "     -b, --bitrate={ 8, 16, ..., 192 }    Output bitrate in kbps. Must be 8 multiple.\n"      "     -o, --output=URI                     Output zmq uri. (e.g. 'tcp://*:9000')\n" +    "                                     -or- Output file uri. (e.g. 'file.dab')\n" +    "                                     -or- a single dash '-' to denote stdout\n"      "     -a, --afterburner                    Turn on AAC encoder quality increaser.\n"      "     -p, --pad=BYTES                      Set PAD size in bytes.\n"      "     -P, --pad-fifo=FILENAME              Set PAD data input fifo name (default: /tmp/pad.fifo).\n" -    "     -d, --device=alsa_device             Set ALSA input device (default: \"default\").\n" -    "     -c, --channels={ 1, 2 }              Nb of input channels for raw input (default: 2).\n" -    "     -r, --rate={ 32000, 48000 }          Sample rate for raw input (default: 48000).\n" -    "     -k, --secret-key=FILE                Set the secret key for encryption.\n" -    "     -l, --level                          Show level indication.\n" -    //"   -V, --version                        Print version and exit.\n" +    "     -c, --channels={ 1, 2 }              Nb of input channels (default: 2).\n" +    "     -r, --rate={ 32000, 48000 }          Input sample rate (default: 48000).\n" +    "     -k, --secret-key=FILE                Enable ZMQ encryption with the given secret key.\n" +    "     -l, --level                          Show peak audio level indication.\n"      "\n" -    "Only the tcp:// zeromq transport has been tested until now.\n" +    "Only the tcp:// zeromq transport has been tested until now,\n" +    " but epgm:// and pgm:// are also accepted\n"      );  } @@ -196,7 +203,17 @@ int main(int argc, char *argv[])  {      int subchannel_index = 8; //64kbps subchannel      int ch=0; -    const char *alsa_device = "default"; + +    // For the ALSA input +    const char *alsa_device = NULL; + +    // For the file input +    const char *infile = NULL; +    int raw_input = 0; + +    // For the file output +    FILE *out_fh; +      const char *outuri = NULL;      int sample_rate=48000, channels=2;      const int bytes_per_sample = 2; @@ -209,13 +226,16 @@ int main(int argc, char *argv[])      int peak_left  = 0;      int peak_right = 0; - +    /* For MOT Slideshow and DLS insertion */      const char* pad_fifo = "/tmp/pad.fifo";      int pad_fd;      unsigned char pad_buf[128];      int padlen; +    /* Encoder status, see the above STATUS macros */      int status = 0; + +    /* Whether to show the 'sox'-like measurement */      int show_level = 0;      /* Data for ZMQ CURVE authentication */ @@ -224,15 +244,17 @@ int main(int argc, char *argv[])      const struct option longopts[] = {          {"bitrate",       required_argument,  0, 'b'}, -        {"output",        required_argument,  0, 'o'}, -        {"device",        required_argument,  0, 'd'}, -        {"rate",          required_argument,  0, 'r'},          {"channels",      required_argument,  0, 'c'}, +        {"device",        required_argument,  0, 'd'}, +        {"format",        required_argument,  0, 'f'}, +        {"input",         required_argument,  0, 'i'}, +        {"output",        required_argument,  0, 'o'},          {"pad",           required_argument,  0, 'p'},          {"pad-fifo",      required_argument,  0, 'P'}, +        {"rate",          required_argument,  0, 'r'},          {"secret-key",    required_argument,  0, 'k'}, -        {"drift-comp",    no_argument,        0, 'D'},          {"afterburner",   no_argument,        0, 'a'}, +        {"drift-comp",    no_argument,        0, 'D'},          {"help",          no_argument,        0, 'h'},          {"level",         no_argument,        0, 'l'},          {0,0,0,0}, @@ -245,11 +267,8 @@ int main(int argc, char *argv[])      int index;      while(ch != -1) { -        ch = getopt_long(argc, argv, "ahDlb:c:k:o:r:d:p:P:", longopts, &index); +        ch = getopt_long(argc, argv, "ahDlb:c:f:i:k:o:r:d:p:P:", longopts, &index);          switch (ch) { -        case 'd': -            alsa_device = optarg; -            break;          case 'a':              afterburner = true;              break; @@ -259,17 +278,29 @@ int main(int argc, char *argv[])          case 'c':              channels = atoi(optarg);              break; -        case 'r': -            sample_rate = atoi(optarg); +        case 'd': +            alsa_device = optarg;              break; -        case 'o': -            outuri = optarg; +        case 'D': +            drift_compensation = true; +            break; +        case 'f': +            if(strcmp(optarg, "raw")==0) { +                raw_input = 1; +            } else if(strcmp(optarg, "wav")!=0) +                usage(argv[0]); +            break; +        case 'i': +            infile = optarg;              break;          case 'k':              keyfile = optarg;              break; -        case 'D': -            drift_compensation = true; +        case 'l': +            show_level = 1; +            break; +        case 'o': +            outuri = optarg;              break;          case 'p':              padlen = atoi(optarg); @@ -277,8 +308,8 @@ int main(int argc, char *argv[])          case 'P':              pad_fifo = optarg;              break; -        case 'l': -            show_level = 1; +        case 'r': +            sample_rate = atoi(optarg);              break;          case '?':          case 'h': @@ -287,7 +318,12 @@ int main(int argc, char *argv[])          }      } -    if(subchannel_index < 1 || subchannel_index > 24) { +    if (alsa_device && infile) { +        fprintf(stderr, "You must define either alsa or file input, not both\n"); +        return 1; +    } + +    if (subchannel_index < 1 || subchannel_index > 24) {          fprintf(stderr, "Bad subchannels number: %d, try other bitrate.\n",                  subchannel_index);          return 1; @@ -298,10 +334,52 @@ int main(int argc, char *argv[])          return 1;      } +    /* We assume that we need to call the encoder +     * enc_calls_per_output before it gives us one encoded audio +     * frame. This information is used when the alsa drift compensation +     * is active +     */      const int enc_calls_per_output = sample_rate / 16000; -    if (!outuri) { -        fprintf(stderr, "ZeroMQ output URI not defined\n"); +    zmq::context_t zmq_ctx; +    zmq::socket_t zmq_sock(zmq_ctx, ZMQ_PUB); + +    if (outuri) { +        if (strcmp(outuri, "-") == 0) { +            out_fh = stdout; +        } +        else if ((strncmp(outuri, "tcp://", 6) == 0) || +                (strncmp(outuri, "pgm://", 6) == 0) || +                (strncmp(outuri, "epgm://", 7) == 0)) { +            if (keyfile) { +                fprintf(stderr, "Enabling encryption\n"); + +                int rc = readkey(keyfile, secretkey); +                if (rc) { +                    fprintf(stderr, "Error reading secret key\n"); +                    return 2; +                } + +                const int yes = 1; +                zmq_sock.setsockopt(ZMQ_CURVE_SERVER, +                        &yes, sizeof(yes)); + +                zmq_sock.setsockopt(ZMQ_CURVE_SECRETKEY, +                        secretkey, CURVE_KEYLEN); +            } +            zmq_sock.connect(outuri); +        } +        else { // We assume it's a file name +            out_fh = fopen(outuri, "wb"); + +            if (!out_fh) { +                fprintf(stderr, "Can't open output file!\n"); +                return 1; +            } +        } +    } +    else { +        fprintf(stderr, "Output URI not defined\n");          return 1;      } @@ -325,26 +403,6 @@ int main(int argc, char *argv[])          }      } -    zmq::context_t zmq_ctx; -    zmq::socket_t zmq_sock(zmq_ctx, ZMQ_PUB); - -    if (keyfile) { -        fprintf(stderr, "Enabling encryption\n"); - -        int rc = readkey(keyfile, secretkey); -        if (rc) { -            fprintf(stderr, "Error reading secret key\n"); -            return 2; -        } - -        const int yes = 1; -        zmq_sock.setsockopt(ZMQ_CURVE_SERVER, -                &yes, sizeof(yes)); - -        zmq_sock.setsockopt(ZMQ_CURVE_SECRETKEY, -                secretkey, CURVE_KEYLEN); -    } -    zmq_sock.connect(outuri);      HANDLE_AACENCODER encoder; @@ -378,11 +436,23 @@ int main(int argc, char *argv[])          return 1;      } -    // We'll use either of the two possible alsa inputs. +    /* No input defined ? default to alsa "default" */ +    if (!alsa_device) { +        alsa_device = "default"; +    } + +    // We'll use one of the tree possible inputs      AlsaInputThreaded alsa_in_threaded(alsa_device, channels, sample_rate, queue); -    AlsaInputDirect alsa_in_direct(alsa_device, channels, sample_rate); +    AlsaInputDirect   alsa_in_direct(alsa_device, channels, sample_rate); +    FileInput         file_in(infile, raw_input, sample_rate); -    if (drift_compensation) { +    if (infile) { +        if (file_in.prepare() != 0) { +            fprintf(stderr, "File input preparation failed\n"); +            return 1; +        } +    } +    else if (drift_compensation) {          if (alsa_in_threaded.prepare() != 0) {              fprintf(stderr, "Alsa preparation failed\n");              return 1; @@ -485,9 +555,20 @@ int main(int argc, char *argv[])          // -------------- Read Data          memset(outbuf, 0x00, outbuf_size); +        memset(input_buf, 0x00, input_size);          ssize_t read; -        if (drift_compensation) { +        if (infile) { +            read = file_in.read(input_buf, input_size); +            if (read < 0) { +                break; +            } +            else if (read != input_size) { +                fprintf(stderr, "Short file read !\n"); +                break; +            } +        } +        else if (drift_compensation) {              if (alsa_in_threaded.fault_detected()) {                  fprintf(stderr, "Detected fault in alsa input!\n");                  break;  | 
