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)
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.
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.
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.
21
#include "mediastreamer2/msconference.h"
22
#include "mediastreamer2/msaudiomixer.h"
25
struct _MSAudioConference{
28
MSAudioConferenceParams params;
32
struct _MSAudioEndpoint{
34
MSFilter *in_resampler,*out_resampler;
35
MSCPoint out_cut_point;
36
MSCPoint in_cut_point;
37
MSCPoint in_cut_point_prev;
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*/
49
MSAudioConference * ms_audio_conference_new(const MSAudioConferenceParams *params){
50
MSAudioConference *obj=ms_new0(MSAudioConference,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);
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);
62
const MSAudioConferenceParams *ms_audio_conference_get_params(MSAudioConference *obj){
66
static MSCPoint just_before(MSFilter *f){
69
if ((q=f->inputs[0])!=NULL){
72
ms_fatal("No filter before %s",f->desc->name);
76
static MSCPoint just_after(MSFilter *f){
79
if ((q=f->outputs[0])!=NULL){
82
ms_fatal("No filter after %s",f->desc->name);
86
static void cut_audio_stream_graph(MSAudioEndpoint *ep, bool_t is_remote){
87
AudioStream *st=ep->st;
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);
93
ep->in_cut_point_prev.pin=0;
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;
98
ep->in_cut_point_prev.filter=st->plc ? st->plc : st->ms.decoder;
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);
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);
106
ms_filter_call_method(st->ms.rtpsend,MS_FILTER_GET_SAMPLE_RATE,&ep->samplerate);
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;
114
ep->mixer_in=ep->out_cut_point;
115
ep->mixer_out=ep->in_cut_point;
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);
126
ms_ticker_attach(st->ms.ticker,st->soundwrite);
129
static int find_free_pin(MSFilter *mixer){
131
for(i=0;i<mixer->desc->ninputs;++i){
132
if (mixer->inputs[i]==NULL){
136
ms_fatal("No more free pin in mixer filter");
140
static void plumb_to_conf(MSAudioEndpoint *ep){
141
MSAudioConference *conf=ep->conference;
142
int in_rate=ep->samplerate,out_rate=ep->samplerate;
144
if (ep->samplerate!=-1){
145
out_rate=in_rate=ep->samplerate;
146
}else in_rate=out_rate=conf->params.samplerate;
149
ms_filter_call_method(ep->recorder,MS_FILTER_SET_SAMPLE_RATE,&conf->params.samplerate);
152
ep->pin=find_free_pin(conf->mixer);
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);
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);
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);
171
void ms_audio_conference_add_member(MSAudioConference *obj, MSAudioEndpoint *ep){
172
/* now connect to the mixer */
174
if (obj->nmembers>0) ms_ticker_detach(obj->ticker,obj->mixer);
176
ms_ticker_attach(obj->ticker,obj->mixer);
180
static void unplumb_from_conf(MSAudioEndpoint *ep){
181
MSAudioConference *conf=ep->conference;
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);
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);
193
void ms_audio_conference_remove_member(MSAudioConference *obj, MSAudioEndpoint *ep){
194
ms_ticker_detach(obj->ticker,obj->mixer);
195
unplumb_from_conf(ep);
198
if (obj->nmembers>0) ms_ticker_attach(obj->ticker,obj->mixer);
201
void ms_audio_conference_mute_member(MSAudioConference *obj, MSAudioEndpoint *ep, bool_t muted){
202
MSAudioMixerCtl ctl={0};
204
ctl.param.active=!muted;
205
ms_filter_call_method(ep->conference->mixer, MS_AUDIO_MIXER_SET_ACTIVE, &ctl);
208
int ms_audio_conference_get_size(MSAudioConference *obj){
209
return obj->nmembers;
213
void ms_audio_conference_destroy(MSAudioConference *obj){
214
ms_ticker_destroy(obj->ticker);
215
ms_filter_destroy(obj->mixer);
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);
227
MSAudioEndpoint * ms_audio_endpoint_get_from_stream(AudioStream *st, bool_t is_remote){
228
MSAudioEndpoint *ep=ms_audio_endpoint_new();
230
cut_audio_stream_graph(ep,is_remote);
234
void ms_audio_endpoint_release_from_stream(MSAudioEndpoint *obj){
235
redo_audio_stream_graph(obj);
236
ms_audio_endpoint_destroy(obj);
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);
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;
257
int ms_audio_recorder_endpoint_start(MSAudioEndpoint *ep, const char *path){
259
MSRecorderState state;
261
ms_error("This endpoint isn't a recorder endpoint.");
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);
272
int ms_audio_recorder_endpoint_stop(MSAudioEndpoint *ep){
276
return ms_filter_call_method_noarg(ep->recorder,MS_RECORDER_CLOSE);