Mercurial > pidgin
annotate src/mediastreamer/osscard.c @ 12116:e75ef7aa913e
[gaim-migrate @ 14416]
" This patch implements a replacement for the queuing
system from 1.x. It also obsoletes a previous patch
[#1338873] I submitted to prioritize the unseen states
in gtk conversations.
The attached envelope.png is ripped from the
msgunread.png already included in gaim. It should be
dropped in the pixmaps directory (Makefile.am is
updated accordingly in this patch).
The two separate queuing preferences from 1.x, queuing
messages while away and queuing all new messages (from
docklet), are replaced with a single 3-way preference
for conversations. The new preference is "Hide new IM
conversations". This preference can be set to never,
away and always.
When a gtk conversation is created, it may be placed in
a hidden conversation window instead of being placed
normally. This decision is based upon the preference
and possibly the away state of the account the
conversation is being created for. This *will* effect
conversations the user explicitly requests to be
created, so in these cases the caller must be sure to
present the conversation to the user, using
gaim_gtkconv_present_conversation(). This is done
already in gtkdialogs.c which handles creating
conversations requested by the user from gaim proper
(menus, double-clicking on budy in blist, etc.).
The main advantage to not queuing messages is that the
conversations exist, the message is written to the
conversation (and logged if appropriate) and the unseen
state is set on the conversation. This means no
additional features are needed to track whether there
are queued messages or not, just use the unseen state
on conversations.
Since conversations may not be visible (messages
"queued"), gaim proper needs some notification that
there are messages waiting. I opted for a menutray icon
that shows up when an im conversation has an unseen
message. Clicking this icon will focus (and show if
hidden) the first conversation with an unseen message.
This is essentially the same behavior of the docklet in
cvs right now, except that the icon is only visible
when there is a conversation with an unread message.
The api that is added is flexible enough to allow
either the docklet or the new blist menutray icon to be
visible for conversations of any/all types and for
unseen messages >= any state. Currently they are set to
only IM conversations and only unseen states >= TEXT
(system messages and no log messages will not trigger
blinking the docklet or showing the blist tray icon),
but these could be made preferences relatively easily
in the future. Other plugins could probably benefit as
well: gaim_gtk_conversations_get_first_unseen().
There is probably some limit to comment size, so I'll
stop rambling now. If anyone has more
questions/comments, catch me in #gaim, here or on
gaim-devel."
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Wed, 16 Nov 2005 18:17:01 +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 |