Commit fd8f21d7 authored by Simon Morlat's avatar Simon Morlat

Merge branch 'dev_callrecording'

parents 1f0374f4 0285f393
......@@ -18,7 +18,6 @@ mediastreamer2_include_HEADERS= ice.h \
mediastream.h \
msv4l.h \
msvideo.h \
waveheader.h \
msvideoout.h \
msvolume.h \
mstee.h \
......
......@@ -132,6 +132,11 @@ struct _AudioStream
MSFilter *write_resampler;
MSFilter *equalizer;
MSFilter *dummy;
MSFilter *send_tee;
MSFilter *recv_tee;
MSFilter *recorder_mixer;
MSFilter *recorder;
char *recorder_file;
uint64_t last_packet_count;
time_t last_packet_time;
EchoLimiterType el_type; /*use echo limiter: two MSVolume, measured input level controlling local output level*/
......@@ -209,13 +214,15 @@ MS2_PUBLIC void audio_stream_play_received_dtmfs(AudioStream *st, bool_t yesno);
**/
MS2_PUBLIC AudioStream *audio_stream_new(int loc_rtp_port, int loc_rtcp_port, bool_t ipv6);
#define AUDIO_STREAM_FEATURE_PLC (1 << 0)
#define AUDIO_STREAM_FEATURE_EC (1 << 1)
#define AUDIO_STREAM_FEATURE_EQUALIZER (1 << 2)
#define AUDIO_STREAM_FEATURE_VOL_SND (1 << 3)
#define AUDIO_STREAM_FEATURE_VOL_RCV (1 << 4)
#define AUDIO_STREAM_FEATURE_DTMF (1 << 5)
#define AUDIO_STREAM_FEATURE_DTMF_ECHO (1 << 6)
#define AUDIO_STREAM_FEATURE_PLC (1 << 0)
#define AUDIO_STREAM_FEATURE_EC (1 << 1)
#define AUDIO_STREAM_FEATURE_EQUALIZER (1 << 2)
#define AUDIO_STREAM_FEATURE_VOL_SND (1 << 3)
#define AUDIO_STREAM_FEATURE_VOL_RCV (1 << 4)
#define AUDIO_STREAM_FEATURE_DTMF (1 << 5)
#define AUDIO_STREAM_FEATURE_DTMF_ECHO (1 << 6)
#define AUDIO_STREAM_FEATURE_MIXED_RECORDING (1 << 7)
#define AUDIO_STREAM_FEATURE_ALL (\
AUDIO_STREAM_FEATURE_PLC | \
AUDIO_STREAM_FEATURE_EC | \
......@@ -223,9 +230,11 @@ MS2_PUBLIC AudioStream *audio_stream_new(int loc_rtp_port, int loc_rtcp_port, bo
AUDIO_STREAM_FEATURE_VOL_SND | \
AUDIO_STREAM_FEATURE_VOL_RCV | \
AUDIO_STREAM_FEATURE_DTMF | \
AUDIO_STREAM_FEATURE_DTMF_ECHO \
AUDIO_STREAM_FEATURE_DTMF_ECHO |\
AUDIO_STREAM_FEATURE_MIXED_RECORDING \
)
MS2_PUBLIC uint32_t audio_stream_get_features(AudioStream *st);
MS2_PUBLIC void audio_stream_set_features(AudioStream *st, uint32_t features);
......@@ -301,6 +310,12 @@ MS2_PUBLIC void audio_stream_stop (AudioStream * stream);
/* send a dtmf */
MS2_PUBLIC int audio_stream_send_dtmf (AudioStream * stream, char dtmf);
MS2_PUBLIC int audio_stream_mixed_record_open(AudioStream *st, const char*filename);
MS2_PUBLIC int audio_stream_mixed_record_start(AudioStream *st);
MS2_PUBLIC int audio_stream_mixed_record_stop(AudioStream *st);
MS2_PUBLIC void audio_stream_set_default_card(int cardindex);
/* retrieve RTP statistics*/
......
......@@ -79,7 +79,7 @@ typedef enum _MSPlayerState MSPlayerState;
/**open a media file*/
#define MS_PLAYER_OPEN \
MS_FILTER_METHOD(MSFilterPlayerInterface,0,const char *)
MS_FILTER_METHOD(MSFilterPlayerInterface,0,const char )
#define MS_PLAYER_START \
MS_FILTER_METHOD_NO_ARG(MSFilterPlayerInterface,1)
......@@ -94,7 +94,39 @@ typedef enum _MSPlayerState MSPlayerState;
MS_FILTER_METHOD(MSFilterPlayerInterface,4,int)
#define MS_PLAYER_GET_STATE \
MS_FILTER_METHOD(MSFilterPlayerInterface,5,int)
MS_FILTER_METHOD(MSFilterPlayerInterface,5,MSPlayerState)
/**
* Interface definitions for recorders
**/
enum _MSRecorderState{
MSRecorderClosed,
MSRecorderPaused,
MSRecorderRunning
};
typedef enum _MSRecorderState MSRecorderState;
/**open a media file for recording*/
#define MS_RECORDER_OPEN \
MS_FILTER_METHOD(MSFilterRecorderInterface,0,const char )
#define MS_RECORDER_START \
MS_FILTER_METHOD_NO_ARG(MSFilterRecorderInterface,1)
#define MS_RECORDER_PAUSE \
MS_FILTER_METHOD_NO_ARG(MSFilterRecorderInterface,2)
#define MS_RECORDER_CLOSE \
MS_FILTER_METHOD_NO_ARG(MSFilterRecorderInterface,3)
#define MS_RECORDER_GET_STATE \
MS_FILTER_METHOD(MSFilterRecorderInterface,5,MSRecorderState)
/** Interface definitions for echo cancellers */
......
......@@ -119,7 +119,8 @@ libmediastreamer_voip_la_SOURCES+= audiofilters/winsnd3.c \
audiofilters/msfilerec_win.c
else
libmediastreamer_voip_la_SOURCES+= audiofilters/msfileplayer.c \
audiofilters/msfilerec.c
audiofilters/msfilerec.c \
audiofilters/waveheader.h
endif
if BUILD_RESAMPLE
......
......@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/waveheader.h"
#include "waveheader.h"
#include "mediastreamer2/msticker.h"
#ifdef HAVE_PCAP
......@@ -44,6 +44,7 @@ struct _PlayerData{
int samplesize;
uint32_t ts;
bool_t swap;
bool_t is_raw;
#ifdef HAVE_PCAP
pcap_t *pcap;
struct pcap_pkthdr *pcap_hdr;
......@@ -58,7 +59,7 @@ struct _PlayerData{
typedef struct _PlayerData PlayerData;
static void player_init(MSFilter *f){
PlayerData *d=ms_new(PlayerData,1);
PlayerData *d=ms_new0(PlayerData,1);
d->fd=-1;
d->state=MSPlayerClosed;
d->swap=FALSE;
......@@ -70,6 +71,7 @@ static void player_init(MSFilter *f){
d->pause_time=0;
d->count=0;
d->ts=0;
d->is_raw=TRUE;
#ifdef HAVE_PCAP
d->pcap = NULL;
d->pcap_hdr = NULL;
......@@ -81,74 +83,87 @@ static void player_init(MSFilter *f){
f->data=d;
}
static int read_wav_header(PlayerData *d){
char header1[sizeof(riff_t)];
char header2[sizeof(format_t)];
char header3[sizeof(data_t)];
int ms_read_wav_header_from_fd(wave_header_t *header,int fd){
int count;
riff_t *riff_chunk=(riff_t*)header1;
format_t *format_chunk=(format_t*)header2;
data_t *data_chunk=(data_t*)header3;
int skip;
int hsize=0;
riff_t *riff_chunk=&header->riff_chunk;
format_t *format_chunk=&header->format_chunk;
data_t *data_chunk=&header->data_chunk;
unsigned long len=0;
len = read(d->fd, header1, sizeof(header1)) ;
if (len != sizeof(header1)){
len = read(fd, (char*)riff_chunk, sizeof(riff_t)) ;
if (len != sizeof(riff_t)){
goto not_a_wav;
}
if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){
if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){
goto not_a_wav;
}
len = read(d->fd, header2, sizeof(header2)) ;
if (len != sizeof(header2)){
len = read(fd, (char*)format_chunk, sizeof(format_t)) ;
if (len != sizeof(format_t)){
ms_warning("Wrong wav header: cannot read file");
goto not_a_wav;
}
d->rate=le_uint32(format_chunk->rate);
d->nchannels=le_uint16(format_chunk->channel);
if (d->nchannels==0) goto not_a_wav;
d->samplesize=le_uint16(format_chunk->blockalign)/d->nchannels;
if (format_chunk->len-0x10>0)
if ((skip=le_uint32(format_chunk->len)-0x10)>0)
{
lseek(d->fd,(format_chunk->len-0x10),SEEK_CUR);
lseek(fd,skip,SEEK_CUR);
}
hsize=sizeof(wave_header_t)-0x10+le_uint32(format_chunk->len);
d->hsize=sizeof(wave_header_t)-0x10+format_chunk->len;
len = read(d->fd, header3, sizeof(header3)) ;
if (len != sizeof(header3)){
ms_warning("Wrong wav header: cannot read file");
goto not_a_wav;
}
count=0;
while (strncmp(data_chunk->data, "data", 4)!=0 && count<30)
{
ms_warning("skipping chunk=%s len=%i", data_chunk->data, data_chunk->len);
lseek(d->fd,data_chunk->len,SEEK_CUR);
count++;
d->hsize=d->hsize+len+data_chunk->len;
len = read(d->fd, header3, sizeof(header3)) ;
if (len != sizeof(header3)){
do{
len = read(fd, data_chunk, sizeof(data_t)) ;
if (len != sizeof(data_t)){
ms_warning("Wrong wav header: cannot read file");
goto not_a_wav;
}
}
if (strncmp(data_chunk->data, "data", 4)!=0){
ms_warning("skipping chunk=%s len=%i", data_chunk->data, data_chunk->len);
lseek(fd,le_uint32(data_chunk->len),SEEK_CUR);
count++;
hsize+=len+le_uint32(data_chunk->len);
}else{
hsize+=len;
break;
}
}while(count<30);
return hsize;
not_a_wav:
/*rewind*/
lseek(fd,0,SEEK_SET);
return -1;
}
static int read_wav_header(PlayerData *d){
wave_header_t header;
format_t *format_chunk=&header.format_chunk;
int ret=ms_read_wav_header_from_fd(&header,d->fd);
if (ret==-1) goto not_a_wav;
d->rate=le_uint32(format_chunk->rate);
d->nchannels=le_uint16(format_chunk->channel);
if (d->nchannels==0) goto not_a_wav;
d->samplesize=le_uint16(format_chunk->blockalign)/d->nchannels;
d->hsize=ret;
#ifdef WORDS_BIGENDIAN
if (le_uint16(format_chunk->blockalign)==le_uint16(format_chunk->channel) * 2)
d->swap=TRUE;
#endif
d->is_raw=FALSE;
return 0;
not_a_wav:
/*rewind*/
lseek(d->fd,0,SEEK_SET);
d->hsize=0;
d->is_raw=TRUE;
return -1;
}
......@@ -374,9 +389,10 @@ static int player_get_sr(MSFilter *f, void*arg){
}
static int player_set_sr(MSFilter *f, void *arg) {
/* This function should be used only when playing a PCAP file */
/* This function should be used only when playing a PCAP or raw file */
PlayerData *d = (PlayerData *)f->data;
d->rate = *((int *)arg);
if (d->is_raw) d->rate = *((int *)arg);
else return -1;
return 0;
}
......
......@@ -22,26 +22,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "mediastreamer2/msfilerec.h"
#include "mediastreamer2/waveheader.h"
#include "waveheader.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static int rec_close(MSFilter *f, void *arg);
typedef enum{
Closed,
Stopped,
Started
} State;
static int rec_close(MSFilter *f, void *arg);
typedef struct RecState{
int fd;
int rate;
int nchannels;
int size;
State state;
MSRecorderState state;
} RecState;
static void rec_init(MSFilter *f){
......@@ -50,7 +45,7 @@ static void rec_init(MSFilter *f){
s->rate=8000;
s->nchannels = 1;
s->size=0;
s->state=Closed;
s->state=MSRecorderClosed;
f->data=s;
}
......@@ -61,7 +56,7 @@ static void rec_process(MSFilter *f){
while((m=ms_queue_get(f->inputs[0]))!=NULL){
mblk_t *it=m;
ms_mutex_lock(&f->lock);
if (s->state==Started){
if (s->state==MSRecorderRunning){
while(it!=NULL){
int len=it->b_wptr-it->b_rptr;
if ((err=write(s->fd,it->b_rptr,len))!=len){
......@@ -77,26 +72,62 @@ static void rec_process(MSFilter *f){
}
}
static int rec_get_length(const char *file, int *length){
wave_header_t header;
int fd=open(file,O_RDONLY);
int ret=ms_read_wav_header_from_fd(&header,fd);
close(fd);
if (ret>0){
*length=le_uint32(header.data_chunk.len);
}else{
*length=0;
}
return ret;
}
static int rec_open(MSFilter *f, void *arg){
RecState *s=(RecState*)f->data;
const char *filename=(const char*)arg;
if (s->fd>=0) rec_close(f,NULL);
ms_mutex_lock(&f->lock);
s->fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
if (s->fd<0){
int flags;
if (s->fd!=-1) rec_close(f,NULL);
if (access(filename,R_OK|W_OK)==0){
flags=O_WRONLY;
if (rec_get_length(filename,&s->size)>0){
ms_message("Opening wav file in append mode, current data size is %i",s->size);
}
}else{
flags=O_WRONLY|O_CREAT|O_TRUNC;
s->size=0;
}
s->fd=open(filename,flags, S_IRUSR|S_IWUSR);
if (s->fd==-1){
ms_warning("Cannot open %s: %s",filename,strerror(errno));
ms_mutex_unlock(&f->lock);
return -1;
}
s->state=Stopped;
if (s->size>0){
struct stat statbuf;
if (fstat(s->fd,&statbuf)==0){
if (lseek(s->fd,statbuf.st_size,SEEK_SET)!=0){
ms_error("Could not lseek to end of file: %s",strerror(errno));
}
}else ms_error("fstat() failed: %s",strerror(errno));
}
ms_mutex_lock(&f->lock);
s->state=MSRecorderPaused;
ms_mutex_unlock(&f->lock);
return 0;
}
static int rec_start(MSFilter *f, void *arg){
RecState *s=(RecState*)f->data;
if (s->state!=MSRecorderPaused){
ms_error("MSFileRec: cannot start, state=%i",s->state);
return -1;
}
ms_mutex_lock(&f->lock);
s->state=Started;
s->state=MSRecorderRunning;
ms_mutex_unlock(&f->lock);
return 0;
}
......@@ -104,7 +135,7 @@ static int rec_start(MSFilter *f, void *arg){
static int rec_stop(MSFilter *f, void *arg){
RecState *s=(RecState*)f->data;
ms_mutex_lock(&f->lock);
s->state=Stopped;
s->state=MSRecorderPaused;
ms_mutex_unlock(&f->lock);
return 0;
}
......@@ -135,8 +166,8 @@ static void write_wav_header(int fd, int rate, int nchannels, int size){
static int rec_close(MSFilter *f, void *arg){
RecState *s=(RecState*)f->data;
ms_mutex_lock(&f->lock);
s->state=Closed;
if (s->fd>=0) {
s->state=MSRecorderClosed;
if (s->fd!=-1){
write_wav_header(s->fd, s->rate, s->nchannels, s->size);
close(s->fd);
s->fd=-1;
......@@ -145,6 +176,12 @@ static int rec_close(MSFilter *f, void *arg){
return 0;
}
static int rec_get_state(MSFilter *f, void *arg){
RecState *s=(RecState*)f->data;
*(MSRecorderState*)arg=s->state;
return 0;
}
static int rec_set_sr(MSFilter *f, void *arg){
RecState *s=(RecState*)f->data;
ms_mutex_lock(&f->lock);
......@@ -161,7 +198,7 @@ static int rec_set_nchannels(MSFilter *f, void *arg) {
static void rec_uninit(MSFilter *f){
RecState *s=(RecState*)f->data;
if (s->fd>=0) rec_close(f,NULL);
if (s->fd!=-1) rec_close(f,NULL);
ms_free(s);
}
......@@ -172,6 +209,11 @@ static MSFilterMethod rec_methods[]={
{ MS_FILE_REC_START , rec_start },
{ MS_FILE_REC_STOP , rec_stop },
{ MS_FILE_REC_CLOSE , rec_close },
{ MS_RECORDER_OPEN , rec_open },
{ MS_RECORDER_START , rec_start },
{ MS_RECORDER_PAUSE , rec_stop },
{ MS_RECORDER_CLOSE , rec_close },
{ MS_RECORDER_GET_STATE , rec_get_state },
{ 0 , NULL }
};
......@@ -183,13 +225,13 @@ MSFilterDesc ms_file_rec_desc={
N_("Wav file recorder"),
MS_FILTER_OTHER,
NULL,
1,
1,
0,
rec_init,
NULL,
rec_process,
rec_process,
NULL,
rec_uninit,
rec_uninit,
rec_methods
};
......
......@@ -74,7 +74,7 @@ typedef struct _format_t {
typedef struct _data_t {
char data[4] ; /* "data" (ASCII characters) */
int len ; /* length of data */
uint32_t len ; /* length of data */
} data_t;
typedef struct _wave_header_t
......@@ -89,4 +89,7 @@ typedef struct _wave_header_t
#define wave_header_get_channel(header) le_uint16((header)->format_chunk.channel)
#define wave_header_get_bpsmpl(header) \
le_uint16((header)->format_chunk.blockalign)
int ms_read_wav_header_from_fd(wave_header_t *header,int fd);
#endif
......@@ -93,7 +93,7 @@ static void cut_audio_stream_graph(MSAudioEndpoint *ep, bool_t is_remote){
/*we would like to keep the volrecv (MSVolume filter) in the graph to measure the output level*/
ep->in_cut_point_prev.filter=st->volrecv;
}else{
ep->in_cut_point_prev.filter=st->ms.decoder;
ep->in_cut_point_prev.filter=st->plc ? st->plc : st->ms.decoder;
}
ep->in_cut_point=just_after(ep->in_cut_point_prev.filter);
ms_filter_unlink(ep->in_cut_point_prev.filter,ep->in_cut_point_prev.pin,ep->in_cut_point.filter, ep->in_cut_point.pin);
......
......@@ -31,6 +31,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msfilerec.h"
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msequalizer.h"
#include "mediastreamer2/mstee.h"
#include "mediastreamer2/msaudiomixer.h"
#include "mediastreamer2/mscodecutils.h"
#include "private.h"
......@@ -42,8 +44,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#endif
void audio_stream_free(AudioStream *stream) {
static void audio_stream_free(AudioStream *stream) {
media_stream_free(&stream->ms);
if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
......@@ -57,6 +58,11 @@ void audio_stream_free(AudioStream *stream) {
if (stream->write_resampler!=NULL) ms_filter_destroy(stream->write_resampler);
if (stream->dtmfgen_rtp!=NULL) ms_filter_destroy(stream->dtmfgen_rtp);
if (stream->dummy) ms_filter_destroy(stream->dummy);
if (stream->recv_tee) ms_filter_destroy(stream->recv_tee);
if (stream->send_tee) ms_filter_destroy(stream->send_tee);
if (stream->recorder) ms_filter_destroy(stream->recorder);
if (stream->recorder_mixer) ms_filter_destroy(stream->recorder_mixer);
if (stream->recorder_file) ms_free(stream->recorder_file);
if (stream->qi) ms_quality_indicator_destroy(stream->qi);
ms_free(stream);
}
......@@ -356,30 +362,48 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
if (stream->ec){
ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
}
if (stream->features & AUDIO_STREAM_FEATURE_MIXED_RECORDING){
int val=0;
int pin=1;
stream->recorder=ms_filter_new(MS_FILE_REC_ID);
stream->recorder_mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
stream->recv_tee=ms_filter_new(MS_TEE_ID);
stream->send_tee=ms_filter_new(MS_TEE_ID);
ms_filter_call_method(stream->recorder_mixer,MS_AUDIO_MIXER_ENABLE_CONFERENCE_MODE,&val);
ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_NCHANNELS,&pt->channels);
ms_filter_call_method(stream->recv_tee,MS_TEE_MUTE,&pin);
ms_filter_call_method(stream->send_tee,MS_TEE_MUTE,&pin);
ms_filter_call_method(stream->recorder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
ms_filter_call_method(stream->recorder,MS_FILTER_SET_NCHANNELS,&pt->channels);
}
/* give the encoder/decoder some parameters*/
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
ms_message("Payload's bitrate is %i",pt->normal_bitrate);
if (pt->normal_bitrate>0){
ms_message("Setting audio encoder network bitrate to %i",pt->normal_bitrate);
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
}
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_NCHANNELS,&pt->channels);
ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_NCHANNELS,&pt->channels);
if (pt->send_fmtp!=NULL) ms_filter_call_method(stream->ms.encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp);
if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->ms.decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
/*create the equalizer*/
if ((stream->features & AUDIO_STREAM_FEATURE_EQUALIZER) != 0)
if ((stream->features & AUDIO_STREAM_FEATURE_EQUALIZER) != 0){
stream->equalizer=ms_filter_new(MS_EQUALIZER_ID);
else
if(stream->equalizer) {
tmp=stream->eq_active;
ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_ACTIVE,&tmp);
}
}else
stream->equalizer=NULL;
if(stream->equalizer) {
tmp=stream->eq_active;
ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_ACTIVE,&tmp);
}
/*configure resampler if needed*/
ms_filter_call_method(stream->ms.rtpsend, MS_FILTER_SET_NCHANNELS, &pt->channels);
......@@ -440,6 +464,8 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
ms_connection_helper_link(&h,stream->volsend,0,0);
if (stream->dtmfgen_rtp)
ms_connection_helper_link(&h,stream->dtmfgen_rtp,0,0);
if (stream->send_tee)
ms_connection_helper_link(&h,stream->send_tee,0,0);
ms_connection_helper_link(&h,stream->ms.encoder,0,0);
ms_connection_helper_link(&h,stream->ms.rtpsend,0,-1);
......@@ -447,12 +473,14 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
ms_connection_helper_start(&h);
ms_connection_helper_link(&h,stream->ms.rtprecv,-1,0);
ms_connection_helper_link(&h,stream->ms.decoder,0,0);
if(stream->plc)
if (stream->plc)
ms_connection_helper_link(&h,stream->plc,0,0);
if (stream->dtmfgen)
ms_connection_helper_link(&h,stream->dtmfgen,0,0);
if (stream->volrecv)
ms_connection_helper_link(&h,stream->volrecv,0,0);
if (stream->recv_tee)
ms_connection_helper_link(&h,stream->recv_tee,0,0);
if (stream->equalizer)
ms_connection_helper_link(&h,stream->equalizer,0,0);
if (stream->ec)
......@@ -461,6 +489,13 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
ms_connection_helper_link(&h,stream->write_resampler,0,0);
ms_connection_helper_link(&h,stream->soundwrite,0,-1);
/*call recording part, attached to both outgoing and incoming graphs*/
if (stream->recorder){
ms_filter_link(stream->send_tee,1,stream->recorder_mixer,0);
ms_filter_link(stream->recv_tee,1,stream->recorder_mixer,1);
ms_filter_link(stream->recorder_mixer,0,stream->recorder,0);
}
/*to make sure all preprocess are done before befre processing audio*/
ms_ticker_attach_multiple( stream->ms.ticker
,stream->soundread
......@@ -543,6 +578,51 @@ void audio_stream_record(AudioStream *st, const char *name){
}
}
int audio_stream_mixed_record_open(AudioStream *st, const char* filename){
if (!(st->features & AUDIO_STREAM_FEATURE_MIXED_RECORDING)){
if (audio_stream_started(st)){
ms_error("Too late - you cannot request a mixed recording when the stream is running because it did not have AUDIO_STREAM_FEATURE_MIXED_RECORDING feature.");
return -1;
}else{
st->features|=AUDIO_STREAM_FEATURE_MIXED_RECORDING;
}
}
if (st->recorder_file){
audio_stream_mixed_record_stop(st);
}
st->recorder_file=filename ? ms_strdup(filename) : NULL;
return 0;
}
int audio_stream_mixed_record_start(AudioStream *st){
if (st->recorder && st->recorder_file){
int pin=1;
MSRecorderState state;
ms_filter_call_method(st->recorder,MS_RECORDER_GET_STATE,&state);
if (state==MSRecorderClosed){
if (ms_filter_call_method(st->recorder,MS_RECORDER_OPEN,st->recorder_file)==-1)
return -1;
}
ms_filter_call_method_noarg(st->recorder,MS_RECORDER_START);
ms_filter_call_method(st->recv_tee,MS_TEE_UNMUTE,&pin);
ms_filter_call_method(st->send_tee,MS_TEE_UNMUTE,&pin);
return 0;
}
return -1;
}
int audio_stream_mixed_record_stop(AudioStream *st){
if (st->recorder && st->recorder_file){
int pin=1;
ms_filter_call_method_noarg(st->recorder,MS_RECORDER_PAUSE);
ms_filter_call_method(st->recv_tee,MS_TEE_MUTE,&pin);
ms_filter_call_method(st->send_tee,MS_TEE_MUTE,&pin);
ms_filter_call_method_noarg(st->recorder,MS_RECORDER_CLOSE);
}
return 0;
}
uint32_t audio_stream_get_features(AudioStream *st){
return st->features;
}
......@@ -632,8 +712,6 @@ void audio_stream_enable_noise_gate(AudioStream *stream, bool_t val){
} else {
ms_warning("cannot set noise gate mode to [%i] because no volume send",val);
}
}
void audio_stream_set_mic_gain(AudioStream *stream, float gain){
......@@ -691,6 +769,8 @@ void audio_stream_stop(AudioStream * stream)
ms_connection_helper_unlink(&h,stream->volsend,0,0);
if (stream->dtmfgen_rtp)
ms_connection_helper_unlink(&h,stream->dtmfgen_rtp,0,0);
if (stream->send_tee)
ms_connection_helper_unlink(&h,stream->send_tee,0,0);
ms_connection_helper_unlink(&h,stream->ms.encoder,0,0);
ms_connection_helper_unlink(&h,stream->ms.rtpsend,0,-1);
......@@ -704,6 +784,8 @@ void audio_stream_stop(AudioStream * stream)
ms_connection_helper_unlink(&h,stream->dtmfgen,0,0);
if (stream->volrecv!=NULL)
ms_connection_helper_unlink(&h,stream->volrecv,0,0);
if (stream->recv_tee)
ms_connection_helper_unlink(&h,stream->recv_tee,0,0);
if (stream->equalizer!=NULL)
ms_connection_helper_unlink(&h,stream->equalizer,0,0);
if (stream->ec!=NULL)
......@@ -711,6 +793,13 @@ void audio_stream_stop(AudioStream * stream)
if (stream->write_resampler!=NULL)
ms_connection_helper_unlink(&h,stream->write_resampler,0,0);
ms_connection_helper_unlink(&h,stream->soundwrite,0,-1);
/*dismantle the call recording */
if (stream->recorder){
ms_filter_unlink(stream->send_tee,1,stream->recorder_mixer,0);
ms_filter_unlink(stream->recv_tee,1,stream->recorder_mixer,1);
ms_filter_unlink(stream->recorder_mixer,0,stream->recorder,0);
}
}
}