Mercurial > pidgin.yaz
annotate src/mediastreamer/audiostream.c @ 12343:a02f877637a6
[gaim-migrate @ 14647]
If no plugin is selected the plugins dialog, then ensure the expander
is collapsed and disabled
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 05 Dec 2005 04:32:32 +0000 |
parents | 1c771536a032 |
children |
rev | line source |
---|---|
12024 | 1 /* |
2 The mediastreamer library aims at providing modular media processing and I/O | |
3 for linphone, but also for any telephony application. | |
4 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org | |
5 | |
6 This library is free software; you can redistribute it and/or | |
7 modify it under the terms of the GNU Lesser General Public | |
8 License as published by the Free Software Foundation; either | |
9 version 2.1 of the License, or (at your option) any later version. | |
10 | |
11 This library 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 GNU | |
14 Lesser General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU Lesser General Public | |
17 License along with this library; if not, write to the Free Software | |
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 */ | |
20 | |
21 #include "mediastream.h" | |
22 #ifdef INET6 | |
23 #include <sys/types.h> | |
24 #include <sys/socket.h> | |
25 #include <netdb.h> | |
26 #endif | |
27 | |
28 | |
29 #define MAX_RTP_SIZE 1500 | |
30 | |
31 /* this code is not part of the library itself, it is part of the mediastream program */ | |
32 void audio_stream_free(AudioStream *stream) | |
33 { | |
34 RtpSession *s; | |
35 RtpSession *destroyed=NULL; | |
36 if (stream->rtprecv!=NULL) { | |
37 s=ms_rtp_recv_get_session(MS_RTP_RECV(stream->rtprecv)); | |
38 if (s!=NULL){ | |
39 destroyed=s; | |
40 rtp_session_destroy(s); | |
41 } | |
42 ms_filter_destroy(stream->rtprecv); | |
43 } | |
44 if (stream->rtpsend!=NULL) { | |
45 s=ms_rtp_send_get_session(MS_RTP_SEND(stream->rtpsend)); | |
46 if (s!=NULL){ | |
47 if (s!=destroyed) | |
48 rtp_session_destroy(s); | |
49 } | |
50 ms_filter_destroy(stream->rtpsend); | |
51 } | |
52 if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread); | |
53 if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite); | |
54 if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder); | |
55 if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder); | |
56 if (stream->timer!=NULL) ms_sync_destroy(stream->timer); | |
57 g_free(stream); | |
58 } | |
59 | |
60 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; | |
61 | |
62 static void on_dtmf_received(RtpSession *s,gint dtmf,gpointer user_data) | |
63 { | |
64 AudioStream *stream=(AudioStream*)user_data; | |
65 if (dtmf>15){ | |
66 g_warning("Unsupported telephone-event type."); | |
67 return; | |
68 } | |
69 g_message("Receiving dtmf %c.",dtmf_tab[dtmf]); | |
70 if (stream!=NULL){ | |
71 if (strcmp(stream->soundwrite->klass->name,"OssWrite")==0) | |
72 ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf_tab[dtmf]); | |
73 } | |
74 } | |
75 | |
76 static void on_timestamp_jump(RtpSession *s,guint32* ts, gpointer user_data) | |
77 { | |
78 g_warning("The remote sip-phone has send data with a future timestamp: %u," | |
79 "resynchronising session.",*ts); | |
80 rtp_session_reset(s); | |
81 } | |
82 | |
83 static const char *ip4local="0.0.0.0"; | |
84 static const char *ip6local="::"; | |
85 | |
86 const char *get_local_addr_for(const char *remote) | |
87 { | |
88 const char *ret; | |
89 #ifdef INET6 | |
90 struct addrinfo hints, *res0; | |
91 int err; | |
92 memset(&hints, 0, sizeof(hints)); | |
93 hints.ai_family = PF_UNSPEC; | |
94 hints.ai_socktype = SOCK_DGRAM; | |
95 err = getaddrinfo(remote,"8000", &hints, &res0); | |
96 if (err!=0) { | |
97 g_warning ("get_local_addr_for: %s", gai_strerror(err)); | |
98 return ip4local; | |
99 } | |
100 ret=(res0->ai_addr->sa_family==AF_INET6) ? ip6local : ip4local; | |
101 freeaddrinfo(res0); | |
102 #else | |
103 ret=ip4local; | |
104 #endif | |
105 return ret; | |
106 } | |
107 | |
108 void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport, | |
109 int payload,int jitt_comp, | |
110 RtpSession **recvsend){ | |
111 RtpSession *rtpr; | |
112 rtpr=rtp_session_new(RTP_SESSION_SENDRECV); | |
113 rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE); | |
114 rtp_session_set_profile(rtpr,profile); | |
115 rtp_session_set_local_addr(rtpr,get_local_addr_for(remip),locport); | |
116 if (remport>0) rtp_session_set_remote_addr(rtpr,remip,remport); | |
117 rtp_session_set_scheduling_mode(rtpr,0); | |
118 rtp_session_set_blocking_mode(rtpr,0); | |
119 rtp_session_set_payload_type(rtpr,payload); | |
120 rtp_session_set_jitter_compensation(rtpr,jitt_comp); | |
121 rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE); | |
122 /*rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);*/ | |
123 *recvsend=rtpr; | |
124 } | |
125 | |
126 void create_rtp_sessions(RtpProfile *profile, int locport,char *remip,int remport, | |
127 int payload,int jitt_comp, | |
128 RtpSession **recv, RtpSession **send){ | |
129 RtpSession *rtps,*rtpr; | |
130 /* creates two rtp filters to recv send streams (remote part)*/ | |
131 | |
132 rtps=rtp_session_new(RTP_SESSION_SENDONLY); | |
133 rtp_session_max_buf_size_set(rtps,MAX_RTP_SIZE); | |
134 rtp_session_set_profile(rtps,profile); | |
135 #ifdef INET6 | |
136 rtp_session_set_local_addr(rtps,"::",locport+2); | |
137 #else | |
138 rtp_session_set_local_addr(rtps,"0.0.0.0",locport+2); | |
139 #endif | |
140 rtp_session_set_remote_addr(rtps,remip,remport); | |
141 rtp_session_set_scheduling_mode(rtps,0); | |
142 rtp_session_set_blocking_mode(rtps,0); | |
143 rtp_session_set_payload_type(rtps,payload); | |
144 rtp_session_set_jitter_compensation(rtps,jitt_comp); | |
145 | |
146 rtpr=rtp_session_new(RTP_SESSION_RECVONLY); | |
147 rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE); | |
148 rtp_session_set_profile(rtpr,profile); | |
149 #ifdef INET6 | |
150 rtp_session_set_local_addr(rtpr,"::",locport); | |
151 #else | |
152 rtp_session_set_local_addr(rtpr,"0.0.0.0",locport); | |
153 #endif | |
154 rtp_session_set_scheduling_mode(rtpr,0); | |
155 rtp_session_set_blocking_mode(rtpr,0); | |
156 rtp_session_set_payload_type(rtpr,payload); | |
157 rtp_session_set_jitter_compensation(rtpr,jitt_comp); | |
158 rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,NULL); | |
159 rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL); | |
160 *recv=rtpr; | |
161 *send=rtps; | |
162 | |
163 } | |
164 | |
165 | |
166 AudioStream * audio_stream_start_full(RtpProfile *profile, int locport,char *remip,int remport, | |
167 int payload,int jitt_comp, gchar *infile, gchar *outfile, SndCard *playcard, SndCard *captcard) | |
168 { | |
169 AudioStream *stream=g_new0(AudioStream,1); | |
170 RtpSession *rtps,*rtpr; | |
171 PayloadType *pt; | |
172 | |
173 //create_rtp_sessions(profile,locport,remip,remport,payload,jitt_comp,&rtpr,&rtps); | |
174 | |
175 create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr); | |
176 rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,(gpointer)stream); | |
177 rtps=rtpr; | |
178 | |
179 stream->rtpsend=ms_rtp_send_new(); | |
180 ms_rtp_send_set_session(MS_RTP_SEND(stream->rtpsend),rtps); | |
181 stream->rtprecv=ms_rtp_recv_new(); | |
182 ms_rtp_recv_set_session(MS_RTP_RECV(stream->rtprecv),rtpr); | |
183 | |
184 | |
185 /* creates the local part */ | |
186 if (infile==NULL) stream->soundread=snd_card_create_read_filter(captcard); | |
187 else stream->soundread=ms_read_new(infile); | |
188 if (outfile==NULL) stream->soundwrite=snd_card_create_write_filter(playcard); | |
189 else stream->soundwrite=ms_write_new(outfile); | |
190 | |
191 /* creates the couple of encoder/decoder */ | |
192 pt=rtp_profile_get_payload(profile,payload); | |
193 if (pt==NULL){ | |
194 g_error("audiostream.c: undefined payload type."); | |
195 return NULL; | |
196 } | |
197 stream->encoder=ms_encoder_new_with_string_id(pt->mime_type); | |
198 stream->decoder=ms_decoder_new_with_string_id(pt->mime_type); | |
199 if ((stream->encoder==NULL) || (stream->decoder==NULL)){ | |
200 /* big problem: we have not a registered codec for this payload...*/ | |
201 audio_stream_free(stream); | |
202 g_error("mediastream.c: No decoder available for payload %i.",payload); | |
203 return NULL; | |
204 } | |
205 /* give the sound filters some properties */ | |
206 ms_filter_set_property(stream->soundread,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); | |
207 ms_filter_set_property(stream->soundwrite,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); | |
208 | |
209 /* give the encoder/decoder some parameters*/ | |
210 ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); | |
211 ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate); | |
212 ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); | |
213 ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate); | |
214 | |
215 ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->fmtp); | |
216 ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->fmtp); | |
217 /* create the synchronisation source */ | |
218 stream->timer=ms_timer_new(); | |
219 | |
220 /* and then connect all */ | |
221 ms_filter_add_link(stream->soundread,stream->encoder); | |
222 ms_filter_add_link(stream->encoder,stream->rtpsend); | |
223 ms_filter_add_link(stream->rtprecv,stream->decoder); | |
224 ms_filter_add_link(stream->decoder,stream->soundwrite); | |
225 | |
226 ms_sync_attach(stream->timer,stream->soundread); | |
227 ms_sync_attach(stream->timer,stream->rtprecv); | |
228 | |
229 /* and start */ | |
230 ms_start(stream->timer); | |
231 | |
232 return stream; | |
233 } | |
234 | |
235 static int defcard=0; | |
236 | |
237 void audio_stream_set_default_card(int cardindex){ | |
238 defcard=cardindex; | |
239 } | |
240 | |
241 AudioStream * audio_stream_start_with_files(RtpProfile *prof,int locport,char *remip, | |
242 int remport,int profile,int jitt_comp,gchar *infile, gchar*outfile) | |
243 { | |
244 return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,infile,outfile,NULL,NULL); | |
245 } | |
246 | |
247 AudioStream * audio_stream_start(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp) | |
248 { | |
249 SndCard *sndcard; | |
250 sndcard=snd_card_manager_get_card(snd_card_manager,defcard); | |
251 return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,sndcard,sndcard); | |
252 } | |
253 | |
254 AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp,SndCard *playcard, SndCard *captcard) | |
255 { | |
256 g_return_val_if_fail(playcard!=NULL,NULL); | |
257 g_return_val_if_fail(captcard!=NULL,NULL); | |
258 return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,playcard,captcard); | |
259 } | |
260 | |
261 void audio_stream_set_rtcp_information(AudioStream *st, const char *cname){ | |
262 if (st->send_session!=NULL){ | |
263 rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL,NULL,"linphone-" "2.0.0", // SME | |
264 "This is free software (GPL) !"); | |
265 } | |
266 } | |
267 | |
268 void audio_stream_stop(AudioStream * stream) | |
269 { | |
270 | |
271 ms_stop(stream->timer); | |
272 ortp_global_stats_display(); | |
273 ms_sync_detach(stream->timer,stream->soundread); | |
274 ms_sync_detach(stream->timer,stream->rtprecv); | |
275 | |
276 ms_filter_remove_links(stream->soundread,stream->encoder); | |
277 ms_filter_remove_links(stream->encoder,stream->rtpsend); | |
278 ms_filter_remove_links(stream->rtprecv,stream->decoder); | |
279 ms_filter_remove_links(stream->decoder,stream->soundwrite); | |
280 | |
281 audio_stream_free(stream); | |
282 } | |
283 | |
284 RingStream * ring_start(gchar *file,gint interval,SndCard *sndcard) | |
285 { | |
286 return ring_start_with_cb(file,interval,sndcard,NULL,NULL); | |
287 } | |
288 | |
289 RingStream * ring_start_with_cb(gchar *file,gint interval,SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data) | |
290 { | |
291 RingStream *stream; | |
292 int tmp; | |
293 g_return_val_if_fail(sndcard!=NULL,NULL); | |
294 stream=g_new0(RingStream,1); | |
295 stream->source=ms_ring_player_new(file,interval); | |
296 if (stream->source==NULL) { | |
297 g_warning("Could not create ring player. Probably the ring file (%s) does not exist.",file); | |
298 return NULL; | |
299 } | |
300 if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data); | |
301 stream->sndwrite=snd_card_create_write_filter(sndcard); | |
302 ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_FREQ,&tmp); | |
303 ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_FREQ,&tmp); | |
304 ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_CHANNELS,&tmp); | |
305 ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_CHANNELS,&tmp); | |
306 stream->timer=ms_timer_new(); | |
307 ms_filter_add_link(stream->source,stream->sndwrite); | |
308 ms_sync_attach(stream->timer,stream->source); | |
309 ms_start(stream->timer); | |
310 return stream; | |
311 } | |
312 | |
313 void ring_stop(RingStream *stream) | |
314 { | |
315 ms_stop(stream->timer); | |
316 ms_sync_detach(stream->timer,stream->source); | |
317 ms_sync_destroy(stream->timer); | |
318 ms_filter_remove_links(stream->source,stream->sndwrite); | |
319 ms_filter_destroy(stream->source); | |
320 ms_filter_destroy(stream->sndwrite); | |
321 g_free(stream); | |
322 } | |
323 | |
324 /* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */ | |
325 gint test_audio_dev(int dev_id) | |
326 { | |
327 gint err; | |
328 SndCard *sndcard=snd_card_manager_get_card(snd_card_manager,dev_id); | |
329 if (sndcard==NULL) return -1; | |
330 err=snd_card_probe(sndcard,16,0,8000); | |
331 return err; /* return latency in number of sample */ | |
332 } | |
333 | |
334 gint audio_stream_send_dtmf(AudioStream *stream, gchar dtmf) | |
335 { | |
336 ms_rtp_send_dtmf(MS_RTP_SEND(stream->rtpsend), dtmf); | |
337 ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf); | |
12029
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
338 |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
339 /* not sure what this should be returning, nothing in mediastreamer calls |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
340 * it directly, assuming 0 is okay here. -- Gary |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
341 */ |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
342 return 0; |
12024 | 343 } |