1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006-2013 Belledonne Communications, Grenoble
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 
20 
21 
22 #include "mediastreamer2/mediastream.h"
23 #include "mediastreamer2/dtmfgen.h"
24 #include "mediastreamer2/msfileplayer.h"
25 #include "private.h"
26 
27 
ring_player_event_handler(void * ud,MSFilter * f,unsigned int evid,void * arg)28 static void ring_player_event_handler(void *ud, MSFilter *f, unsigned int evid, void *arg){
29 	RingStream *stream=(RingStream*)ud;
30 
31 	if (evid==MS_FILTER_OUTPUT_FMT_CHANGED){
32 		MSPinFormat pinfmt={0};
33 		ms_filter_call_method(stream->source, MS_FILTER_GET_OUTPUT_FMT, &pinfmt);
34 		if (pinfmt.fmt == NULL){
35 			pinfmt.pin = 1;
36 			ms_filter_call_method(stream->source, MS_FILTER_GET_OUTPUT_FMT, &pinfmt);
37 		}
38 
39 		if (stream->write_resampler){
40 			ms_message("Configuring resampler input with rate=[%i], nchannels=[%i]",pinfmt.fmt->rate, pinfmt.fmt->nchannels);
41 			ms_filter_call_method(stream->write_resampler,MS_FILTER_SET_NCHANNELS,(void*)&pinfmt.fmt->nchannels);
42 			ms_filter_call_method(stream->write_resampler,MS_FILTER_SET_SAMPLE_RATE,(void*)&pinfmt.fmt->rate);
43 		}
44 		ms_filter_call_method(stream->gendtmf,MS_FILTER_SET_SAMPLE_RATE, (void*)&pinfmt.fmt->rate);
45 		ms_filter_call_method(stream->gendtmf,MS_FILTER_SET_NCHANNELS, (void*)&pinfmt.fmt->nchannels);
46 	}
47 }
48 
ring_start(MSFactory * factory,const char * file,int interval,MSSndCard * sndcard)49 RingStream * ring_start(MSFactory *factory, const char *file, int interval, MSSndCard *sndcard){
50    return ring_start_with_cb(factory, file,interval,sndcard,NULL,NULL);
51 }
52 
ring_start_with_cb(MSFactory * factory,const char * file,int interval,MSSndCard * sndcard,MSFilterNotifyFunc func,void * user_data)53 RingStream * ring_start_with_cb(MSFactory* factory, const char *file, int interval, MSSndCard *sndcard, MSFilterNotifyFunc func,void * user_data )
54 {
55 	RingStream *stream;
56 	int srcchannels=1, dstchannels=1;
57 	int srcrate,dstrate;
58 	MSConnectionHelper h;
59 	MSTickerParams params={0};
60 	MSPinFormat pinfmt={0};
61 
62 	stream=(RingStream *)ms_new0(RingStream,1);
63 	if (file) {
64 		stream->source=_ms_create_av_player(file,factory);
65 		if (stream->source == NULL){
66 			ms_error("ring_start_with_cb(): could not create player for playing '%s'", file);
67 			ms_free(stream);
68 			return NULL;
69 		}
70 	} else {
71 		/*create dummy source*/
72 		stream->source=ms_factory_create_filter(factory, MS_FILE_PLAYER_ID);
73 	}
74 	ms_filter_add_notify_callback(stream->source,ring_player_event_handler,stream,TRUE);
75 	if (func!=NULL)
76 		ms_filter_add_notify_callback(stream->source,func,user_data,FALSE);
77 	stream->gendtmf=ms_factory_create_filter(factory, MS_DTMF_GEN_ID);
78 	stream->sndwrite=ms_snd_card_create_writer(sndcard);
79 	stream->write_resampler=ms_factory_create_filter(factory, MS_RESAMPLE_ID);
80 
81 	if (file){
82 		/*in we failed to open the file, we must release the stream*/
83 		if (ms_filter_call_method(stream->source,MS_PLAYER_OPEN,(void*)file) != 0) {
84 			ring_stop(stream);
85 			return NULL;
86 		}
87 		ms_filter_call_method(stream->source,MS_PLAYER_SET_LOOP,&interval);
88 		ms_filter_call_method_noarg(stream->source,MS_PLAYER_START);
89 	}
90 
91 	/*configure sound output filter*/
92 	ms_filter_call_method(stream->source, MS_FILTER_GET_OUTPUT_FMT, &pinfmt);
93 	if (pinfmt.fmt == NULL){
94 		pinfmt.pin = 1;
95 		ms_filter_call_method(stream->source, MS_FILTER_GET_OUTPUT_FMT, &pinfmt);
96 		if (pinfmt.fmt == NULL){
97 			/*probably no file is being played, assume pcm*/
98 			pinfmt.fmt = ms_factory_get_audio_format(factory, "pcm", 8000, 1, NULL);
99 		}
100 	}
101 	srcrate = pinfmt.fmt->rate;
102 	srcchannels = pinfmt.fmt->nchannels;
103 
104 	ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&srcrate);
105 	ms_filter_call_method(stream->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&dstrate);
106 	ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_NCHANNELS,&srcchannels);
107 	ms_filter_call_method(stream->sndwrite,MS_FILTER_GET_NCHANNELS,&dstchannels);
108 
109 	/*eventually create a decoder*/
110 	if (strcasecmp(pinfmt.fmt->encoding, "pcm") != 0){
111 		stream->decoder = ms_factory_create_decoder(factory, pinfmt.fmt->encoding);
112 		if (!stream->decoder){
113 			ms_error("RingStream: could not create decoder for '%s'", pinfmt.fmt->encoding);
114 			ring_stop(stream);
115 			return NULL;
116 		}
117 	}
118 
119 	/*configure output of resampler*/
120 	if (stream->write_resampler){
121 		ms_filter_call_method(stream->write_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&dstrate);
122 		ms_filter_call_method(stream->write_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&dstchannels);
123 
124 		/*the input of the resampler, as well as dtmf generator are configured within the ring_player_event_handler()
125 		 * callback triggered during the open of the file player*/
126 		ms_message("configuring resampler output to rate=[%i], nchannels=[%i]",dstrate,dstchannels);
127 	}
128 
129 	params.name="Ring MSTicker";
130 	params.prio=MS_TICKER_PRIO_HIGH;
131 	stream->ticker=ms_ticker_new_with_params(&params);
132 
133 	ms_connection_helper_start(&h);
134 	ms_connection_helper_link(&h,stream->source, -1, pinfmt.pin);
135 	stream->srcpin = pinfmt.pin;
136 	if (stream->decoder){
137 		ms_filter_call_method(stream->decoder, MS_FILTER_SET_NCHANNELS, &srcchannels);
138 		ms_connection_helper_link(&h, stream->decoder, 0, 0);
139 	}
140 	ms_connection_helper_link(&h,stream->gendtmf,0,0);
141 	if (stream->write_resampler)
142 		ms_connection_helper_link(&h,stream->write_resampler,0,0);
143 	ms_connection_helper_link(&h, stream->sndwrite, 0, -1);
144 	ms_ticker_attach(stream->ticker,stream->source);
145 
146 	return stream;
147 }
148 
ring_play_dtmf(RingStream * stream,char dtmf,int duration_ms)149 void ring_play_dtmf(RingStream *stream, char dtmf, int duration_ms){
150 	if (duration_ms>0)
151 		ms_filter_call_method(stream->gendtmf, MS_DTMF_GEN_PLAY, &dtmf);
152 	else ms_filter_call_method(stream->gendtmf, MS_DTMF_GEN_START, &dtmf);
153 }
154 
ring_stop_dtmf(RingStream * stream)155 void ring_stop_dtmf(RingStream *stream){
156 	ms_filter_call_method_noarg(stream->gendtmf, MS_DTMF_GEN_STOP);
157 }
158 
ring_stop(RingStream * stream)159 void ring_stop(RingStream *stream){
160 	MSConnectionHelper h;
161 
162 	if (stream->ticker){
163 		ms_ticker_detach(stream->ticker,stream->source);
164 
165 		ms_connection_helper_start(&h);
166 		ms_connection_helper_unlink(&h,stream->source,-1, stream->srcpin);
167 		if (stream->decoder){
168 			ms_connection_helper_unlink(&h,stream->decoder, 0, 0);
169 		}
170 		ms_connection_helper_unlink(&h,stream->gendtmf,0,0);
171 		if (stream->write_resampler)
172 			ms_connection_helper_unlink(&h,stream->write_resampler,0,0);
173 		ms_connection_helper_unlink(&h,stream->sndwrite,0,-1);
174 		ms_ticker_destroy(stream->ticker);
175 	}
176 	if (stream->source) ms_filter_destroy(stream->source);
177 	if (stream->gendtmf) ms_filter_destroy(stream->gendtmf);
178 	if (stream->sndwrite) ms_filter_destroy(stream->sndwrite);
179 	if (stream->decoder) ms_filter_destroy(stream->decoder);
180 	if (stream->write_resampler)
181 		ms_filter_destroy(stream->write_resampler);
182 	ms_free(stream);
183 }
184