~ubuntu-branches/ubuntu/trusty/linphone/trusty

« back to all changes in this revision

Viewing changes to mediastreamer2/src/voip/audioconference.c

  • Committer: Package Import Robot
  • Author(s): Luk Claes
  • Date: 2013-09-11 19:08:43 UTC
  • mfrom: (1.1.19) (16.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20130911190843-fkydjxsdvy1fmx24
Tags: 3.6.1-2.1
* Non-maintainer upload.
* Apply Sebastian Ramacher's patch to fix FTBFS (Closes: #720668).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
mediastreamer2 library - modular sound and video processing and streaming
 
3
Copyright (C) 2011 Belledonne Communications SARL
 
4
Author: Simon MORLAT (simon.morlat@linphone.org)
 
5
 
 
6
This program is free software; you can redistribute it and/or
 
7
modify it under the terms of the GNU General Public License
 
8
as published by the Free Software Foundation; either version 2
 
9
of the License, or (at your option) any later version.
 
10
 
 
11
This program is distributed in the hope that it will be useful,
 
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with this program; if not, write to the Free Software
 
18
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
19
*/
 
20
 
 
21
#include "mediastreamer2/msconference.h"
 
22
#include "mediastreamer2/msaudiomixer.h"
 
23
#include "private.h"
 
24
 
 
25
struct _MSAudioConference{
 
26
        MSTicker *ticker;
 
27
        MSFilter *mixer;
 
28
        MSAudioConferenceParams params;
 
29
        int nmembers;
 
30
};
 
31
 
 
32
struct _MSAudioEndpoint{
 
33
        AudioStream *st;
 
34
        MSFilter *in_resampler,*out_resampler;
 
35
        MSCPoint out_cut_point;
 
36
        MSCPoint in_cut_point;
 
37
        MSCPoint in_cut_point_prev;
 
38
        MSCPoint mixer_in;
 
39
        MSCPoint mixer_out;
 
40
        MSAudioConference *conference;
 
41
        MSFilter *recorder; /* in case it is a recorder endpoint*/
 
42
        MSFilter *player; /* not used at the moment, but we need it so that there is a source connected to the mixer*/
 
43
        int pin;
 
44
        int samplerate;
 
45
};
 
46
 
 
47
 
 
48
 
 
49
MSAudioConference * ms_audio_conference_new(const MSAudioConferenceParams *params){
 
50
        MSAudioConference *obj=ms_new0(MSAudioConference,1);
 
51
        int tmp=1;
 
52
        obj->ticker=ms_ticker_new();
 
53
        ms_ticker_set_name(obj->ticker,"Audio conference MSTicker");
 
54
        ms_ticker_set_priority(obj->ticker,__ms_get_default_prio(FALSE));
 
55
        obj->mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
 
56
        obj->params=*params;
 
57
        ms_filter_call_method(obj->mixer,MS_AUDIO_MIXER_ENABLE_CONFERENCE_MODE,&tmp);
 
58
        ms_filter_call_method(obj->mixer,MS_FILTER_SET_SAMPLE_RATE,&obj->params.samplerate);
 
59
        return obj;
 
60
}
 
61
 
 
62
const MSAudioConferenceParams *ms_audio_conference_get_params(MSAudioConference *obj){
 
63
        return &obj->params;
 
64
}
 
65
 
 
66
static MSCPoint just_before(MSFilter *f){
 
67
        MSQueue *q;
 
68
        MSCPoint pnull={0};
 
69
        if ((q=f->inputs[0])!=NULL){
 
70
                return q->prev;
 
71
        }
 
72
        ms_fatal("No filter before %s",f->desc->name);
 
73
        return pnull;
 
74
}
 
75
 
 
76
static MSCPoint just_after(MSFilter *f){
 
77
        MSQueue *q;
 
78
        MSCPoint pnull={0};
 
79
        if ((q=f->outputs[0])!=NULL){
 
80
                return q->next;
 
81
        }
 
82
        ms_fatal("No filter after %s",f->desc->name);
 
83
        return pnull;
 
84
}
 
85
 
 
86
static void cut_audio_stream_graph(MSAudioEndpoint *ep, bool_t is_remote){
 
87
        AudioStream *st=ep->st;
 
88
 
 
89
        /*stop the audio graph*/
 
90
        ms_ticker_detach(st->ms.ticker,st->soundread);
 
91
        if (!st->ec) ms_ticker_detach(st->ms.ticker,st->soundwrite);
 
92
 
 
93
        ep->in_cut_point_prev.pin=0;
 
94
        if (is_remote){
 
95
                /*we would like to keep the volrecv (MSVolume filter) in the graph to measure the output level*/
 
96
                ep->in_cut_point_prev.filter=st->volrecv;
 
97
        }else{
 
98
                ep->in_cut_point_prev.filter=st->plc ? st->plc : st->ms.decoder;
 
99
        }
 
100
        ep->in_cut_point=just_after(ep->in_cut_point_prev.filter);
 
101
        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);
 
102
 
 
103
        ep->out_cut_point=just_before(st->ms.encoder);
 
104
        ms_filter_unlink(ep->out_cut_point.filter,ep->out_cut_point.pin,st->ms.encoder,0);
 
105
 
 
106
        ms_filter_call_method(st->ms.rtpsend,MS_FILTER_GET_SAMPLE_RATE,&ep->samplerate);
 
107
 
 
108
        if (is_remote){
 
109
                ep->mixer_in.filter=ep->in_cut_point_prev.filter;
 
110
                ep->mixer_in.pin=ep->in_cut_point_prev.pin;
 
111
                ep->mixer_out.filter=st->ms.encoder;
 
112
                ep->mixer_out.pin=0;
 
113
        }else{
 
114
                ep->mixer_in=ep->out_cut_point;
 
115
                ep->mixer_out=ep->in_cut_point;
 
116
        }
 
117
}
 
118
 
 
119
 
 
120
static void redo_audio_stream_graph(MSAudioEndpoint *ep){
 
121
        AudioStream *st=ep->st;
 
122
        ms_filter_link(ep->in_cut_point_prev.filter,ep->in_cut_point_prev.pin,ep->in_cut_point.filter,ep->in_cut_point.pin);
 
123
        ms_filter_link(ep->out_cut_point.filter,ep->out_cut_point.pin,st->ms.encoder,0);
 
124
        ms_ticker_attach(st->ms.ticker,st->soundread);
 
125
        if (!st->ec)
 
126
                ms_ticker_attach(st->ms.ticker,st->soundwrite);
 
127
}
 
128
 
 
129
static int find_free_pin(MSFilter *mixer){
 
130
        int i;
 
131
        for(i=0;i<mixer->desc->ninputs;++i){
 
132
                if (mixer->inputs[i]==NULL){
 
133
                        return i;
 
134
                }
 
135
        }
 
136
        ms_fatal("No more free pin in mixer filter");
 
137
        return -1;
 
138
}
 
139
 
 
140
static void plumb_to_conf(MSAudioEndpoint *ep){
 
141
        MSAudioConference *conf=ep->conference;
 
142
        int in_rate=ep->samplerate,out_rate=ep->samplerate;
 
143
        
 
144
        if (ep->samplerate!=-1){
 
145
                out_rate=in_rate=ep->samplerate;
 
146
        }else in_rate=out_rate=conf->params.samplerate;
 
147
        
 
148
        if (ep->recorder){
 
149
                ms_filter_call_method(ep->recorder,MS_FILTER_SET_SAMPLE_RATE,&conf->params.samplerate);
 
150
        }
 
151
        
 
152
        ep->pin=find_free_pin(conf->mixer);
 
153
        
 
154
        if (ep->mixer_in.filter){
 
155
                ms_filter_link(ep->mixer_in.filter,ep->mixer_in.pin,ep->in_resampler,0);
 
156
                ms_filter_link(ep->in_resampler,0,conf->mixer,ep->pin);
 
157
        }
 
158
        if (ep->mixer_out.filter){
 
159
                ms_filter_link(conf->mixer,ep->pin,ep->out_resampler,0);
 
160
                ms_filter_link(ep->out_resampler,0,ep->mixer_out.filter,ep->mixer_out.pin);
 
161
        }
 
162
 
 
163
        /*configure resamplers*/
 
164
        ms_filter_call_method(ep->in_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&conf->params.samplerate);
 
165
        ms_filter_call_method(ep->out_resampler,MS_FILTER_SET_SAMPLE_RATE,&conf->params.samplerate);
 
166
        ms_filter_call_method(ep->in_resampler,MS_FILTER_SET_SAMPLE_RATE,&in_rate);
 
167
        ms_filter_call_method(ep->out_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&out_rate);
 
168
        
 
169
}
 
170
 
 
171
void ms_audio_conference_add_member(MSAudioConference *obj, MSAudioEndpoint *ep){
 
172
        /* now connect to the mixer */
 
173
        ep->conference=obj;
 
174
        if (obj->nmembers>0) ms_ticker_detach(obj->ticker,obj->mixer);
 
175
        plumb_to_conf(ep);
 
176
        ms_ticker_attach(obj->ticker,obj->mixer);
 
177
        obj->nmembers++;
 
178
}
 
179
 
 
180
static void unplumb_from_conf(MSAudioEndpoint *ep){
 
181
        MSAudioConference *conf=ep->conference;
 
182
        
 
183
        if (ep->mixer_in.filter){
 
184
                ms_filter_unlink(ep->mixer_in.filter,ep->mixer_in.pin,ep->in_resampler,0);
 
185
                ms_filter_unlink(ep->in_resampler,0,conf->mixer,ep->pin);
 
186
        }
 
187
        if (ep->mixer_out.filter){
 
188
                ms_filter_unlink(conf->mixer,ep->pin,ep->out_resampler,0);
 
189
                ms_filter_unlink(ep->out_resampler,0,ep->mixer_out.filter,ep->mixer_out.pin);
 
190
        }
 
191
}
 
192
 
 
193
void ms_audio_conference_remove_member(MSAudioConference *obj, MSAudioEndpoint *ep){
 
194
        ms_ticker_detach(obj->ticker,obj->mixer);
 
195
        unplumb_from_conf(ep);
 
196
        ep->conference=NULL;
 
197
        obj->nmembers--;
 
198
        if (obj->nmembers>0) ms_ticker_attach(obj->ticker,obj->mixer);
 
199
}
 
200
 
 
201
void ms_audio_conference_mute_member(MSAudioConference *obj, MSAudioEndpoint *ep, bool_t muted){
 
202
        MSAudioMixerCtl ctl={0};
 
203
        ctl.pin=ep->pin;
 
204
        ctl.param.active=!muted;
 
205
        ms_filter_call_method(ep->conference->mixer, MS_AUDIO_MIXER_SET_ACTIVE, &ctl);
 
206
}
 
207
 
 
208
int ms_audio_conference_get_size(MSAudioConference *obj){
 
209
        return obj->nmembers;
 
210
}
 
211
 
 
212
 
 
213
void ms_audio_conference_destroy(MSAudioConference *obj){
 
214
        ms_ticker_destroy(obj->ticker);
 
215
        ms_filter_destroy(obj->mixer);
 
216
        ms_free(obj);
 
217
}
 
218
 
 
219
MSAudioEndpoint *ms_audio_endpoint_new(void){
 
220
        MSAudioEndpoint *ep=ms_new0(MSAudioEndpoint,1);
 
221
        ep->in_resampler=ms_filter_new(MS_RESAMPLE_ID);
 
222
        ep->out_resampler=ms_filter_new(MS_RESAMPLE_ID);
 
223
        ep->samplerate=8000;
 
224
        return ep;
 
225
}
 
226
 
 
227
MSAudioEndpoint * ms_audio_endpoint_get_from_stream(AudioStream *st, bool_t is_remote){
 
228
        MSAudioEndpoint *ep=ms_audio_endpoint_new();
 
229
        ep->st=st;
 
230
        cut_audio_stream_graph(ep,is_remote);
 
231
        return ep;
 
232
}
 
233
 
 
234
void ms_audio_endpoint_release_from_stream(MSAudioEndpoint *obj){
 
235
        redo_audio_stream_graph(obj);
 
236
        ms_audio_endpoint_destroy(obj);
 
237
}
 
238
 
 
239
void ms_audio_endpoint_destroy(MSAudioEndpoint *ep){
 
240
        if (ep->in_resampler) ms_filter_destroy(ep->in_resampler);
 
241
        if (ep->out_resampler) ms_filter_destroy(ep->out_resampler);
 
242
        if (ep->recorder) ms_filter_destroy(ep->recorder);
 
243
        if (ep->player) ms_filter_destroy(ep->player);
 
244
        ms_free(ep);
 
245
}
 
246
 
 
247
MSAudioEndpoint * ms_audio_endpoint_new_recorder(){
 
248
        MSAudioEndpoint *ep=ms_audio_endpoint_new();
 
249
        ep->recorder=ms_filter_new(MS_FILE_REC_ID);
 
250
        ep->player=ms_filter_new(MS_FILE_PLAYER_ID);
 
251
        ep->mixer_out.filter=ep->recorder;
 
252
        ep->mixer_in.filter=ep->player;
 
253
        ep->samplerate=-1;
 
254
        return ep;
 
255
}
 
256
 
 
257
int ms_audio_recorder_endpoint_start(MSAudioEndpoint *ep, const char *path){
 
258
        int err;
 
259
        MSRecorderState state;
 
260
        if (!ep->recorder){
 
261
                ms_error("This endpoint isn't a recorder endpoint.");
 
262
                return -1;
 
263
        }
 
264
        ms_filter_call_method(ep->recorder,MS_RECORDER_GET_STATE,&state);
 
265
        if (state!=MSRecorderClosed)
 
266
                ms_filter_call_method_noarg(ep->recorder,MS_RECORDER_CLOSE);
 
267
        err=ms_filter_call_method(ep->recorder,MS_RECORDER_OPEN,(void*)path);
 
268
        if (err==-1) return -1;
 
269
        return ms_filter_call_method_noarg(ep->recorder,MS_RECORDER_START);
 
270
}
 
271
 
 
272
int ms_audio_recorder_endpoint_stop(MSAudioEndpoint *ep){
 
273
        if (!ep->recorder){
 
274
                return -1;
 
275
        }
 
276
        return ms_filter_call_method_noarg(ep->recorder,MS_RECORDER_CLOSE);
 
277
}
 
278