r2670 - in trunk: libminisip libminisip/include
libminisip/include/libminisip/mediahandler
libminisip/source/mediahandler minisip/minisip/gui/gtkgui
Cesc
cesc.santa at gmail.com
Sun Jul 2 16:41:04 CEST 2006
I forgot to mention ... the call record can be st arted and stopped
... and all is saved on to the same file ...
I'll go test the stuff ...
On 7/2/06, cesc at minisip.org <cesc at minisip.org> wrote:
> Author: cesc
> Date: 2006-07-02 16:35:38 +0200 (Sun, 02 Jul 2006)
> New Revision: 2670
> Log:
> NEW Feature: Call Recording
> It allows to record each call separately to a file.
> It does so on a 2 channel, 8Khz, 16 bit, raw file. Each side of the call (incoming and
> outgoing audio) is recorded separately to a channel (it is clearer to listen than if everything
> was mixed).
>
> By hooking a CallRecorder object into the MediaStreamReceiver and the SoundCallBacks.
> It uses the FileSoundDevice to write the recorded call to a file.
> There is a new button on the GTK gui (a red circle, next to the silence headset and microphone).
>
> BTW, it needs testing and improvement ... I'll do it in the coming days. But it already works ... with some perks :)
>
> Cesc
>
>
>
> Modified: trunk/libminisip/Makefile.am
> ===================================================================
> --- trunk/libminisip/Makefile.am 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/Makefile.am 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -84,6 +84,7 @@
> source/mediahandler/AudioPlugin.cxx \
> source/mediahandler/AudioPlugin.h \
> source/mediahandler/SessionRegistry.cxx \
> + source/mediahandler/CallRecorder.cxx \
> source/mediahandler/DtmfSender.cxx
>
> if P2T_SUPPORT
>
> Modified: trunk/libminisip/include/Makefile.am
> ===================================================================
> --- trunk/libminisip/include/Makefile.am 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/include/Makefile.am 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -16,6 +16,7 @@
> libminisip/mediahandler/MediaHandler.h \
> libminisip/mediahandler/Media.h \
> libminisip/mediahandler/Session.h \
> + libminisip/mediahandler/CallRecorder.h \
> libminisip/p2t/SipDialogP2Tuser.h \
> libminisip/p2t/SipDialogP2T.h \
> libminisip/p2t/RtcpTransactionGrantFloor.h \
>
> Added: trunk/libminisip/include/libminisip/mediahandler/CallRecorder.h
> ===================================================================
> --- trunk/libminisip/include/libminisip/mediahandler/CallRecorder.h 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/include/libminisip/mediahandler/CallRecorder.h 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -0,0 +1,261 @@
> +/*
> + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +/* Copyright (C) 2004, 2005
> + *
> + * Authors: Cesc Santasusana (cesc DOT santa A{T gmail D.OT com )
> +*/
> +
> +
> +#ifndef CALL_RECORDER_H
> +#define CALL_RECORDER_H
> +
> +#define CALLREC_BUFF_SIZE 16000
> +
> +#include<libminisip/mediahandler/MediaStream.h>
> +#include<libminisip/soundcard/SoundRecorderCallback.h>
> +
> +template <class T> class MRef;
> +class MediaStreamReceiver;
> +class FileSoundDevice;
> +class AudioMedia;
> +class RtpReceiver;
> +class IpProvider;
> +class RtpPacket;
> +class SRtpPacket;
> +class Mutex;
> +class CircularBuffer;
> +
> +/**
> + The call recorder is to be used to record all audio in & out related
> + to a particular call.
> + It inherits from SoundRecorderCallback (to be registered as a recorder receiver
> + in SoundIO) and from MediaStreamReceiver (to be registered as a stream receiver
> + to the associated RtpReceiver).
> + It implements a producer/consumer model, where we have two producers (one for the
> + SoundIO::playerLoop() and another for the RtpReceiver::run(). The nice thing
> + is that we do not need an extra thread for the consumer: everytime one of the
> + producers writes to its buffer, it executes a consume (flush() ) function.
> + This is mutex protected as well as it keeps control of the last time it was
> + executed, allowing one execution every 20 ms (time enough to have received
> + on bunch of samples from each producer).
> +*/
> +class CallRecorder:
> + public MediaStreamReceiver,
> + public SoundRecorderCallback {
> + public:
> + /**
> + * Upgrade constructor ... build an override receiver from
> + * a normal receiver
> + * @param ssrc ssrc of the call, so we can register to the AudioMedia and
> + * receive the rtp packets related to it. Actually, it is
> + * the Session::callid.
> + * @param media reference to the Media object (actually, an AudioMedia)
> + */
> + CallRecorder( MRef<AudioMedia *> aMedia,
> + MRef<RtpReceiver *> rtpReceiver,
> + MRef<IpProvider *> ipProvider );
> + virtual ~CallRecorder( );
> +
> + virtual std::string getMemObjectType(){return "CallRecorder";}
> +
> + /**
> + * Inherited from SoundRecorderCallback
> + * Function that will be called when sound data is available from
> + * the soundcard.
> + * @param samplearr Array of raw sound data. Typically 160
> + * samples, 16 bit, but it can be specified in SoundCard.
> + * @param length length of samplearr
> + * @see SoundCard
> + */
> + virtual void srcb_handleSound(void *samplearr, int length);
> + #ifdef AEC_SUPPORT
> + virtual void srcb_handleSound(void *samplearr, void *samplearrR);
> + #endif
> +
> + /**
> + Inherited from MediaStreamReceiver
> + */
> + virtual void handleRtpPacket( MRef<SRtpPacket *> packet, MRef<IPAddress *> from );
> +// virtual void handleRtpPacket( MRef<SRtpPacket *> packet );
> +
> + /**
> + Get the filename of the file where audio is stored
> + */
> + std::string getFilename() { return filename; };
> +
> + /**
> + Sets the name to be used for the file (use it before opening it!)
> + @param name a user supplied string, to ease identification of the file
> + @param ssrc ssrc of the call
> + */
> + void setFilename( std::string name, int ssrc );
> +
> +#if 0
> + /**
> + Set the ssrc (int) of the AudioMediaSource
> + @param ssrc a std::string identifying this source.
> + */
> + void setSsrc( std::string ssrc );
> +#endif
> +
> + /**
> + set/get functions to check whether the callRecorder is
> + enabled or not. We can enable/disable the network side and
> + the microphone side.
> + */
> + bool isEnabled() { return enabledMic && enabledNtwk; };
> + void setEnabledMic( bool en ) {
> + enabledMic = en;
> + #ifdef DEBUG_OUTPUT
> + std::cerr << getDebugString() << "[1]" << end;
> + #endif
> + };
> + void setEnabledNetwork( bool en ) {
> + enabledNtwk = en;
> + #ifdef DEBUG_OUTPUT
> + std::cerr << getDebugString() << "[2]" << end;
> + #endif
> + };
> +
> + void setAllowStart( bool allow ) {
> + allowStart = allow;
> + #ifdef DEBUG_OUTPUT
> + std::cerr << getDebugString() << "[3]" << end;
> + #endif
> + if( getFilename() != "" ) {
> + std::cerr << "CallRecorder: Stopped recording to file <"
> + << getFilename() << ">" << end;
> + }
> + };
> +
> +
> + /**
> + Used by the microphone producer thread (SoundIO::playerLoop)
> + to add samples to the mic buffer.
> + @param data a short * buffer
> + @param nSamples number of samples in the buffer (short size)
> + */
> + void addMicData( void * data, int nSamples );
> +
> + /**
> + Used by the network producer thread (RtpReceiver::run)
> + to add samples to the ntwk buffer.
> + @param data a short * buffer
> + @param nSamples number of samples in the buffer (short size)
> + */
> + void addNtwkData( void * data, int nSamples );
> +
> + /**
> + Consumer function, called by either of the two producer functions.
> + It only allows execution every Xms. When this time has elapsed,
> + it reads a bunch of samples from each buffer and "mixes" them
> + accordingly, and then sends them to write()
> + */
> + void flush( );
> +
> + /**
> + Write audio samples to the file, via the FileDevice
> + @param data Audio samples to be written to the file
> + @param length length of the data, in samples
> + */
> + int write( void * data, int length );
> +
> +#ifdef DEBUG_OUTPUT
> + std::string getDebugString();
> +#endif
> +
> + protected:
> +
> +
> + /**
> + Name of the file to which we record to.
> + */
> + std::string filename;
> +
> + /**
> + Whether it is active or not. If enabled = false, nothing
> + will be written to the file.
> + */
> + bool enabledMic;
> + bool enabledNtwk;
> +
> + /**
> + Allow start acts like a global enable/disable ...
> + */
> + bool allowStart;
> +
> + /**
> + Physical access to a file, where we can write.
> + */
> + MRef<FileSoundDevice *> fileDev;
> +
> + Mutex fileDevMutex;
> +
> + /**
> + Via this object we can access all the other audio related
> + objects ... SoundIO, AudioSoundSource, Codecs, ...
> + */
> + MRef<AudioMedia *> audioMedia;
> +
> + /**
> + Temp buffer used to hold the output of the codec, when
> + decoding the samples received from the network.
> + */
> + short codecOutput[320]; //we take max 160 samples ...
> +
> + /**
> + Temp buffer used to receive the resampled samples from the
> + soundcard (we get at 48000Hz, we need 8000Hz, thus downsample).
> + */
> + short resampledData[160];
> +
> + /**
> + Buffer where the microphone producer dumps the audio samples
> + collected.
> + */
> + CircularBuffer * micData;
> + Mutex micMutex;
> +
> + /**
> + Buffer where the network producer dumps the audio samples
> + collected.
> + */
> + CircularBuffer * ntwkData;
> + Mutex ntwkMutex;
> +
> + /**
> + Temp Buffer used in the flush function ... we use it
> + to read the samples from the circular buffers previous to mixing,
> + as well as after "normalizing", to send to the write() function
> + */
> + short tempFlush[160*2];
> +
> + /**
> + Temp buffer, where we can mix several streams (it has a bigger
> + byte size, 32 bits, thus not easy to overflow).
> + */
> + int mixedData[160*2];
> +
> + /**
> + Used in the flush() function to keep track of the last time
> + we sent to write some audio samples. Only allow execution
> + every Xms ...
> + */
> + uint64_t flushLastTime;
> +};
> +
> +#endif
>
> Modified: trunk/libminisip/include/libminisip/mediahandler/MediaHandler.h
> ===================================================================
> --- trunk/libminisip/include/libminisip/mediahandler/MediaHandler.h 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/include/libminisip/mediahandler/MediaHandler.h 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -127,6 +127,10 @@
> */
> void setSessionSoundSettings( std::string callid, std::string side, bool turnOn );
>
> + /**
> + Used to start/stop the call recorder ...
> + */
> + void sessionCallRecorderStart( std::string callid, bool start );
> };
>
> #endif
>
> Modified: trunk/libminisip/include/libminisip/mediahandler/Session.h
> ===================================================================
> --- trunk/libminisip/include/libminisip/mediahandler/Session.h 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/include/libminisip/mediahandler/Session.h 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -241,6 +241,12 @@
> return mediaStreamSenders;
> }
>
> + /**
> + CallRecorder object ... we store it as MObject because it creates
> + header file dependency problems when building. No comment.
> + */
> + MRef<MObject *> callRecorder;
> +
> private:
> /* Key management handling */
> std::string initiatorCreate();
>
> Added: trunk/libminisip/source/mediahandler/CallRecorder.cxx
> ===================================================================
> --- trunk/libminisip/source/mediahandler/CallRecorder.cxx 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/source/mediahandler/CallRecorder.cxx 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -0,0 +1,350 @@
> +/*
> + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +/* Copyright (C) 2004, 2005
> + *
> + * Author: Cesc Santasusana (cesc DOT santa A{T gmail D.OT com )
> +*/
> +
> +#include<config.h>
> +
> +#include<libminisip/mediahandler/CallRecorder.h>
> +
> +#include<libminisip/mediahandler/AudioMedia.h>
> +#include"../soundcard/FileSoundDevice.h"
> +
> +#include<libmutil/itoa.h>
> +#include<libmutil/Mutex.h>
> +#include<libmutil/mtime.h>
> +#include<libmutil/CircularBuffer.h>
> +
> +#define AUDIO_FRAME_DURATION_MS 20
> +
> +using namespace std;
> +
> +
> +CallRecorder::CallRecorder( MRef<AudioMedia *> aMedia,
> + MRef<RtpReceiver *> rtpReceiver,
> + MRef<IpProvider *> ipProvider ):
> + MediaStreamReceiver( (Media *)*aMedia, rtpReceiver, ipProvider ),
> + fileDev( NULL ),
> + audioMedia( aMedia) {
> + static int count = 0;
> + count ++;
> +
> + flushLastTime = 0;
> +
> + setAllowStart( false );
> + setEnabledMic( false );
> + setEnabledNetwork( false );
> +
> + //Init the circular buffers ... max delay of 5 "groups" of samples = 100ms
> + micData = ntwkData = NULL;
> + micData = new CircularBuffer( 160 * 5 );
> + ntwkData = new CircularBuffer( 160 * 5 );
> +
> + setFilename( itoa(count), 0 );
> +
> + fileDev = new FileSoundDevice( "", getFilename(), FILESOUND_TYPE_RAW );
> + fileDev->setSleepTime( 0 );
> + fileDev->setLoopRecord(false );
> +
> + start(); //register to rtp receiver and start getting packets
> +
> + audioMedia->getSoundIO()->register_recorder_receiver( this,
> + SOUND_CARD_FREQ * AUDIO_FRAME_DURATION_MS / 1000,
> + false );
> +
> +#ifdef DEBUG_OUTPUT
> + cerr << "CallRecorder::created: " << getDebugString() << endl;
> +#endif
> +// setEnabledMic( true );
> +// setEnabledNetwork( true );
> +}
> +
> +CallRecorder::~CallRecorder( ) {
> + #ifdef DEBUG_OUTPUT
> + cerr << "CallRecorder Destroyed - " << getFilename() << endl;
> + #endif
> + if( fileDev->isOpenedPlayback() ) {
> + if( fileDev->closePlayback() == -1 ) {
> + cerr << "CallRecorder::destroy - ERROR closing file opened to record = " << filename << endl;
> + } else {
> + cerr << "CallRecorder::destroy - closing file opened to record = " << filename << endl;
> + }
> + }
> + audioMedia->getSoundIO()->unRegisterRecorderReceiver( this );
> + if( micData!=NULL ) delete micData;
> + if( ntwkData!=NULL ) delete ntwkData;
> +//
> +}
> +
> +void CallRecorder::setFilename( string name, int ssrc ) {
> + filename = "minisip.callrecord." + name + "." + itoa( ssrc ) + ".8khz.16bit.signed.raw.sw";
> +#ifdef DEBUG_OUTPUT
> + cerr << "CallRecorder::setFilename - " << filename << endl;;
> +#endif
> +}
> +
> +//we receive the audio from the mic via this function ...(from SoundIO)
> +//length is in samples
> +void CallRecorder::srcb_handleSound(void *samplearr, int nSamples) {
> + //printf( "YY" );
> + if( !allowStart ) { return; }
> + if( !enabledMic ) { return; }
> +
> + if( !audioMedia || !audioMedia->getResampler() ) { return; }
> + audioMedia->getResampler()->resample( (short *)samplearr, resampledData );
> +
> + addMicData( (void *)resampledData, 160 );
> + flush();
> +}
> +
> +#ifdef AEC_SUPPORT
> + void CallRecorder::srcb_handleSound(void *samplearr, void *samplearrR){
> + printf( "CallRecorder:: Function not implemented!!!\n" );
> + if( ! enabledMic ) { return; }
> + }
> +#endif
> +
> +//This function receives the audio from the mediastreamreceiver, that is,
> +//from the network
> +void CallRecorder::handleRtpPacket( MRef<SRtpPacket *> packet, MRef<IPAddress *> from ) {
> + if( !allowStart ) { return; }
> + if( ! enabledNtwk ) { return; }
> +
> + //if we have a timeout notification from the rtpreceiver ...
> + if( !packet ) {
> + return;
> + }
> +
> + uint32_t packetSsrc = packet->getHeader().getSSRC();
> + uint16_t seq_no = packet->getHeader().getSeqNo();
> +
> + if( packet->unprotect( getCryptoContext( packetSsrc, seq_no ) )){
> + // Authentication or replay protection failed
> + return;
> + }
> +
> +// media->playData( *packet );
> + if( !audioMedia ) {
> + audioMedia = dynamic_cast<AudioMedia *>(*media);
> + if( !audioMedia ) {
> + cerr << "ERROR!!! MediaStreamReceiverOverride being used for something not Audio!!" << endl;
> + }
> + #ifdef DEBUG_OUTPUT
> + cerr << "CallRecorder: not audioMeida" << endl;
> + #endif
> + return;
> + }
> +
> + //we implement the ::playData functionality from AudioMedia and from AudioMediaSource ..
> + MRef<AudioMediaSource *> source = audioMedia->getSource( packet->getHeader().SSRC );
> + if( !source ) {
> + #ifdef DEBUG_OUTPUT
> + cerr << "CALLREC: no source" << endl;
> + #endif
> + return;
> + }
> +
> + //we are sure we got a source ... let's get the codec to decode the data
> + RtpHeader hdr = packet->getHeader();
> + MRef<CodecState *> codec = source->findCodec( hdr.getPayloadType() );
> +
> + if( !codec ) {
> + #ifdef DEBUG_OUTPUT
> + cerr << "CALLREC: no codec" << endl;
> + #endif
> + return;
> + }
> +
> + //Now we got the codec. We need to decode the audio
> + uint32_t outputSize = codec->decode( packet->getContent(),
> + packet->getContentLength(),
> + codecOutput );
> +
> + addNtwkData( (void *)codecOutput, outputSize );
> + flush();
> +}
> +
> +//length in samples
> +void CallRecorder::addMicData( void * data, int nSamples ) {
> + bool ret;
> +
> + //printf("M1\n");
> + micMutex.lock();
> + //printf("M2\n");
> +
> + if( micData->getFree() < nSamples ) {
> +// printf("CRMIC_OF\n");
> + micMutex.unlock();
> + return;
> + }
> + ret = micData->write( (short *)data, nSamples );
> + if( !ret ) {
> +#ifdef DEBUG_OUTPUT
> + printf("CR: Error in addMicData\n");
> +#endif
> + }
> +
> + //printf("M3 - byteLength=%d - storedSamples=%d\n", length, micWrite-micData);
> + micMutex.unlock();
> + //printf("M4\n");
> +}
> +
> +//length in samples
> +void CallRecorder::addNtwkData( void * data, int nSamples ) {
> + bool ret;
> +
> + //printf("N1\n");
> + ntwkMutex.lock();
> + //printf("N2\n");
> +
> + if( ntwkData->getFree() < nSamples ) {
> +// printf("CRNTWK_OF\n");
> + ntwkMutex.unlock();
> + return;
> + }
> + ret = ntwkData->write( (short *)data, nSamples );
> + if( !ret ) {
> +#ifdef DEBUG_OUTPUT
> + printf("CR: Error in addMicData\n");
> +#endif
> + }
> +
> + //printf("N3 - byteLength=%d - storedSamples=%d\n", length, ntwkWrite-ntwkData);
> + ntwkMutex.unlock();
> + //printf("N4\n");
> +}
> +
> +//flush (write to the file device) the audio samples in the mic and ntwk buffers
> +//Only let this function take samples every 20ms
> +void CallRecorder::flush( ) {
> +
> + bool ret;
> +
> + //printf("FA\n");
> + fileDevMutex.lock();
> + micMutex.lock();
> + ntwkMutex.lock();
> +
> + if (flushLastTime==0)
> + flushLastTime=mtime();
> + uint64_t currentTime = mtime();
> +
> + if(currentTime - flushLastTime < AUDIO_FRAME_DURATION_MS ) {
> +// printf( "F0 - not time to write\n" );
> + ntwkMutex.unlock();
> + micMutex.unlock();
> + fileDevMutex.unlock();
> + return;
> + }
> +
> + //make sure there is no left overs from previous executions
> + memset( mixedData, 0, 160 * 2 * sizeof(int) );
> + //now we only use half this buffer ... we reading a mono stream
> + memset( tempFlush, 0, 160 * 2 * sizeof(short) );
> +
> + ret = micData->read( tempFlush, 160 );
> + if( ret ) {
> + for( int i=0; i < 160; i++ ) {
> + mixedData[i * 2] = tempFlush[i];
> + }
> + } else {
> +// printf( "FLUSHMIC_UF\n" );
> + }
> +
> + //now we only use half this buffer ... we reading a mono stream
> + memset( tempFlush, 0, 160 * 2 * sizeof(short) );
> + ret = ntwkData->read( tempFlush, 160 );
> + if( ret ) {
> + for( int i=0; i < 160; i++ ) {
> + mixedData[i * 2 + 1] = tempFlush[i];
> + }
> + } else {
> +// printf( "FLUSHNTWK_UF\n" );
> + }
> +
> + //normalize ... not really needed ... we ain't mixing
> + //Here we are using all the tempFlush ... it is a stereo stream
> + // after mixing
> + memset( tempFlush, 0, 160 * 2 * sizeof(short) );
> + for( int j = 0; j < 160 * fileDev->getNChannelsPlay(); j++ ) {
> + if( mixedData[j] > 32737 ) {
> + tempFlush[j] = 32737;
> + } else if( mixedData[j] < -32737 ) {
> + tempFlush[j] = -32737;
> + } else {
> + tempFlush[j] = (short)mixedData[j];
> + }
> + }
> +
> + write( (void *)tempFlush, 160 );
> +
> + flushLastTime = mtime();
> +
> + ntwkMutex.unlock();
> + micMutex.unlock();
> + fileDevMutex.unlock();
> + //printf("F12\n");
> +}
> +
> +/*
> +Write audio samples to the file.
> + at param data Audio samples to be written to the file
> + at param length length of the data, in samples
> +*/
> +int CallRecorder::write( void * data, int nSamples ) {
> + if( !fileDev ) {
> + return 0;
> + }
> + //if enabled, check if open ... if not, do it
> + if( !fileDev->isOpenedPlayback() ) {
> + //don't care about the params ... the function does not use them
> + #ifdef DEBUG_OUTPUT
> + cerr << "CallRecorder: Start recording to file <"
> + << getFilename() << ">" << endl;
> + #endif
> + fileDev->openPlayback( 8000, //sampling rate ...
> + 2 /* number of channels */
> + /*, SOUND_S16LE*/);
> + }
> +
> + int writtenBytes;
> + //the filedevice returns the number of samples written
> + writtenBytes = fileDev->write( (byte_t *)data, nSamples );
> + if( writtenBytes < nSamples ) {
> +#ifdef DEBUG_OUTPUT
> + cerr << "CallRecorder::write - not all written ("
> + << itoa(writtenBytes) << "/"
> + << itoa(nSamples) << ")" << endl;
> +#endif
> + }
> +// printf("write:: %d/%d\n", writtenBytes, nSamples);
> + return 0;
> +}
> +
> +#ifdef DEBUG_OUTPUT
> +string CallRecorder::getDebugString() {
> + string ret;
> + ret= "CallRecorder: filename=" + getFilename();
> + ret+= (enabledMic?"; MIC enabled":"; MIC disabled");
> + ret+= (enabledNtwk?"; NTWK enabled":"; NTWK disabled");
> + ret+= (allowStart?"; START allowed":"; START not allowed");
> + return ret;
> +}
> +#endif
> +
> +
>
> Modified: trunk/libminisip/source/mediahandler/MediaHandler.cxx
> ===================================================================
> --- trunk/libminisip/source/mediahandler/MediaHandler.cxx 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/source/mediahandler/MediaHandler.cxx 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -45,6 +45,8 @@
> #include<libminisip/soundcard/SoundDevice.h>
> #include<libminisip/codecs/Codec.h>
>
> +#include<libminisip/mediahandler/CallRecorder.h>
> +
> #ifdef _WIN32_WCE
> # include"../include/minisip_wce_extra_includes.h"
> #endif
> @@ -126,6 +128,11 @@
> rtpReceiver = new RtpReceiver( ipProvider );
> rStream = new MediaStreamReceiver( media, rtpReceiver, ipProvider );
> session->addMediaStreamReceiver( rStream );
> + if( (*i) == this->audioMedia ) {
> + CallRecorder * cr;
> + cr = new CallRecorder( audioMedia, rtpReceiver, ipProvider );
> + session->callRecorder = cr;
> + }
> #ifdef ZRTP_SUPPORT
> if(securityConfig.use_zrtp) {
> zhb = new ZrtpHostBridgeMinisip();
> @@ -192,18 +199,18 @@
> }
>
> if( command.getOp() == MediaCommandString::session_debug ){
> -#ifdef DEBUG_OUTPUT
> + #ifdef DEBUG_OUTPUT
> cerr << getDebugString() << endl;
> -#endif
> + #endif
> return;
> }
>
> if( command.getOp() == MediaCommandString::set_session_sound_settings ){
> bool turnOn;
> -#ifdef DEBUG_OUTPUT
> + #ifdef DEBUG_OUTPUT
> cerr << "MediaHandler::handleCmd: received set session sound settings"
> << endl << " " << command.getString() << endl;
> -#endif
> + #endif
> if( command.getParam2() == "ON" ) turnOn = true;
> else turnOn = false;
> setSessionSoundSettings( command.getDestinationId(),
> @@ -216,6 +223,15 @@
> init();
> return;
> }
> +
> + if( command.getOp() == "call_recorder_start_stop" ){
> + #ifdef DEBUG_OUTPUT
> + cerr << "MediaHandler::handleCmd: call_recorder_start_stop" << endl
> + << command.getString() << endl;
> + #endif
> + bool start = (command.getParam() == "START" );
> + sessionCallRecorderStart( command.getDestinationId(), start );
> + }
> }
>
> std::string MediaHandler::getExtIP(){
> @@ -253,6 +269,24 @@
>
> }
>
> +void MediaHandler::sessionCallRecorderStart( string callid, bool start ) {
> + CallRecorder * cr;
> + list<MRef<Session *> >::iterator iSession;
> +
> + sessionsLock.lock();
> + for( iSession = sessions.begin(); iSession != sessions.end(); iSession++ ){
> + if( (*iSession)->getCallId() == callid ){
> + cr = dynamic_cast<CallRecorder *>( *((*iSession)->callRecorder) );
> + if( cr ) {
> + cr->setAllowStart( start );
> + }
> + }
> + }
> + sessionsLock.unlock();
> +}
> +
> +
> +
> #ifdef DEBUG_OUTPUT
> string MediaHandler::getDebugString() {
> string ret;
>
> Modified: trunk/libminisip/source/mediahandler/Session.cxx
> ===================================================================
> --- trunk/libminisip/source/mediahandler/Session.cxx 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/libminisip/source/mediahandler/Session.cxx 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -28,6 +28,7 @@
>
> #include<libminisip/mediahandler/Session.h>
>
> +#include<libminisip/mediahandler/CallRecorder.h>
> #include<libminisip/mediahandler/MediaStream.h>
> #include<libminisip/mediahandler/Media.h>
> #include<libminisip/mediahandler/AudioMedia.h>
> @@ -482,6 +483,10 @@
> (*iS)->start();
> }
> }
> + /* if( callRecorder ) {
> + MRef<CallRecorder *> cr = dynamic_cast<CallRecorder *>(*callRecorder);
> + cr->setEnabled( f
> + }*/
> mediaStreamSendersLock.unlock();
> }
>
> @@ -501,6 +506,16 @@
> (*iS)->stop();
> }
> }
> + MRef<CallRecorder *> cr = dynamic_cast<CallRecorder *>(*callRecorder);
> + if( !cr ) {
> + #ifdef DEBUG_OUTPUT
> + cerr << "Session::stop - no call recorder?" << end;
> + #endif
> + } else {
> + cr->setAllowStart( false );
> + }
> + callRecorder = NULL; //stop the call recorder object
> +
> mediaStreamSendersLock.unlock();
>
> }
> @@ -559,8 +574,17 @@
> it != mediaStreamSenders.end(); it++ ) {
> (*it)->setMuted( mute );
> }
> +
> + MRef<CallRecorder *> cr = dynamic_cast<CallRecorder *>(*callRecorder);
> + if( !cr ) {
> + #ifdef DEBUG_OUTPUT
> + cerr << "Session::muteSenders - no call recorder?" << endl;
> + #endif
> + } else {
> + cr->setEnabledMic( !mute );
> + }
> +
> mediaStreamSendersLock.unlock();
> -
> }
>
> void Session::silenceSources ( bool silence ) {
> @@ -600,13 +624,21 @@
> }
> }
> }
> + MRef<CallRecorder *> cr = dynamic_cast<CallRecorder *>(*callRecorder);
> + if( !cr ) {
> + #ifdef DEBUG_OUTPUT
> + cerr << "Session::silenceSources - no call recorder?" << endl;
> + #endif
> + } else {
> + cr->setEnabledNetwork( !silence );
> + }
> }
>
> #ifdef DEBUG_OUTPUT
> string Session::getDebugString() {
> string ret;
> ret = getMemObjectType() + ": this=" + itoa((int64_t)this) +
> - "\n; callid=" + getCallId() +
> + "\n ; callid=" + getCallId() +
> "; peerUri=" + peerUri;
>
> ret += "\n ";
> @@ -620,6 +652,13 @@
> ret += "; silencedSources = true";
> else
> ret += "; silencedSources = false";
> +
> + MRef<CallRecorder *> cr = dynamic_cast<CallRecorder *>(*callRecorder);
> + if( cr ) {
> + ret += "\n ";
> + cr = dynamic_cast<CallRecorder *>( *callRecorder );
> + ret += "; " + cr->getDebugString();
> + }
>
> for( std::list< MRef<MediaStreamReceiver *> >::iterator it = mediaStreamReceivers.begin();
> it != mediaStreamReceivers.end(); it++ ) {
>
> Modified: trunk/minisip/minisip/gui/gtkgui/CallWidget.cxx
> ===================================================================
> --- trunk/minisip/minisip/gui/gtkgui/CallWidget.cxx 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/minisip/minisip/gui/gtkgui/CallWidget.cxx 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -56,6 +56,7 @@
> // audioOutSilenceButton( "Silence for my ears"),
> monitoringButton( Gtk::StockID( "minisip_record" ), Gtk::StockID( "minisip_norecord" ) ),
> audioOutSilenceButton( Gtk::StockID( "minisip_play" ), Gtk::StockID( "minisip_noplay" ) ),
> + callRecordButton( Gtk::Stock::MEDIA_RECORD, Gtk::Stock::MEDIA_RECORD ),
> #endif
> secureImage(),// Gtk::StockID( "minisip_insecure" ),
> // Gtk::ICON_SIZE_DIALOG ),
> @@ -115,6 +116,11 @@
> SLOT( *this,
> &CallWidget::audioOutSilenceButtonToggled ) );
>
> + topBox->pack_start( callRecordButton, false, false );
> + callRecordButton.signal_toggled().connect(
> + SLOT( *this,
> + &CallWidget::callRecordButtonToggled ) );
> +
> pack_start( *topBox, false, false, 4 );
>
> DtmfWidget * dtmfWidget = manage( new DtmfWidget() );
> @@ -270,6 +276,21 @@
> #endif
> }
>
> +void CallWidget::callRecordButtonToggled () {
> +#ifndef OLDLIBGLADEMM
> + string param;
> + if( callRecordButton.get_active() ) {
> + param = "START";
> + } else {
> + param = "STOP";
> + }
> + CommandString cmdstr( getMainCallId(),
> + "call_recorder_start_stop",
> + param );
> + mainWindow->getCallback()->handleCommand( "media", cmdstr );
> +#endif
> +}
> +
> void CallWidget::hideAcceptButton(){
> acceptButton.set_sensitive( false );
> }
> @@ -294,6 +315,7 @@
> #ifndef OLDLIBGLADEMM
> monitoringButton.show();
> audioOutSilenceButton.show();
> + callRecordButton.show();
> transferArrow.show_all();
> dtmfArrow.show_all();
> #endif
> @@ -360,6 +382,7 @@
> #ifndef OLDLIBGLADEMM
> monitoringButton.hide();
> audioOutSilenceButton.hide();
> + callRecordButton.hide();
> transferArrow.hide();
> dtmfArrow.hide();
> #endif
> @@ -377,6 +400,7 @@
> #ifndef OLDLIBGLADEMM
> monitoringButton.hide();
> audioOutSilenceButton.hide();
> + callRecordButton.hide();
> transferArrow.hide();
> dtmfArrow.hide();
> #endif
>
> Modified: trunk/minisip/minisip/gui/gtkgui/CallWidget.h
> ===================================================================
> --- trunk/minisip/minisip/gui/gtkgui/CallWidget.h 2006-06-29 15:53:29 UTC (rev 2669)
> +++ trunk/minisip/minisip/gui/gtkgui/CallWidget.h 2006-07-02 14:35:38 UTC (rev 2670)
> @@ -105,6 +105,10 @@
> */
> void audioOutSilenceButtonToggled ();
>
> + /**
> + Event handler for call recording button ... on toggle()
> + */
> + void callRecordButtonToggled();
>
> protected:
> void startRinging();
> @@ -135,6 +139,7 @@
> // Gtk::CheckButton audioOutSilenceButton;
> IconToggleButton monitoringButton;
> IconToggleButton audioOutSilenceButton;
> + IconToggleButton callRecordButton;
>
> #endif
> Gtk::Image secureImage;
>
> _______________________________________________
> Minisip-devel mailing list
> Minisip-devel at minisip.org
> http://lists.minisip.org/mailman/listinfo/minisip-devel
>
More information about the Minisip-devel
mailing list