#include <typeinfo> #include <iostream> #include <time.h> #include "mpluginAudio.h" #include "../../config.h" #include "../convert.h" #include "../MonitorExceptions.h" #include "../MonitorLogging.h" #ifdef HAVE_LIBMP3LAME #include <lame/lame.h> #endif #ifndef WIN32 typedef short SHORT ; #include <dlfcn.h> #else #include <windows.h> #endif using namespace std ; class MonitorAudioPlugInRecorder : public MonitorAudioPlugIn { public: #ifdef HAVE_LIBMP3LAME /** * */ lame_global_flags *gfp ; #endif MonitorAudioPlugInRecorder() { useLame=false ; m_channelNum=0 ; } virtual ~MonitorAudioPlugInRecorder() { #ifdef HAVE_LIBMP3LAME lame_close(gfp) ; gfp=NULL ; #endif } virtual bool InitAudioProcessing(class MonitorConfiguration* configPtr, XMLNode config, int channelNum) { std::string logFile="screen" ; std::string logLevel="DEBUG" ; XMLNode parameters ; m_channelNum=channelNum; if (!((parameters=config.getChildNode("parameters"))).isEmpty()) { m_filePath=getNodeText(parameters,"path","./") ; logFile=getNodeText(parameters,"logfile","screen") ; logLevel=getNodeText(parameters,"loglevel","INFO") ; } // TODO log4cxx #ifdef WIN32 if (!(logFile=="screen")) { FILE* pFile = fopen(logFile.c_str(), "a"); Output2FILE::Stream() = pFile; } FILELog::ReportingLevel() = FILELog::FromString(logLevel); LOG_INFO("logging started") #endif #ifdef HAVE_LIBMP3LAME try { LOG_INFO("enabling lame mp3 support") LOG_INFO("Using MP3Lame Lib Version: " << get_lame_version()) gfp=lame_init() ; if (gfp==NULL) { ThrowMonitorException("Error initializing lame library!") ; } lame_set_bWriteVbrTag(gfp,0) ; // Kein ID3 Tag lame_mp3_tags_fid(gfp,NULL) ; lame_set_num_channels(gfp,1) ; lame_set_in_samplerate(gfp,22050) ; lame_set_brate(gfp,32) ; lame_set_mode(gfp,MONO) ; lame_set_quality(gfp,7) ; int retCode = lame_init_params(gfp) ; if (retCode<0) { ThrowMonitorException("LIBMP3Lame init failed") ; }else{ useLame=1 ; } } catch (MonitorException e) { LOG_ERROR(e.what()) } #endif return true ; } virtual void Show() { LOG_INFO("MonitorAudioPluginRecorder successfully loaded") } virtual void WriteRAWToFile (FILE *pFile,SHORT buffer[],unsigned int bufferSize) { size_t len=fwrite(buffer, sizeof(SHORT), bufferSize,pFile); if (len!=bufferSize) { LOG_ERROR("Fehler beim Schreiben: " << len << " statt " << bufferSize) // Fehler beim Schreiben ? } } virtual void WriteMP3ToFile (FILE *pFile,unsigned char buffer[],unsigned int bufferSize) { size_t len=fwrite(buffer, sizeof(unsigned char), bufferSize,pFile); if (len!=bufferSize) { LOG_ERROR("Fehler beim Schreiben: " << len << " statt " << bufferSize) // Fehler beim Schreiben ? } } virtual void ProcessAudio(float *buffer, int length) { const int MAXTEMP=20000 ; int jobID=0 ; int retCode=0 ; // LIB_MP3Lame encoding return code static SHORT tempBuf[MAXTEMP] ; static unsigned char mp3Buffer[2*MAXTEMP] ; unsigned int tempBufCounter=0 ; FILE* pFile=NULL ; time_t startTime ; if (length>MAXTEMP) { ThrowMonitorException ("Audiobuffer size exceeds temporary buffer size!") ; } //if (m_bRecording) { for (int i=0;i<length;i++) { tempBuf[tempBufCounter++]=(SHORT)((*buffer)*32768.0) ; buffer++; } #ifdef HAVE_LIBMP3LAME if (useLame==1) { retCode=lame_encode_buffer(gfp,tempBuf,NULL,length,mp3Buffer,0) ; if (retCode<0) { ThrowMonitorException("Error while lame (mp3) encoding") ; } } #endif for (jobID=0;jobID<MAXAUDIOCLIENTS;jobID++) { pFile=(FILE*) getCustomValue(jobID); unsigned long seconds = getInfo(jobID) ; SocketThread* pClient=getClient(jobID) ; startTime=getTime1(jobID) ; if ((pFile) && (pClient)) { // if (useLame==1) { WriteMP3ToFile(pFile,mp3Buffer,retCode) ; } else { WriteRAWToFile(pFile,tempBuf,tempBufCounter) ; } time_t curTime=time(NULL) ; if ( (curTime-startTime)>(time_t) seconds) { StopRecording(jobID) ; } } } } } void StartRecording(int jobID,std::string fname,int Sekunden) { LOG_INFO("Starte Aufnahme ..") // Aufnahmedatei erzeugen LOG_INFO("Starte mit dauer:" << Sekunden) if (fname.size()>0) { // Dateiname wurde vorgegeben } else { fname="kein_datename" ; } FILE * f_File = fopen(fname.c_str(), "wb"); if(f_File==NULL) { LOG_ERROR("File ist NICHT erstellt") } else { LOG_ERROR("File ist erstellt"<< fname) } // Aufnahme starten, Daten beim Job hinterlegen updateClient(jobID, (unsigned long) f_File, 0, Sekunden, fname, time(NULL)) ; addThreadMessage(jobID,std::string("104:" +convertIntToString(m_channelNum)+ ":1:") + convertStringToHex(fname)) ; } void StopRecording(int jobID) { LOG_INFO("Aufnahme beendet") FILE* pFile=(FILE*) getCustomValue(jobID) ; std::string fname=getInfoText(jobID) ; fclose(pFile) ; addThreadMessage(jobID,std::string("104:" +convertIntToString(m_channelNum)+ ":0:") + convertStringToHex(fname)) ; clearClient(jobID) ; } virtual std::string DoCommand(std::string command, SocketThread* pClient) { std::string resultString="" ; std::string fname ; int Sekunden=0 ; LOG_INFO("Kommando: " << command) parseCommand(command) ; for (int i=0;i<10;i++) { LOG_INFO("Param " << i << ":" << m_param[i]) } if (m_param[0]=="RECORD") //RECORD:<zeit> { if (m_paramCount>1) { try { Sekunden=convertToInt(m_param[1]) ; LOG_INFO("Sekunden als param:" << m_param[1]) LOG_INFO("Sekunden als int:" << Sekunden) } catch (BadConversion e) { LOG_ERROR("Fehler bei der Datenkonvertierung " << m_param[1]) Sekunden=60 ; } } int jobID=addClient(pClient) ; //< Auftraggeber, fuer callback mit Result LOG_INFO("jobID=" << jobID) // Laeuft mit der jobID schon eine Aufzeichnung ? // Wenn, dann keine neue starten, sondern nur verlaengern long SekundenAlterJob = getInfo(jobID) ; LOG_INFO("Zeitdauer alte Aufnahme:" << SekundenAlterJob) if (SekundenAlterJob>0) { // Nur die Zeit anpassen time_t curTime=time(NULL) ; time_t startTime=getTime1(jobID) ; LOG_DEBUG("Zeiten curTime+Sekunden:" << curTime+Sekunden) LOG_DEBUG("Zeiten startTime+SekundenAlterJob:" << startTime+SekundenAlterJob) if (curTime+Sekunden>startTime+SekundenAlterJob) { fname=getInfoText(jobID) ; Sekunden=curTime+Sekunden-startTime ; LOG_INFO("Aufnahme wird auf " << Sekunden << "verlaengert ") updateClient(jobID,getCustomValue(jobID),0,Sekunden,getInfoText(jobID),startTime) ; addThreadMessage(jobID,std::string("104:" +convertIntToString(m_channelNum)+ ":2:") + convertStringToHex(fname)) ; } } else { time_t m_startTime=time(NULL) ; struct tm *strTime = localtime(&m_startTime) ; char zeitString[60] ; sprintf(zeitString,"%04d%02d%02d%02d%02d%02d", 1900+strTime->tm_year, 1+strTime->tm_mon, strTime->tm_mday, strTime->tm_hour, strTime->tm_min, strTime->tm_sec) ; LOG_DEBUG(zeitString) if (m_paramCount<2) { m_param[2]="X" ; } fname= m_filePath + std::string(zeitString) + "_" + m_param[2] + "_"+ convertIntToString(jobID) ; cout << fname << endl ; if (useLame==1) { fname+=".mp3"; ; } else { fname+=".raw"; ; } StartRecording(jobID,fname,Sekunden) ; } } ; resultString="OK" ; return (resultString) ; } protected: std::string m_filePath ; int useLame ; int m_channelNum ; }; class MonitorAudioPlugInRecorderFactory : public MonitorAudioPlugInFactory { public: MonitorAudioPlugInRecorderFactory() { } ~MonitorAudioPlugInRecorderFactory() { } virtual MonitorAudioPlugIn * CreatePlugIn() { return new MonitorAudioPlugInRecorder; } }; // // The "C" linkage factory0() function creates the PlugInFunFactory // class for this library // DLL_EXPORT void * factory0( void ) { return new MonitorAudioPlugInRecorderFactory; }