Created
June 27, 2014 13:00
-
-
Save wrl/2faeb4b5889fc718321b to your computer and use it in GitHub Desktop.
edcast with better float -> int conversion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define HAVE_FLAC TRUE | |
/* it doesn't detect I got flac atleast on my system -drr */ | |
#include <math.h> | |
#include <fcntl.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/timeb.h> | |
#include <time.h> | |
#include <stdarg.h> | |
#ifdef HAVE_VORBIS | |
#include <vorbis/vorbisenc.h> | |
#endif | |
#include "libedcast.h" | |
#include "libedcast_socket.h" | |
#ifdef WIN32 | |
#include <bass.h> | |
#else | |
#ifdef HAVE_LAME | |
#include <lame/lame.h> | |
#endif | |
#include <errno.h> | |
#endif | |
#ifdef HAVE_FAAC | |
#include <faac.h> | |
#endif | |
#define GUINT16_TO_LE(val) ((unsigned short) (val)) | |
#define GUINT32_TO_LE(val) ((unsigned int) (val)) | |
#define GUINT16_FROM_LE(val) (GUINT16_TO_LE(val)) | |
#ifdef WIN32 | |
#define FILE_SEPARATOR "\\" | |
#else | |
#define FILE_SEPARATOR "/" | |
typedef struct | |
{ | |
short wFormatTag; | |
short nChannels; | |
long nSamplesPerSec; | |
long nAvgBytesPerSec; | |
short nBlockAlign; | |
short wBitsPerSample; | |
short cbSize; | |
} WAVEFORMATEX; | |
#define WAVE_FORMAT_PCM (0x0001) | |
#define DWORD long | |
#endif | |
long dwDataBlockPos = 0; | |
long TotalWritten = 0; | |
#define MAX_ENCODERS 10 | |
extern edcastGlobals *g[MAX_ENCODERS]; | |
extern edcastGlobals gMain; | |
int buffer_blocksize = 0; | |
#ifdef HAVE_AACP | |
/* | |
======================================================================================================================= | |
uninteresting stuff ; | |
for the input plugin | |
======================================================================================================================= | |
*/ | |
static void SAAdd(void *data, int timestamp, int csa) { | |
} | |
static void VSAAdd(void *data, int timestamp) { | |
} | |
static void SAVSAInit(int maxlatency_in_ms, int srate) { | |
} | |
static void SAVSADeInit() { | |
} | |
static void SAAddPCMData(void *PCMData, int nch, int bps, int timestamp) { | |
} | |
static int SAGetMode() { | |
return 0; | |
} | |
static int VSAGetMode(int *specNch, int *waveNch) { | |
return 0; | |
} | |
static void VSAAddPCMData(void *PCMData, int nch, int bps, int timestamp) { | |
} | |
static void VSASetInfo(int nch, int srate) { | |
} | |
static int dsp_isactive() { | |
return 0; | |
} | |
static int dsp_dosamples(short int *samples, int ns, int bps, int nch, int srate) { | |
return ns; | |
} | |
static void SetInfo(int bitrate0, int srate0, int stereo, int synched) { | |
} | |
#endif | |
typedef struct tagConfigFileValue | |
{ | |
char_t Variable[256]; | |
char_t Value[256]; | |
char_t Description[1024]; | |
} configFileValue; | |
static configFileValue configFileValues[100]; | |
static int numConfigValues = 0; | |
static int greconnectFlag = 0; | |
char_t defaultLogFileName[1024] = "edcast.log"; | |
void setDefaultLogFileName(char_t *filename) { | |
strcpy(defaultLogFileName, filename); | |
} | |
int getReconnectFlag(edcastGlobals *g) { | |
return g->gAutoReconnect; | |
} | |
int getReconnectSecs(edcastGlobals *g) { | |
return g->gReconnectSec; | |
} | |
void addVorbisComment(edcastGlobals *g, char_t *comment) { | |
int commentLen = strlen(comment) + 1; | |
g->vorbisComments[g->numVorbisComments] = (char_t *) calloc(1, commentLen); | |
if (g->vorbisComments[g->numVorbisComments]) { | |
memset(g->vorbisComments[g->numVorbisComments], '\000', commentLen); | |
strcpy(g->vorbisComments[g->numVorbisComments], comment); | |
g->numVorbisComments++; | |
} | |
} | |
void freeVorbisComments(edcastGlobals *g) { | |
for(int i = 0; i < g->numVorbisComments; i++) { | |
if(g->vorbisComments[i]) { | |
free(g->vorbisComments[i]); | |
g->vorbisComments[i] = NULL; | |
} | |
} | |
g->numVorbisComments = 0; | |
} | |
void addConfigVariable(edcastGlobals *g, char_t *variable) { | |
g->configVariables[g->numConfigVariables] = strdup(variable); | |
g->numConfigVariables++; | |
} | |
long getWritten(edcastGlobals *g) { | |
return g->written; | |
} | |
void setWritten(edcastGlobals *g, long writ) { | |
g->written = writ; | |
} | |
void setAutoConnect(edcastGlobals *g, int flag) { | |
g->autoconnect = flag; | |
} | |
FILE *getSaveFileP(edcastGlobals *g) { | |
return g->gSaveFile; | |
} | |
int getLiveRecordingSetFlag(edcastGlobals *g) { | |
return g->gLiveRecordingFlag; | |
} | |
bool getLiveRecordingFlag(edcastGlobals *g) { | |
return g->areLiveRecording; | |
} | |
void setLiveRecordingFlag(edcastGlobals *g, bool flag) { | |
g->areLiveRecording = flag; | |
} | |
int getLiveInSamplerate(edcastGlobals *g) { | |
return g->gLiveInSamplerate; | |
} | |
void setLiveInSamplerate(edcastGlobals *g, int rate) { | |
g->gLiveInSamplerate = rate; | |
} | |
int getOggFlag(edcastGlobals *g) { | |
return g->gOggFlag; | |
} | |
char_t *getServerDesc(edcastGlobals *g) { | |
return g->gServDesc; | |
} | |
char_t *getSourceURL(edcastGlobals *g) { | |
return g->gSourceURL; | |
} | |
void setSourceURL(edcastGlobals *g, char_t *url) { | |
strcpy(g->gSourceURL, url); | |
} | |
int getIsConnected(edcastGlobals *g) { | |
return g->weareconnected; | |
} | |
long getCurrentSamplerate(edcastGlobals *g) { | |
return g->currentSamplerate; | |
} | |
int getCurrentBitrate(edcastGlobals *g) { | |
return g->currentBitrate; | |
} | |
int getCurrentChannels(edcastGlobals *g) { | |
return g->currentChannels; | |
} | |
void setSourceDescription(edcastGlobals *g, char_t *desc) { | |
strcpy(g->sourceDescription, desc); | |
} | |
long getVUShow(edcastGlobals *g) { | |
return g->vuShow; | |
} | |
void setVUShow(edcastGlobals *g, long x) { | |
g->vuShow = x; | |
} | |
long getLastXWindow(edcastGlobals *g) { | |
return g->lastX; | |
} | |
long getLastYWindow(edcastGlobals *g) { | |
return g->lastY; | |
} | |
void setLastXWindow(edcastGlobals *g, long x) { | |
g->lastX = x; | |
} | |
void setLastYWindow(edcastGlobals *g, long y) { | |
g->lastY = y; | |
} | |
long getLastDummyXWindow(edcastGlobals *g) { | |
return g->lastDummyX; | |
} | |
long getLastDummyYWindow(edcastGlobals *g) { | |
return g->lastDummyY; | |
} | |
void setLastDummyXWindow(edcastGlobals *g, long x) { | |
g->lastDummyX = x; | |
} | |
void setLastDummyYWindow(edcastGlobals *g, long y) { | |
g->lastDummyY = y; | |
} | |
int getSaveAsWAV(edcastGlobals *g) { | |
return g->gSaveAsWAV; | |
} | |
void setSaveAsWAV(edcastGlobals *g, int flag) { | |
g->gSaveAsWAV = flag; | |
} | |
char_t *getCurrentRecordingName(edcastGlobals *g) { | |
return(g->gCurrentRecordingName); | |
} | |
void setCurrentRecordingName(edcastGlobals *g, char_t *name) { | |
strcpy(g->gCurrentRecordingName, name); | |
} | |
int getFrontEndType(edcastGlobals *g) { | |
return(g->frontEndType); | |
} | |
void setFrontEndType(edcastGlobals *g, int x) { | |
g->frontEndType = x; | |
} | |
int getReconnectTrigger(edcastGlobals *g) { | |
return(g->ReconnectTrigger); | |
} | |
void setReconnectTrigger(edcastGlobals *g, int x) { | |
g->ReconnectTrigger = x; | |
} | |
char_t *getLockedMetadata(edcastGlobals *g) { | |
return g->gManualSongTitle; | |
} | |
void setLockedMetadata(edcastGlobals *g, char_t *buf) { | |
memset(g->gManualSongTitle, '\000', sizeof(g->gManualSongTitle)); | |
strncpy(g->gManualSongTitle, buf, sizeof(g->gManualSongTitle) - 1); | |
} | |
int getLockedMetadataFlag(edcastGlobals *g) { | |
return g->gLockSongTitle; | |
} | |
void setLockedMetadataFlag(edcastGlobals *g, int flag) { | |
g->gLockSongTitle = flag; | |
} | |
void setSaveDirectory(edcastGlobals *g, char_t *saveDir) { | |
memset(g->gSaveDirectory, '\000', sizeof(g->gSaveDirectory)); | |
strncpy(g->gSaveDirectory, saveDir, sizeof(g->gSaveDirectory) - 1); | |
} | |
char_t *getSaveDirectory(edcastGlobals *g) { | |
return(g->gSaveDirectory); | |
} | |
void setSaveDirectoryFlag(edcastGlobals *g, int flag) { | |
g->gSaveDirectoryFlag = flag; | |
} | |
int getSaveDirectoryFlag(edcastGlobals *g) { | |
return(g->gSaveDirectoryFlag); | |
} | |
void setgLogFile(edcastGlobals *g, char_t *logFile) { | |
strcpy(g->gLogFile, logFile); | |
} | |
char_t *getgLogFile(edcastGlobals *g) { | |
return(g->gLogFile); | |
} | |
/* Gratuitously ripped from util.c */ | |
static char_t base64table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; | |
static signed char_t base64decode[256] = { -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -1, -2, -2, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2, -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 }; | |
/* | |
======================================================================================================================= | |
This isn't efficient, but it doesn't need to be | |
======================================================================================================================= | |
*/ | |
char_t *util_base64_encode(char_t *data) { | |
int len = strlen(data); | |
char_t *out = (char_t *) malloc(len * 4 / 3 + 4); | |
char_t *result = out; | |
int chunk; | |
while(len > 0) { | |
chunk = (len > 3) ? 3 : len; | |
*out++ = base64table[(*data & 0xFC) >> 2]; | |
*out++ = base64table[((*data & 0x03) << 4) | ((*(data + 1) & 0xF0) >> 4)]; | |
switch(chunk) { | |
case 3: | |
*out++ = base64table[((*(data + 1) & 0x0F) << 2) | ((*(data + 2) & 0xC0) >> 6)]; | |
*out++ = base64table[(*(data + 2)) & 0x3F]; | |
break; | |
case 2: | |
*out++ = base64table[((*(data + 1) & 0x0F) << 2)]; | |
*out++ = '='; | |
break; | |
case 1: | |
*out++ = '='; | |
*out++ = '='; | |
break; | |
} | |
data += chunk; | |
len -= chunk; | |
} | |
*out = 0; | |
return result; | |
} | |
char_t *util_base64_decode(unsigned char_t *input) { | |
int len = strlen((char_t *) input); | |
char_t *out = (char_t *) malloc(len * 3 / 4 + 5); | |
char_t *result = out; | |
signed char_t vals[4]; | |
while(len > 0) { | |
if(len < 4) { | |
free(result); | |
return NULL; /* Invalid Base64 data */ | |
} | |
vals[0] = base64decode[*input++]; | |
vals[1] = base64decode[*input++]; | |
vals[2] = base64decode[*input++]; | |
vals[3] = base64decode[*input++]; | |
if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) { | |
continue; | |
} | |
*out++ = vals[0] << 2 | vals[1] >> 4; | |
if(vals[2] >= 0) | |
*out++ = ((vals[1] & 0x0F) << 4) | (vals[2] >> 2); | |
else | |
*out++ = 0; | |
if(vals[3] >= 0) | |
*out++ = ((vals[2] & 0x03) << 6) | (vals[3]); | |
else | |
*out++ = 0; | |
len -= 4; | |
} | |
*out = 0; | |
return result; | |
} | |
#define HEADER_TYPE 1 | |
#define CODEC_TYPE 2 | |
void closeArchiveFile(edcastGlobals *g) { | |
if(g->gSaveFile) { | |
if(g->gSaveAsWAV) { | |
wav_header.length = GUINT32_TO_LE(g->written + sizeof(struct wavhead) - 8); | |
wav_header.data_length = GUINT32_TO_LE(g->written); | |
fseek(g->gSaveFile, 0, SEEK_SET); | |
fwrite(&wav_header, sizeof(struct wavhead), 1, g->gSaveFile); | |
g->written = 0; | |
} | |
fclose(g->gSaveFile); | |
g->gSaveFile = 0; | |
} | |
} | |
int openArchiveFile(edcastGlobals *g) { | |
char_t outFilename[1024] = ""; | |
char_t outputFile[1024] = ""; | |
struct tm *newtime; | |
time_t aclock; | |
time(&aclock); | |
newtime = localtime(&aclock); | |
sprintf(outFilename, "%s_%s", g->gServDesc, asctime(newtime)); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
ReplaceString(outFilename, outputFile, "\"", "'"); | |
memset(outFilename, '\000', sizeof(outFilename)); | |
ReplaceString(outputFile, outFilename, FILE_SEPARATOR, ""); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
ReplaceString(outFilename, outputFile, "/", ""); | |
memset(outFilename, '\000', sizeof(outFilename)); | |
ReplaceString(outputFile, outFilename, ":", ""); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
ReplaceString(outFilename, outputFile, "*", ""); | |
memset(outFilename, '\000', sizeof(outFilename)); | |
ReplaceString(outputFile, outFilename, "?", ""); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
ReplaceString(outFilename, outputFile, "<", ""); | |
memset(outFilename, '\000', sizeof(outFilename)); | |
ReplaceString(outputFile, outFilename, ">", ""); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
ReplaceString(outFilename, outputFile, "|", ""); | |
memset(outFilename, '\000', sizeof(outFilename)); | |
ReplaceString(outputFile, outFilename, "\n", ""); | |
memset(outputFile, '\000', sizeof(outputFile)); | |
strcpy(outputFile, outFilename); | |
if(g->gSaveAsWAV) { | |
strcat(outputFile, ".wav"); | |
} | |
else { | |
if(g->gOggFlag) { | |
strcat(outputFile, ".ogg"); | |
} | |
if(g->gLAMEFlag) { | |
strcat(outputFile, ".mp3"); | |
} | |
if(g->gAACFlag) { | |
strcat(outputFile, ".aac"); | |
} | |
if(g->gAACPFlag) { | |
strcat(outputFile, ".aac"); | |
} | |
} | |
sprintf(outFilename, "%s%s%s", g->gSaveDirectory, FILE_SEPARATOR, outputFile); | |
g->gSaveFile = fopen(outFilename, "wb"); | |
if(!g->gSaveFile) { | |
char_t buff[1024] = ""; | |
sprintf(buff, "Cannot open %s", outputFile); | |
LogMessage(g,LOG_ERROR, buff); | |
return 0; | |
} | |
if(g->gSaveAsWAV) { | |
int nch = 2; | |
int rate = 44100; | |
memcpy(&wav_header.main_chunk, "RIFF", 4); | |
wav_header.length = GUINT32_TO_LE(0); | |
memcpy(&wav_header.chunk_type, "WAVE", 4); | |
memcpy(&wav_header.sub_chunk, "fmt ", 4); | |
wav_header.sc_len = GUINT32_TO_LE(16); | |
wav_header.format = GUINT16_TO_LE(1); | |
wav_header.modus = GUINT16_TO_LE(nch); | |
wav_header.sample_fq = GUINT32_TO_LE(rate); | |
wav_header.bit_p_spl = GUINT16_TO_LE(16); | |
wav_header.byte_p_sec = GUINT32_TO_LE(rate * wav_header.modus * (GUINT16_FROM_LE(wav_header.bit_p_spl) / 8)); | |
wav_header.byte_p_spl = GUINT16_TO_LE((GUINT16_FROM_LE(wav_header.bit_p_spl) / (8 / nch))); | |
memcpy(&wav_header.data_chunk, "data", 4); | |
wav_header.data_length = GUINT32_TO_LE(0); | |
fwrite(&wav_header, sizeof(struct wavhead), 1, g->gSaveFile); | |
} | |
return 1; | |
} | |
int sendToServer(edcastGlobals *g, int sd, char_t *data, int length, int type) { | |
int ret = 0; | |
int sendflags = 0; | |
if(g->gSaveDirectoryFlag) { | |
if(!g->gSaveFile) { | |
openArchiveFile(g); | |
} | |
} | |
#if !defined(WIN32) && !defined(__FreeBSD__) | |
sendflags = MSG_NOSIGNAL; | |
#endif | |
switch(type) { | |
case HEADER_TYPE: | |
ret = send(sd, data, length, sendflags); | |
break; | |
case CODEC_TYPE: | |
ret = send(sd, data, length, sendflags); | |
if(g->gSaveDirectoryFlag) { | |
if(g->gSaveFile) { | |
if(!g->gSaveAsWAV) { | |
fwrite(data, length, 1, g->gSaveFile); | |
} | |
} | |
} | |
break; | |
} | |
if(ret > 0) { | |
if(g->writeBytesCallback) { | |
g->writeBytesCallback((void *) g, (void *) ret); | |
} | |
} | |
return ret; | |
} | |
int readConfigFile(edcastGlobals *g, int readOnly) { | |
FILE *filep; | |
char_t buffer[1024]; | |
char_t configFile[1024] = ""; | |
char_t defaultConfigName[] = "edcast"; | |
numConfigValues = 0; | |
memset(&configFileValues, '\000', sizeof(configFileValues)); | |
if(readOnly) { | |
sprintf(configFile, "%s", g->gConfigFileName); | |
} | |
else { | |
if(strlen(g->gConfigFileName) == 0) { | |
sprintf(configFile, "%s_%d.cfg", defaultConfigName, g->encoderNumber); | |
} | |
else { | |
sprintf(configFile, "%s_%d.cfg", g->gConfigFileName, g->encoderNumber); | |
} | |
} | |
filep = fopen(configFile, "r"); | |
if(filep == 0) { | |
/* | |
* LogMessage(g,g,LOG_ERROR, "Cannot open config file %s\n", configFile); | |
* strcpy(g->gConfigFileName, defaultConfigName); | |
*/ | |
} | |
else { | |
while(!feof(filep)) { | |
char_t *p2; | |
memset(buffer, '\000', sizeof(buffer)); | |
fgets(buffer, sizeof(buffer) - 1, filep); | |
p2 = strchr(buffer, '\r'); | |
if(p2) { | |
*p2 = '\000'; | |
} | |
p2 = strchr(buffer, '\n'); | |
if(p2) { | |
*p2 = '\000'; | |
} | |
if(buffer[0] != '#') { | |
char_t *p1 = strchr(buffer, '='); | |
if(p1) { | |
strncpy(configFileValues[numConfigValues].Variable, buffer, p1 - buffer); | |
p1++; /* Get past the = */ | |
strcpy(configFileValues[numConfigValues].Value, p1); | |
numConfigValues++; | |
} | |
} | |
} | |
if(filep) { | |
fclose(filep); | |
} | |
} | |
config_read(g); | |
if(!readOnly) { | |
writeConfigFile(g); | |
} | |
return 1; | |
} | |
int deleteConfigFile(edcastGlobals *g) { | |
char_t configFile[1024] = ""; | |
char_t defaultConfigName[] = "edcast"; | |
if(strlen(g->gConfigFileName) == 0) { | |
sprintf(configFile, "%s_%d.cfg", defaultConfigName, g->encoderNumber); | |
} | |
else { | |
sprintf(configFile, "%s_%d.cfg", g->gConfigFileName, g->encoderNumber); | |
} | |
unlink(configFile); | |
return 1; | |
} | |
void setConfigFileName(edcastGlobals *g, char_t *configFile) { | |
strcpy(g->gConfigFileName, configFile); | |
} | |
char_t *getConfigFileName(edcastGlobals *g) { | |
return g->gConfigFileName; | |
} | |
int writeConfigFile(edcastGlobals *g) { | |
char_t configFile[1024] = ""; | |
char_t defaultConfigName[] = "edcast"; | |
config_write(g); | |
if(strlen(g->gConfigFileName) == 0) { | |
sprintf(configFile, "%s_%d.cfg", defaultConfigName, g->encoderNumber); | |
} | |
else { | |
sprintf(configFile, "%s_%d.cfg", g->gConfigFileName, g->encoderNumber); | |
} | |
FILE *filep = fopen(configFile, "w"); | |
if(filep == 0) { | |
LogMessage(g,LOG_ERROR, "Cannot open config file %s\n", configFile); | |
return 0; | |
} | |
for(int i = 0; i < numConfigValues; i++) { | |
int ok = 1; | |
if (g->configVariables) { | |
ok = 0; | |
for (int j=0;j<g->numConfigVariables;j++) { | |
if (!strcmp(g->configVariables[j], configFileValues[i].Variable)) { | |
ok = 1; | |
break; | |
} | |
} | |
} | |
if (ok) { | |
if (strlen(configFileValues[i].Description) > 0) { | |
fprintf(filep, "# %s\n", configFileValues[i].Description); | |
} | |
fprintf(filep, "%s=%s\n", configFileValues[i].Variable, configFileValues[i].Value); | |
} | |
} | |
fclose(filep); | |
return 1; | |
} | |
void printConfigFileValues() { | |
// for(int i = 0; i < numConfigValues; i++) { | |
// LogMessage(g,LOG_DEBUG, "(%s) = (%s)\n", configFileValues[i].Variable, configFileValues[i].Value); | |
// } | |
} | |
void GetConfigVariable(edcastGlobals *g, char_t *appName, char_t *paramName, char_t *defaultvalue, char_t *destValue, int destSize, char_t *desc) { | |
if (g->configVariables) { | |
int ok = 0; | |
for (int j=0;j<g->numConfigVariables;j++) { | |
if (!strcmp(g->configVariables[j], paramName)) { | |
ok = 1; | |
break; | |
} | |
} | |
if (!ok) { | |
strcpy(destValue, defaultvalue); | |
return; | |
} | |
} | |
for(int i = 0; i < numConfigValues; i++) { | |
if(!strcmp(paramName, configFileValues[i].Variable)) { | |
strcpy(destValue, configFileValues[i].Value); | |
if (desc) { | |
strcpy(configFileValues[i].Description, desc); | |
} | |
return; | |
} | |
} | |
strcpy(configFileValues[numConfigValues].Variable, paramName); | |
strcpy(configFileValues[numConfigValues].Value, defaultvalue); | |
if (desc) { | |
strcpy(configFileValues[numConfigValues].Description, desc); | |
} | |
strcpy(destValue, configFileValues[numConfigValues].Value); | |
numConfigValues++; | |
return; | |
} | |
long GetConfigVariableLong(edcastGlobals *g, char_t *appName, char_t *paramName, long defaultvalue, char_t *desc) { | |
char_t buf[1024] = ""; | |
char_t defaultbuf[1024] = ""; | |
sprintf(defaultbuf, "%d", defaultvalue); | |
GetConfigVariable(g, appName, paramName, defaultbuf, buf, sizeof(buf), desc); | |
return atol(buf); | |
} | |
void PutConfigVariable(edcastGlobals *g, char_t *appName, char_t *paramName, char_t *destValue) { | |
if (g->configVariables) { | |
int ok = 0; | |
for (int j=0;j<g->numConfigVariables;j++) { | |
if (!strcmp(g->configVariables[j], paramName)) { | |
ok = 1; | |
break; | |
} | |
} | |
if (!ok) { | |
return; | |
} | |
} | |
for(int i = 0; i < numConfigValues; i++) { | |
if(!strcmp(paramName, configFileValues[i].Variable)) { | |
strcpy(configFileValues[i].Value, destValue); | |
return; | |
} | |
} | |
strcpy(configFileValues[numConfigValues].Variable, paramName); | |
strcpy(configFileValues[numConfigValues].Value, destValue); | |
strcpy(configFileValues[numConfigValues].Description, ""); | |
numConfigValues++; | |
return; | |
} | |
void PutConfigVariableLong(edcastGlobals *g, char_t *appName, char_t *paramName, long value) { | |
char_t buf[1024] = ""; | |
sprintf(buf, "%d", value); | |
PutConfigVariable(g, appName, paramName, buf); | |
return; | |
} | |
void restartConnection() { | |
; | |
} | |
int trimVariable(char_t *variable) { | |
char_t *p1; | |
/* Trim off the back */ | |
for(p1 = variable + strlen(variable) - 1; p1 > variable; p1--) { | |
if((*p1 == ' ') || (*p1 == ' ')) { | |
*p1 = '\000'; | |
} | |
else { | |
break; | |
} | |
} | |
/* Trim off the front */ | |
char_t tempVariable[1024] = ""; | |
memset(tempVariable, '\000', sizeof(tempVariable)); | |
for(p1 = variable; p1 < variable + strlen(variable) - 1; p1++) { | |
if((*p1 == ' ') || (*p1 == ' ')) { | |
; | |
} | |
else { | |
break; | |
} | |
} | |
strcpy(tempVariable, p1); | |
strcpy(variable, tempVariable); | |
return 1; | |
} | |
void setDestURLCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->destURLCallback = pCallback; | |
} | |
void setSourceURLCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->sourceURLCallback = pCallback; | |
} | |
void setServerStatusCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->serverStatusCallback = pCallback; | |
} | |
void setGeneralStatusCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->generalStatusCallback = pCallback; | |
} | |
void setWriteBytesCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->writeBytesCallback = pCallback; | |
} | |
void setServerTypeCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->serverTypeCallback = pCallback; | |
} | |
void setServerNameCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->serverNameCallback = pCallback; | |
} | |
void setStreamTypeCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->streamTypeCallback = pCallback; | |
} | |
void setBitrateCallback(edcastGlobals *g, void (*pCallback) (void *, void *)) { | |
g->bitrateCallback = pCallback; | |
} | |
void setOggEncoderText(edcastGlobals *g, char_t *text) { | |
strcpy(g->gOggEncoderText, text); | |
} | |
void setVUCallback(edcastGlobals *g, void (*pCallback) (int, int)) { | |
g->VUCallback = pCallback; | |
} | |
void setForceStop(edcastGlobals *g, int forceStop) { | |
g->gForceStop = forceStop; | |
} | |
void initializeGlobals(edcastGlobals *g) { | |
/* Global variables....gotta love em... */ | |
g->gSCSocket = 0; | |
g->gSCSocket2 = 0; | |
g->gSCSocketControl = 0; | |
g->gSCFlag = 0; | |
g->gReconnectSec = 10; | |
g->gAutoCountdown = 10; | |
g->automaticconnect = 1; | |
memset(g->gServer, '\000', sizeof(g->gServer)); | |
memset(g->gPort, '\000', sizeof(g->gPort)); | |
memset(g->gPassword, '\000', sizeof(g->gPassword)); | |
memset(g->gIniFile, '\000', sizeof(g->gIniFile)); | |
memset(g->gAppName, '\000', sizeof(g->gAppName)); | |
memset(g->gCurrentSong, '\000', sizeof(g->gCurrentSong)); | |
g->gPubServ = 0; | |
memset(g->gServIRC, '\000', sizeof(g->gServIRC)); | |
memset(g->gServAIM, '\000', sizeof(g->gServAIM)); | |
memset(g->gServICQ, '\000', sizeof(g->gServICQ)); | |
memset(g->gServURL, '\000', sizeof(g->gServURL)); | |
memset(g->gServDesc, '\000', sizeof(g->gServDesc)); | |
memset(g->gMountpoint, '\000', sizeof(g->gMountpoint)); | |
g->gAutoReconnect = 0; | |
memset(g->gAutoStart, '\000', sizeof(g->gAutoStart)); | |
memset(g->gAutoStartSec, '\000', sizeof(g->gAutoStartSec)); | |
memset(g->gQuality, '\000', sizeof(g->gQuality)); | |
g->gOggFlag = 0; | |
memset(g->gIceFlag, '\000', sizeof(g->gIceFlag)); | |
g->gLAMEFlag = 0; | |
memset(g->gSaveDirectory, '\000', sizeof(g->gSaveDirectory)); | |
memset(g->gLogFile, '\000', sizeof(g->gLogFile)); | |
g->gLogLevel = LM_ERROR; | |
g->gSaveDirectoryFlag = 0; | |
memset(g->gSongTitle, '\000', sizeof(g->gSongTitle)); | |
memset(g->gManualSongTitle, '\000', sizeof(g->gManualSongTitle)); | |
g->gLockSongTitle = 0; | |
g->startTime = 0; | |
g->endTime = 0; | |
g->weareconnected = 0; | |
pthread_mutex_init(&(g->mutex), NULL); | |
memset(g->WindowsRecDevice, '\000', sizeof(g->WindowsRecDevice)); | |
g->LAMEJointStereoFlag = 1; | |
#ifndef WIN32 | |
#ifdef HAVE_LAME | |
g->gf = NULL; | |
#endif | |
#endif | |
g->gCurrentlyEncoding = 0; | |
g->gShoutcastFlag = 0; | |
g->gIcecastFlag = 0; | |
g->gSaveFile = 0; | |
g->destURLCallback = NULL; | |
g->sourceURLCallback = NULL; | |
g->serverStatusCallback = NULL; | |
g->generalStatusCallback = NULL; | |
g->writeBytesCallback = NULL; | |
g->serverTypeCallback = NULL; | |
g->serverNameCallback = NULL; | |
g->streamTypeCallback = NULL; | |
g->bitrateCallback = NULL; | |
g->VUCallback = NULL; | |
memset(g->sourceDescription, '\000', sizeof(g->sourceDescription)); | |
/* OGG Stuff */ | |
g->oggflag = 1; | |
g->ice2songChange = false; | |
g->in_header = 0; | |
g->gLiveRecordingFlag = 0; | |
g->areLiveRecording = FALSE; | |
memset(g->gOggEncoderText, '\000', sizeof(g->gOggEncoderText)); | |
g->gForceStop = 0; | |
#ifdef HAVE_VORBIS | |
memset(&(g->vi), '\000', sizeof(g->vi)); | |
#endif | |
g->vuShow = 0; | |
g->ReconnectTrigger = 0; | |
} | |
char_t *getCurrentlyPlaying(edcastGlobals *g) { | |
return(g->gSongTitle); | |
} | |
int setCurrentSongTitle(edcastGlobals *g, char_t *song) { | |
char_t *pCurrent; | |
char_t modifiedSong[1024] = ""; | |
if(g->gLockSongTitle) { | |
pCurrent = g->gManualSongTitle; | |
} | |
else { | |
pCurrent = song; | |
} | |
if(strcmp(g->gSongTitle, pCurrent)) { | |
strcpy(g->gSongTitle, pCurrent); | |
updateSongTitle(g, 0); | |
return 1; | |
} | |
return 0; | |
} | |
int setCurrentSongTitleURL(edcastGlobals *g, char_t *song) { | |
char_t *pCurrent; | |
if(g->gLockSongTitle) { | |
pCurrent = g->gManualSongTitle; | |
} | |
else { | |
pCurrent = song; | |
} | |
if(strcmp(g->gSongTitle, pCurrent)) { | |
strcpy(g->gSongTitle, pCurrent); | |
updateSongTitle(g, 0); | |
return 1; | |
} | |
return 0; | |
} | |
void getCurrentSongTitle(edcastGlobals *g, char_t *song, char_t *artist, char_t *full) { | |
char_t songTitle[1024] = ""; | |
char_t songTitle2[1024] = ""; | |
memset(songTitle2, '\000', sizeof(songTitle2)); | |
char_t *pCurrent; | |
if(g->gLockSongTitle) { | |
pCurrent = g->gManualSongTitle; | |
} | |
else { | |
pCurrent = g->gSongTitle; | |
} | |
strcpy(songTitle, pCurrent); | |
strcpy(full, songTitle); | |
char_t *p1 = strchr(songTitle, '-'); | |
if(p1) { | |
if(*(p1 - 1) == ' ') { | |
p1--; | |
} | |
strncpy(artist, songTitle, p1 - songTitle); | |
p1 = strchr(songTitle, '-'); | |
p1++; | |
if(*p1 == ' ') { | |
p1++; | |
} | |
strcpy(song, p1); | |
} | |
else { | |
strcpy(artist, ""); | |
strcpy(song, songTitle); | |
} | |
} | |
void ReplaceString(char_t *source, char_t *dest, char_t *from, char_t *to) { | |
int loop = 1; | |
char_t *p2 = (char_t *) 1; | |
char_t *p1 = source; | |
while(p2) { | |
p2 = strstr(p1, from); | |
if(p2) { | |
strncat(dest, p1, p2 - p1); | |
strcat(dest, to); | |
p1 = p2 + strlen(from); | |
} | |
else { | |
strcat(dest, p1); | |
} | |
} | |
} | |
/* | |
======================================================================================================================= | |
This function URLencodes strings for use in sending them thru ; | |
the Shoutcast admin.cgi interface to update song titles.. | |
======================================================================================================================= | |
*/ | |
void URLize(char_t *input, char_t *output, int inputlen, int outputlen) { | |
ReplaceString(input, output, "%", "%25"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, ";", "%3B"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "/", "%2F"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, "?", "%3F"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, ":", "%3A"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, "@", "%40"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "&", "%26"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, "=", "%3D"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "+", "%2B"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, " ", "%20"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "\"", "%22"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, "#", "%23"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "<", "%3C"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, ">", "%3E"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "!", "%21"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, "*", "%2A"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, "'", "%27"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, "(", "%28"); | |
memset(output, '\000', outputlen); | |
ReplaceString(input, output, ")", "%29"); | |
memset(input, '\000', inputlen); | |
ReplaceString(output, input, ",", "%2C"); | |
memset(output, '\000', outputlen); | |
strcpy(output, input); | |
} | |
int updateSongTitle(edcastGlobals *g, int forceURL) { | |
char_t contentString[2056] = ""; | |
char_t URLPassword[255] = ""; | |
char_t URLSong[1024] = ""; | |
char_t Song[1024] = ""; | |
if(getIsConnected(g)) { | |
if((!g->gOggFlag) || (forceURL)) { | |
if((g->gSCFlag) || (g->gIcecastFlag) || (g->gIcecast2Flag) || forceURL) { | |
URLize(g->gPassword, URLPassword, sizeof(g->gPassword), sizeof(URLPassword)); | |
strcpy(g->gCurrentSong, g->gSongTitle); | |
URLize(g->gCurrentSong, URLSong, sizeof(g->gSongTitle), sizeof(URLSong)); | |
if(g->gIcecast2Flag) { | |
char_t userAuth[1024] = ""; | |
sprintf(userAuth, "source:%s", g->gPassword); | |
char_t *puserAuthbase64 = util_base64_encode(userAuth); | |
if(puserAuthbase64) { | |
sprintf(contentString, | |
"GET /admin/metadata?pass=%s&mode=updinfo&mount=%s&song=%s HTTP/1.0\r\nAuthorization: Basic %s\r\nUser-Agent: (Mozilla Compatible)\r\n\r\n", | |
URLPassword, | |
g->gMountpoint, | |
URLSong, | |
puserAuthbase64); | |
free(puserAuthbase64); | |
} | |
} | |
if(g->gIcecastFlag) { | |
sprintf(contentString, | |
"GET /admin.cgi?pass=%s&mode=updinfo&mount=%s&song=%s HTTP/1.0\r\nUser-Agent: (Mozilla Compatible)\r\n\r\n", | |
URLPassword, | |
g->gMountpoint, | |
URLSong); | |
} | |
if(g->gSCFlag) { | |
sprintf(contentString, | |
"GET /admin.cgi?pass=%s&mode=updinfo&song=%s HTTP/1.0\r\nUser-Agent: (Mozilla Compatible)\r\n\r\n", | |
URLPassword, | |
URLSong); | |
} | |
g->gSCSocketControl = g->controlChannel.DoSocketConnect(g->gServer, atoi(g->gPort)); | |
if(g->gSCSocketControl != -1) { | |
int sent = send(g->gSCSocketControl, contentString, strlen(contentString), 0); | |
//int sent = sendToServer(g, g->gSCSocketControl, contentString, strlen(contentString), HEADER_TYPE); | |
closesocket(g->gSCSocketControl); | |
} | |
else { | |
LogMessage(g,LOG_ERROR, "Cannot connect to server"); | |
} | |
} | |
} | |
else { | |
g->ice2songChange = true; | |
} | |
return 1; | |
} | |
return 0; | |
} | |
/* | |
======================================================================================================================= | |
This function does some magic in order to change the metadata ; | |
in a vorbis stream....Vakor helped me with this, and it's pretty ; | |
much all his idea anyway...and probably the reason why it actually ; | |
does work..:) | |
======================================================================================================================= | |
*/ | |
void icecast2SendMetadata(edcastGlobals *g) | |
{ | |
/* | |
#ifdef HAVE_VORBIS | |
pthread_mutex_lock(&(g->mutex)); | |
vorbis_analysis_wrote(&g->vd, 0); | |
ogg_encode_dataout(g); | |
initializeencoder(g); | |
pthread_mutex_unlock(&(g->mutex)); | |
#endif | |
*/ | |
} | |
#ifdef HAVE_FLAC | |
extern "C" { | |
FLAC__StreamEncoderWriteStatus FLACWriteCallback( | |
const FLAC__StreamEncoder *encoder, | |
const FLAC__byte buffer[], | |
unsigned bytes, | |
unsigned samples, | |
unsigned current_frame, | |
void *client_data | |
) { | |
edcastGlobals *g = (edcastGlobals *) client_data; | |
int sentbytes = sendToServer(g, g->gSCSocket, (char_t *) buffer, bytes, CODEC_TYPE); | |
if(sentbytes < 0) { | |
g->flacFailure = 1; | |
} | |
else { | |
g->flacFailure = 0; | |
} | |
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; | |
} | |
} | |
extern "C" { | |
void FLACMetadataCallback(const FLAC__StreamEncoder *encoder, | |
const FLAC__StreamMetadata *metadata, | |
void *client_data) { | |
edcastGlobals *g = (edcastGlobals *) client_data; | |
return; | |
} | |
} | |
#endif | |
/* | |
======================================================================================================================= | |
This function will disconnect the DSP from the server (duh) | |
======================================================================================================================= | |
*/ | |
int disconnectFromServer(edcastGlobals *g) { | |
g->weareconnected = 0; | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (char_t *) "Disconnecting"); | |
} | |
if(g->gCurrentlyEncoding) | |
{ | |
#ifdef WIN32 | |
Sleep(1000); | |
#else | |
sleep(1); | |
#endif | |
} | |
/* Close all open sockets */ | |
closesocket(g->gSCSocket); | |
closesocket(g->gSCSocketControl); | |
/* | |
* Reset the Status to Disconnected, and reenable the config ; | |
* button | |
*/ | |
g->gSCSocket = 0; | |
g->gSCSocketControl = 0; | |
#ifdef HAVE_VORBIS | |
ogg_stream_clear(&g->os); | |
vorbis_block_clear(&g->vb); | |
vorbis_dsp_clear(&g->vd); | |
vorbis_info_clear(&g->vi); | |
memset(&(g->vi), '\000', sizeof(g->vi)); | |
#endif | |
#ifdef HAVE_LAME | |
#ifndef WIN32 | |
if(g->gf) { | |
lame_close(g->gf); | |
g->gf = NULL; | |
} | |
#endif | |
#endif | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Disconnected"); | |
} | |
closeArchiveFile(g); | |
return 1; | |
} | |
/* | |
======================================================================================================================= | |
This funciton will connect to a server (Shoutcast/Icecast/Icecast2) ; | |
and send the appropriate password info and check to make sure things ; | |
are connected.... | |
======================================================================================================================= | |
*/ | |
int connectToServer(edcastGlobals *g) { | |
int s_socket = 0; | |
char_t buffer[1024] = ""; | |
char_t contentString[1024] = ""; | |
char_t brate[25] = ""; | |
char_t ypbrate[25] = ""; | |
LogMessage(g,LOG_DEBUG, "Connecting encoder %d", g->encoderNumber); | |
sprintf(brate, "%d", g->currentBitrate); | |
if(g->gOggFlag) { | |
if(!g->gOggBitQualFlag) { | |
sprintf(ypbrate, "Quality %s", g->gOggQuality); | |
} | |
else { | |
strcpy(ypbrate, brate); | |
} | |
} | |
else { | |
strcpy(ypbrate, brate); | |
} | |
g->gSCFlag = 0; | |
greconnectFlag = 0; | |
if(g->serverStatusCallback) { | |
sprintf(buffer, "Connnecting to %s:%d", g->gServer, atoi(g->gPort)); | |
g->serverStatusCallback(g, (void *) buffer); | |
} | |
/* If we are Icecast/Icecast2, then connect to specified port */ | |
if(g->gIcecastFlag || g->gIcecast2Flag) { | |
g->gSCSocket = g->dataChannel.DoSocketConnect(g->gServer, atoi(g->gPort)); | |
} | |
else { | |
/* | |
* If we are Shoutcast, then the control socket (used for password) ; | |
* is port+1. | |
*/ | |
g->gSCSocket = g->dataChannel.DoSocketConnect(g->gServer, atoi(g->gPort) + 1); | |
} | |
/* Check to see if we connected okay */ | |
if(g->gSCSocket == -1) { | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Unable to connect to socket"); | |
} | |
return 0; | |
} | |
int pswdok = 1; | |
/* Yup, we did. */ | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Socket connected"); | |
} | |
char_t contentType[255] = ""; | |
if(g->gOggFlag) { | |
strcpy(contentType, "application/ogg"); | |
} | |
else { | |
if(g->gAACFlag) { | |
strcpy(contentType, "audio/aac"); | |
} | |
else { | |
if(g->gAACPFlag) { | |
strcpy(contentType, "audio/aacp"); | |
} | |
else { | |
if(g->gFLACFlag) { | |
strcpy(contentType, "application/ogg"); | |
} | |
else { | |
strcpy(contentType, "audio/mpeg"); | |
} | |
} | |
} | |
} | |
/* | |
* Here are all the variations of sending the password to ; | |
* a server..This if statement really is ugly...must fix. | |
*/ | |
if(g->gIcecastFlag || g->gIcecast2Flag) { | |
/* The Icecast/Icecast2 Way */ | |
if(g->gIcecastFlag) { | |
sprintf(contentString, | |
"SOURCE %s %s\r\ncontent-type: %s\r\nx-audiocast-name: %s\r\nx-audiocast-url: %s\r\nx-audiocast-genre: %s\r\nx-audiocast-bitrate: %s\r\nx-audiocast-public: %d\r\nx-audiocast-description: %s\r\n\r\n", | |
g->gPassword, | |
g->gMountpoint, | |
contentType, | |
g->gServDesc, | |
g->gServURL, | |
g->gServGenre, | |
brate, | |
g->gPubServ, | |
g->gServDesc); | |
} | |
if(g->gIcecast2Flag) { | |
char_t audioInfo[1024] = ""; | |
sprintf(audioInfo, | |
"ice-samplerate=%d;ice-bitrate=%s;ice-channels=%d", | |
getCurrentSamplerate(g), | |
ypbrate, | |
getCurrentChannels(g)); | |
char_t userAuth[1024] = ""; | |
sprintf(userAuth, "source:%s", g->gPassword); | |
char_t *puserAuthbase64 = util_base64_encode(userAuth); | |
if(puserAuthbase64) { | |
sprintf(contentString, | |
"SOURCE %s ICE/1.0\ncontent-type: %s\nAuthorization: Basic %s\nice-name: %s\nice-url: %s\nice-genre: %s\nice-bitrate: %s\nice-private: %d\nice-public: %d\nice-description: %s\nice-audio-info: %s\n\n", | |
g->gMountpoint, | |
contentType, | |
puserAuthbase64, | |
g->gServName, | |
g->gServURL, | |
g->gServGenre, | |
ypbrate, | |
!g->gPubServ, | |
g->gPubServ, | |
g->gServDesc, | |
audioInfo); | |
free(puserAuthbase64); | |
} | |
} | |
} | |
else { | |
/* The Shoutcast way */ | |
sendToServer(g, g->gSCSocket, g->gPassword, strlen(g->gPassword), HEADER_TYPE); | |
sendToServer(g, g->gSCSocket, "\r\n", strlen("\r\n"), HEADER_TYPE); | |
recv(g->gSCSocket, buffer, sizeof(buffer), (int) 0); | |
/* | |
* if we get an OK, then we are not a Shoutcast server ; | |
* (could be live365 or other variant)..And OK2 means it's ; | |
* Shoutcast and we can safely send in metadata via the ; | |
* admin.cgi interface. | |
*/ | |
if(!strncmp(buffer, "OK", strlen("OK"))) { | |
if(!strncmp(buffer, "OK2", strlen("OK2"))) { | |
g->gSCFlag = 1; | |
} | |
else { | |
g->gSCFlag = 0; | |
} | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Password OK"); | |
} | |
} | |
else { | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Password Failed"); | |
} | |
closesocket(g->gSCSocket); | |
return 0; | |
} | |
memset(contentString, '\000', sizeof(contentString)); | |
if(strlen(g->gServICQ) == 0) { | |
strcpy(g->gServICQ, "N/A"); | |
} | |
if(strlen(g->gServAIM) == 0) { | |
strcpy(g->gServAIM, "N/A"); | |
} | |
if(strlen(g->gServIRC) == 0) { | |
strcpy(g->gServIRC, "N/A"); | |
} | |
sprintf(contentString, | |
"content-type:%s\r\nicy-name:%s\r\nicy-genre:%s\r\nicy-url:%s\r\nicy-pub:%d\r\nicy-irc:%s\r\nicy-icq:%s\r\nicy-aim:%s\r\nicy-br:%s\r\n\r\n", | |
contentType, | |
g->gServName, | |
g->gServGenre, | |
g->gServURL, | |
g->gPubServ, | |
g->gServIRC, | |
g->gServICQ, | |
g->gServAIM, | |
brate); | |
} | |
sendToServer(g, g->gSCSocket, contentString, strlen(contentString), HEADER_TYPE); | |
if(g->gIcecastFlag) { | |
/* | |
* Here we are checking the response from Icecast/Icecast2 ; | |
* from when we sent in the password...OK means we are good..if the ; | |
* password is bad, Icecast just disconnects the socket. | |
*/ | |
if(g->gOggFlag) { | |
recv(g->gSCSocket, buffer, sizeof(buffer), 0); | |
if(!strncmp(buffer, "OK", strlen("OK"))) { | |
/* I don't think this check is needed.. */ | |
if(!strncmp(buffer, "OK2", strlen("OK2"))) { | |
g->gSCFlag = 1; | |
} | |
else { | |
g->gSCFlag = 0; | |
} | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Password OK"); | |
} | |
} | |
else { | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Password Failed"); | |
} | |
closesocket(g->gSCSocket); | |
return 0; | |
} | |
} | |
} | |
/* We are connected */ | |
char_t outFilename[1024] = ""; | |
char_t outputFile[1024] = ""; | |
struct tm *newtime; | |
time_t aclock; | |
time(&aclock); | |
newtime = localtime(&aclock); | |
int ret = 0; | |
ret = initializeencoder(g); | |
g->forcedDisconnect = false; | |
if(ret) { | |
g->weareconnected = 1; | |
g->automaticconnect = 1; | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Success"); | |
} | |
/* Start up song title check */ | |
} | |
else { | |
disconnectFromServer(g); | |
if(g->serverStatusCallback) | |
{ | |
g->serverStatusCallback(g, (void *) "Encoder init failed"); | |
} | |
return 0; | |
} | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Connected"); | |
} | |
setCurrentSongTitle(g, g->gSongTitle); | |
updateSongTitle(g, 0); | |
return 1; | |
} | |
/* | |
======================================================================================================================= | |
These are some ogg routines that are used for Icecast2 | |
======================================================================================================================= | |
*/ | |
int ogg_encode_dataout(edcastGlobals *g) | |
{ | |
#ifdef HAVE_VORBIS | |
ogg_packet op; | |
ogg_page og; | |
int result; | |
int sentbytes = 0; | |
if(g->in_header) { | |
result = ogg_stream_flush(&g->os, &og); | |
g->in_header = 0; | |
} | |
while(vorbis_analysis_blockout(&g->vd, &g->vb) == 1) { | |
vorbis_analysis(&g->vb, NULL); | |
vorbis_bitrate_addblock(&g->vb); | |
int packetsdone = 0; | |
while(vorbis_bitrate_flushpacket(&g->vd, &op)) { | |
/* Add packet to bitstream */ | |
ogg_stream_packetin(&g->os, &op); | |
packetsdone++; | |
/* | |
* If we've gone over a page boundary, we can do actual output, so do so (for | |
* however many pages are available) | |
*/ | |
int eos = 0; | |
while(!eos) { | |
//printf("sslf: %d\n", g->SamplesSinceFlush ); | |
//printf("lfs: %d\n", g->LastFlushSamples ); | |
if ((g->SamplesSinceFlush + g->LastFlushSamples) >= (g->LastFlushSamples + (4096 * 4))) { | |
//printf("force flusing\n"); | |
while(ogg_stream_flush(&g->os, &og) != 0) { | |
sentbytes = sendToServer(g, g->gSCSocket, (char_t *) og.header, og.header_len, CODEC_TYPE); | |
sentbytes += sendToServer(g, g->gSCSocket, (char_t *) og.body, og.body_len, CODEC_TYPE); | |
g->LastFlushSamples = ogg_page_granulepos(&og); | |
g->SamplesSinceFlush = 0; | |
} | |
} | |
else { | |
while(ogg_stream_pageout(&g->os, &og) != 0) { | |
//printf("normal flusing\n"); | |
sentbytes = sendToServer(g, g->gSCSocket, (char_t *) og.header, og.header_len, CODEC_TYPE); | |
sentbytes += sendToServer(g, g->gSCSocket, (char_t *) og.body, og.body_len, CODEC_TYPE); | |
g->LastFlushSamples = ogg_page_granulepos(&og); | |
g->SamplesSinceFlush = 0; | |
} | |
} | |
if(sentbytes < 0) { | |
return sentbytes; | |
} else { | |
break; | |
} | |
if(ogg_page_eos(&og)) { | |
eos = 1; | |
} | |
} | |
} | |
} | |
return sentbytes; | |
#else | |
return 0; | |
#endif | |
} | |
void oddsock_error_handler_function(const char_t *format, va_list ap) { | |
return; | |
} | |
int initializeencoder(edcastGlobals *g) { | |
int ret = 0; | |
char_t outFilename[1024] = ""; | |
char_t message[1024] = ""; | |
if(g->gLAMEFlag) | |
{ | |
#ifdef HAVE_LAME | |
g->gf = lame_init(); | |
lame_set_errorf(g->gf, oddsock_error_handler_function); | |
lame_set_debugf(g->gf, oddsock_error_handler_function); | |
lame_set_msgf(g->gf, oddsock_error_handler_function); | |
lame_set_brate(g->gf, g->currentBitrate); | |
lame_set_quality(g->gf, g->gLAMEOptions.quality); | |
lame_set_num_channels(g->gf, 2); | |
if(g->currentChannels == 1) { | |
lame_set_mode(g->gf, MONO); | |
/* | |
* lame_set_num_channels(g->gf, 1); | |
*/ | |
} | |
else { | |
lame_set_mode(g->gf, STEREO); | |
} | |
/* | |
* Make the input sample rate the same as output..i.e. don't make lame do ; | |
* any resampling->..cause we are handling it ourselves... | |
*/ | |
lame_set_in_samplerate(g->gf, g->currentSamplerate); | |
lame_set_out_samplerate(g->gf, g->currentSamplerate); | |
lame_set_copyright(g->gf, g->gLAMEOptions.copywrite); | |
lame_set_strict_ISO(g->gf, g->gLAMEOptions.strict_ISO); | |
lame_set_disable_reservoir(g->gf, g->gLAMEOptions.disable_reservoir); | |
if(!g->gLAMEOptions.cbrflag) { | |
if(!strcmp(g->gLAMEOptions.VBR_mode, "vbr_rh")) { | |
lame_set_VBR(g->gf, vbr_rh); | |
} | |
if(!strcmp(g->gLAMEOptions.VBR_mode, "vbr_mtrh")) { | |
lame_set_VBR(g->gf, vbr_mtrh); | |
} | |
if(!strcmp(g->gLAMEOptions.VBR_mode, "vbr_abr")) { | |
lame_set_VBR(g->gf, vbr_abr); | |
} | |
lame_set_VBR_mean_bitrate_kbps(g->gf, g->currentBitrate); | |
lame_set_VBR_min_bitrate_kbps(g->gf, g->currentBitrateMin); | |
lame_set_VBR_max_bitrate_kbps(g->gf, g->currentBitrateMax); | |
} | |
if(strlen(g->gLAMEbasicpreset) > 0) { | |
if(!strcmp(g->gLAMEbasicpreset, "r3mix")) { | |
/* | |
* presets_set_r3mix(g->gf, g->gLAMEbasicpreset, stdout); | |
*/ | |
} | |
else { | |
/* | |
* presets_set_basic(g->gf, g->gLAMEbasicpreset, stdout); | |
*/ | |
} | |
} | |
if(strlen(g->gLAMEaltpreset) > 0) { | |
int altbitrate = atoi(g->gLAMEaltpreset); | |
/* | |
* dm_presets(g->gf, 0, altbitrate, g->gLAMEaltpreset, "edcast"); | |
*/ | |
} | |
/* do internal inits... */ | |
lame_set_lowpassfreq(g->gf, g->gLAMEOptions.lowpassfreq); | |
lame_set_highpassfreq(g->gf, g->gLAMEOptions.highpassfreq); | |
int lame_ret = lame_init_params(g->gf); | |
if(lame_ret != 0) { | |
printf("Error initializing LAME"); | |
} | |
#else | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Not compiled with LAME support"); | |
} | |
LogMessage(g,LOG_ERROR, "Not compiled with LAME support"); | |
return 0; | |
#endif | |
} | |
if(g->gAACFlag) | |
{ | |
#ifdef HAVE_FAAC | |
faacEncConfigurationPtr m_pConfig; | |
if(g->aacEncoder) { | |
faacEncClose(g->aacEncoder); | |
g->aacEncoder = NULL; | |
} | |
g->aacEncoder = faacEncOpen(g->currentSamplerate, g->currentChannels, &g->samplesInput, &g->maxBytesOutput); | |
if(g->faacFIFO) { | |
free(g->faacFIFO); | |
} | |
g->faacFIFO = (float *) malloc(g->samplesInput * sizeof(float) * 16); | |
g->faacFIFOendpos = 0; | |
m_pConfig = faacEncGetCurrentConfiguration(g->aacEncoder); | |
m_pConfig->mpegVersion = MPEG2; | |
m_pConfig->quantqual = atoi(g->gAACQuality); | |
int cutoff = atoi(g->gAACCutoff); | |
if(cutoff > 0) { | |
m_pConfig->bandWidth = cutoff; | |
} | |
/* | |
* m_pConfig->bitRate = (g->currentBitrate * 1000) / g->currentChannels; | |
*/ | |
m_pConfig->allowMidside = 1; | |
m_pConfig->useLfe = 0; | |
m_pConfig->useTns = 1; | |
m_pConfig->aacObjectType = LOW; | |
m_pConfig->outputFormat = 1; | |
m_pConfig->inputFormat = FAAC_INPUT_FLOAT; | |
/* set new config */ | |
faacEncSetConfiguration(g->aacEncoder, m_pConfig); | |
#else | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Not compiled with AAC support"); | |
} | |
LogMessage(g,LOG_ERROR, "Not compiled with AAC support"); | |
return 0; | |
#endif | |
} | |
if(g->gAACPFlag) | |
{ | |
#ifdef HAVE_AACP | |
if(g->aacpEncoder) { | |
delete g->aacpEncoder; | |
g->aacpEncoder = NULL; | |
} | |
unsigned int outt = 1346584897; | |
char_t *conf_file = "edcast_aacp.ini"; /* Default ini file */ | |
/* 1 - Mono 2 - Stereo 3 - Stereo Independent 4 - Parametric 5 - Dual Channel */ | |
char_t sampleRate[255] = ""; | |
char_t channelMode[255] = ""; | |
char_t bitrateValue[255] = ""; | |
char_t aacpV2Enable[255] = "1"; | |
long bitrateLong = g->currentBitrate * 1000; | |
sprintf(bitrateValue, "%d", bitrateLong); | |
if(bitrateLong >= 64000) { | |
if(g->currentChannels == 2) { | |
strcpy(channelMode, "2"); | |
} | |
else { | |
strcpy(channelMode, "1"); | |
} | |
} | |
if((bitrateLong <= 48000) && (bitrateLong >= 16000)) { | |
if(g->currentChannels == 2) { | |
strcpy(channelMode, "4"); | |
} | |
else { | |
strcpy(channelMode, "1"); | |
} | |
} | |
if(bitrateLong <= 12000) { | |
strcpy(channelMode, "1"); | |
} | |
sprintf(sampleRate, "%d", g->currentSamplerate); | |
WritePrivateProfileString("audio_aacplus", "samplerate", sampleRate, conf_file); | |
WritePrivateProfileString("audio_aacplus", "channelmode", channelMode, conf_file); | |
WritePrivateProfileString("audio_aacplus", "bitrate", bitrateValue, conf_file); | |
WritePrivateProfileString("audio_aacplus", "v2enable", aacpV2Enable, conf_file); | |
WritePrivateProfileString("audio_aacplus", "bitstream", "0", conf_file); | |
WritePrivateProfileString("audio_aacplus", "nsignallingmode", "0", conf_file); | |
g->aacpEncoder = g->CreateAudio3((int) g->currentChannels, | |
(int) g->currentSamplerate, | |
16, | |
mmioFOURCC('P', 'C', 'M', ' '), | |
&outt, | |
conf_file); | |
if(!g->aacpEncoder) { | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Invalid AAC+ settings"); | |
} | |
LogMessage(g,LOG_ERROR, "Invalid AAC+ settings"); | |
return 0; | |
} | |
#else | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Not compiled with AAC Plus support"); | |
} | |
LogMessage(g,LOG_ERROR, "Not compiled with AAC Plus support"); | |
return 0; | |
#endif | |
} | |
if(g->gOggFlag) | |
{ | |
#ifdef HAVE_VORBIS | |
/* Ogg Vorbis Initialization */ | |
ogg_stream_clear(&g->os); | |
vorbis_block_clear(&g->vb); | |
vorbis_dsp_clear(&g->vd); | |
vorbis_info_clear(&g->vi); | |
int bitrate = 0; | |
vorbis_info_init(&g->vi); | |
int encode_ret = 0; | |
/* | |
if(!g->gOggBitQualFlag) { | |
// Clients FAIL with VBR streams that have silence | |
// so we must manage all the damn time | |
switch(atoi(g->gOggQuality)){ | |
case 0: g->currentBitrate = 64; break; | |
case 1: g->currentBitrate = 80; break; | |
case 2: g->currentBitrate = 96; break; | |
case 3: g->currentBitrate = 112; break; | |
case 4: g->currentBitrate = 128; break; | |
case 5: g->currentBitrate = 160; break; | |
case 6: g->currentBitrate = 192; break; | |
case 7: g->currentBitrate = 224; break; | |
case 8: g->currentBitrate = 256; break; | |
case 9: g->currentBitrate = 320; break; | |
case 10: g->currentBitrate = 500; break; | |
default: g->currentBitrate = 160; break; | |
} | |
} | |
if (true) { | |
//else { | |
// of course the whole min and max bitrate thing doesn't really do any good | |
encode_ret = vorbis_encode_init(&g->vi, | |
g->currentChannels, | |
g->currentSamplerate, | |
(g->currentBitrate - 0) * 1000, | |
g->currentBitrate * 1000, | |
(g->currentBitrate + 0) * 1000); | |
*/ | |
//printf("wtf: %d %d %d ::: %d", g->currentChannels, g->currentSamplerate, (g->currentBitrate * 1000), encode_ret ); | |
encode_ret = vorbis_encode_setup_vbr(&g->vi, | |
g->currentChannels, | |
g->currentSamplerate, | |
((float) atof(g->gOggQuality) * (float) .1)); | |
if(encode_ret) { | |
vorbis_info_clear(&g->vi); | |
} | |
//} | |
if(encode_ret == OV_EIMPL) { | |
LogMessage(g,LOG_ERROR, "Sorry, but this vorbis mode is not supported currently..."); | |
return 0; | |
} | |
if(encode_ret == OV_EINVAL) { | |
LogMessage(g,LOG_ERROR, "Sorry, but this is an illegal vorbis mode..."); | |
return 0; | |
} | |
ret = vorbis_encode_setup_init(&g->vi); | |
/* | |
* Now, set up the analysis engine, stream encoder, and other preparation before | |
* the encoding begins | |
*/ | |
ret = vorbis_analysis_init(&g->vd, &g->vi); | |
ret = vorbis_block_init(&g->vd, &g->vb); | |
g->serialno = 0; | |
srand(time(0)); | |
ret = ogg_stream_init(&g->os, rand()); | |
/* | |
* Now, build the three header packets and send through to the stream output stage | |
* (but defer actual file output until the main encode loop) | |
*/ | |
ogg_packet header_main; | |
ogg_packet header_comments; | |
ogg_packet header_codebooks; | |
vorbis_comment vc; | |
char_t title[1024] = ""; | |
char_t artist[1024] = ""; | |
char_t FullTitle[1024] = ""; | |
char_t SongTitle[1024] = ""; | |
char_t Artist[1024] = ""; | |
char_t Streamed[1024] = ""; | |
wchar_t widestring[4096]; | |
char tempstring[4096]; | |
memset(Artist, '\000', sizeof(Artist)); | |
memset(SongTitle, '\000', sizeof(SongTitle)); | |
memset(FullTitle, '\000', sizeof(FullTitle)); | |
memset(Streamed, '\000', sizeof(Streamed)); | |
vorbis_comment_init(&vc); | |
bool bypass = false; | |
if(!getLockedMetadataFlag(g)) { | |
if(g->numVorbisComments) { | |
for(int i = 0; i < g->numVorbisComments; i++) | |
{ | |
vorbis_comment_add(&vc, g->vorbisComments[i]); | |
} | |
bypass = true; | |
} | |
} | |
if(!bypass) { | |
getCurrentSongTitle(g, SongTitle, Artist, FullTitle); | |
if((strlen(SongTitle) == 0) && (strlen(Artist) == 0)) { | |
sprintf(title, "TITLE=%s", FullTitle); | |
} | |
else { | |
sprintf(title, "TITLE=%s", SongTitle); | |
} | |
vorbis_comment_add(&vc, title); | |
sprintf(artist, "ARTIST=%s", Artist); | |
vorbis_comment_add(&vc, artist); | |
} | |
sprintf(Streamed, "ENCODEDBY=edcast2"); | |
vorbis_comment_add(&vc, Streamed); | |
if(strlen(g->sourceDescription) > 0) { | |
sprintf(Streamed, "TRANSCODEDFROM=%s", g->sourceDescription); | |
vorbis_comment_add(&vc, Streamed); | |
} | |
/* Build the packets */ | |
memset(&header_main, '\000', sizeof(header_main)); | |
memset(&header_comments, '\000', sizeof(header_comments)); | |
memset(&header_codebooks, '\000', sizeof(header_codebooks)); | |
vorbis_analysis_headerout(&g->vd, &vc, &header_main, &header_comments, &header_codebooks); | |
ogg_stream_packetin(&g->os, &header_main); | |
ogg_stream_packetin(&g->os, &header_comments); | |
ogg_stream_packetin(&g->os, &header_codebooks); | |
g->in_header = 1; | |
ogg_page og; | |
int eos = 0; | |
int sentbytes = 0; | |
int ret = 0; | |
while(!eos) { | |
int result = ogg_stream_flush(&g->os, &og); | |
if(result == 0) break; | |
sentbytes += sendToServer(g, g->gSCSocket, (char *) og.header, og.header_len, CODEC_TYPE); | |
sentbytes += sendToServer(g, g->gSCSocket, (char *) og.body, og.body_len, CODEC_TYPE); | |
} | |
vorbis_comment_clear(&vc); | |
if(g->numVorbisComments) { | |
freeVorbisComments(g); | |
} | |
#else | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Not compiled with Ogg Vorbis support"); | |
} | |
LogMessage(g,LOG_ERROR, "Not compiled with Ogg Vorbis support"); | |
return 0; | |
#endif | |
} | |
if(g->gFLACFlag) | |
{ | |
#ifdef HAVE_FLAC | |
char FullTitle[1024] = ""; | |
char SongTitle[1024] = ""; | |
char Artist[1024] = ""; | |
char Streamed[1024] = ""; | |
memset(Artist, '\000', sizeof(Artist)); | |
memset(SongTitle, '\000', sizeof(SongTitle)); | |
memset(FullTitle, '\000', sizeof(FullTitle)); | |
memset(Streamed, '\000', sizeof(Streamed)); | |
if(g->flacEncoder) { | |
FLAC__stream_encoder_finish(g->flacEncoder); | |
FLAC__stream_encoder_delete(g->flacEncoder); | |
FLAC__metadata_object_delete(g->flacMetadata); | |
g->flacEncoder = NULL; | |
g->flacMetadata = NULL; | |
} | |
g->flacEncoder = FLAC__stream_encoder_new(); | |
g->flacMetadata = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); | |
FLAC__stream_encoder_set_streamable_subset(g->flacEncoder, false); | |
// FLAC__stream_encoder_set_client_data(g->flacEncoder, (void*)g); | |
FLAC__stream_encoder_set_channels(g->flacEncoder, g->currentChannels); | |
if (g->flacBitDepth == 24) { | |
FLAC__stream_encoder_set_bits_per_sample(g->flacEncoder, 24); | |
} | |
/* | |
FLAC__stream_encoder_set_write_callback(g->flacEncoder,(FLAC__StreamEncoderWriteCallback) FLACWriteCallback, | |
(FLAC__StreamEncoderWriteCallback) FLACWriteCallback); | |
FLAC__stream_encoder_set_metadata_callback(g->flacEncoder, | |
(FLAC__StreamEncoderMetadataCallback) FLACMetadataCallback); | |
*/ | |
srand(time(0)); | |
if(!getLockedMetadataFlag(g)) { | |
FLAC__StreamMetadata_VorbisComment_Entry entry; | |
FLAC__StreamMetadata_VorbisComment_Entry entry3; | |
FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ENCODEDBY", "edcast2"); | |
FLAC__metadata_object_vorbiscomment_append_comment(g->flacMetadata, entry, true); | |
if(strlen(g->sourceDescription) > 0) { | |
FLAC__StreamMetadata_VorbisComment_Entry entry2; | |
FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry2, "TRANSCODEDFROM", g->sourceDescription); | |
FLAC__metadata_object_vorbiscomment_append_comment(g->flacMetadata, entry2, true); | |
} | |
getCurrentSongTitle(g, SongTitle, Artist, FullTitle); | |
FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry3, "TITLE", FullTitle); | |
FLAC__metadata_object_vorbiscomment_append_comment(g->flacMetadata, entry3, true); | |
} | |
FLAC__stream_encoder_set_ogg_serial_number(g->flacEncoder, rand()); | |
FLAC__StreamEncoderInitStatus ret = FLAC__stream_encoder_init_ogg_stream(g->flacEncoder, NULL, (FLAC__StreamEncoderWriteCallback) FLACWriteCallback, NULL, NULL, (FLAC__StreamEncoderMetadataCallback) FLACMetadataCallback, (void*)g); | |
if(ret == FLAC__STREAM_ENCODER_INIT_STATUS_OK) { | |
if(g->serverStatusCallback) { | |
if (g->flacBitDepth == 24) { | |
g->serverStatusCallback(g, (void *) "24 Bit FLAC initialized"); | |
} else { | |
g->serverStatusCallback(g, (void *) "16 Bit FLAC initialized"); | |
} | |
} | |
} | |
else { | |
if(g->serverStatusCallback) { | |
g->serverStatusCallback(g, (void *) "Error Initializing FLAC"); | |
} | |
LogMessage(g,LOG_ERROR, "Error Initializing FLAC"); | |
return 0; | |
} | |
#endif | |
} | |
return 1; | |
} | |
void addToFIFO(edcastGlobals *g, float *samples, int numsamples) { | |
int currentFIFO = g->faacFIFOendpos; | |
for(int i = 0; i < numsamples; i++) { | |
g->faacFIFO[currentFIFO] = samples[i]; | |
currentFIFO++; | |
} | |
g->faacFIFOendpos = currentFIFO; | |
} | |
void FloatScale(float *destination, float *source, int numsamples, int destchannels) { | |
int i; | |
if(destchannels == 2) { | |
for(i = 0; i < numsamples; i++) { | |
*destination++ = *source++ *32767.f; | |
} | |
} | |
else { | |
for(i = 0; i < numsamples >> 1; i++) { | |
*destination++ = (*source++ +*source++) * 16383.f; | |
} | |
} | |
} | |
void ExtractFromFIFO(float *destination, float *source, int numsamples) { | |
for(int i = 0; i < numsamples; i++) { | |
*destination++ = *source++; | |
} | |
} | |
/** | |
* stuff from JACK | |
*/ | |
/* | |
Copyright (C) 2000 Paul Davis | |
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 2 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, write to the Free Software | |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
*/ | |
#define SAMPLE_24BIT_SCALING 8388607.0f | |
#define SAMPLE_24BIT_MAX 8388607 | |
#define SAMPLE_24BIT_MIN -8388607 | |
#define SAMPLE_16BIT_SCALING 32767.0f | |
#define SAMPLE_16BIT_MAX 32767 | |
#define SAMPLE_16BIT_MIN -32767 | |
#define NORMALIZED_FLOAT_MIN -1.0f | |
#define NORMALIZED_FLOAT_MAX 1.0f | |
#define f_round(f) lrintf(f) | |
#define float_24(s, d) \ | |
if ((s) <= NORMALIZED_FLOAT_MIN) {\ | |
(d) = SAMPLE_24BIT_MIN;\ | |
} else if ((s) >= NORMALIZED_FLOAT_MAX) {\ | |
(d) = SAMPLE_24BIT_MAX;\ | |
} else {\ | |
(d) = f_round ((s) * SAMPLE_24BIT_SCALING);\ | |
} | |
#define float_16(s, d)\ | |
if ((s) <= NORMALIZED_FLOAT_MIN) {\ | |
(d) = SAMPLE_16BIT_MIN;\ | |
} else if ((s) >= NORMALIZED_FLOAT_MAX) {\ | |
(d) = SAMPLE_16BIT_MAX;\ | |
} else {\ | |
(d) = f_round ((s) * SAMPLE_16BIT_SCALING);\ | |
} | |
/** | |
* thx | |
*/ | |
int do_encoding(edcastGlobals *g, float *lsamples, float *rsamples, int numsamples, int nch) { | |
g->gCurrentlyEncoding = 1; | |
int s; | |
int count = 0; | |
//unsigned char mp3buffer[LAME_MAXMP3BUFFER]; | |
int imp3; | |
short int *int_samples; | |
int eos = 0; | |
int ret = 0; | |
int sentbytes = 0; | |
char buf[255] = ""; | |
g->gCurrentlyEncoding = 1; | |
if(g->weareconnected) { | |
s = numsamples * nch; | |
long leftMax = 0; | |
long rightMax = 0; | |
int samplecounter = 0; | |
/* | |
LogMessage(g,LOG_DEBUG, "determining left/right max..."); | |
for(int i = 0; i < numsamples * 2; i = i + 2) { | |
leftMax += abs((int) ((float) samples[i] * 32767.f)); | |
rightMax += abs((int) ((float) samples[i + 1] * 32767.f)); | |
} | |
if(numsamples > 0) { | |
leftMax = leftMax / (numsamples * 2); | |
rightMax = rightMax / (numsamples * 2); | |
if(g->VUCallback) { | |
g->VUCallback(leftMax, rightMax); | |
} | |
} | |
*/ | |
if(g->gOggFlag) | |
{ | |
#ifdef HAVE_VORBIS | |
/* | |
* If a song change was detected, close the stream and resend new ; | |
* vorbis headers (with new comments) - all done by icecast2SendMetadata(); | |
*/ | |
if(g->ice2songChange) { | |
LogMessage(g,LOG_DEBUG, "Song change processing..."); | |
g->ice2songChange = false; | |
icecast2SendMetadata(g); | |
} | |
//LogMessage(g,LOG_DEBUG, "vorbis_analysis_buffer..."); | |
float **buffer = vorbis_analysis_buffer(&g->vd, numsamples); | |
int samplecount = 0; | |
int i; | |
samplecounter = 0; | |
/* | |
for(i = 0; i < numsamples * 2; i = i + 2) { | |
buffer[0][samplecounter] = samples[i]; | |
if(g->currentChannels == 2) { | |
buffer[1][samplecounter] = samples[i + 1]; | |
} | |
samplecounter++; | |
} | |
*/ | |
memcpy(&buffer[0][0], lsamples, numsamples * 4); | |
memcpy(&buffer[1][0], rsamples, numsamples * 4); | |
//LogMessage(g,LOG_DEBUG, "vorbis_analysis_wrote..."); | |
ret = vorbis_analysis_wrote(&g->vd, numsamples); | |
pthread_mutex_lock(&(g->mutex)); | |
//LogMessage(g,LOG_DEBUG, "ogg_encode_dataout..."); | |
/* Stream out what we just prepared for Vorbis... */ | |
sentbytes = ogg_encode_dataout(g); | |
//LogMessage(g,LOG_DEBUG, "done ogg_ecndoe_dataout..."); | |
pthread_mutex_unlock(&(g->mutex)); | |
#endif | |
} | |
if(g->gAACFlag) | |
{ | |
#ifdef HAVE_FAAC | |
float *buffer = (float *) malloc(numsamples * 2 * sizeof(float)); | |
FloatScale(buffer, samples, numsamples * 2, g->currentChannels); | |
addToFIFO(g, buffer, numsamples * g->currentChannels); | |
while(g->faacFIFOendpos > (int)g->samplesInput) { | |
float *buffer2 = (float *) malloc(g->samplesInput * 2 * sizeof(float)); | |
ExtractFromFIFO(buffer2, g->faacFIFO, g->samplesInput); | |
int counter = 0; | |
for(int i = g->samplesInput; i < g->faacFIFOendpos; i++) { | |
g->faacFIFO[counter] = g->faacFIFO[i]; | |
counter++; | |
} | |
g->faacFIFOendpos = counter; | |
unsigned long dwWrite = 0; | |
unsigned char *aacbuffer = (unsigned char *) malloc(g->maxBytesOutput); | |
imp3 = faacEncEncode(g->aacEncoder, (int32_t *) buffer2, g->samplesInput, aacbuffer, g->maxBytesOutput); | |
if(imp3) { | |
sentbytes = sendToServer(g, g->gSCSocket, (char *) aacbuffer, imp3, CODEC_TYPE); | |
} | |
if(buffer2) { | |
free(buffer2); | |
} | |
if(aacbuffer) { | |
free(aacbuffer); | |
} | |
} | |
if(buffer) { | |
free(buffer); | |
} | |
#endif | |
} | |
if(g->gAACPFlag) | |
{ | |
#ifdef HAVE_AACP | |
static char outbuffer[32768]; | |
static char inbuffer[32768]; | |
static int inbufferused = 0; | |
int len = numsamples * g->currentChannels * sizeof(short); | |
int_samples = (short *) malloc(len); | |
int samplecount = 0; | |
if(g->currentChannels == 1) { | |
for(int i = 0; i < numsamples * 2; i = i + 2) { | |
int_samples[samplecount] = (short int) (samples[i] * 32767.0); | |
samplecount++; | |
} | |
} | |
else { | |
for(int i = 0; i < numsamples * 2; i++) { | |
int_samples[i] = (short int) (samples[i] * 32767.0); | |
samplecount++; | |
} | |
} | |
char *bufcounter = (char *) int_samples; | |
for(;;) { | |
int in_used = 0; | |
if(len <= 0) break; | |
int enclen = g->aacpEncoder->Encode(in_used, bufcounter, len, &in_used, outbuffer, sizeof(outbuffer)); | |
if(enclen > 0) { | |
sentbytes = sendToServer(g, g->gSCSocket, (char *) outbuffer, enclen, CODEC_TYPE); | |
} | |
else { | |
break; | |
} | |
if(in_used > 0) { | |
bufcounter += in_used; | |
len -= in_used; | |
} | |
} | |
if(int_samples) { | |
free(int_samples); | |
} | |
#endif | |
} | |
if(g->gLAMEFlag) | |
{ | |
#ifdef HAVE_LAME | |
/* Lame encoding is simple, we are passing it interleaved samples | |
int_samples = (short int *) malloc(numsamples * 2 * sizeof(short int)); | |
int samplecount = 0; | |
if(g->currentChannels == 1) { | |
for(int i = 0; i < numsamples * 2; i = i + 2) { | |
int_samples[samplecount] = (int) (samples[i] * 32767.0); | |
samplecount++; | |
} | |
} | |
else { | |
for(int i = 0; i < numsamples * 2; i++) { | |
int_samples[i] = (int) (samples[i] * 32767.0); | |
samplecount++; | |
} | |
} | |
sample_t *samples_left; | |
sample_t *samples_right; | |
samples_left = (sample_t *) malloc(numsamples * (sizeof(float))); | |
samples_right = (sample_t *) malloc(numsamples * (sizeof(sample_t))); | |
*/ | |
// lame sucks, not even actually float | |
for(int i = 0; i < numsamples; i++) { | |
g->samples_left[i] = lsamples[i] * 32767.0; | |
g->samples_right[i] = rsamples[i] * 32767.0; | |
} | |
imp3 = lame_encode_buffer_float(g->gf, | |
g->samples_left, | |
g->samples_right, | |
numsamples, | |
g->mp3buffer, | |
LAME_MAXMP3BUFFER); | |
/* | |
if(samples_left) { | |
free(samples_left); | |
} | |
if(samples_right) { | |
free(samples_right); | |
} | |
*/ | |
//if(int_samples) { | |
// free(int_samples); | |
//} | |
if(imp3 == -1) { | |
LogMessage(g,LOG_ERROR, "mp3 buffer is not big enough!"); | |
return -1; | |
} | |
/* Send out the encoded buffer */ | |
sentbytes = sendToServer(g, g->gSCSocket, (char *) g->mp3buffer, imp3, CODEC_TYPE); | |
#endif | |
} | |
if(g->gFLACFlag) | |
{ | |
#ifdef HAVE_FLAC | |
int i, ix = 0; | |
FLAC__int32 smp[2]; | |
if (g->flacBitDepth == 24) { | |
for (i = 0; i < numsamples; i++) { | |
float_24(lsamples[i], g->int32_samples[ix]); | |
ix++; | |
float_24(rsamples[i], g->int32_samples[ix]); | |
ix++; | |
} | |
} else { | |
for (i = 0; i < numsamples; i++) { | |
float_16(lsamples[i], g->int32_samples[ix]); | |
ix++; | |
float_16(rsamples[i], g->int32_samples[ix]); | |
ix++; | |
} | |
} | |
FLAC__stream_encoder_process_interleaved(g->flacEncoder, g->int32_samples, numsamples); | |
sentbytes = (g->flacFailure) ? 0 : 1; | |
#endif | |
} | |
/* | |
* Generic error checking, if there are any socket problems, the trigger ; | |
* a disconnection handling->.. | |
*/ | |
if(sentbytes < 0) { | |
int rret = triggerDisconnect(g); | |
if (rret == 0) { | |
return 0; | |
} | |
} | |
} | |
g->gCurrentlyEncoding = 0; | |
return 1; | |
} | |
int triggerDisconnect(edcastGlobals *g) { | |
char buf[2046] = ""; | |
disconnectFromServer(g); | |
if(g->gForceStop) { | |
g->gForceStop = 0; | |
return 0; | |
} | |
sprintf(buf, "Disconnected from server"); | |
g->forcedDisconnect = true; | |
g->forcedDisconnectSecs = time(&(g->forcedDisconnectSecs)); | |
g->serverStatusCallback(g, (void *) buf); | |
return 1; | |
} | |
void config_read(edcastGlobals *g) { | |
strcpy(g->gAppName, "edcast"); | |
char buf[255] = ""; | |
char desc[1024] = ""; | |
#ifdef XMMS_PLUGIN | |
sprintf(desc, "This is the named pipe used to communicate with the XMMS effect plugin. Make sure it matches the settings in that plugin"); | |
GetConfigVariable(g, g->gAppName, "SourceURL", "/tmp/edcastFIFO", g->gSourceURL, sizeof(g->gSourceURL), desc); | |
#else | |
sprintf(desc, "The source URL for the broadcast. It must be in the form http://server:port/mountpoint. For those servers without a mountpoint (Shoutcast) use http://server:port."); | |
GetConfigVariable(g, g->gAppName, "SourceURL", "http://localhost/", g->gSourceURL, sizeof(g->gSourceURL), desc); | |
#endif | |
if(g->sourceURLCallback) { | |
g->sourceURLCallback(g, (char *) g->gSourceURL); | |
} | |
sprintf(desc, "Destination server details (to where you are encoding). Valid server types : Shoutcast, Icecast, Icecast2"); | |
GetConfigVariable(g, g->gAppName, "ServerType", "Icecast2", g->gServerType, sizeof(g->gServerType), desc); | |
// sprintf(desc, "The server to which the stream is sent. It can be a hostname or IP (example: www.stream.com, 192.168.1.100)"); | |
GetConfigVariable(g, g->gAppName, "Server", "localhost", g->gServer, sizeof(g->gServer), NULL); | |
// sprintf(desc, "The port to which the stream is sent. Must be a number (example: 8000)"); | |
GetConfigVariable(g, g->gAppName, "Port", "8000", g->gPort, sizeof(g->gPort), NULL); | |
// sprintf(desc, "This is the encoder password for the destination server (example: hackme)"); | |
GetConfigVariable(g, g->gAppName, "ServerPassword", "changemenow", g->gPassword, sizeof(g->gPassword), NULL); | |
// sprintf(desc,"Used for Icecast/Icecast2 servers, The mountpoint must end in .ogg for Vorbis streams and have NO extention for MP3 streams. If you are sending to a Shoutcast server, this MUST be blank. (example: /mp3, /myvorbis.ogg)"); | |
GetConfigVariable(g, g->gAppName, "ServerMountpoint", "/stream.ogg", g->gMountpoint, sizeof(g->gMountpoint), NULL); | |
// sprintf(desc,"This setting tells the destination server to list on any available YP listings. Not all servers support this (Shoutcast does, Icecast2 doesn't) (example: 1 for YES, 0 for NO)"); | |
sprintf(desc,"YP (Stream Directory) Settings"); | |
g->gPubServ = GetConfigVariableLong(g, g->gAppName, "ServerPublic", 1, desc); | |
// sprintf(desc, "This is used in the YP listing, I think only Shoutcast supports this (example: #mystream)"); | |
GetConfigVariable(g, g->gAppName, "ServerIRC", "", g->gServIRC, sizeof(g->gServIRC), NULL); | |
// sprintf(desc, "This is used in the YP listing, I think only Shoutcast supports this (example: myAIMaccount)"); | |
GetConfigVariable(g, g->gAppName, "ServerAIM", "", g->gServAIM, sizeof(g->gServAIM), NULL); | |
// sprintf(desc, "This is used in the YP listing, I think only Shoutcast supports this (example: 332123132)"); | |
GetConfigVariable(g, g->gAppName, "ServerICQ", "", g->gServICQ, sizeof(g->gServICQ), NULL); | |
// sprintf(desc, "The URL that is associated with your stream. (example: http://www.mystream.com)"); | |
GetConfigVariable(g, g->gAppName, "ServerStreamURL", "http://www.oddsock.org", g->gServURL, sizeof(g->gServURL), NULL); | |
// sprintf(desc, "The Stream Name"); | |
GetConfigVariable(g, g->gAppName, "ServerName", "This is my server name", g->gServName, sizeof(g->gServName), NULL); | |
// sprintf(desc, "A short description of the stream (example: Stream House on Fire!)"); | |
GetConfigVariable(g, g->gAppName, "ServerDescription", "This is my server description", g->gServDesc, sizeof(g->gServDesc), NULL); | |
// sprintf(desc, "Genre of music, can be anything you want... (example: Rock)"); | |
GetConfigVariable(g, g->gAppName, "ServerGenre", "Rock", g->gServGenre, sizeof(g->gServGenre), NULL); | |
// sprintf(desc,"Wether or not edcast will reconnect if it is disconnected from the destination server (example: 1 for YES, 0 for NO)"); | |
sprintf(desc,"Misc encoder properties"); | |
g->gAutoReconnect = GetConfigVariableLong(g, g->gAppName, "AutomaticReconnect", 1, desc); | |
// sprintf(desc, "How long it will wait (in seconds) between reconnect attempts. (example: 10)"); | |
g->gReconnectSec = GetConfigVariableLong(g, g->gAppName, "AutomaticReconnectSecs", 10, NULL); | |
g->autoconnect = GetConfigVariableLong(g, g->gAppName, "AutoConnect", 0, NULL); | |
// sprintf(desc, "What format to encode to. Valid values are (OGG, LAME) (example: OGG, LAME)"); | |
sprintf(desc, "Output codec selection (Valid selections : MP3, OggVorbis, Ogg FLAC, AAC, AAC Plus)"); | |
GetConfigVariable(g, g->gAppName, "Encode", "OggVorbis", g->gEncodeType, sizeof(g->gEncodeType), desc); | |
if(!strncmp(g->gEncodeType, "MP3", 3)) { | |
/* LAME */ | |
g->gAACPFlag = 0; | |
g->gOggFlag = 0; | |
g->gLAMEFlag = 1; | |
g->gAACFlag = 0; | |
g->gFLACFlag = 0; | |
} | |
if(!strncmp(g->gEncodeType, "AAC Plus", 8)) { | |
/* AAC */ | |
g->gOggFlag = 0; | |
g->gLAMEFlag = 0; | |
g->gAACFlag = 0; | |
g->gAACPFlag = 1; | |
g->gFLACFlag = 0; | |
} | |
if(!strcmp(g->gEncodeType, "AAC")) { | |
/* AAC */ | |
g->gAACPFlag = 0; | |
g->gOggFlag = 0; | |
g->gLAMEFlag = 0; | |
g->gAACFlag = 1; | |
g->gFLACFlag = 0; | |
} | |
if(!strcmp(g->gEncodeType, "OggVorbis")) { | |
/* OggVorbis */ | |
g->gOggFlag = 1; | |
g->gAACPFlag = 0; | |
g->gLAMEFlag = 0; | |
g->gAACFlag = 0; | |
g->gFLACFlag = 0; | |
} | |
if(!strcmp(g->gEncodeType, "Ogg FLAC")) { | |
/* OggVorbis */ | |
g->gOggFlag = 0; | |
g->gAACPFlag = 0; | |
g->gLAMEFlag = 0; | |
g->gAACFlag = 0; | |
g->gFLACFlag = 1; | |
} | |
if(g->streamTypeCallback) { | |
if(g->gOggFlag) { | |
g->streamTypeCallback(g, (void *) "OggVorbis"); | |
} | |
if(g->gLAMEFlag) { | |
g->streamTypeCallback(g, (void *) "MP3"); | |
} | |
if(g->gAACFlag) { | |
g->streamTypeCallback(g, (void *) "AAC"); | |
} | |
if(g->gAACPFlag) { | |
g->streamTypeCallback(g, (void *) "AAC+"); | |
} | |
if(g->gFLACFlag) { | |
g->streamTypeCallback(g, (void *) "OggFLAC"); | |
} | |
} | |
if(g->destURLCallback) { | |
sprintf(buf, "http://%s:%s%s", g->gServer, g->gPort, g->gMountpoint); | |
g->destURLCallback(g, (char *) buf); | |
} | |
// sprintf(desc, "Bitrate. This is the mean bitrate if using VBR."); | |
sprintf(desc, "General settings (non-codec related). Note : NumberChannels = 1 for MONO, 2 for STEREO"); | |
g->currentBitrate = GetConfigVariableLong(g, g->gAppName, "BitrateNominal", 128, desc); | |
// sprintf(desc,"Minimum Bitrate. Used only if using Bitrate Management (not recommended) or LAME VBR(example: 64, 128)"); | |
g->currentBitrateMin = GetConfigVariableLong(g, g->gAppName, "BitrateMin", 128, NULL); | |
// sprintf(desc,"Maximum Bitrate. Used only if using Bitrate Management (not recommended) or LAME VBR (example: 64, 128)"); | |
g->currentBitrateMax = GetConfigVariableLong(g, g->gAppName, "BitrateMax", 128, NULL); | |
// sprintf(desc, "Number of channels. Valid values are (1, 2). 1 means Mono, 2 means Stereo (example: 2,1)"); | |
g->currentChannels = GetConfigVariableLong(g, g->gAppName, "NumberChannels", 2, NULL); | |
// sprintf(desc, "Sample rate for the stream. Valid values depend on wether using lame or vorbis. Vorbis supports odd samplerates such as 32kHz and 48kHz, but lame appears to not.feel free to experiment (example: 44100, 22050, 11025)"); | |
g->currentSamplerate = GetConfigVariableLong(g, g->gAppName, "Samplerate", 44100, NULL); | |
// sprintf(desc, "Vorbis Quality Level. Valid values are between -1 (lowest quality) and 10 (highest). The lower the quality the lower the output bitrate. (example: -1, 3)"); | |
sprintf(desc, "Ogg Vorbis specific settings. Note: Valid settings for BitrateQuality flag are (Quality, Bitrate Management)"); | |
GetConfigVariable(g, g->gAppName, "OggQuality", "0", g->gOggQuality, sizeof(g->gOggQuality), desc); | |
// sprintf(desc,"This flag specifies if you want Vorbis Quality or Bitrate Management. Quality is always recommended. Valid values are (Bitrate, Quality). (example: Quality, Bitrate Management)"); | |
GetConfigVariable(g, g->gAppName, "OggBitrateQualityFlag", "Quality", g->gOggBitQual, sizeof(g->gOggBitQual), NULL); | |
g->gOggBitQualFlag = 0; | |
if(!strncmp(g->gOggBitQual, "Q", 1)) { | |
/* Quality */ | |
g->gOggBitQualFlag = 0; | |
} | |
if(!strncmp(g->gOggBitQual, "B", 1)) { | |
/* Bitrate */ | |
g->gOggBitQualFlag = 1; | |
} | |
g->gAutoCountdown = atoi(g->gAutoStartSec); | |
if(strlen(g->gMountpoint) > 0) { | |
strcpy(g->gIceFlag, "1"); | |
} | |
else { | |
strcpy(g->gIceFlag, "0"); | |
} | |
char tempString[255] = ""; | |
memset(tempString, '\000', sizeof(tempString)); | |
ReplaceString(g->gServer, tempString, " ", ""); | |
strcpy(g->gServer, tempString); | |
memset(tempString, '\000', sizeof(tempString)); | |
ReplaceString(g->gPort, tempString, " ", ""); | |
strcpy(g->gPort, tempString); | |
// sprintf(desc,"This LAME flag indicates that CBR encoding is desired. If this flag is set then LAME with use CBR, if not set then it will use VBR (and you must then specify a VBR mode). Valid values are (1 for SET, 0 for NOT SET) (example: 1)"); | |
sprintf(desc,"LAME specific settings. Note: Setting the low/highpass freq to 0 will disable them."); | |
g->gLAMEOptions.cbrflag = GetConfigVariableLong(g, g->gAppName, "LameCBRFlag", 1, desc); | |
// sprintf(desc,"A number between 1 and 10 which indicates the desired quality level of the stream. The higher the number, the higher the quality. Also, the higher the number, the higher the CPU utilization. So for slower CPUs, try a low quality number (example: 5)"); | |
g->gLAMEOptions.quality = GetConfigVariableLong(g, g->gAppName, "LameQuality", 1, NULL); | |
// sprintf(desc, "Copywrite flag-> Not used for much. Valid values (1 for YES, 0 for NO)"); | |
g->gLAMEOptions.copywrite = GetConfigVariableLong(g, g->gAppName, "LameCopywrite", 0, NULL); | |
// sprintf(desc, "Original flag-> Not used for much. Valid values (1 for YES, 0 for NO)"); | |
g->gLAMEOptions.original = GetConfigVariableLong(g, g->gAppName, "LameOriginal", 0, NULL); | |
// sprintf(desc, "Strict ISO flag-> Not used for much. Valid values (1 for YES, 0 for NO)"); | |
g->gLAMEOptions.strict_ISO = GetConfigVariableLong(g, g->gAppName, "LameStrictISO", 0, NULL); | |
// sprintf(desc, "Disable Reservior flag-> Not used for much. Valid values (1 for YES, 0 for NO)"); | |
g->gLAMEOptions.disable_reservoir = GetConfigVariableLong(g, g->gAppName, "LameDisableReservior", 0, NULL); | |
// sprintf(desc, "This specifies the type of VBR encoding LAME will perform if VBR encoding is set (CBRFlag is NOT SET). See the LAME documention for more on what these mean. Valid values are (vbr_rh, vbr_mt, vbr_mtrh, vbr_abr)"); | |
GetConfigVariable(g, g->gAppName, "LameVBRMode", "vbr_abr", g->gLAMEOptions.VBR_mode, sizeof(g->gLAMEOptions.VBR_mode), NULL); | |
// sprintf(desc, "Use LAMEs lowpass filter. If you set this to 0, then no filtering is done."); | |
g->gLAMEOptions.lowpassfreq = GetConfigVariableLong(g, g->gAppName, "LameLowpassfreq", 0, NULL); | |
// sprintf(desc, "Use LAMEs highpass filter. If you set this to 0, then no filtering is done."); | |
g->gLAMEOptions.highpassfreq = GetConfigVariableLong(g, g->gAppName, "LameHighpassfreq", 0, NULL); | |
if(g->gLAMEOptions.lowpassfreq > 0) { | |
g->gLAMELowpassFlag = 1; | |
} | |
if(g->gLAMEOptions.highpassfreq > 0) { | |
g->gLAMELowpassFlag = 1; | |
} | |
sprintf(desc, "LAME Preset"); | |
int defaultPreset = 0; | |
#ifdef WIN32 | |
defaultPreset = LQP_NOPRESET; | |
#endif | |
g->gLAMEpreset = GetConfigVariableLong(g, g->gAppName, "LAMEPreset", defaultPreset, NULL); | |
sprintf(desc, "AAC (FAAC) specific settings."); | |
// sprintf(desc, "AAC Quality Level. Valid values are between 10 (lowest quality) and 500 (highest)."); | |
GetConfigVariable(g, g->gAppName, "AACQuality", "100", g->gAACQuality, sizeof(g->gAACQuality), desc); | |
// sprintf(desc, "AAC Cutoff Frequency."); | |
GetConfigVariable(g, g->gAppName, "AACCutoff", "", g->gAACCutoff, sizeof(g->gAACCutoff), NULL); | |
if(!strcmp(g->gServerType, "KasterBlaster")) { | |
g->gShoutcastFlag = 1; | |
g->gIcecastFlag = 0; | |
g->gIcecast2Flag = 0; | |
} | |
if(!strcmp(g->gServerType, "Shoutcast")) { | |
g->gShoutcastFlag = 1; | |
g->gIcecastFlag = 0; | |
g->gIcecast2Flag = 0; | |
} | |
if(!strcmp(g->gServerType, "Icecast")) { | |
g->gShoutcastFlag = 0; | |
g->gIcecastFlag = 1; | |
g->gIcecast2Flag = 0; | |
} | |
if(!strcmp(g->gServerType, "Icecast2")) { | |
g->gShoutcastFlag = 0; | |
g->gIcecastFlag = 0; | |
g->gIcecast2Flag = 1; | |
} | |
if(g->serverTypeCallback) { | |
g->serverTypeCallback(g, (void *) g->gServerType); | |
} | |
if(g->serverNameCallback) { | |
char *pdata = NULL; | |
int pdatalen = strlen(g->gServDesc) + strlen(g->gServName) + strlen(" () ") + 1; | |
pdata = (char *) calloc(1, pdatalen); | |
sprintf(pdata, "%s (%s)", g->gServName, g->gServDesc); | |
g->serverNameCallback(g, (void *) pdata); | |
free(pdata); | |
} | |
sprintf(desc, "If recording from linein, what device to use (not needed for win32) (example: /dev/dsp)"); | |
GetConfigVariable(g, g->gAppName, "AdvRecDevice", "/dev/dsp", buf, sizeof(buf), desc); | |
strcpy(g->gAdvRecDevice, buf); | |
sprintf(desc, "If recording from linein, what sample rate to open the device with. (example: 44100, 48000)"); | |
GetConfigVariable(g, g->gAppName, "LiveInSamplerate", "44100", buf, sizeof(buf), desc); | |
g->gLiveInSamplerate = atoi(buf); | |
sprintf(desc, "Used for any window positions (X value)"); | |
g->lastX = GetConfigVariableLong(g, g->gAppName, "lastX", 0, desc); | |
sprintf(desc, "Used for any window positions (Y value)"); | |
g->lastY = GetConfigVariableLong(g, g->gAppName, "lastY", 0, desc); | |
sprintf(desc, "Used for dummy window positions (X value)"); | |
g->lastDummyX = GetConfigVariableLong(g, g->gAppName, "lastDummyX", 0, desc); | |
sprintf(desc, "Used for dummy window positions (Y value)"); | |
g->lastDummyY = GetConfigVariableLong(g, g->gAppName, "lastDummyY", 0, desc); | |
sprintf(desc, "Used for plugins that show the VU meter"); | |
g->vuShow = GetConfigVariableLong(g, g->gAppName, "showVU", 0, desc); | |
sprintf(desc, "Flag which indicates we are recording from line in"); | |
int lineInDefault = 0; | |
#ifdef ODDCASTSTANDALONE | |
lineInDefault = 1; | |
#endif | |
g->gLiveRecordingFlag = GetConfigVariableLong(g, g->gAppName, "LineInFlag", lineInDefault, desc); | |
sprintf(desc, "Locked Metadata"); | |
GetConfigVariable(g, g->gAppName, "LockMetadata", "", g->gManualSongTitle, sizeof(g->gManualSongTitle), desc); | |
sprintf(desc, "Flag which indicates if we are using locked metadata"); | |
g->gLockSongTitle = GetConfigVariableLong(g, g->gAppName, "LockMetadataFlag", 0, desc); | |
sprintf(desc, "Save directory for archive streams"); | |
GetConfigVariable(g, g->gAppName, "SaveDirectory", "", g->gSaveDirectory, sizeof(g->gSaveDirectory), desc); | |
sprintf(desc, "Flag which indicates if we are saving archives"); | |
g->gSaveDirectoryFlag = GetConfigVariableLong(g, g->gAppName, "SaveDirectoryFlag", 0, desc); | |
sprintf(desc, "Log Level 1 = LOG_ERROR, 2 = LOG_ERROR+LOG_INFO, 3 = LOG_ERROR+LOG_INFO+LOG_DEBUG"); | |
g->gLogLevel = GetConfigVariableLong(g, g->gAppName, "LogLevel", 2, desc); | |
sprintf(desc, "Log File"); | |
GetConfigVariable(g, g->gAppName, "LogFile", defaultLogFileName, g->gLogFile, sizeof(g->gLogFile), desc); | |
setgLogFile(g, g->gLogFile); | |
sprintf(desc, "Save Archives in WAV format"); | |
g->gSaveAsWAV = GetConfigVariableLong(g, g->gAppName, "SaveAsWAV", 0, desc); | |
sprintf(desc, "Append this string to all metadata"); | |
GetConfigVariable(g, g->gAppName, "MetadataAppend", "", g->metadataAppendString, sizeof(g->metadataAppendString), desc); | |
sprintf(desc, | |
"Remove this string (and everything after) from the window title of the window class the metadata is coming from"); | |
GetConfigVariable(g, g->gAppName, "MetadataRemoveAfter", "", g->metadataRemoveStringAfter, sizeof(g->metadataRemoveStringAfter), desc); | |
sprintf(desc,"Remove this string (and everything before) from the window title of the window class the metadata is coming from"); | |
GetConfigVariable(g, g->gAppName, "MetadataRemoveBefore", "", g->metadataRemoveStringBefore, sizeof(g->metadataRemoveStringBefore), desc); | |
sprintf(desc, "Window classname to grab metadata from (uses window title)"); | |
GetConfigVariable(g, g->gAppName, "MetadataWindowClass", "", g->metadataWindowClass, sizeof(g->metadataWindowClass), desc); | |
sprintf(desc, "Indicator which tells edcast to grab metadata from a defined window class"); | |
if (GetConfigVariableLong(g, g->gAppName, "MetadataWindowClassInd", 0, desc)) { | |
g->metadataWindowClassInd = true; | |
} | |
else { | |
g->metadataWindowClassInd = false; | |
} | |
/* Set some derived values */ | |
char localBitrate[255] = ""; | |
char mode[50] = ""; | |
if(g->currentChannels == 1) { | |
strcpy(mode, "Mono"); | |
} | |
if(g->currentChannels == 2) { | |
strcpy(mode, "Stereo"); | |
} | |
if(g->gOggFlag) { | |
if(g->bitrateCallback) { | |
if(g->gOggBitQualFlag == 0) { | |
/* Quality */ | |
sprintf(localBitrate, "Vorbis: Quality %s/%s/%d", g->gOggQuality, mode, g->currentSamplerate); | |
} | |
else { | |
sprintf(localBitrate, "Vorbis: %dkbps/%s/%d", g->currentBitrate, mode, g->currentSamplerate); | |
} | |
g->bitrateCallback(g, (void *) localBitrate); | |
} | |
} | |
if(g->gLAMEFlag) { | |
if(g->bitrateCallback) { | |
if(g->gLAMEOptions.cbrflag) { | |
sprintf(localBitrate, "MP3: %dkbps/%dHz/%s", g->currentBitrate, g->currentSamplerate, mode); | |
} | |
else { | |
sprintf(localBitrate, | |
"MP3: (%d/%d/%d)/%s/%d", | |
g->currentBitrateMin, | |
g->currentBitrate, | |
g->currentBitrateMax, | |
mode, | |
g->currentSamplerate); | |
} | |
g->bitrateCallback(g, (void *) localBitrate); | |
} | |
} | |
if(g->gAACFlag) { | |
if(g->bitrateCallback) { | |
sprintf(localBitrate, "AAC: Quality %s/%dHz/%s", g->gAACQuality, g->currentSamplerate, mode); | |
g->bitrateCallback(g, (void *) localBitrate); | |
} | |
} | |
if(g->gAACPFlag) { | |
if(g->bitrateCallback) { | |
long bitrateLong = g->currentBitrate * 1000; | |
if(bitrateLong >= 64000) { | |
if(g->currentChannels == 2) { | |
strcpy(mode, "Stereo"); | |
} | |
else { | |
strcpy(mode, "Mono"); | |
} | |
} | |
if((bitrateLong <= 48000) && (bitrateLong >= 16000)) { | |
if(g->currentChannels == 2) { | |
strcpy(mode, "Parametric Stereo"); | |
} | |
else { | |
strcpy(mode, "Mono"); | |
} | |
} | |
if(bitrateLong <= 12000) { | |
strcpy(mode, "Mono"); | |
} | |
sprintf(localBitrate, "AAC+V2: %dkbps/%dHz/%s", g->currentBitrate, g->currentSamplerate, mode); | |
g->bitrateCallback(g, (void *) localBitrate); | |
} | |
} | |
if(g->gFLACFlag) { | |
if(g->bitrateCallback) { | |
sprintf(localBitrate, "FLAC: %dHz/%s", g->currentSamplerate, mode); | |
g->bitrateCallback(g, (void *) localBitrate); | |
} | |
} | |
if(g->serverStatusCallback) { | |
//g->serverStatusCallback(g, (void *) "Disconnected"); | |
} | |
sprintf(desc, "Number of encoders to use"); | |
g->gNumEncoders = GetConfigVariableLong(g, g->gAppName, "NumEncoders", 0, desc); | |
sprintf(desc, "Enable external metadata calls (DISABLED, URL, FILE)"); | |
GetConfigVariable(g, g->gAppName, "ExternalMetadata", "DISABLED", g->externalMetadata, sizeof(g->gLogFile), desc); | |
sprintf(desc, "URL to retrieve for external metadata"); | |
GetConfigVariable(g, g->gAppName, "ExternalURL", "", g->externalURL, sizeof(g->externalURL), desc); | |
sprintf(desc, "File to retrieve for external metadata"); | |
GetConfigVariable(g, g->gAppName, "ExternalFile", "", g->externalFile, sizeof(g->externalFile), desc); | |
sprintf(desc, "Interval for retrieving external metadata"); | |
GetConfigVariable(g, g->gAppName, "ExternalInterval", "60", g->externalInterval, sizeof(g->externalInterval), desc); | |
sprintf(desc, "Advanced setting"); | |
GetConfigVariable(g, g->gAppName, "OutputControl", "", g->outputControl, sizeof(g->outputControl), desc); | |
sprintf(desc, "Windows Recording Device"); | |
GetConfigVariable(g, g->gAppName, "WindowsRecDevice", "", buf, sizeof(buf), desc); | |
strcpy(g->WindowsRecDevice, buf); | |
sprintf(desc, "LAME Joint Stereo Flag"); | |
g->LAMEJointStereoFlag = GetConfigVariableLong(g, g->gAppName, "LAMEJointStereo", 1, desc); | |
} | |
void config_write(edcastGlobals *g) { | |
strcpy(g->gAppName, "edcast"); | |
char buf[255] = ""; | |
char desc[1024] = ""; | |
char tempString[1024] = ""; | |
memset(tempString, '\000', sizeof(tempString)); | |
ReplaceString(g->gServer, tempString, " ", ""); | |
strcpy(g->gServer, tempString); | |
memset(tempString, '\000', sizeof(tempString)); | |
ReplaceString(g->gPort, tempString, " ", ""); | |
strcpy(g->gPort, tempString); | |
PutConfigVariable(g, g->gAppName, "SourceURL", g->gSourceURL); | |
PutConfigVariable(g, g->gAppName, "ServerType", g->gServerType); | |
PutConfigVariable(g, g->gAppName, "Server", g->gServer); | |
PutConfigVariable(g, g->gAppName, "Port", g->gPort); | |
PutConfigVariable(g, g->gAppName, "ServerMountpoint", g->gMountpoint); | |
PutConfigVariable(g, g->gAppName, "ServerPassword", g->gPassword); | |
PutConfigVariableLong(g, g->gAppName, "ServerPublic", g->gPubServ); | |
PutConfigVariable(g, g->gAppName, "ServerIRC", g->gServIRC); | |
PutConfigVariable(g, g->gAppName, "ServerAIM", g->gServAIM); | |
PutConfigVariable(g, g->gAppName, "ServerICQ", g->gServICQ); | |
PutConfigVariable(g, g->gAppName, "ServerStreamURL", g->gServURL); | |
PutConfigVariable(g, g->gAppName, "ServerDescription", g->gServDesc); | |
PutConfigVariable(g, g->gAppName, "ServerName", g->gServName); | |
PutConfigVariable(g, g->gAppName, "ServerGenre", g->gServGenre); | |
PutConfigVariableLong(g, g->gAppName, "AutomaticReconnect", g->gAutoReconnect); | |
PutConfigVariableLong(g, g->gAppName, "AutomaticReconnectSecs", g->gReconnectSec); | |
PutConfigVariableLong(g, g->gAppName, "AutoConnect", g->autoconnect); | |
PutConfigVariable(g, g->gAppName, "Encode", g->gEncodeType); | |
PutConfigVariableLong(g, g->gAppName, "BitrateNominal", g->currentBitrate); | |
PutConfigVariableLong(g, g->gAppName, "BitrateMin", g->currentBitrateMin); | |
PutConfigVariableLong(g, g->gAppName, "BitrateMax", g->currentBitrateMax); | |
PutConfigVariableLong(g, g->gAppName, "NumberChannels", g->currentChannels); | |
PutConfigVariableLong(g, g->gAppName, "Samplerate", g->currentSamplerate); | |
PutConfigVariable(g, g->gAppName, "OggQuality", g->gOggQuality); | |
if(g->gOggBitQualFlag) { | |
strcpy(g->gOggBitQual, "Bitrate"); | |
} | |
else { | |
strcpy(g->gOggBitQual, "Quality"); | |
} | |
PutConfigVariable(g, g->gAppName, "OggBitrateQualityFlag", g->gOggBitQual); | |
PutConfigVariableLong(g, g->gAppName, "LameCBRFlag", g->gLAMEOptions.cbrflag); | |
PutConfigVariableLong(g, g->gAppName, "LameQuality", g->gLAMEOptions.quality); | |
PutConfigVariableLong(g, g->gAppName, "LameCopywrite", g->gLAMEOptions.copywrite); | |
PutConfigVariableLong(g, g->gAppName, "LameOriginal", g->gLAMEOptions.original); | |
PutConfigVariableLong(g, g->gAppName, "LameStrictISO", g->gLAMEOptions.strict_ISO); | |
PutConfigVariableLong(g, g->gAppName, "LameDisableReservior", g->gLAMEOptions.disable_reservoir); | |
PutConfigVariable(g, g->gAppName, "LameVBRMode", g->gLAMEOptions.VBR_mode); | |
PutConfigVariableLong(g, g->gAppName, "LameLowpassfreq", g->gLAMEOptions.lowpassfreq); | |
PutConfigVariableLong(g, g->gAppName, "LameHighpassfreq", g->gLAMEOptions.highpassfreq); | |
PutConfigVariableLong(g, g->gAppName, "LAMEPreset", g->gLAMEpreset); | |
PutConfigVariable(g, g->gAppName, "AACQuality", g->gAACQuality); | |
PutConfigVariable(g, g->gAppName, "AACCutoff", g->gAACCutoff); | |
PutConfigVariable(g, g->gAppName, "AdvRecDevice", g->gAdvRecDevice); | |
PutConfigVariableLong(g, g->gAppName, "LiveInSamplerate", g->gLiveInSamplerate); | |
PutConfigVariableLong(g, g->gAppName, "LineInFlag", g->gLiveRecordingFlag); | |
PutConfigVariableLong(g, g->gAppName, "lastX", g->lastX); | |
PutConfigVariableLong(g, g->gAppName, "lastY", g->lastY); | |
PutConfigVariableLong(g, g->gAppName, "lastDummyX", g->lastDummyX); | |
PutConfigVariableLong(g, g->gAppName, "lastDummyY", g->lastDummyY); | |
PutConfigVariableLong(g, g->gAppName, "showVU", g->vuShow); | |
PutConfigVariable(g, g->gAppName, "LockMetadata", g->gManualSongTitle); | |
PutConfigVariableLong(g, g->gAppName, "LockMetadataFlag", g->gLockSongTitle); | |
PutConfigVariable(g, g->gAppName, "SaveDirectory", g->gSaveDirectory); | |
PutConfigVariableLong(g, g->gAppName, "SaveDirectoryFlag", g->gSaveDirectoryFlag); | |
PutConfigVariableLong(g, g->gAppName, "LogLevel", g->gLogLevel); | |
PutConfigVariableLong(g, g->gAppName, "SaveAsWAV", g->gSaveAsWAV); | |
PutConfigVariable(g, g->gAppName, "LogFile", g->gLogFile); | |
PutConfigVariableLong(g, g->gAppName, "NumEncoders", g->gNumEncoders); | |
PutConfigVariable(g, g->gAppName, "ExternalMetadata", g->externalMetadata); | |
PutConfigVariable(g, g->gAppName, "ExternalURL", g->externalURL); | |
PutConfigVariable(g, g->gAppName, "ExternalFile", g->externalFile); | |
PutConfigVariable(g, g->gAppName, "ExternalInterval", g->externalInterval); | |
PutConfigVariable(g, g->gAppName, "OutputControl", g->outputControl); | |
PutConfigVariable(g, g->gAppName, "MetadataAppend", g->metadataAppendString); | |
PutConfigVariable(g, g->gAppName, "MetadataRemoveBefore", g->metadataRemoveStringBefore); | |
PutConfigVariable(g, g->gAppName, "MetadataRemoveAfter", g->metadataRemoveStringAfter); | |
PutConfigVariable(g, g->gAppName, "MetadataWindowClass", g->metadataWindowClass); | |
PutConfigVariableLong(g, g->gAppName, "MetadataWindowClassInd", g->metadataWindowClassInd); | |
PutConfigVariable(g, g->gAppName, "WindowsRecDevice", g->WindowsRecDevice); | |
PutConfigVariableLong(g, g->gAppName, "LAMEJointStereo", g->LAMEJointStereoFlag); | |
} | |
/* | |
======================================================================================================================= | |
Input is in interleaved float samples | |
======================================================================================================================= | |
*/ | |
int handle_output(edcastGlobals *g, float *lsamples, float *rsamples, int nsamples, int nchannels, int in_samplerate) { | |
int ret = 1; | |
static int current_insamplerate = 0; | |
static int current_nchannels = 0; | |
long out_samplerate = 0; | |
long out_nch = 0; | |
int samplecount = 0; | |
float *samplePtr = 0; | |
int in_nch = nchannels; | |
nchannels = 2; | |
//float *samples_resampled = NULL; | |
//short *samples_resampled_int = NULL; | |
//float *samples_rechannel = NULL; | |
if(g == NULL) { | |
return 1; | |
} | |
g->SamplesSinceFlush += nsamples; | |
if(g->weareconnected) { | |
// LogMessage(g,LOG_DEBUG, "%d Calling handle output", g->encoderNumber); | |
out_samplerate = getCurrentSamplerate(g); | |
out_nch = getCurrentChannels(g); | |
/* | |
if (g->gSaveFile) { | |
if(g->gSaveAsWAV) { | |
int sizeofData = nsamples * nchannels * sizeof(short int); | |
short int *int_samples; | |
int_samples = (short int *) malloc(sizeofData); | |
for(int i = 0; i < nsamples * nchannels; i = i + 1) { | |
int_samples[i] = (short int) (samples[i] * 32767.f); | |
} | |
fwrite(int_samples, sizeofData, 1, g->gSaveFile); | |
g->written += sizeofData; | |
free(int_samples); | |
/* | |
* int sizeofData = nsamples*nchannels*sizeof(float); | |
* fwrite(samples, sizeofData, 1, g->gSaveFile); | |
* g->written += sizeofData; | |
* ; | |
* Write to WAV file | |
} | |
} | |
samples_rechannel = (float *) malloc(sizeof(float) * nsamples * nchannels); | |
memset(samples_rechannel, '\000', sizeof(float) * nsamples * nchannels); | |
samplePtr = samples; | |
int make_mono = 0; | |
int make_stereo = 0; | |
if((in_nch == 2) && (out_nch == 1)) { | |
make_mono = 1; | |
} | |
if((in_nch == 1) && (out_nch == 2)) { | |
make_stereo = 1; | |
} | |
if((in_nch == 1) && (out_nch == 1)) { | |
make_stereo = 1; | |
} | |
int samplecounter = 0; | |
if(make_mono) { | |
for(int i = 0; i < nsamples * 2; i = i + 2) { | |
samples_rechannel[i] = (samples[i] + samples[i + 1]) / 2; | |
samples_rechannel[i + 1] = (samples[i] + samples[i + 1]) / 2; | |
} | |
} | |
if(make_stereo) { | |
for(int i = 0; i < nsamples; i = i + 1) { | |
samples_rechannel[samplecounter] = (samples[i]); | |
samplecounter++; | |
samples_rechannel[samplecounter] = (samples[i]); | |
samplecounter++; | |
} | |
} | |
if(!(make_mono) && !(make_stereo)) { | |
for(int i = 0; i < nsamples * 2; i = i + 1) { | |
samples_rechannel[i] = (samples[i]); | |
} | |
} | |
LogMessage(g,LOG_DEBUG, "In samplerate = %d, Out = %d", in_samplerate, out_samplerate); | |
samplePtr = samples_rechannel; | |
*/ | |
LogMessage(g,LOG_DEBUG, "do_encoding start"); | |
ret = do_encoding(g, lsamples, rsamples, nsamples, nchannels); | |
LogMessage(g,LOG_DEBUG, "do_encoding end (%d)", ret); | |
/* | |
if(samples_rechannel) { | |
free(samples_rechannel); | |
samples_rechannel = NULL; | |
} | |
LogMessage(g,LOG_DEBUG, "%d Calling handle output - Ret = %d", g->encoderNumber, ret); | |
*/ | |
} | |
return ret; | |
} | |
void addUISettings(edcastGlobals *g) { | |
addConfigVariable(g, "AutomaticReconnect"); | |
addConfigVariable(g, "AutomaticReconnectSecs"); | |
addConfigVariable(g, "AutoConnect"); | |
addConfigVariable(g, "AdvRecDevice"); | |
addConfigVariable(g, "LiveInSamplerate"); | |
addConfigVariable(g, "LineInFlag"); | |
addConfigVariable(g, "lastX"); | |
addConfigVariable(g, "lastY"); | |
addConfigVariable(g, "lastDummyX"); | |
addConfigVariable(g, "lastDummyY"); | |
addConfigVariable(g, "showVU"); | |
addConfigVariable(g, "LockMetadata"); | |
addConfigVariable(g, "LockMetadataFlag"); | |
addConfigVariable(g, "SaveDirectory"); | |
addConfigVariable(g, "SaveDirectoryFlag"); | |
addConfigVariable(g, "LogLevel"); | |
addConfigVariable(g, "SaveAsWAV"); | |
addConfigVariable(g, "LogFile"); | |
addConfigVariable(g, "NumEncoders"); | |
addConfigVariable(g, "ExternalMetadata"); | |
addConfigVariable(g, "ExternalURL"); | |
addConfigVariable(g, "ExternalFile"); | |
addConfigVariable(g, "ExternalInterval"); | |
addConfigVariable(g, "OutputControl"); | |
addConfigVariable(g, "MetadataAppend"); | |
addConfigVariable(g, "MetadataRemoveBefore"); | |
addConfigVariable(g, "MetadataRemoveAfter"); | |
addConfigVariable(g, "MetadataWindowClass"); | |
addConfigVariable(g, "MetadataWindowClassInd"); | |
addConfigVariable(g, "WindowsRecDevice"); | |
} | |
void addBasicEncoderSettings(edcastGlobals *g) { | |
addConfigVariable(g, "ServerType"); | |
addConfigVariable(g, "Server"); | |
addConfigVariable(g, "Port"); | |
addConfigVariable(g, "ServerMountpoint"); | |
addConfigVariable(g, "ServerPassword"); | |
addConfigVariable(g, "ServerPublic"); | |
addConfigVariable(g, "ServerIRC"); | |
addConfigVariable(g, "ServerAIM"); | |
addConfigVariable(g, "ServerICQ"); | |
addConfigVariable(g, "ServerStreamURL"); | |
addConfigVariable(g, "ServerDescription"); | |
addConfigVariable(g, "ServerName"); | |
addConfigVariable(g, "ServerGenre"); | |
// addConfigVariable(g, "AutomaticReconnect"); | |
addConfigVariable(g, "AutomaticReconnectSecs"); | |
addConfigVariable(g, "AutoConnect"); | |
addConfigVariable(g, "Encode"); | |
addConfigVariable(g, "BitrateNominal"); | |
addConfigVariable(g, "BitrateMin"); | |
addConfigVariable(g, "BitrateMax"); | |
addConfigVariable(g, "NumberChannels"); | |
addConfigVariable(g, "Samplerate"); | |
addConfigVariable(g, "OggQuality"); | |
addConfigVariable(g, "OggBitrateQualityFlag"); | |
addConfigVariable(g, "LameCBRFlag"); | |
addConfigVariable(g, "LameQuality"); | |
addConfigVariable(g, "LameCopywrite"); | |
addConfigVariable(g, "LameOriginal"); | |
addConfigVariable(g, "LameStrictISO"); | |
addConfigVariable(g, "LameDisableReservior"); | |
addConfigVariable(g, "LameVBRMode"); | |
addConfigVariable(g, "LameLowpassfreq"); | |
addConfigVariable(g, "LameHighpassfreq"); | |
addConfigVariable(g, "LAMEPreset"); | |
addConfigVariable(g, "AACQuality"); | |
addConfigVariable(g, "AACCutoff"); | |
addConfigVariable(g, "LogLevel"); | |
addConfigVariable(g, "LogFile"); | |
addConfigVariable(g, "LAMEJointStereo"); | |
addConfigVariable(g, "SaveDirectory"); | |
addConfigVariable(g, "SaveDirectoryFlag"); | |
addConfigVariable(g, "SaveAsWAV"); | |
} | |
void LogMessage(edcastGlobals *g, int type, char *source, int line, char *fmt, ...) { | |
va_list parms; | |
char errortype[25] = ""; | |
int addNewline = 1; | |
struct tm *tp; | |
time_t t; | |
int parseableOutput = 0; | |
char timeStamp[255]; | |
char sourceLine[1024] = ""; | |
char *p1 = NULL; | |
#ifdef WIN32 | |
p1 = strrchr(source, '\\'); | |
#else | |
p1 = strrchr(source, '/'); | |
#endif | |
if (type <= g->gLogLevel) { | |
if (p1) { | |
strcpy(sourceLine, p1+1); | |
} | |
else { | |
strcpy(sourceLine, source); | |
} | |
memset(timeStamp, '\000', sizeof(timeStamp)); | |
time(&t); | |
tp = localtime(&t); | |
strftime(timeStamp, sizeof(timeStamp), "%m/%d/%y %H:%M:%S", tp); | |
switch (type) { | |
case LM_ERROR: | |
strcpy(errortype, "Error"); | |
break; | |
case LM_INFO: | |
strcpy(errortype, "Info"); | |
break; | |
case LM_DEBUG: | |
strcpy(errortype, "Debug"); | |
break; | |
default: | |
strcpy(errortype, "Unknown"); | |
break; | |
} | |
if (fmt[strlen(fmt)-1] == '\n') { | |
addNewline = 0; | |
} | |
va_start(parms, fmt); | |
char_t logfile[1024] = ""; | |
if (g->logFilep == 0) { | |
sprintf(logfile, "%s.log", g->gLogFile); | |
g->logFilep = fopen(logfile, "a"); | |
} | |
if (!g->logFilep) { | |
fprintf(stdout, "Cannot open logfile: %s(%s:%d): ", logfile, sourceLine, line); | |
vfprintf(stdout, fmt, parms); | |
va_end(parms); | |
if (addNewline) { | |
fprintf(stdout, "\n"); | |
} | |
} | |
else { | |
fprintf(g->logFilep, "%s %s(%s:%d): ", timeStamp, errortype, sourceLine, line); | |
vfprintf(g->logFilep, fmt, parms); | |
va_end(parms); | |
if (addNewline) { | |
fprintf(g->logFilep, "\n"); | |
} | |
fflush(g->logFilep); | |
} | |
} | |
} | |
char_t *getWindowsRecordingDevice(edcastGlobals *g) { | |
return g->WindowsRecDevice; | |
} | |
void setWindowsRecordingDevice(edcastGlobals *g, char_t *device) { | |
strcpy(g->WindowsRecDevice, device); | |
} | |
int getLAMEJointStereoFlag(edcastGlobals *g) { | |
return g->LAMEJointStereoFlag; | |
} | |
void setLAMEJointStereoFlag(edcastGlobals *g, int flag) { | |
g->LAMEJointStereoFlag = flag; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment