diff options
author | Matthias P. Braendli (think) <matthias@mpb.li> | 2012-08-23 20:20:30 +0200 |
---|---|---|
committer | Matthias P. Braendli (think) <matthias@mpb.li> | 2012-08-23 20:20:30 +0200 |
commit | 3b9073ec178d1ebd8563d94ebbb9b95726e31835 (patch) | |
tree | 895ed780d41501089e1464efd20482ab9a0e4c1c /src/DabMux.cpp | |
parent | 37f3f44cc1c0f5cf3a9b3f0ffc32f638b281994e (diff) | |
download | dabmux-r5.tar.gz dabmux-r5.tar.bz2 dabmux-r5.zip |
crc-dabmux: configuration file support for ensemble definitionr5
Diffstat (limited to 'src/DabMux.cpp')
-rw-r--r-- | src/DabMux.cpp | 1896 |
1 files changed, 48 insertions, 1848 deletions
diff --git a/src/DabMux.cpp b/src/DabMux.cpp index 3f5f87c..8a065a0 100644 --- a/src/DabMux.cpp +++ b/src/DabMux.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Her Majesty the Queen in Right of Canada (Communications + 2011, 2012 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) Includes modifications @@ -21,23 +21,28 @@ You should have received a copy of the GNU General Public License along with CRC-DabMux. If not, see <http://www.gnu.org/licenses/>. - */ - +*/ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include <stdio.h> +#include <cstdio> #include <stdlib.h> #include <iostream> #include <fstream> #include <iomanip> -#include <cstdio> #include <cstring> +#include <string> #include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> + +// for basename +#include <libgen.h> -using namespace std; #include <vector> #include <set> #include <functional> @@ -72,11 +77,6 @@ typedef DWORD32 uint32_t; # include <linux/netdevice.h> #endif -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <signal.h> - #ifdef _WIN32 # pragma warning ( disable : 4103 ) # include "Eti.h" @@ -84,6 +84,7 @@ typedef DWORD32 uint32_t; #else # include "Eti.h" #endif + #include "dabInputFile.h" #include "dabInputFifo.h" #include "dabInputMpegFile.h" @@ -110,579 +111,13 @@ typedef DWORD32 uint32_t; #include "InetAddress.h" #include "dabUtils.h" #include "PcDebug.h" +#include "DabMux.h" +#include "MuxElements.h" +#include "utils.h" +#include "ParserCmdline.h" +#include "ParserConfigfile.h" - -// DAB Mode -#define DEFAULT_DAB_MODE 2 - -// Taille de la trame de donnee, sous-canal 3, nb de paquets de 64bits, -// STL3 * 8 = x kbytes par trame ETI - -// Data bitrate in kbits/s. Must be 64 kb/s multiple. -#define DEFAULT_DATA_BITRATE 384 -#define DEFAULT_PACKET_BITRATE 32 - -// Etiquettes des sous-canaux et de l'ensemble, 16 characteres incluant les -// espaces -#define DEFAULT_ENSEMBLE_LABEL "CRC-Dr.Radio" -#define DEFAULT_ENSEMBLE_SHORT_LABEL 0xe000 -#define DEFAULT_ENSEMBLE_ID 0xc000 -#define DEFAULT_ENSEMBLE_ECC 0xa1 - -//Numeros des sous-canaux -#define DEFAULT_SERVICE_ID 50 -#define DEFAULT_PACKET_ADDRESS 0 - - -struct dabOutput { - const char* outputProto; - const char* outputName; - void* data; - dabOutputOperations operations; -}; - - -struct dabLabel { - char text[16]; - uint16_t flag; -}; - - -struct dabService; -struct dabComponent; -struct dabSubchannel; -struct dabEnsemble { - uint16_t id; - uint8_t ecc; - dabLabel label; - uint8_t mode; - vector<dabService*> services; - vector<dabComponent*> components; - vector<dabSubchannel*> subchannels; -}; - - -struct dabProtectionShort { - unsigned char tableSwitch; - unsigned char tableIndex; -}; - - -struct dabProtectionLong { - unsigned char option; -}; - - -struct dabProtection { - unsigned char level; - unsigned char form; - union { - dabProtectionShort shortForm; - dabProtectionLong longForm; - }; -}; - - -struct dabSubchannel { - const char* inputProto; - const char* inputName; - void* data; - dabInputOperations operations; - unsigned char id; - unsigned char type; - uint16_t startAddress; - uint16_t bitrate; - dabProtection protection; -}; - - -class SubchannelId : public std::binary_function <dabSubchannel*, int, bool> { -public: - bool operator()(const dabSubchannel* subchannel, const int id) const { - return subchannel->id == id; - } -}; - - -vector<dabSubchannel*>::iterator getSubchannel( - vector<dabSubchannel*>& subchannels, int id) -{ - return find_if( - subchannels.begin(), - subchannels.end(), - bind2nd(SubchannelId(), id) - ); -} - - -struct dabAudioComponent { -}; - - -struct dabDataComponent { -}; - - -struct dabFidcComponent { -}; - - -struct dabPacketComponent { - uint16_t id; - uint16_t address; - uint16_t appType; - bool datagroup; -}; - - -struct dabComponent { - dabLabel label; - uint32_t serviceId; - uint8_t subchId; - uint8_t type; - uint8_t SCIdS; - union { - dabAudioComponent audio; - dabDataComponent data; - dabFidcComponent fidc; - dabPacketComponent packet; - }; - - bool isPacketComponent(vector<dabSubchannel*>& subchannels) - { - if (subchId > 63) { - etiLog.printHeader(TcpLog::ERR, - "You must define subchannel id in the " - "packet component before defining packet "); - return false; - } - if (getSubchannel(subchannels, subchId) == subchannels.end()) { - etiLog.printHeader(TcpLog::ERR, - "Invalid subchannel id in the packet component " - "for defining packet "); - return false; - } - if ((*getSubchannel(subchannels, subchId))->type != 3) { - etiLog.printHeader(TcpLog::ERR, - "Invalid component type for defining packet "); - return false; - } - return true; - } -}; - - -vector<dabComponent*>::iterator getComponent( - vector<dabComponent*>& components, - uint32_t serviceId, - vector<dabComponent*>::iterator current) -{ - if (current == components.end()) { - current = components.begin(); - } else { - ++current; - } - - while (current != components.end()) { - if ((*current)->serviceId == serviceId) { - return current; - } - ++current; - } - - return components.end(); -} - - -vector<dabComponent*>::iterator getComponent( - vector<dabComponent*>& components, - uint32_t serviceId) { - return getComponent(components, serviceId, components.end()); -} - - -struct dabService { - dabLabel label; - uint32_t id; - unsigned char pty; - unsigned char language; - bool program; - - unsigned char getType(dabEnsemble* ensemble) - { - vector<dabSubchannel*>::iterator subchannel; - vector<dabComponent*>::iterator component = - getComponent(ensemble->components, id); - if (component == ensemble->components.end()) { - return 4; - } - subchannel = getSubchannel(ensemble->subchannels, (*component)->subchId); - if (subchannel == ensemble->subchannels.end()) { - return 8; - } - - return (*subchannel)->type; - } - unsigned char nbComponent(vector<dabComponent*>& components) - { - int nb = 0; - vector<dabComponent*>::iterator current; - - for (current = components.begin(); current != components.end(); - ++current) { - if ((*current)->serviceId == id) { - ++nb; - } - } - return nb; - } -}; - - -vector<dabService*>::iterator getService( - dabComponent* component, - vector<dabService*>& services) -{ - vector<dabService*>::iterator service; - - for (service = services.begin(); service != services.end(); ++service) { - if ((*service)->id == component->serviceId) { - break; - } - } - - return service; -} - - -/****************************************************************************** - ***************** Definitions des stuctures des FIGs ********************** - ******************************************************************************/ -struct FIGtype0 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -struct FIGtype0_0 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; - - uint16_t EId; - uint8_t CIFcnt_hight:5; - uint8_t Al:1; - uint8_t Change:2; - uint8_t CIFcnt_low:8; -} PACKED; - - -struct FIGtype0_2 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -struct FIGtype0_2_Service { - uint16_t SId; - uint8_t NbServiceComp:4; - uint8_t CAId:3; - uint8_t Local_flag:1; -} PACKED; - - -struct FIGtype0_2_Service_data { - uint32_t SId; - uint8_t NbServiceComp:4; - uint8_t CAId:3; - uint8_t Local_flag:1; -} PACKED; - - -struct FIGtype0_2_audio_component { - uint8_t ASCTy:6; - uint8_t TMid:2; - uint8_t CA_flag:1; - uint8_t PS:1; - uint8_t SubChId:6; -} PACKED; - - -struct FIGtype0_2_data_component { - uint8_t DSCTy:6; - uint8_t TMid:2; - uint8_t CA_flag:1; - uint8_t PS:1; - uint8_t SubChId:6; -} PACKED; - - -struct FIGtype0_2_packet_component { - uint8_t SCId_high:6; - uint8_t TMid:2; - uint8_t CA_flag:1; - uint8_t PS:1; - uint8_t SCId_low:6; - void setSCId(uint16_t SCId) { - SCId_high = SCId >> 6; - SCId_low = SCId & 0x3f; - } -} PACKED; - - -struct FIGtype0_3_header { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -/* Warning: When bit SCCA_flag is unset(0), the multiplexer R&S does not send - * the SCCA field. But, in the Factum ETI analyzer, if this field is not there, - * it is an error. - */ -struct FIGtype0_3_data { - uint8_t SCId_high; - uint8_t SCCA_flag:1; - uint8_t rfa:3; - uint8_t SCId_low:4; - uint8_t DSCTy:6; - uint8_t rfu:1; - uint8_t DG_flag:1; - uint8_t Packet_address_high:2; - uint8_t SubChId:6; - uint8_t Packet_address_low; - uint16_t SCCA; - void setSCId(uint16_t SCId) { - SCId_high = SCId >> 4; - SCId_low = SCId & 0xf; - } - void setPacketAddress(uint16_t address) { - Packet_address_high = address >> 8; - Packet_address_low = address & 0xff; - } -} PACKED; - - -struct FIGtype0_8_short { - uint8_t SCIdS:4; - uint8_t rfa_1:3; - uint8_t ext:1; - uint8_t Id:6; - uint8_t MscFic:1; - uint8_t LS:1; - uint8_t rfa_2; -} PACKED; - - -struct FIGtype0_8_long { - uint8_t SCIdS:4; - uint8_t rfa_1:3; - uint8_t ext:1; - uint8_t SCId_high:4; - uint8_t rfa:3; - uint8_t LS:1; - uint8_t SCId_low; - uint8_t rfa_2; - void setSCId(uint16_t id) { - SCId_high = id >> 8; - SCId_low = id & 0xff; - } - uint16_t getSCid() { - return (SCId_high << 8) | SCId_low; - } -} PACKED; - - -struct FIGtype0_9 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; - - uint8_t ensembleLto:6; - uint8_t lto:1; - uint8_t ext:1; - uint8_t ensembleEcc; - uint8_t tableId; -} PACKED; - - -struct FIGtype0_10 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; - - uint8_t MJD_high:7; - uint8_t RFU:1; - uint8_t MJD_med; - uint8_t Hours_high:3; - uint8_t UTC:1; - uint8_t ConfInd:1; - uint8_t LSI:1; - uint8_t MJD_low:2; - uint8_t Minutes:6; - uint8_t Hours_low:2; - void setMJD(uint32_t date) { - MJD_high = (date >> 10) & 0x7f; - MJD_med = (date >> 2) & 0xff; - MJD_low = date & 0x03; - } - void setHours(uint16_t hours) { - Hours_high = (hours >> 2) & 0x07; - Hours_low = hours & 0x03; - } -} PACKED; - - -struct FIGtype0_17_programme { - uint16_t SId; - uint8_t NFC:2; - uint8_t Rfa:2; - uint8_t CC:1; - uint8_t L:1; - uint8_t PS:1; - uint8_t SD:1; -} PACKED; - - -struct FIGtype0_1 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -struct FIG_01_SubChannel_ShortF { - uint8_t StartAdress_high:2; - uint8_t SubChId:6; - uint8_t StartAdress_low:8; - uint8_t TableIndex:6; - uint8_t TableSwitch:1; - uint8_t Short_Long_form:1; -} PACKED; - - -struct FIG_01_SubChannel_LongF { - uint8_t StartAdress_high:2; - uint8_t SubChId:6; - uint8_t StartAdress_low:8; - uint8_t Sub_ChannelSize_high:2; - uint8_t ProtectionLevel:2; - uint8_t Option:3; - uint8_t Short_Long_form:1; - uint8_t Sub_ChannelSize_low:8; -} PACKED; - - -struct FIG0_13_shortAppInfo { - uint16_t SId; - uint8_t No:4; - uint8_t SCIdS:4; -} PACKED; - - -struct FIG0_13_longAppInfo { - uint32_t SId; - uint8_t No:4; - uint8_t SCIdS:4; -} PACKED; - - -struct FIG0_13_app { - uint8_t typeHigh; - uint8_t length:5; - uint8_t typeLow:3; - void setType(uint16_t type) { - typeHigh = type >> 3; - typeLow = type & 0x1f; - } -} PACKED; - - -struct FIGtype1_0 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:3; - uint8_t OE:1; - uint8_t Charset:4; - - uint16_t EId; -} PACKED; - - -struct FIGtype1_1 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:3; - uint8_t OE:1; - uint8_t Charset:4; - - uint16_t Sld; -} PACKED; - - -struct FIGtype1_5 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:3; - uint8_t OE:1; - uint8_t Charset:4; - uint32_t SId; -} PACKED; - - -struct FIGtype1_4_programme { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:3; - uint8_t OE:1; - uint8_t Charset:4; - uint8_t SCIdS:4; - uint8_t rfa:3; - uint8_t PD:1; - uint16_t SId; -} PACKED; - - -struct FIGtype1_4_data { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:3; - uint8_t OE:1; - uint8_t Charset:4; - uint8_t SCIdS:4; - uint8_t rfa:3; - uint8_t PD:1; - uint32_t SId; -} PACKED; - - -#ifdef _WIN32 -# pragma pack(pop) -#endif +using namespace std; static unsigned char Padding_FIB[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -700,17 +135,6 @@ const unsigned short Bit_Rate_SpecifiedTable[16] = { }; -const unsigned short Sub_Channel_SizeTable[64] = { - 16, 21, 24, 29, 35, 24, 29, 35, - 42, 52, 29, 35, 42, 52, 32, 42, - 48, 58, 70, 40, 52, 58, 70, 84, - 48, 58, 70, 84, 104, 58, 70, 84, - 104, 64, 84, 96, 116, 140, 80, 104, - 116, 140, 168, 96, 116, 140, 168, 208, - 116, 140, 168, 208, 232, 128, 168, 192, - 232, 280, 160, 208, 280, 192, 280, 416 -}; - const unsigned char ProtectionLevelTable[64] = { 4, 3, 2, 1, 0, 4, 3, 2, @@ -736,250 +160,6 @@ const unsigned short BitRateTable[64] = { }; -unsigned short getSizeByte(dabSubchannel* subchannel) -{ - return subchannel->bitrate * 3; -} - - -unsigned short getSizeWord(dabSubchannel* subchannel) -{ - return (subchannel->bitrate * 3) >> 2; -} - - -unsigned short getSizeDWord(dabSubchannel* subchannel) -{ - return (subchannel->bitrate * 3) >> 3; -} - - -unsigned short getSizeCu(dabSubchannel* subchannel) -{ - if (subchannel->protection.form == 0) { - return Sub_Channel_SizeTable[subchannel-> - protection.shortForm.tableIndex]; - } else { - dabProtectionLong* protection = - &subchannel->protection.longForm; - switch (protection->option) { - case 0: - switch (subchannel->protection.level) { - case 0: - return (subchannel->bitrate * 12) >> 3; - break; - case 1: - return subchannel->bitrate; - break; - case 2: - return (subchannel->bitrate * 6) >> 3; - break; - case 3: - return (subchannel->bitrate >> 1); - break; - default: // Should not happens - etiLog.print(TcpLog::ERR, "Bad protection level on " - "subchannel\n"); - return 0; - } - break; - case 1: - switch (subchannel->protection.level) { - case 0: - return (subchannel->bitrate * 27) >> 5; - break; - case 1: - return (subchannel->bitrate * 21) >> 5; - break; - case 2: - return (subchannel->bitrate * 18) >> 5; - break; - case 3: - return (subchannel->bitrate * 15) >> 5; - break; - default: // Should not happens - etiLog.print(TcpLog::ERR, - "Bad protection level on subchannel\n"); - return 0; - } - break; - default: - etiLog.print(TcpLog::ERR, "Invalid protection option\n"); - return 0; - } - } - return 0; -} - - -time_t getDabTime() -{ - static time_t oldTime = 0; - static int offset = 0; - if (oldTime == 0) { - oldTime = time(NULL); - } else { - offset+= 24; - if (offset >= 1000) { - offset -= 1000; - ++oldTime; - } - } - return oldTime; -} - - -void printUsage(char *name, FILE* out = stderr) -{ - fprintf(out, "NAME\n"); - fprintf(out, " %s - A software DAB multiplexer\n", name); - fprintf(out, "\nSYNOPSYS\n"); - fprintf(out, " %s" - " [ensemble]" - " [subchannel1 subchannel2 ...]" - " [service1 component1 [component2 ...] service2 ...]" - " [output1 ...]" - " [-h]" - " [-m mode]" - " [-n nbFrames]" - " [-o]" - " [-s]" - " [-V]" - " [-z]" - "\n", - name); - fprintf(out, "\n Where ensemble =" - " [-i ensembleId]" - " [-L label]" - " [-l sLabel]" - "\n"); - fprintf(out, "\n Where subchannel =" - " -(A | B | D | E | F | M | P | T) inputName" - " [-b bitrate]" - " [-i subchannelId]" - " [-k]" - " [-p protection]" - "\n"); - fprintf(out, "\n Where service =" - " -S" - " [-g language]" - " [-i serviceId]" - " [-L label]" - " [-l sLabel]" - " [-y PTy]" - "\n"); - fprintf(out, "\n Where component =" - " -C" - " [-a address]" - " [-d]" - " [-f figType]" - " [-i subchannelId]" - " [-L label]" - " [-l sLabel]" - " [-t type]" - "\n"); - fprintf(out, "\nDESCRIPTION\n"); - fprintf(out, - " %s is a software multiplexer that generates an ETI stream from\n" - " audio and data streams. Because of its software based architecture,\n" - " many typical DAB services can be generated and multiplexed on a single\n" - " PC platform with live or pre-recorded sources.\n" - "\n" - " A DAB multiplex configuration is composed of one ensemble. An ensemble\n" - " is the entity that receivers tune to and process. An ensemble contains\n" - " several services. A service is the listener-selectable output. Each\n" - " service contains one mandatory service component which is called pri-\n" - " mary component. An audio primary component define a program service\n" - " while a data primary component define a data service. Service can con-\n" - " tain additional components which are called secondary components. Maxi-\n" - " mum total number of components is 12 for program services and 11 for\n" - " data services. A service component is a link to one subchannel (of Fast\n" - " Information Data Channel). A subchannel is the physical space used\n" - " within the common interleaved frame.\n" - "\n" - " __________________________________________________\n" - " | CRC-Ensemble | ENSEMBLE\n" - " |__________________________________________________|\n" - " | | |\n" - " | | |\n" - " _______V______ _______V______ _______V______\n" - " | CRC-Service1 | | CRC-Service2 | | CRC-Service3 | SERVICES\n" - " |______________| |______________| |______________|\n" - " | | | | |______ |\n" - " | | | | | |\n" - " __V__ __V__ __V__ __V__ __V__ __V__\n" - " | SC1 | | SC2 | | SC3 | | SC4 | | SC5 | | SC6 | SERVICE\n" - " |_____| |_____| |_____| |_____| |_____| |_____| COMPONENTS\n" - " | | _____| | | ____|\n" - " | | | | | |\n" - " __V________V__V______________V________V___V_______ COMMON\n" - " | SubCh1 | SubCh9 | ... | SubCh3 | SubCh60 | ... | INTERLEAVED\n" - " |________|________|_______|________|_________|_____| FRAME\n" - " Figure 1: An example of a DAB multiplex configuration\n", - name); - - fprintf(out, "\nGENERAL OPTIONS\n"); - fprintf(out, " -h : get this help\n"); - fprintf(out, " -m : DAB mode (default: 2)\n"); - fprintf(out, " -n nbFrames : number of frames to produce\n"); - fprintf(out, " -o : turn on TCP log on port 12222\n"); - fprintf(out, " -r : throttle the output rate to one ETI frame every 24ms\n"); - fprintf(out, " -V : print version information and " - "exit\n"); - fprintf(out, " -z : write SCCA field for Factum ETI" - " analyzer\n"); - fprintf(out, "\nINPUT OPTIONS\n"); - fprintf(out, " -A : set audio service\n"); - fprintf(out, " -B : set CRC-Bridge data service\n"); - fprintf(out, " -D : set data service\n"); - fprintf(out, " -E : set enhanced packet service\n"); - fprintf(out, " -F : set DAB+ service\n"); - fprintf(out, " -M : set DMB service\n"); - fprintf(out, " -P : set packet service\n"); - fprintf(out, " -T : set test service\n"); - fprintf(out, " inputName<n> : name of file for audio and " - "packet service and Udp input address for data service " - "([address]:port)\n"); - fprintf(out, " -a : packet address (default: 0x%x " - "(%i))\n", DEFAULT_PACKET_ADDRESS, DEFAULT_PACKET_ADDRESS); - fprintf(out, " -b bitrate<n> : bitrate (in kbits/s) of the " - "subchannel (default: audio 1st frame, data %i, packet %i)\n", - DEFAULT_DATA_BITRATE, DEFAULT_PACKET_BITRATE); - fprintf(out, " -c : set the extendend country code ECC " - "(default: %u (0x%2x)\n", DEFAULT_ENSEMBLE_ECC, DEFAULT_ENSEMBLE_ECC); - fprintf(out, " -d : turn on datagroups in packet " - "mode\n"); - fprintf(out, " -f figType : user application type in FIG " - "0/13 for packet mode\n"); - fprintf(out, " -g language : Primary service component " - "language: english=9, french=15\n"); - fprintf(out, " -i id<n> : service|subchannel|" - "serviceComponent id <n> (default: <n>)\n"); - fprintf(out, " -k : set non-blocking file input " - "(audio and packet only)\n"); - fprintf(out, " -L label<n> : label of service <n>" - " (default: CRC-Audio<n>)\n"); - fprintf(out, " -l sLabel<n> : short label flag of service <n>" - " (default: 0xf040)\n"); - fprintf(out, " -p protection<n> : protection level (default: 3)\n"); - fprintf(out, " -s : enable TIST, synchronized on 1PPS at level 2. This also transmits time using the MNSC.\n"); - fprintf(out, " -t type : audio/data service component type" - " (default: 0)\n"); - fprintf(out, " audio: foreground=0, " - "background=1, multi-channel=2\n"); - fprintf(out, " data: unspecified=0, TMC=1, " - "EWS=2, ITTS=3, paging=4, TDC=5, DMB=24, IP=59, MOT=60, " - "proprietary=61\n"); - fprintf(out, " -y PTy : Primary service component program" - " type international code\n"); - fprintf(out, "\nOUTPUT OPTIONS\n"); - fprintf(out, " -O output : name of the output in format " - "scheme://[address][:port][/name]\n" - " where scheme is (raw|udp|tcp|file|fifo|simul)\n" - ); -} - - bool running = true; void signalHandler(int signum) @@ -1021,259 +201,10 @@ void signalHandler(int signum) } -void printEnsemble(dabEnsemble* ensemble) -{ - char label[17]; - memcpy(label, ensemble->label.text, 16); - label[16] = 0; - - etiLog.printHeader(TcpLog::INFO, "Ensemble\n"); - etiLog.printHeader(TcpLog::INFO, " id: 0x%lx (%lu)\n", - ensemble->id, ensemble->id); - etiLog.printHeader(TcpLog::INFO, " ecc: 0x%x (%u)\n", - ensemble->ecc, ensemble->ecc); - etiLog.printHeader(TcpLog::INFO, " label: %s\n", label); - etiLog.printHeader(TcpLog::INFO, " short label: "); - for (int i = 0; i < 32; ++i) { - if (ensemble->label.flag & 0x8000 >> i) { - etiLog.printHeader(TcpLog::INFO, "%c", ensemble->label.text[i]); - } - } - etiLog.printHeader(TcpLog::INFO, " (0x%x)\n", ensemble->label.flag); - etiLog.printHeader(TcpLog::INFO, " mode: %u\n", ensemble->mode); -} - - -void printSubchannels(vector<dabSubchannel*>& subchannels) -{ - vector<dabSubchannel*>::iterator subchannel; - int index = 0; - - for (subchannel = subchannels.begin(); subchannel != subchannels.end(); - ++subchannel) { - dabProtection* protection = &(*subchannel)->protection; - etiLog.printHeader(TcpLog::INFO, "Subchannel %i\n", index); - etiLog.printHeader(TcpLog::INFO, " input\n"); - etiLog.printHeader(TcpLog::INFO, " protocol: %s\n", - (*subchannel)->inputProto); - etiLog.printHeader(TcpLog::INFO, " name: %s\n", - (*subchannel)->inputName); - etiLog.printHeader(TcpLog::INFO, " type: "); - switch ((*subchannel)->type) { - case 0: - etiLog.printHeader(TcpLog::INFO, "audio\n"); - break; - case 1: - etiLog.printHeader(TcpLog::INFO, "data\n"); - break; - case 2: - etiLog.printHeader(TcpLog::INFO, "fidc\n"); - break; - case 3: - etiLog.printHeader(TcpLog::INFO, "packet\n"); - break; - default: - etiLog.printHeader(TcpLog::INFO, "Unknown data type " - "(service->type)\n"); - break; - } - etiLog.printHeader(TcpLog::INFO, " id: %i\n", - (*subchannel)->id); - etiLog.printHeader(TcpLog::INFO, " bitrate: %i\n", - (*subchannel)->bitrate); - etiLog.printHeader(TcpLog::INFO, " protection: "); - if (protection->form == 0) { - etiLog.printHeader(TcpLog::INFO, "UEP %i\n", protection->level + 1); - } else { - etiLog.printHeader(TcpLog::INFO, "EEP %i-%c\n", - protection->level + 1, - protection->longForm.option == 0 ? 'A' : 'B'); - } - if (protection->form == 0) { - etiLog.printHeader(TcpLog::INFO, - " form: short\n switch: %i\n index: %i\n", - protection->shortForm.tableSwitch, - protection->shortForm.tableIndex); - } else { - etiLog.printHeader(TcpLog::INFO, - " form: long\n option: %i\n level: %i\n", - protection->longForm.option, - (*subchannel)->protection.level); - } - etiLog.printHeader(TcpLog::INFO, " SAD: %i\n", - (*subchannel)->startAddress); - etiLog.printHeader(TcpLog::INFO, " size (CU): %i\n", - getSizeCu(*subchannel)); - ++index; - } -} - - -void printComponent(dabComponent* component) -{ - char label[17]; - memcpy(label, component->label.text, 16); - label[16] = 0; - if (label[0] == 0) { - sprintf(label, "<none>"); - } - - etiLog.printHeader(TcpLog::INFO, " service id: %i\n", - component->serviceId); - etiLog.printHeader(TcpLog::INFO, " subchannel id: %i\n", - component->subchId); - etiLog.printHeader(TcpLog::INFO, " label: %s\n", - label); - etiLog.printHeader(TcpLog::INFO, " short label: "); - for (int i = 0; i < 32; ++i) { - if (component->label.flag & 0x8000 >> i) { - etiLog.printHeader(TcpLog::INFO, "%c", component->label.text[i]); - } - } - etiLog.printHeader(TcpLog::INFO, " (0x%x)\n", component->label.flag); - etiLog.printHeader(TcpLog::INFO, " service component type: 0x%x (%u)\n", - component->type, component->type); - etiLog.printHeader(TcpLog::INFO, " (packet) id: %u\n", - component->packet.id); - etiLog.printHeader(TcpLog::INFO, " (packet) address: %u\n", - component->packet.address); - etiLog.printHeader(TcpLog::INFO, " (packet) app type: %u\n", - component->packet.appType); - etiLog.printHeader(TcpLog::INFO, " (packet) datagroup: %u\n", - component->packet.datagroup); -} - - -void printComponents(vector<dabComponent*>& components) -{ - vector<dabComponent*>::const_iterator current; - unsigned int index = 0; - - for (current = components.begin(); current != components.end(); ++current) { - etiLog.printHeader(TcpLog::INFO, "Component %i\n", index); - printComponent(*current); - ++index; - } -} - - -void printServices(vector<dabService*>& services) -{ - vector<dabService*>::const_iterator current; - int index = 0; - - for (current = services.begin(); current != services.end(); ++current) { - char label[17]; - memcpy(label, (*current)->label.text, 16); - label[16] = 0; - - etiLog.printHeader(TcpLog::INFO, "Service %i\n", index); - etiLog.printHeader(TcpLog::INFO, " label: %s\n", label); - etiLog.printHeader(TcpLog::INFO, " short label: "); - for (int i = 0; i < 32; ++i) { - if ((*current)->label.flag & 0x8000 >> i) { - etiLog.printHeader(TcpLog::INFO, "%c", (*current)->label.text[i]); - } - } - etiLog.printHeader(TcpLog::INFO, " (0x%x)\n", (*current)->label.flag); - etiLog.printHeader(TcpLog::INFO, " id: 0x%lx (%lu)\n", - (*current)->id, (*current)->id); - etiLog.printHeader(TcpLog::INFO, " pty: 0x%x (%u)\n", - (*current)->pty, (*current)->pty); - etiLog.printHeader(TcpLog::INFO, " language: 0x%x (%u)\n", - (*current)->language, (*current)->language); - ++index; - } -} - - -void printOutputs(vector<dabOutput*>& outputs) -{ - vector<dabOutput*>::const_iterator output; - int index = 0; - - for (output = outputs.begin(); output != outputs.end(); ++output) { - etiLog.printHeader(TcpLog::INFO, "Output %i\n", index); - etiLog.printHeader(TcpLog::INFO, " protocol: %s\n", - (*output)->outputProto); - etiLog.printHeader(TcpLog::INFO, " name: %s\n", - (*output)->outputName); - ++index; - } -} - - int main(int argc, char *argv[]) { - etiLog.printHeader(TcpLog::INFO, - "Welcome to %s %s, compiled at %s, %s\n\n", - PACKAGE_NAME, PACKAGE_VERSION, __DATE__, __TIME__); - etiLog.printHeader(TcpLog::INFO, - "Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011\n" - "Her Majesty the Queen in Right of Canada,\n" - "(Communications Research Centre Canada) All rights reserved.\n\n"); - etiLog.printHeader(TcpLog::INFO, "Input URLs supported:"); -#if defined(HAVE_INPUT_PRBS) - etiLog.printHeader(TcpLog::INFO, " prbs"); -#endif -#if defined(HAVE_INPUT_TEST) - etiLog.printHeader(TcpLog::INFO, " test"); -#endif -#if defined(HAVE_INPUT_SLIP) - etiLog.printHeader(TcpLog::INFO, " slip"); -#endif -#if defined(HAVE_INPUT_UDP) - etiLog.printHeader(TcpLog::INFO, " udp"); -#endif -#if defined(HAVE_INPUT_FIFO) - etiLog.printHeader(TcpLog::INFO, " fifo"); -#endif -#if defined(HAVE_INPUT_FILE) - etiLog.printHeader(TcpLog::INFO, " file"); -#endif - etiLog.printHeader(TcpLog::INFO, "\n"); - etiLog.printHeader(TcpLog::INFO, "Inputs format supported:"); -#if defined(HAVE_FORMAT_RAW) - etiLog.printHeader(TcpLog::INFO, " raw"); -#endif -#if defined(HAVE_FORMAT_BRIDGE) - etiLog.printHeader(TcpLog::INFO, " bridge"); -#endif -#if defined(HAVE_FORMAT_MPEG) - etiLog.printHeader(TcpLog::INFO, " mpeg"); -#endif -#if defined(HAVE_FORMAT_PACKET) - etiLog.printHeader(TcpLog::INFO, " packet"); -#endif -#if defined(HAVE_FORMAT_DMB) - etiLog.printHeader(TcpLog::INFO, " dmb"); -#endif -#if defined(HAVE_FORMAT_EPM) - etiLog.printHeader(TcpLog::INFO, " epm"); -#endif - etiLog.printHeader(TcpLog::INFO, "\n"); - - etiLog.printHeader(TcpLog::INFO, "Output URLs supported:"); -#if defined(HAVE_OUTPUT_FILE) - etiLog.printHeader(TcpLog::INFO, " file"); -#endif -#if defined(HAVE_OUTPUT_FIFO) - etiLog.printHeader(TcpLog::INFO, " fifo"); -#endif -#if defined(HAVE_OUTPUT_UDP) - etiLog.printHeader(TcpLog::INFO, " udp"); -#endif -#if defined(HAVE_OUTPUT_TCP) - etiLog.printHeader(TcpLog::INFO, " tcp"); -#endif -#if defined(HAVE_OUTPUT_RAW) - etiLog.printHeader(TcpLog::INFO, " raw"); -#endif -#if defined(HAVE_OUTPUT_SIMUL) - etiLog.printHeader(TcpLog::INFO, " simul"); -#endif - etiLog.printHeader(TcpLog::INFO, "\n\n"); + header_message(); /* for (int signum = 1; signum < 16; ++signum) { signal(signum, signalHandler); @@ -1389,778 +320,46 @@ int main(int argc, char *argv[]) bool MNSC_increment_time = false; - char* progName = strrchr(argv[0], '/'); - if (progName == NULL) { - progName = argv[0]; - } else { - ++progName; - } - - - while (1) { - int c = getopt(argc, argv, - "A:B:CD:E:F:L:M:O:P:STVa:b:c:de:f:g:hi:kl:m:n:op:rst:y:z"); - if (c == -1) { - break; - } - switch (c) { - case 'O': - outputs.push_back(new dabOutput); - output = outputs.end() - 1; - - memset(*output, 0, sizeof(dabOutput)); - (*output)->outputProto = NULL; - (*output)->outputName = NULL; - (*output)->data = NULL; - (*output)->operations = dabOutputDefaultOperations; - - char* proto; - - proto = strstr(optarg, "://"); - if (proto == NULL) { - etiLog.printHeader(TcpLog::ERR, - "No protocol defined for output\n"); - returnCode = -1; - goto EXIT; - } else { - (*output)->outputProto = optarg; - (*output)->outputName = proto + 3; - *proto = 0; - } - subchannel = ensemble->subchannels.end(); - protection = NULL; - component = ensemble->components.end(); - service = ensemble->services.end(); - break; - case 'S': - ensemble->services.push_back(new dabService); - - subchannel = ensemble->subchannels.end(); - protection = NULL; - component = ensemble->components.end(); - service = ensemble->services.end() - 1; - output = outputs.end(); - - memset((*service)->label.text, 0, 16); - sprintf((*service)->label.text, "CRC-Service%i", - (int)ensemble->services.size()); - (*service)->label.flag = 0xe01f; - (*service)->id = DEFAULT_SERVICE_ID + ensemble->services.size(); - (*service)->pty = 0; - (*service)->language = 0; - currentFrame = 0; // Will be used temporaly for SCIdS - - break; - case 'C': - if (service == ensemble->services.end()) { - etiLog.printHeader(TcpLog::ERR, "You must define a service" - " before using option -%c\n", c); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - - ensemble->components.push_back(new dabComponent); - - component = ensemble->components.end() - 1; - subchannel = ensemble->subchannels.end(); - protection = NULL; - output = outputs.end(); + /* TODO Okay, this is clearly not the nicest way to handle the two + * ways of defining the ensemble, but it works. + */ + if (strncmp(basename(argv[0]), "CRC-DabMux-cfg", 16) == 0) { + try { - memset(*component, 0, sizeof(dabComponent)); - memset((*component)->label.text, 0, 16); - (*component)->label.flag = 0xffff; - (*component)->serviceId = (*service)->id; - (*component)->subchId = (*(ensemble->subchannels.end() - 1))->id; - (*component)->SCIdS = currentFrame++; - break; - case 'A': - case 'B': - case 'D': - case 'E': - case 'F': - case 'M': - case 'P': - case 'T': - if (optarg == NULL && c != 'T') { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -%c\n", c); - printUsage(progName); - returnCode = -1; + if (argc != 2) { + printUsageConfigfile(argv[0]); goto EXIT; } - ensemble->subchannels.push_back(new dabSubchannel); - - subchannel = ensemble->subchannels.end() - 1; - protection = &(*subchannel)->protection; - component = ensemble->components.end(); - service = ensemble->services.end(); - output = outputs.end(); - - if (c != 'T') { - (*subchannel)->inputName = optarg; - } else { - (*subchannel)->inputName = NULL; - } - if (0) { -#if defined(HAVE_INPUT_FILE) && defined(HAVE_FORMAT_MPEG) - } else if (c == 'A') { - (*subchannel)->inputProto = "file"; - (*subchannel)->type = 0; - (*subchannel)->bitrate = 0; - (*subchannel)->operations = dabInputMpegFileOperations; -#endif // defined(HAVE_INPUT_FILE) && defined(HAVE_FORMAT_MPEG) -#if defined(HAVE_FORMAT_DABPLUS) - } else if (c == 'F') { - (*subchannel)->type = 0; - (*subchannel)->bitrate = 32; - - char* proto; - - proto = strstr(optarg, "://"); - if (proto == NULL) { - (*subchannel)->inputProto = "file"; - } else { - (*subchannel)->inputProto = optarg; - (*subchannel)->inputName = proto + 3; - *proto = 0; - } - - if (0) { -#if defined(HAVE_INPUT_FILE) - } else if (strcmp((*subchannel)->inputProto, "file") == 0) { - (*subchannel)->operations = dabInputDabplusFileOperations; -#endif // defined(HAVE_INPUT_FILE) - } else { - etiLog.printHeader(TcpLog::ERR, - "Invalid protocol for DAB+ input (%s)\n", - (*subchannel)->inputProto); - printUsage(progName); - returnCode = -1; - goto EXIT; - } -#endif // defined(HAVE_FORMAT_DABPLUS) - } else if (c == 'B') { - char* proto; - - proto = strstr(optarg, "://"); - if (proto == NULL) { - (*subchannel)->inputProto = "udp"; - } else { - (*subchannel)->inputProto = optarg; - (*subchannel)->inputName = proto + 3; - *proto = 0; - } - if (0) { -#if defined(HAVE_FORMAT_BRIDGE) -#if defined(HAVE_INPUT_UDP) - } else if (strcmp((*subchannel)->inputProto, "udp") == 0) { - (*subchannel)->operations = dabInputBridgeUdpOperations; -#endif // defined(HAVE_INPUT_UDP) -#if defined(HAVE_INPUT_SLIP) - } else if (strcmp((*subchannel)->inputProto, "slip") == 0) { - (*subchannel)->operations = dabInputSlipOperations; -#endif // defined(HAVE_INPUT_SLIP) -#endif // defined(HAVE_FORMAT_BRIDGE) - } - } else if (c == 'D') { - char* proto; - - proto = strstr(optarg, "://"); - if (proto == NULL) { - (*subchannel)->inputProto = "udp"; - } else { - (*subchannel)->inputProto = optarg; - (*subchannel)->inputName = proto + 3; - *proto = 0; - } - if (0) { -#if defined(HAVE_INPUT_UDP) - } else if (strcmp((*subchannel)->inputProto, "udp") == 0) { - (*subchannel)->operations = dabInputUdpOperations; -#endif -#if defined(HAVE_INPUT_PRBS) && defined(HAVE_FORMAT_RAW) - } else if (strcmp((*subchannel)->inputProto, "prbs") == 0) { - (*subchannel)->operations = dabInputPrbsOperations; -#endif -#if defined(HAVE_INPUT_FILE) && defined(HAVE_FORMAT_RAW) - } else if (strcmp((*subchannel)->inputProto, "file") == 0) { - (*subchannel)->operations = dabInputRawFileOperations; -#endif - } else if (strcmp((*subchannel)->inputProto, "fifo") == 0) { - (*subchannel)->operations = dabInputRawFifoOperations; - } else { - etiLog.printHeader(TcpLog::ERR, - "Invalid protocol for data input (%s)\n", - (*subchannel)->inputProto); - printUsage(progName); - returnCode = -1; - goto EXIT; - } + string conf_file = argv[1]; - (*subchannel)->type = 1; - (*subchannel)->bitrate = DEFAULT_DATA_BITRATE; -#if defined(HAVE_INPUT_TEST) && defined(HAVE_FORMAT_RAW) - } else if (c == 'T') { - (*subchannel)->inputProto = "test"; - (*subchannel)->type = 1; - (*subchannel)->bitrate = DEFAULT_DATA_BITRATE; - (*subchannel)->operations = dabInputTestOperations; -#endif // defined(HAVE_INPUT_TEST)) && defined(HAVE_FORMAT_RAW) -#ifdef HAVE_FORMAT_PACKET - } else if (c == 'P') { - (*subchannel)->inputProto = "file"; - (*subchannel)->type = 3; - (*subchannel)->bitrate = DEFAULT_PACKET_BITRATE; -#ifdef HAVE_INPUT_FILE - (*subchannel)->operations = dabInputPacketFileOperations; -#elif defined(HAVE_INPUT_FIFO) - (*subchannel)->operations = dabInputFifoOperations; -#else -# pragma error("Must defined at least one packet input") -#endif // defined(HAVE_INPUT_FILE) -#ifdef HAVE_FORMAT_EPM - } else if (c == 'E') { - (*subchannel)->inputProto = "file"; - (*subchannel)->type = 3; - (*subchannel)->bitrate = DEFAULT_PACKET_BITRATE; - (*subchannel)->operations = dabInputEnhancedPacketFileOperations; -#endif // defined(HAVE_FORMAT_EPM) -#endif // defined(HAVE_FORMAT_PACKET) -#ifdef HAVE_FORMAT_DMB - } else if (c == 'M') { - char* proto; - - proto = strstr(optarg, "://"); - if (proto == NULL) { - (*subchannel)->inputProto = "udp"; - } else { - (*subchannel)->inputProto = optarg; - (*subchannel)->inputName = proto + 3; - *proto = 0; - } - if (strcmp((*subchannel)->inputProto, "udp") == 0) { - (*subchannel)->operations = dabInputDmbUdpOperations; - } else if (strcmp((*subchannel)->inputProto, "file") == 0) { - (*subchannel)->operations = dabInputDmbFileOperations; - } else { - etiLog.printHeader(TcpLog::ERR, - "Invalid protocol for DMB input (%s)\n", - (*subchannel)->inputProto); - printUsage(progName); - returnCode = -1; - goto EXIT; - } + parse_configfile(conf_file, outputs, ensemble, &enableTist, &FICL, + &factumAnalyzer, &limit); - (*subchannel)->type = 1; - (*subchannel)->bitrate = DEFAULT_DATA_BITRATE; -#endif - } else { - etiLog.printHeader(TcpLog::ERR, - "Service '%c' not yet coded!\n", c); - returnCode = -1; - goto EXIT; - } - (*subchannel)->operations.init(&(*subchannel)->data); - for (int i = 0; i < 64; ++i) { // Find first free subchannel - subchannel = getSubchannel(ensemble->subchannels, i); - if (subchannel == ensemble->subchannels.end()) { - subchannel = ensemble->subchannels.end() - 1; - (*subchannel)->id = i; - break; - } - } - (*subchannel)->startAddress = 0; + printSubchannels(ensemble->subchannels); + cerr << endl; + printServices(ensemble->services); + cerr << endl; + printComponents(ensemble->components); + cerr << endl; + printOutputs(outputs); - if (c == 'A') { - protection->form = 0; - protection->level = 2; - protection->shortForm.tableSwitch = 0; - protection->shortForm.tableIndex = 0; - } else { - protection->level = 2; - protection->form = 1; - protection->longForm.option = 0; - } - break; - case 'L': - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -L\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (service == ensemble->services.end()) { - memset(ensemble->label.text, 0, 16); - strncpy(ensemble->label.text, optarg, 16); - ensemble->label.flag = 0xff00; - } else if (component != ensemble->components.end()) { - memset((*component)->label.text, 0, 16); - strncpy((*component)->label.text, optarg, 16); - (*component)->label.flag = 0xff00; - } else { // Service - memset((*service)->label.text, 0, 16); - strncpy((*service)->label.text, optarg, 16); - (*service)->label.flag = 0xff00; - } - // TODO Check strlen before doing short label - // TODO Check if short label already set - break; - case 'V': - goto EXIT; - case 'l': - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -l\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (service == ensemble->services.end()) { - char* end; - ensemble->label.flag = strtoul(optarg, &end, 0); - if (*end != 0) { - end = optarg; - ensemble->label.flag = 0; - for (int i = 0; i < 32; ++i) { - if (*end == ensemble->label.text[i]) { - ensemble->label.flag |= 0x8000 >> i; - if (*(++end) == 0) { - break; - } - } - } - if (*end != 0) { - etiLog.printHeader(TcpLog::ERR, - "Error at '%c' in ensemble short label '%s'!\n" - "Not in label '%s'!\n", - *end, optarg, ensemble->label.text); - returnCode = -1; - goto EXIT; - } - } - int count = 0; - for (int i = 0; i < 16; ++i) { - if (ensemble->label.flag & (1 << i)) { - ++count; - } - } - if (count > 8) { - etiLog.printHeader(TcpLog::ERR, - "Ensemble short label too long!\n" - "Must be < 8 characters.\n"); - returnCode = -1; - goto EXIT; - } - } else if (component != ensemble->components.end()) { - char* end; - (*component)->label.flag = strtoul(optarg, &end, 0); - if (*end != 0) { - end = optarg; - (*component)->label.flag = 0; - for (int i = 0; i < 32; ++i) { - if (*end == (*component)->label.text[i]) { - (*component)->label.flag |= 0x8000 >> i; - if (*(++end) == 0) { - break; - } - } - } - if (*end != 0) { - etiLog.printHeader(TcpLog::ERR, - "Error at '%c' in component short label '%s'!\n" - "Not in label '%s'!\n", - *end, optarg, (*component)->label.text); - returnCode = -1; - goto EXIT; - } - } - int count = 0; - for (int i = 0; i < 16; ++i) { - if ((*component)->label.flag & (1 << i)) { - ++count; - } - } - if (count > 8) { - etiLog.printHeader(TcpLog::ERR, - "Service '%s' short label too long!\n" - "Must be < 8 characters.\n", (*component)->label.text); - returnCode = -1; - goto EXIT; - } - } else { - char* end; - (*service)->label.flag = strtoul(optarg, &end, 0); - if (*end != 0) { - end = optarg; - (*service)->label.flag = 0; - for (int i = 0; i < 32; ++i) { - if (*end == (*service)->label.text[i]) { - (*service)->label.flag |= 0x8000 >> i; - if (*(++end) == 0) { - break; - } - } - } - if (*end != 0) { - etiLog.printHeader(TcpLog::ERR, - "Error at '%c' in service short label '%s'!\n" - "Not in label '%s'!\n", - *end, optarg, (*service)->label.text); - returnCode = -1; - goto EXIT; - } - } - int count = 0; - for (int i = 0; i < 16; ++i) { - if ((*service)->label.flag & (1 << i)) { - ++count; - } - } - if (count > 8) { - etiLog.printHeader(TcpLog::ERR, - "Service '%s' short label too long!\n" - "Must be < 8 characters.\n", (*service)->label.text); - returnCode = -1; - goto EXIT; - } - } - break; - case 'i': - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -i\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (component != ensemble->components.end()) { - (*component)->subchId = strtoul(optarg, NULL, 0); - } else if (subchannel != ensemble->subchannels.end()) { - (*subchannel)->id = strtoul(optarg, NULL, 0); - } else if (service != ensemble->services.end()) { - (*service)->id = strtoul(optarg, NULL, 0); - if ((*service)->id == 0) { - etiLog.printHeader(TcpLog::ERR, - "Service id 0 is invalid\n"); - returnCode = -1; - goto EXIT; - } - } else { - ensemble->id = strtoul(optarg, NULL, 0); - } - break; - case 'b': - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -b\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (subchannel == ensemble->subchannels.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a subchannel first!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*subchannel)->bitrate = strtoul(optarg, NULL, 0); - if (((*subchannel)->bitrate & 0x7) != 0) { - (*subchannel)->bitrate += 8; - (*subchannel)->bitrate &= ~0x7; - etiLog.printHeader(TcpLog::WARNING, - "bitrate must be multiple of 8 -> ceiling to %i\n", - (*subchannel)->bitrate); - } - break; - case 'c': - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -c\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - ensemble->ecc = strtoul(optarg, NULL, 0); - break; -#if defined(HAVE_INPUT_FIFO) && defined(HAVE_INPUT_FILE) - case 'k': - if (subchannel == ensemble->subchannels.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a subchannel first!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - switch ((*subchannel)->type) { -#ifdef HAVE_FORMAT_PACKET - case 3: - (*subchannel)->operations.clean(&(*subchannel)->data); - if ((*subchannel)->operations == dabInputPacketFileOperations) { - (*subchannel)->operations = dabInputFifoOperations; -#ifdef HAVE_FORMAT_EPM - } else if ((*subchannel)->operations == dabInputEnhancedPacketFileOperations) { - (*subchannel)->operations = dabInputEnhancedFifoOperations; -#endif // defined(HAVE_FORMAT_EPM) - } else { - etiLog.printHeader(TcpLog::ERR, - "Error, wrong packet subchannel operations!\n"); - returnCode = -1; - goto EXIT; - } - (*subchannel)->operations.init(&(*subchannel)->data); - (*subchannel)->inputProto = "fifo"; - break; -#endif // defined(HAVE_FORMAT_PACKET) -#ifdef HAVE_FORMAT_MPEG - case 0: - (*subchannel)->operations.clean(&(*subchannel)->data); - if ((*subchannel)->operations == dabInputMpegFileOperations) { - (*subchannel)->operations = dabInputMpegFifoOperations; - } else if ((*subchannel)->operations == - dabInputDabplusFileOperations) { - (*subchannel)->operations = dabInputDabplusFifoOperations; - } else { - etiLog.printHeader(TcpLog::ERR, - "Error, wrong audio subchannel operations!\n"); - returnCode = -1; - goto EXIT; - } - (*subchannel)->operations.init(&(*subchannel)->data); - (*subchannel)->inputProto = "fifo"; - break; -#endif // defined(HAVE_FORMAT_MPEG) - default: - etiLog.printHeader(TcpLog::ERR, - "sorry, non-blocking input file is " - "only valid with audio or packet services\n"); - returnCode = -1; - goto EXIT; - } - break; -#endif // defined(HAVE_INPUT_FIFO) && defined(HAVE_INPUT_FILE) - case 'p': - int level; - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -P\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (subchannel == ensemble->subchannels.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a subchannel first!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - level = strtoul(optarg, NULL, 0) - 1; - if (protection->form == 0) { - if ((level < 0) || (level > 4)) { - etiLog.printHeader(TcpLog::ERR, - "protection level must be between " - "1 to 5 inclusively (current = %i)\n", level); - returnCode = -1; - goto EXIT; - } - } else { - if ((level < 0) || (level > 3)) { - etiLog.printHeader(TcpLog::ERR, - "protection level must be between " - "1 to 4 inclusively (current = %i)\n", level); - returnCode = -1; - goto EXIT; - } - } - protection->level = level; - break; - case 'm': - if (optarg) { - ensemble->mode = strtoul(optarg, NULL, 0); - if ((ensemble->mode < 1) || (ensemble->mode > 4)) { - etiLog.printHeader(TcpLog::ERR, - "Mode must be between 1-4\n"); - returnCode = -1; - goto EXIT; - } - if (ensemble->mode == 4) - ensemble->mode = 0; - if (ensemble->mode == 3) { - FICL = 32; - } else { - FICL = 24; - } - } else { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -m\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - break; - case 'n': - if (optarg) { - limit = strtoul(optarg, NULL, 0); - } else { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -n\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - break; - case 'o': - etiLog.open("createETI", 0, 12222); - break; - case 't': - if (optarg == NULL) { - etiLog.printHeader(TcpLog::ERR, - "Missing parameter for option -t\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (component == ensemble->components.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a component before setting " - "service type!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*component)->type = strtoul(optarg, NULL, 0); - break; - case 'a': - if (component == ensemble->components.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a component before setting " - "packet address!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (!(*component)->isPacketComponent(ensemble->subchannels)) { - etiLog.printHeader(TcpLog::ERR, "address\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*component)->packet.address = strtoul(optarg, NULL, 0); - break; - case 'd': - if (component == ensemble->components.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a component before setting " - "datagroup!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (!(*component)->isPacketComponent(ensemble->subchannels)) { - etiLog.printHeader(TcpLog::ERR, "datagroup\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*component)->packet.datagroup = true; - break; - case 'f': - if (component == ensemble->components.end()) { - etiLog.printHeader(TcpLog::ERR, - "You must define a component first!\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - if (!(*component)->isPacketComponent(ensemble->subchannels)) { - etiLog.printHeader(TcpLog::ERR, "application type\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*component)->packet.appType = strtoul(optarg, NULL, 0); - break; - case 'g': - if (service == ensemble->services.end()) { - etiLog.printHeader(TcpLog::ERR, "You must define a service" - " before using option -%c\n", c); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*service)->language = strtoul(optarg, NULL, 0); - break; - case 's': - { - /* - struct timeval tv; - gettimeofday(&tv, NULL); - unsigned _8ms = (tv.tv_usec / 1000) / 8; - unsigned _1ms = (tv.tv_usec - (_8ms * 8000)) / 1000; - unsigned _4us = 20; - unsigned _488ns = 0; - unsigned _61ns = 0; - timestamp = (((((((_8ms << 3) | _1ms) << 8) | _4us) << 3) | _488ns) << 8) | _61ns; - */ - enableTist = true; - } - break; - case 'y': - if (service == ensemble->services.end()) { - etiLog.printHeader(TcpLog::ERR, "You must define a service" - " before using option -%c\n", c); - printUsage(progName); - returnCode = -1; - goto EXIT; - } - (*service)->pty = strtoul(optarg, NULL, 0); - break; - case 'z': - factumAnalyzer = true; - break; - case 'r': - etiLog.printHeader(TcpLog::INFO, - "Enabling throttled output using simul, one frame every 24ms\n"); - outputs.push_back(new dabOutput); - output = outputs.end() - 1; - - memset(*output, 0, sizeof(dabOutput)); - (*output)->outputProto = "simul"; - (*output)->outputName = ""; - (*output)->data = NULL; - (*output)->operations = dabOutputDefaultOperations; - - subchannel = ensemble->subchannels.end(); - protection = NULL; - component = ensemble->components.end(); - service = ensemble->services.end(); - break; - case '?': - returnCode = -1; - case 'h': - printUsage(progName, stdout); - goto EXIT; - default: - etiLog.printHeader(TcpLog::ERR, "Option '%c' not coded yet\n", c); - returnCode = -1; + } + catch (runtime_error &e) { + etiLog.printHeader(TcpLog::ERR, "Configuration file parsing error: %s\n", + e.what()); goto EXIT; } } - if (optind < argc) { - etiLog.printHeader(TcpLog::ERR, "Too much parameters:"); - while (optind < argc) { - etiLog.printHeader(TcpLog::ERR, " %s", argv[optind++]); + else { + if (!parse_cmdline(argv, argc, outputs, ensemble, &enableTist, &FICL, + &factumAnalyzer, &limit)) { + goto EXIT; } - etiLog.printHeader(TcpLog::ERR, "\n"); - printUsage(progName); - returnCode = -1; - goto EXIT; } + + if (outputs.size() == 0) { etiLog.printHeader(TcpLog::WARNING, "no output defined\n"); @@ -2211,7 +410,8 @@ int main(int argc, char *argv[]) component = getComponent(ensemble->components, (*service)->id); if (component == ensemble->components.end()) { etiLog.printHeader(TcpLog::ERR, - "Service %u includes no component!\n"); + "Service id 0x%x (%u) includes no component!\n", + (*service)->id, (*service)->id); returnCode = -1; goto EXIT; } |