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(¶ms);
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