Mercurial > pidgin
annotate src/mediastreamer/msringplayer.c @ 12767:53218d758ba9
[gaim-migrate @ 15114]
Make the dns lookup for udp connecting asynchronous. Thomas pointed out that it should be instantaneous anyway because the SRV lookup that has just been done, but this'll avoid blocking if the SRV lookup failed or something.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Sun, 08 Jan 2006 22:09:28 +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 "msringplayer.h" | |
22 #include "mssync.h" | |
23 #include <unistd.h> | |
24 #include <fcntl.h> | |
25 #include <sys/types.h> | |
26 #include <string.h> | |
27 #include <errno.h> | |
12029
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
28 #include <stdlib.h> |
12024 | 29 |
30 #include "waveheader.h" | |
31 | |
32 #define WAVE_HEADER_OFFSET sizeof(wave_header_t) | |
33 | |
34 enum { PLAY_RING, PLAY_SILENCE}; | |
35 | |
36 static int supported_freq[6]={8000,11025,16000,22050,32000,44100}; | |
37 | |
38 gint freq_is_supported(gint freq){ | |
39 int i; | |
40 for (i=0;i<6;i++){ | |
41 if (abs(supported_freq[i]-freq)<50) return supported_freq[i]; | |
42 } | |
43 return 0; | |
44 } | |
45 | |
46 static MSRingPlayerClass *ms_ring_player_class=NULL; | |
47 | |
48 /** | |
49 * ms_ring_player_new: | |
50 * @name: The path to the 16-bit 8khz raw file to be played as a ring. | |
51 * @seconds: The number of seconds that separates two rings. | |
52 * | |
53 * Allocates a new MSRingPlayer object. | |
54 * | |
55 * | |
56 * Returns: a pointer the the object, NULL if name could not be open. | |
57 */ | |
58 MSFilter * ms_ring_player_new(char *name, gint seconds) | |
59 { | |
60 MSRingPlayer *r; | |
61 int fd=-1; | |
62 | |
63 if ((name!=NULL) && (strlen(name)!=0)) | |
64 { | |
65 fd=open(name,O_RDONLY); | |
66 if (fd<0) | |
67 { | |
68 g_warning("ms_ring_player_new: failed to open %s.\n",name); | |
69 return NULL; | |
70 } | |
71 | |
72 }else { | |
73 g_warning("ms_ring_player_new: Bad file name"); | |
74 return NULL; | |
75 } | |
76 | |
77 r=g_new(MSRingPlayer,1); | |
78 ms_ring_player_init(r); | |
79 if (ms_ring_player_class==NULL) | |
80 { | |
81 ms_ring_player_class=g_new(MSRingPlayerClass,1); | |
82 ms_ring_player_class_init(ms_ring_player_class); | |
83 } | |
84 MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ring_player_class); | |
85 | |
86 r->fd=fd; | |
87 r->silence=seconds; | |
88 r->freq=8000; | |
89 if (strstr(name,".wav")!=NULL){ | |
90 wave_header_t header; | |
91 int freq,freq2; | |
92 /* read the header */ | |
93 read(fd,&header,sizeof(wave_header_t)); | |
94 freq=wave_header_get_rate(&header); | |
95 if ((freq2=freq_is_supported(freq))>0){ | |
96 r->freq=freq2; | |
97 }else { | |
98 g_warning("Unsupported sampling rate %i",freq); | |
99 r->freq=8000; | |
100 } | |
101 r->channel=wave_header_get_channel(&header); | |
102 lseek(fd,WAVE_HEADER_OFFSET,SEEK_SET); | |
103 #ifdef WORDS_BIGENDIAN | |
104 r->need_swap=1; | |
105 #else | |
106 r->need_swap=0; | |
107 #endif | |
108 } | |
109 ms_ring_player_set_property(r, MS_FILTER_PROPERTY_FREQ,&r->freq); | |
110 r->state=PLAY_RING; | |
111 return(MS_FILTER(r)); | |
112 } | |
113 | |
114 | |
115 /* FOR INTERNAL USE*/ | |
116 void ms_ring_player_init(MSRingPlayer *r) | |
117 { | |
118 ms_filter_init(MS_FILTER(r)); | |
119 MS_FILTER(r)->outfifos=r->foutputs; | |
120 MS_FILTER(r)->outqueues=r->qoutputs; | |
121 memset(r->foutputs,0,sizeof(MSFifo*)*MS_RING_PLAYER_MAX_OUTPUTS); | |
122 memset(r->qoutputs,0,sizeof(MSQueue*)*MS_RING_PLAYER_MAX_OUTPUTS); | |
123 r->fd=-1; | |
124 r->current_pos=0; | |
125 r->need_swap=0; | |
126 r->sync=NULL; | |
127 } | |
128 | |
129 gint ms_ring_player_set_property(MSRingPlayer *f,MSFilterProperty prop, void *value) | |
130 { | |
131 switch(prop){ | |
132 case MS_FILTER_PROPERTY_FREQ: | |
133 f->rate=((gint*)value)[0]*2; | |
134 f->silence_bytes=f->silence*f->rate; | |
135 if (f->sync!=NULL) | |
136 f->gran=(f->rate*f->sync->interval/1000)*2; | |
137 break; | |
12029
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
138 case MS_FILTER_PROPERTY_BITRATE: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
139 case MS_FILTER_PROPERTY_CHANNELS: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
140 case MS_FILTER_PROPERTY_FMTP: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
141 default: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
142 break; |
12024 | 143 } |
144 return 0; | |
145 } | |
146 | |
147 gint ms_ring_player_get_property(MSRingPlayer *f,MSFilterProperty prop, void *value) | |
148 { | |
149 switch(prop){ | |
150 case MS_FILTER_PROPERTY_FREQ: | |
151 ((gint*)value)[0]=f->freq; | |
152 | |
153 break; | |
154 case MS_FILTER_PROPERTY_CHANNELS: | |
155 ((gint*)value)[0]=f->channel; | |
156 break; | |
12029
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
157 case MS_FILTER_PROPERTY_BITRATE: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
158 case MS_FILTER_PROPERTY_FMTP: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
159 default: |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
160 break; |
12024 | 161 } |
162 return 0; | |
163 } | |
164 | |
165 gint ms_ring_player_get_sample_freq(MSRingPlayer *obj){ | |
166 return obj->freq; | |
167 } | |
168 | |
169 | |
170 void ms_ring_player_class_init(MSRingPlayerClass *klass) | |
171 { | |
172 ms_filter_class_init(MS_FILTER_CLASS(klass)); | |
173 ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ringplay"); | |
174 ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE); | |
175 MS_FILTER_CLASS(klass)->max_foutputs=MS_RING_PLAYER_MAX_OUTPUTS; | |
176 MS_FILTER_CLASS(klass)->max_qoutputs=MS_RING_PLAYER_MAX_OUTPUTS; | |
177 MS_FILTER_CLASS(klass)->w_maxgran=MS_RING_PLAYER_DEF_GRAN; | |
178 MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ring_player_setup; | |
179 MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ring_player_destroy; | |
180 MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ring_player_process; | |
181 MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ring_player_set_property; | |
182 MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ring_player_get_property; | |
183 } | |
184 | |
185 void ms_ring_player_process(MSRingPlayer *r) | |
186 { | |
187 MSFifo *f; | |
188 gint err; | |
189 gint processed=0; | |
190 gint gran=r->gran; | |
191 char *p; | |
192 | |
193 g_return_if_fail(gran>0); | |
194 /* process output fifos*/ | |
195 | |
196 f=r->foutputs[0]; | |
197 ms_fifo_get_write_ptr(f,gran,(void**)&p); | |
198 g_return_if_fail(p!=NULL); | |
199 for (processed=0;processed<gran;){ | |
200 switch(r->state){ | |
201 case PLAY_RING: | |
202 err=read(r->fd,&p[processed],gran-processed); | |
203 if (err<0) | |
204 { | |
205 memset(&p[processed],0,gran-processed); | |
206 processed=gran; | |
207 g_warning("ms_ring_player_process: failed to read: %s.\n",strerror(errno)); | |
208 return; | |
209 } | |
210 else if (err<gran) | |
211 {/* end of file */ | |
212 | |
213 r->current_pos=r->silence_bytes; | |
214 lseek(r->fd,WAVE_HEADER_OFFSET,SEEK_SET); | |
215 r->state=PLAY_SILENCE; | |
216 ms_filter_notify_event(MS_FILTER(r),MS_RING_PLAYER_END_OF_RING_EVENT,NULL); | |
217 } | |
218 if (r->need_swap) swap_buffer(&p[processed],err); | |
219 processed+=err; | |
220 break; | |
221 case PLAY_SILENCE: | |
222 err=gran-processed; | |
223 if (r->current_pos>err){ | |
224 memset(&p[processed],0,err); | |
225 r->current_pos-=gran; | |
226 processed=gran; | |
227 }else{ | |
228 memset(&p[processed],0,r->current_pos); | |
229 processed+=r->current_pos; | |
230 r->state=PLAY_RING; | |
231 } | |
232 break; | |
233 } | |
234 } | |
235 } | |
236 | |
237 /** | |
238 * ms_ring_player_destroy: | |
239 * @obj: A valid MSRingPlayer object. | |
240 * | |
241 * Destroy a MSRingPlayer object. | |
242 * | |
243 * | |
244 */ | |
245 | |
246 void ms_ring_player_destroy( MSRingPlayer *obj) | |
247 { | |
248 if (obj->fd!=0) close(obj->fd); | |
249 g_free(obj); | |
250 } | |
251 | |
252 void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync) | |
253 { | |
254 r->sync=sync; | |
255 r->gran=(r->rate*r->sync->interval/1000)*r->channel; | |
256 } |