Mercurial > pidgin
annotate src/mediastreamer/osscard.c @ 13160:1b48f0ec55e9
[gaim-migrate @ 15523]
It seems more correct to work in locale format for struct tm.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Tue, 07 Feb 2006 16:29:25 +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 "osscard.h" | |
22 | |
23 #include "msossread.h" | |
24 #include "msosswrite.h" | |
25 | |
12029
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
26 #include <sys/ioctl.h> |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
27 #include <unistd.h> |
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
28 |
12024 | 29 #ifdef HAVE_SYS_SOUNDCARD_H |
30 #include <sys/soundcard.h> | |
31 | |
32 #include <errno.h> | |
33 #include <fcntl.h> | |
34 #include <sys/time.h> | |
35 | |
36 #if 0 | |
37 void * oss_thread(OssCard *obj) | |
38 { | |
39 gint i; | |
40 gint err; | |
41 g_message("oss_thread: starting **********"); | |
42 while(1){ | |
43 for(i=0;i<OSS_CARD_BUFFERS;i++){ | |
44 g_mutex_lock(obj->lock); | |
45 if (obj->ref==0){ | |
46 g_cond_signal(obj->cond); | |
47 g_mutex_unlock(obj->lock); | |
48 g_thread_exit(NULL); | |
49 } | |
50 g_mutex_unlock(obj->lock); | |
51 obj->readindex=i; | |
52 | |
53 err=read(obj->fd,obj->readbuf[i],SND_CARD(obj)->bsize); | |
54 if (err<0) g_warning("oss_thread: read() error:%s.",strerror(errno)); | |
55 obj->writeindex=i; | |
56 write(obj->fd,obj->writebuf[i],SND_CARD(obj)->bsize); | |
57 memset(obj->writebuf[i],0,SND_CARD(obj)->bsize); | |
58 } | |
59 } | |
60 } | |
61 #endif | |
62 int oss_open(OssCard *obj, int bits,int stereo, int rate) | |
63 { | |
64 int fd; | |
65 int p=0,cond=0; | |
66 int i=0; | |
67 int min_size=0,blocksize=512; | |
68 int err; | |
69 | |
70 //g_message("opening sound device"); | |
71 fd=open(obj->dev_name,O_RDWR|O_NONBLOCK); | |
72 if (fd<0) return -EWOULDBLOCK; | |
73 /* unset nonblocking mode */ | |
74 /* We wanted non blocking open but now put it back to normal ; thanks Xine !*/ | |
75 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK); | |
76 | |
77 /* reset is maybe not needed but takes time*/ | |
78 /*ioctl(fd, SNDCTL_DSP_RESET, 0); */ | |
79 | |
80 | |
81 #ifdef WORDS_BIGENDIAN | |
82 p=AFMT_U16_BE; | |
83 #else | |
84 p=AFMT_U16_LE; | |
85 #endif | |
86 | |
87 err=ioctl(fd,SNDCTL_DSP_SETFMT,&p); | |
88 if (err<0){ | |
89 g_warning("oss_open: can't set sample format:%s.",strerror(errno)); | |
90 } | |
91 | |
92 | |
93 p = bits; /* 16 bits */ | |
94 err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p); | |
95 if (err<0){ | |
96 g_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno)); | |
97 } | |
98 | |
99 p = rate; /* rate in khz*/ | |
100 err=ioctl(fd, SNDCTL_DSP_SPEED, &p); | |
101 if (err<0){ | |
102 g_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno)); | |
103 } | |
104 | |
105 p = stereo; /* stereo or not */ | |
106 err=ioctl(fd, SNDCTL_DSP_STEREO, &p); | |
107 if (err<0){ | |
108 g_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno)); | |
109 } | |
110 | |
111 if (rate==16000) blocksize=4096; /* oss emulation is not very good at 16khz */ | |
112 else blocksize=blocksize*(rate/8000); | |
113 ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); | |
114 | |
115 /* try to subdivide BLKSIZE to reach blocksize if necessary */ | |
116 if (min_size>blocksize) | |
117 { | |
118 cond=1; | |
119 p=min_size/blocksize; | |
120 while(cond) | |
121 { | |
122 i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p); | |
123 //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno); | |
124 if ((i==0) || (p==1)) cond=0; | |
125 else p=p/2; | |
126 } | |
127 } | |
128 ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); | |
129 if (min_size>blocksize) | |
130 { | |
131 g_warning("dsp block size set to %i.",min_size); | |
132 }else{ | |
133 /* no need to access the card with less latency than needed*/ | |
134 min_size=blocksize; | |
135 } | |
136 | |
137 g_message("dsp blocksize is %i.",min_size); | |
138 | |
139 /* start recording !!! Alex */ | |
140 { | |
141 int fl,res; | |
142 | |
143 fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT; | |
144 res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl); | |
145 if (res<0) g_warning("OSS_TRIGGER: %s",strerror(errno)); | |
146 } | |
147 | |
148 obj->fd=fd; | |
149 obj->readpos=0; | |
150 obj->writepos=0; | |
151 SND_CARD(obj)->bits=bits; | |
152 SND_CARD(obj)->stereo=stereo; | |
153 SND_CARD(obj)->rate=rate; | |
154 SND_CARD(obj)->bsize=min_size; | |
155 return fd; | |
156 } | |
157 | |
158 int oss_card_probe(OssCard *obj,int bits,int stereo,int rate) | |
159 { | |
160 | |
161 int fd; | |
162 int p=0,cond=0; | |
163 int i=0; | |
164 int min_size=0,blocksize=512; | |
165 | |
166 if (obj->fd>0) return SND_CARD(obj)->bsize; | |
167 fd=open(obj->dev_name,O_RDWR|O_NONBLOCK); | |
168 if (fd<0) { | |
169 g_warning("oss_card_probe: can't open %s: %s.",obj->dev_name,strerror(errno)); | |
170 return -1; | |
171 } | |
172 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
173 | |
174 p = bits; /* 16 bits */ | |
175 ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p); | |
176 | |
177 p = stereo; /* number of channels */ | |
178 ioctl(fd, SNDCTL_DSP_CHANNELS, &p); | |
179 | |
180 p = rate; /* rate in khz*/ | |
181 ioctl(fd, SNDCTL_DSP_SPEED, &p); | |
182 | |
183 ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); | |
184 | |
185 /* try to subdivide BLKSIZE to reach blocksize if necessary */ | |
186 if (min_size>blocksize) | |
187 { | |
188 cond=1; | |
189 p=min_size/blocksize; | |
190 while(cond) | |
191 { | |
192 i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p); | |
193 //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno); | |
194 if ((i==0) || (p==1)) cond=0; | |
195 else p=p/2; | |
196 } | |
197 } | |
198 ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); | |
199 if (min_size>blocksize) | |
200 { | |
201 g_warning("dsp block size set to %i.",min_size); | |
202 }else{ | |
203 /* no need to access the card with less latency than needed*/ | |
204 min_size=blocksize; | |
205 } | |
206 close(fd); | |
207 return min_size; | |
208 } | |
209 | |
210 | |
211 int oss_card_open(OssCard *obj,int bits,int stereo,int rate) | |
212 { | |
213 int fd; | |
214 obj->ref++; | |
215 if (obj->fd==0){ | |
216 fd=oss_open(obj,bits,stereo,rate); | |
217 if (fd<0) { | |
218 obj->fd=0; | |
219 obj->ref--; | |
220 return -1; | |
221 } | |
222 } | |
223 | |
224 obj->readbuf=g_malloc0(SND_CARD(obj)->bsize); | |
225 obj->writebuf=g_malloc0(SND_CARD(obj)->bsize); | |
226 | |
227 SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED; | |
228 return 0; | |
229 } | |
230 | |
231 void oss_card_close(OssCard *obj) | |
232 { | |
233 obj->ref--; | |
234 if (obj->ref==0) { | |
235 close(obj->fd); | |
236 obj->fd=0; | |
237 SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED; | |
238 g_free(obj->readbuf); | |
239 obj->readbuf=NULL; | |
240 g_free(obj->writebuf); | |
241 obj->writebuf=NULL; | |
242 | |
243 } | |
244 } | |
245 | |
246 void oss_card_destroy(OssCard *obj) | |
247 { | |
248 snd_card_uninit(SND_CARD(obj)); | |
249 g_free(obj->dev_name); | |
250 g_free(obj->mixdev_name); | |
251 if (obj->readbuf!=NULL) g_free(obj->readbuf); | |
252 if (obj->writebuf!=NULL) g_free(obj->writebuf); | |
253 } | |
254 | |
255 gboolean oss_card_can_read(OssCard *obj) | |
256 { | |
257 struct timeval tout={0,0}; | |
258 int err; | |
259 fd_set fdset; | |
260 if (obj->readpos!=0) return TRUE; | |
261 FD_ZERO(&fdset); | |
262 FD_SET(obj->fd,&fdset); | |
263 err=select(obj->fd+1,&fdset,NULL,NULL,&tout); | |
264 if (err>0) return TRUE; | |
265 else return FALSE; | |
266 } | |
267 | |
268 int oss_card_read(OssCard *obj,char *buf,int size) | |
269 { | |
270 int err; | |
271 gint bsize=SND_CARD(obj)->bsize; | |
272 if (size<bsize){ | |
273 gint canread=MIN(bsize-obj->readpos,size); | |
274 if (obj->readpos==0){ | |
275 err=read(obj->fd,obj->readbuf,bsize); | |
276 if (err<0) { | |
277 g_warning("oss_card_read: read() failed:%s.",strerror(errno)); | |
278 return -1; | |
279 } | |
280 } | |
281 | |
282 memcpy(buf,&obj->readbuf[obj->readpos],canread); | |
283 obj->readpos+=canread; | |
284 if (obj->readpos>=bsize) obj->readpos=0; | |
285 return canread; | |
286 }else{ | |
287 err=read(obj->fd,buf,size); | |
288 if (err<0) { | |
289 g_warning("oss_card_read: read-2() failed:%s.",strerror(errno)); | |
290 } | |
291 return err; | |
292 } | |
293 | |
294 } | |
295 | |
296 int oss_card_write(OssCard *obj,char *buf,int size) | |
297 { | |
298 int err; | |
299 gint bsize=SND_CARD(obj)->bsize; | |
300 | |
301 if (size<bsize){ | |
302 gint canwrite; | |
303 canwrite=MIN(bsize-obj->writepos,size); | |
304 memcpy(&obj->writebuf[obj->writepos],buf,canwrite); | |
305 obj->writepos+=canwrite; | |
306 if (obj->writepos>=bsize){ | |
307 err=write(obj->fd,obj->writebuf,bsize); | |
308 obj->writepos=0; | |
309 } | |
310 return canwrite; | |
311 }else{ | |
312 return write(obj->fd,buf,bsize); | |
313 } | |
314 } | |
315 | |
316 void oss_card_set_level(OssCard *obj,gint way,gint a) | |
317 { | |
318 int p,mix_fd; | |
319 int osscmd; | |
320 g_return_if_fail(obj->mixdev_name!=NULL); | |
321 #ifdef HAVE_SYS_SOUNDCARD_H | |
322 switch(way){ | |
323 case SND_CARD_LEVEL_GENERAL: | |
324 osscmd=SOUND_MIXER_VOLUME; | |
325 break; | |
326 case SND_CARD_LEVEL_INPUT: | |
327 osscmd=SOUND_MIXER_IGAIN; | |
328 break; | |
329 case SND_CARD_LEVEL_OUTPUT: | |
330 osscmd=SOUND_MIXER_PCM; | |
331 break; | |
332 default: | |
333 g_warning("oss_card_set_level: unsupported command."); | |
334 return; | |
335 } | |
336 p=(((int)a)<<8 | (int)a); | |
337 mix_fd = open(obj->mixdev_name, O_WRONLY); | |
338 ioctl(mix_fd,MIXER_WRITE(osscmd), &p); | |
339 close(mix_fd); | |
340 #endif | |
341 } | |
342 | |
343 gint oss_card_get_level(OssCard *obj,gint way) | |
344 { | |
345 int p=0,mix_fd; | |
346 int osscmd; | |
12029
1c771536a032
[gaim-migrate @ 14322]
Gary Kramlich <grim@reaperworld.com>
parents:
12024
diff
changeset
|
347 g_return_val_if_fail(obj->mixdev_name!=NULL, -1); |
12024 | 348 #ifdef HAVE_SYS_SOUNDCARD_H |
349 switch(way){ | |
350 case SND_CARD_LEVEL_GENERAL: | |
351 osscmd=SOUND_MIXER_VOLUME; | |
352 break; | |
353 case SND_CARD_LEVEL_INPUT: | |
354 osscmd=SOUND_MIXER_IGAIN; | |
355 break; | |
356 case SND_CARD_LEVEL_OUTPUT: | |
357 osscmd=SOUND_MIXER_PCM; | |
358 break; | |
359 default: | |
360 g_warning("oss_card_get_level: unsupported command."); | |
361 return -1; | |
362 } | |
363 mix_fd = open(obj->mixdev_name, O_RDONLY); | |
364 ioctl(mix_fd,MIXER_READ(SOUND_MIXER_VOLUME), &p); | |
365 close(mix_fd); | |
366 #endif | |
367 return p>>8; | |
368 } | |
369 | |
370 void oss_card_set_source(OssCard *obj,int source) | |
371 { | |
372 gint p=0; | |
373 gint mix_fd; | |
374 g_return_if_fail(obj->mixdev_name!=NULL); | |
375 #ifdef HAVE_SYS_SOUNDCARD_H | |
376 if (source == 'c') | |
377 p = 1 << SOUND_MIXER_CD; | |
378 if (source == 'l') | |
379 p = 1 << SOUND_MIXER_LINE; | |
380 if (source == 'm') | |
381 p = 1 << SOUND_MIXER_MIC; | |
382 | |
383 | |
384 mix_fd = open(obj->mixdev_name, O_WRONLY); | |
385 ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p); | |
386 close(mix_fd); | |
387 #endif | |
388 } | |
389 | |
390 MSFilter *oss_card_create_read_filter(OssCard *card) | |
391 { | |
392 MSFilter *f=ms_oss_read_new(); | |
393 ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index); | |
394 return f; | |
395 } | |
396 | |
397 MSFilter *oss_card_create_write_filter(OssCard *card) | |
398 { | |
399 MSFilter *f=ms_oss_write_new(); | |
400 ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index); | |
401 return f; | |
402 } | |
403 | |
404 | |
405 SndCard * oss_card_new(char *devname, char *mixdev_name) | |
406 { | |
407 OssCard * obj= g_new0(OssCard,1); | |
408 SndCard *base= SND_CARD(obj); | |
409 snd_card_init(base); | |
410 obj->dev_name=g_strdup(devname); | |
411 obj->mixdev_name=g_strdup( mixdev_name); | |
412 #ifdef HAVE_GLIB | |
413 base->card_name=g_strdup_printf("%s (Open Sound System)",devname); | |
414 #else | |
415 base->card_name=malloc(100); | |
416 snprintf(base->card_name, 100, "%s (Open Sound System)",devname); | |
417 #endif | |
418 base->_probe=(SndCardOpenFunc)oss_card_probe; | |
419 base->_open_r=(SndCardOpenFunc)oss_card_open; | |
420 base->_open_w=(SndCardOpenFunc)oss_card_open; | |
421 base->_can_read=(SndCardPollFunc)oss_card_can_read; | |
422 base->_read=(SndCardIOFunc)oss_card_read; | |
423 base->_write=(SndCardIOFunc)oss_card_write; | |
424 base->_close_r=(SndCardCloseFunc)oss_card_close; | |
425 base->_close_w=(SndCardCloseFunc)oss_card_close; | |
426 base->_set_rec_source=(SndCardMixerSetRecSourceFunc)oss_card_set_source; | |
427 base->_set_level=(SndCardMixerSetLevelFunc)oss_card_set_level; | |
428 base->_get_level=(SndCardMixerGetLevelFunc)oss_card_get_level; | |
429 base->_destroy=(SndCardDestroyFunc)oss_card_destroy; | |
430 base->_create_read_filter=(SndCardCreateFilterFunc)oss_card_create_read_filter; | |
431 base->_create_write_filter=(SndCardCreateFilterFunc)oss_card_create_write_filter; | |
432 return base; | |
433 } | |
434 | |
435 #define DSP_NAME "/dev/dsp" | |
436 #define MIXER_NAME "/dev/mixer" | |
437 | |
438 gint oss_card_manager_init(SndCardManager *manager, gint tabindex) | |
439 { | |
440 gchar *devname; | |
441 gchar *mixername; | |
442 gint devindex=0; | |
443 gint found=0; | |
444 | |
445 /* search for /dev/dsp and /dev/mixer */ | |
446 #ifdef HAVE_GLIB | |
447 if (g_file_test(DSP_NAME,G_FILE_TEST_EXISTS)){ | |
448 tabindex++; | |
449 devindex++; | |
450 manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME); | |
451 manager->cards[0]->index=0; | |
452 found++; | |
453 g_message("Found /dev/dsp."); | |
454 } | |
455 for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){ | |
456 devname=g_strdup_printf("%s%i",DSP_NAME,devindex); | |
457 mixername=g_strdup_printf("%s%i",MIXER_NAME,devindex); | |
458 if (g_file_test(devname,G_FILE_TEST_EXISTS)){ | |
459 manager->cards[tabindex]=oss_card_new(devname,mixername); | |
460 manager->cards[tabindex]->index=tabindex; | |
461 tabindex++; | |
462 found++; | |
463 } | |
464 g_free(devname); | |
465 g_free(mixername); | |
466 } | |
467 #else | |
468 if (access(DSP_NAME,F_OK)==0){ | |
469 tabindex++; | |
470 devindex++; | |
471 manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME); | |
472 manager->cards[0]->index=0; | |
473 found++; | |
474 g_message("Found /dev/dsp."); | |
475 } | |
476 for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){ | |
477 devname=malloc(100); | |
478 snprintf(devname, 100, "%s%i",DSP_NAME,devindex); | |
479 mixername=malloc(100); | |
480 snprintf(mixername, 100, "%s%i",MIXER_NAME,devindex); | |
481 | |
482 if (access(devname,F_OK)==0){ | |
483 manager->cards[tabindex]=oss_card_new(devname,mixername); | |
484 manager->cards[tabindex]->index=tabindex; | |
485 tabindex++; | |
486 found++; | |
487 } | |
488 g_free(devname); | |
489 g_free(mixername); | |
490 } | |
491 #endif | |
492 if (tabindex==0) g_warning("No sound cards found !"); | |
493 return found; | |
494 } | |
495 | |
496 | |
497 #endif |