Mercurial > pidgin
annotate src/mediastreamer/msringplayer.c @ 12643:29c034547358
[gaim-migrate @ 14980]
This allows sametime to compile if you have the libmeanwhile devel package.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Fri, 23 Dec 2005 18:33:52 +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 } |