commit de lancement : 2.0.1-1
[asterisk-app-conference.git] / conference.c
1
2 // $Id: conference.c 886 2007-08-06 14:33:34Z bcholew $
3
4 /*
5 * app_conference
6 *
7 * A channel independent conference application for Asterisk
8 *
9 * Copyright (C) 2002, 2003 Junghanns.NET GmbH
10 * Copyright (C) 2003, 2004 HorizonLive.com, Inc.
11 * Copyright (C) 2005, 2006 HorizonWimba, Inc.
12 * Copyright (C) 2007 Wimba, Inc.
13 *
14 * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
15 *
16 * Video Conferencing support added by
17 * Neil Stratford <neils@vipadia.com>
18 * Copyright (C) 2005, 2005 Vipadia Limited
19 *
20 * VAD driven video conferencing, text message support
21 * and miscellaneous enhancements added by
22 * Mihai Balea <mihai at hates dot ms>
23 *
24 * This program may be modified and distributed under the
25 * terms of the GNU General Public License. You should have received
26 * a copy of the GNU General Public License along with this
27 * program; if not, write to the Free Software Foundation, Inc.
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 */
30
31 #include "asterisk/autoconfig.h"
32 #include "conference.h"
33 #include "asterisk/utils.h"
34
35 //
36 // static variables
37 //
38
39 // single-linked list of current conferences
40 struct ast_conference *conflist = NULL ;
41
42 // mutex for synchronizing access to conflist
43 //static ast_mutex_t conflist_lock = AST_MUTEX_INITIALIZER ;
44 AST_MUTEX_DEFINE_STATIC(conflist_lock);
45
46 static int conference_count = 0 ;
47
48
49 //
50 // main conference function
51 //
52
53 void conference_exec( struct ast_conference *conf )
54 {
55
56 struct ast_conf_member *next_member;
57 struct ast_conf_member *member, *video_source_member, *dtmf_source_member;;
58 struct conf_frame *cfr, *spoken_frames, *send_frames;
59
60 // count number of speakers, number of listeners
61 int speaker_count ;
62 int listener_count ;
63
64 ast_log( AST_CONF_DEBUG, "Entered conference_exec, name => %s\n", conf->name ) ;
65
66 // timer timestamps
67 struct timeval base, curr, notify ;
68 base = notify = ast_tvnow();
69
70 // holds differences of curr and base
71 long time_diff = 0 ;
72 long time_sleep = 0 ;
73
74 int since_last_slept = 0 ;
75
76 //
77 // variables for checking thread frequency
78 //
79
80 // count to AST_CONF_FRAMES_PER_SECOND
81 int tf_count = 0 ;
82 long tf_diff = 0 ;
83 float tf_frequency = 0.0 ;
84
85 struct timeval tf_base, tf_curr ;
86 tf_base = ast_tvnow();
87
88 //
89 // main conference thread loop
90 //
91
92
93 while ( 42 == 42 )
94 {
95 // update the current timestamp
96 curr = ast_tvnow();
97
98 // calculate difference in timestamps
99 time_diff = ast_tvdiff_ms(curr, base);
100
101 // calculate time we should sleep
102 time_sleep = AST_CONF_FRAME_INTERVAL - time_diff ;
103
104 if ( time_sleep > 0 )
105 {
106 // sleep for sleep_time ( as milliseconds )
107 usleep( time_sleep * 1000 ) ;
108
109 // reset since last slept counter
110 since_last_slept = 0 ;
111
112 continue ;
113 }
114 else
115 {
116 // long sleep warning
117 if (
118 since_last_slept == 0
119 && time_diff > AST_CONF_CONFERENCE_SLEEP * 2
120 )
121 {
122 ast_log(
123 AST_CONF_DEBUG,
124 "long scheduling delay, time_diff => %ld, AST_CONF_FRAME_INTERVAL => %d\n",
125 time_diff, AST_CONF_FRAME_INTERVAL
126 ) ;
127 }
128
129 // increment times since last slept
130 ++since_last_slept ;
131
132 // sleep every other time
133 if ( since_last_slept % 2 )
134 usleep( 0 ) ;
135 }
136
137 // adjust the timer base ( it will be used later to timestamp outgoing frames )
138 add_milliseconds( &base, AST_CONF_FRAME_INTERVAL ) ;
139
140 //
141 // check thread frequency
142 //
143
144 if ( ++tf_count >= AST_CONF_FRAMES_PER_SECOND )
145 {
146 // update current timestamp
147 tf_curr = ast_tvnow();
148
149 // compute timestamp difference
150 tf_diff = ast_tvdiff_ms(tf_curr, tf_base);
151
152 // compute sampling frequency
153 tf_frequency = ( float )( tf_diff ) / ( float )( tf_count ) ;
154
155 if (
156 ( tf_frequency <= ( float )( AST_CONF_FRAME_INTERVAL - 1 ) )
157 || ( tf_frequency >= ( float )( AST_CONF_FRAME_INTERVAL + 1 ) )
158 )
159 {
160 ast_log(
161 LOG_WARNING,
162 "processed frame frequency variation, name => %s, tf_count => %d, tf_diff => %ld, tf_frequency => %2.4f\n",
163 conf->name, tf_count, tf_diff, tf_frequency
164 ) ;
165 }
166
167 // reset values
168 tf_base = tf_curr ;
169 tf_count = 0 ;
170 }
171
172 //-----------------//
173 // INCOMING FRAMES //
174 //-----------------//
175
176 // ast_log( AST_CONF_DEBUG, "PROCESSING FRAMES, conference => %s, step => %d, ms => %ld\n",
177 // conf->name, step, ( base.tv_usec / 20000 ) ) ;
178
179 //
180 // check if the conference is empty and if so
181 // remove it and break the loop
182 //
183
184 // acquire the conference list lock
185 ast_mutex_lock(&conflist_lock);
186
187 // acquire the conference mutex
188 ast_mutex_lock(&conf->lock);
189
190 if ( conf->membercount == 0 )
191 {
192 if (conf->debug_flag)
193 {
194 ast_log( LOG_NOTICE, "removing conference, count => %d, name => %s\n", conf->membercount, conf->name ) ;
195 }
196 remove_conf( conf ) ; // stop the conference
197
198 // We don't need to release the conf mutex, since it was destroyed anyway
199
200 // release the conference list lock
201 ast_mutex_unlock(&conflist_lock);
202
203 break ; // break from main processing loop
204 }
205
206 // release the conference mutex
207 ast_mutex_unlock(&conf->lock);
208
209 // release the conference list lock
210 ast_mutex_unlock(&conflist_lock);
211
212
213 //
214 // Start processing frames
215 //
216
217 // acquire conference mutex
218 TIMELOG(ast_mutex_lock( &conf->lock ),1,"conf thread conf lock");
219
220 if ( conf->membercount == 0 )
221 {
222 // release the conference mutex
223 ast_mutex_unlock(&conf->lock);
224 continue; // We'll check again at the top of the loop
225 }
226
227 // update the current delivery time
228 conf->delivery_time = base ;
229
230 //
231 // loop through the list of members
232 // ( conf->memberlist is a single-linked list )
233 //
234
235 // ast_log( AST_CONF_DEBUG, "begin processing incoming audio, name => %s\n", conf->name ) ;
236
237 // reset speaker and listener count
238 speaker_count = 0 ;
239 listener_count = 0 ;
240
241 // get list of conference members
242 member = conf->memberlist ;
243
244 // reset pointer lists
245 spoken_frames = NULL ;
246
247 // reset video source
248 video_source_member = NULL;
249
250 // reset dtmf source
251 dtmf_source_member = NULL;
252
253 // loop over member list to retrieve queued frames
254 while ( member != NULL )
255 {
256 // take note of next member - before it's too late
257 next_member = member->next;
258
259 // this MIGHT delete member
260 member_process_spoken_frames(conf,member,&spoken_frames,time_diff,
261 &listener_count, &speaker_count);
262
263 // adjust our pointer to the next inline
264 member = next_member;
265 }
266
267 // ast_log( AST_CONF_DEBUG, "finished processing incoming audio, name => %s\n", conf->name ) ;
268
269
270 //---------------//
271 // MIXING FRAMES //
272 //---------------//
273
274 // mix frames and get batch of outgoing frames
275 send_frames = mix_frames( spoken_frames, speaker_count, listener_count ) ;
276
277 // accounting: if there are frames, count them as one incoming frame
278 if ( send_frames != NULL )
279 {
280 // set delivery timestamp
281 //set_conf_frame_delivery( send_frames, base ) ;
282 // ast_log ( LOG_WARNING, "base = %d,%d: conf->delivery_time = %d,%d\n",base.tv_sec,base.tv_usec, conf->delivery_time.tv_sec, conf->delivery_time.tv_usec);
283
284 // ast_log( AST_CONF_DEBUG, "base => %ld.%ld %d\n", base.tv_sec, base.tv_usec, ( int )( base.tv_usec / 1000 ) ) ;
285
286 conf->stats.frames_in++ ;
287 }
288
289 //-----------------//
290 // OUTGOING FRAMES //
291 //-----------------//
292
293 //
294 // loop over member list to queue outgoing frames
295 //
296 for ( member = conf->memberlist ; member != NULL ; member = member->next )
297 {
298 member_process_outgoing_frames(conf, member, send_frames);
299 }
300
301 //-------//
302 // VIDEO //
303 //-------//
304
305 // loop over the incoming frames and send to all outgoing
306 // TODO: this is an O(n^2) algorithm. Can we speed it up without sacrificing per-member switching?
307 for (video_source_member = conf->memberlist;
308 video_source_member != NULL;
309 video_source_member = video_source_member->next)
310 {
311 while ((cfr = get_incoming_video_frame( video_source_member )))
312 {
313 for (member = conf->memberlist; member != NULL; member = member->next)
314 {
315 // skip members that are not ready or are not supposed to receive video
316 if ( !member->ready_for_outgoing || member->norecv_video )
317 continue ;
318
319 if ( conf->video_locked )
320 {
321 // Always send video from the locked source
322 if ( conf->current_video_source_id == video_source_member->id )
323 queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time);
324 } else
325 {
326 // If the member has vad switching disabled and dtmf switching enabled, use that
327 if ( member->dtmf_switch &&
328 !member->vad_switch &&
329 member->req_id == video_source_member->id
330 )
331 {
332 queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time);
333 } else
334 {
335 // If no dtmf switching, then do VAD switching
336 // The VAD switching decision code should make sure that our video source
337 // is legit
338 if ( (conf->current_video_source_id == video_source_member->id) ||
339 (conf->current_video_source_id < 0 &&
340 conf->default_video_source_id == video_source_member->id
341 )
342 )
343 {
344 queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time);
345 }
346 }
347
348
349 }
350 }
351 // Garbage collection
352 delete_conf_frame(cfr);
353 }
354 }
355
356 //------//
357 // DTMF //
358 //------//
359
360 // loop over the incoming frames and send to all outgoing
361 for (dtmf_source_member = conf->memberlist; dtmf_source_member != NULL; dtmf_source_member = dtmf_source_member->next)
362 {
363 while ((cfr = get_incoming_dtmf_frame( dtmf_source_member )))
364 {
365 for (member = conf->memberlist; member != NULL; member = member->next)
366 {
367 // skip members that are not ready
368 if ( member->ready_for_outgoing == 0 )
369 {
370 continue ;
371 }
372
373 if (member != dtmf_source_member)
374 {
375 // Send the latest frame
376 queue_outgoing_dtmf_frame(member, cfr->fr);
377 }
378 }
379 // Garbage collection
380 delete_conf_frame(cfr);
381 }
382 }
383
384 //---------//
385 // CLEANUP //
386 //---------//
387
388 // clean up send frames
389 while ( send_frames != NULL )
390 {
391 // accouting: count all frames and mixed frames
392 if ( send_frames->member == NULL )
393 conf->stats.frames_out++ ;
394 else
395 conf->stats.frames_mixed++ ;
396
397 // delete the frame
398 send_frames = delete_conf_frame( send_frames ) ;
399 }
400
401 //
402 // notify the manager of state changes every 100 milliseconds
403 // we piggyback on this for VAD switching logic
404 //
405
406 if ( ( ast_tvdiff_ms(curr, notify) / AST_CONF_NOTIFICATION_SLEEP ) >= 1 )
407 {
408 // Do VAD switching logic
409 // We need to do this here since send_state_change_notifications
410 // resets the flags
411 if ( !conf->video_locked )
412 do_VAD_switching(conf);
413
414 // send the notifications
415 send_state_change_notifications( conf->memberlist ) ;
416
417 // increment the notification timer base
418 add_milliseconds( &notify, AST_CONF_NOTIFICATION_SLEEP ) ;
419 }
420
421 // release conference mutex
422 ast_mutex_unlock( &conf->lock ) ;
423
424 // !!! TESTING !!!
425 // usleep( 1 ) ;
426 }
427 // end while ( 42 == 42 )
428
429 //
430 // exit the conference thread
431 //
432
433 ast_log( AST_CONF_DEBUG, "exit conference_exec\n" ) ;
434
435 // exit the thread
436 pthread_exit( NULL ) ;
437
438 return ;
439 }
440
441 //
442 // manange conference functions
443 //
444
445 // called by app_conference.c:load_module()
446 void init_conference( void )
447 {
448 ast_mutex_init( &conflist_lock ) ;
449 }
450
451 struct ast_conference* start_conference( struct ast_conf_member* member )
452 {
453 // check input
454 if ( member == NULL )
455 {
456 ast_log( LOG_WARNING, "unable to handle null member\n" ) ;
457 return NULL ;
458 }
459
460 struct ast_conference* conf = NULL ;
461
462 // acquire the conference list lock
463 ast_mutex_lock(&conflist_lock);
464
465
466
467 // look for an existing conference
468 ast_log( AST_CONF_DEBUG, "attempting to find requested conference\n" ) ;
469 conf = find_conf( member->conf_name ) ;
470
471 // unable to find an existing conference, try to create one
472 if ( conf == NULL )
473 {
474 // create a new conference
475 ast_log( AST_CONF_DEBUG, "attempting to create requested conference\n" ) ;
476
477 // create the new conference with one member
478 conf = create_conf( member->conf_name, member ) ;
479
480 // return an error if create_conf() failed
481 if ( conf == NULL )
482 ast_log( LOG_ERROR, "unable to find or create requested conference\n" ) ;
483 }
484 else
485 {
486 //
487 // existing conference found, add new member to the conference
488 //
489 // once we call add_member(), this thread
490 // is responsible for calling delete_member()
491 //
492 add_member( member, conf ) ;
493 }
494
495 // release the conference list lock
496 ast_mutex_unlock(&conflist_lock);
497
498 return conf ;
499 }
500
501 // This function should be called with conflist_lock mutex being held
502 struct ast_conference* find_conf( const char* name )
503 {
504 // no conferences exist
505 if ( conflist == NULL )
506 {
507 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", name ) ;
508 return NULL ;
509 }
510
511 struct ast_conference *conf = conflist ;
512
513 // loop through conf list
514 while ( conf != NULL )
515 {
516 if ( strncasecmp( (char*)&(conf->name), name, 80 ) == 0 )
517 {
518 // found conf name match
519 ast_log( AST_CONF_DEBUG, "found conference in conflist, name => %s\n", name ) ;
520 return conf;
521 }
522 conf = conf->next ;
523 }
524
525 ast_log( AST_CONF_DEBUG, "unable to find conference in conflist, name => %s\n", name ) ;
526 return NULL;
527 }
528
529 // This function should be called with conflist_lock held
530 struct ast_conference* create_conf( char* name, struct ast_conf_member* member )
531 {
532 ast_log( AST_CONF_DEBUG, "entered create_conf, name => %s\n", name ) ;
533
534 //
535 // allocate memory for conference
536 //
537
538 struct ast_conference *conf = malloc( sizeof( struct ast_conference ) ) ;
539
540 if ( conf == NULL )
541 {
542 ast_log( LOG_ERROR, "unable to malloc ast_conference\n" ) ;
543 return NULL ;
544 }
545
546 //
547 // initialize conference
548 //
549
550 conf->next = NULL ;
551 conf->memberlist = NULL ;
552
553 conf->membercount = 0 ;
554 conf->conference_thread = -1 ;
555
556 conf->debug_flag = 0 ;
557
558 conf->id_count = 0;
559
560 conf->default_video_source_id = -1;
561 conf->current_video_source_id = -1;
562 //conf->current_video_source_timestamp = ast_tvnow();
563 conf->video_locked = 0;
564
565 // zero stats
566 memset( &conf->stats, 0x0, sizeof( ast_conference_stats ) ) ;
567
568 // record start time
569 conf->stats.time_entered = ast_tvnow();
570
571 // copy name to conference
572 strncpy( (char*)&(conf->name), name, sizeof(conf->name) - 1 ) ;
573 strncpy( (char*)&(conf->stats.name), name, sizeof(conf->name) - 1 ) ;
574
575 // initialize mutexes
576 ast_mutex_init( &conf->lock ) ;
577
578 // build translation paths
579 conf->from_slinear_paths[ AC_SLINEAR_INDEX ] = NULL ;
580 conf->from_slinear_paths[ AC_ULAW_INDEX ] = ast_translator_build_path( AST_FORMAT_ULAW, AST_FORMAT_SLINEAR ) ;
581 conf->from_slinear_paths[ AC_ALAW_INDEX ] = ast_translator_build_path( AST_FORMAT_ALAW, AST_FORMAT_SLINEAR ) ;
582 conf->from_slinear_paths[ AC_GSM_INDEX ] = ast_translator_build_path( AST_FORMAT_GSM, AST_FORMAT_SLINEAR ) ;
583 conf->from_slinear_paths[ AC_SPEEX_INDEX ] = ast_translator_build_path( AST_FORMAT_SPEEX, AST_FORMAT_SLINEAR ) ;
584 #ifdef AC_USE_G729A
585 conf->from_slinear_paths[ AC_G729A_INDEX ] = ast_translator_build_path( AST_FORMAT_G729A, AST_FORMAT_SLINEAR ) ;
586 #endif
587
588 // add the initial member
589 add_member( member, conf ) ;
590
591 ast_log( AST_CONF_DEBUG, "added new conference to conflist, name => %s\n", name ) ;
592
593 //
594 // spawn thread for new conference, using conference_exec( conf )
595 //
596 // acquire conference mutexes
597 ast_mutex_lock( &conf->lock ) ;
598
599 if ( ast_pthread_create( &conf->conference_thread, NULL, (void*)conference_exec, conf ) == 0 )
600 {
601 // detach the thread so it doesn't leak
602 pthread_detach( conf->conference_thread ) ;
603
604 // prepend new conference to conflist
605 conf->next = conflist ;
606 conflist = conf ;
607
608 // release conference mutexes
609 ast_mutex_unlock( &conf->lock ) ;
610
611 ast_log( AST_CONF_DEBUG, "started conference thread for conference, name => %s\n", conf->name ) ;
612 }
613 else
614 {
615 ast_log( LOG_ERROR, "unable to start conference thread for conference %s\n", conf->name ) ;
616
617 conf->conference_thread = -1 ;
618
619 // release conference mutexes
620 ast_mutex_unlock( &conf->lock ) ;
621
622 // clean up conference
623 free( conf ) ;
624 conf = NULL ;
625 }
626
627 // count new conference
628 if ( conf != NULL )
629 ++conference_count ;
630
631 return conf ;
632 }
633
634 //This function should be called with conflist_lock and conf->lock held
635 void remove_conf( struct ast_conference *conf )
636 {
637 int c;
638
639 // ast_log( AST_CONF_DEBUG, "attempting to remove conference, name => %s\n", conf->name ) ;
640
641 struct ast_conference *conf_current = conflist ;
642 struct ast_conference *conf_temp = NULL ;
643
644 // loop through list of conferences
645 while ( conf_current != NULL )
646 {
647 // if conf_current point to the passed conf,
648 if ( conf_current == conf )
649 {
650 if ( conf_temp == NULL )
651 {
652 // this is the first conf in the list, so we just point
653 // conflist past the current conf to the next
654 conflist = conf_current->next ;
655 }
656 else
657 {
658 // this is not the first conf in the list, so we need to
659 // point the preceeding conf to the next conf in the list
660 conf_temp->next = conf_current->next ;
661 }
662
663 //
664 // do some frame clean up
665 //
666
667 for ( c = 0 ; c < AC_SUPPORTED_FORMATS ; ++c )
668 {
669 // free the translation paths
670 if ( conf_current->from_slinear_paths[ c ] != NULL )
671 {
672 ast_translator_free_path( conf_current->from_slinear_paths[ c ] ) ;
673 conf_current->from_slinear_paths[ c ] = NULL ;
674 }
675 }
676
677 // calculate time in conference
678 // total time converted to seconds
679 long tt = ast_tvdiff_ms(ast_tvnow(),
680 conf_current->stats.time_entered) / 1000;
681
682 // report accounting information
683 if (conf->debug_flag)
684 {
685 ast_log( LOG_NOTICE, "conference accounting, fi => %ld, fo => %ld, fm => %ld, tt => %ld\n",
686 conf_current->stats.frames_in, conf_current->stats.frames_out, conf_current->stats.frames_mixed, tt ) ;
687
688 ast_log( AST_CONF_DEBUG, "removed conference, name => %s\n", conf_current->name ) ;
689 }
690
691 ast_mutex_unlock( &conf_current->lock ) ;
692
693 free( conf_current ) ;
694 conf_current = NULL ;
695
696 break ;
697 }
698
699 // save a refence to the soon to be previous conf
700 conf_temp = conf_current ;
701
702 // move conf_current to the next in the list
703 conf_current = conf_current->next ;
704 }
705
706 // count new conference
707 --conference_count ;
708
709 return ;
710 }
711
712 int get_new_id( struct ast_conference *conf )
713 {
714 // must have the conf lock when calling this
715 int newid;
716 struct ast_conf_member *othermember;
717 // get a video ID for this member
718 newid = 0;
719 othermember = conf->memberlist;
720 while (othermember)
721 {
722 if (othermember->id == newid)
723 {
724 newid++;
725 othermember = conf->memberlist;
726 }
727 else
728 {
729 othermember = othermember->next;
730 }
731 }
732 return newid;
733 }
734
735
736 int end_conference(const char *name, int hangup )
737 {
738 struct ast_conference *conf;
739
740 // acquire the conference list lock
741 ast_mutex_lock(&conflist_lock);
742
743 conf = find_conf(name);
744 if ( conf == NULL )
745 {
746 ast_log( LOG_WARNING, "could not find conference\n" ) ;
747
748 // release the conference list lock
749 ast_mutex_unlock(&conflist_lock);
750
751 return -1 ;
752 }
753
754 // acquire the conference lock
755 ast_mutex_lock( &conf->lock ) ;
756
757 // get list of conference members
758 struct ast_conf_member* member = conf->memberlist ;
759
760 // loop over member list and request hangup
761 while ( member != NULL )
762 {
763 // acquire member mutex and request hangup
764 // or just kick
765 ast_mutex_lock( &member->lock ) ;
766 if (hangup)
767 ast_softhangup( member->chan, 1 ) ;
768 else
769 member->kick_flag = 1;
770 ast_mutex_unlock( &member->lock ) ;
771
772 // go on to the next member
773 // ( we have the conf lock, so we know this is okay )
774 member = member->next ;
775 }
776
777 // release the conference lock
778 ast_mutex_unlock( &conf->lock ) ;
779
780 // release the conference list lock
781 ast_mutex_unlock(&conflist_lock);
782
783 return 0 ;
784 }
785
786 //
787 // member-related functions
788 //
789
790 // This function should be called with conflist_lock held
791 void add_member( struct ast_conf_member *member, struct ast_conference *conf )
792 {
793 int newid, last_id;
794 struct ast_conf_member *othermember;
795 int count;
796
797 if ( conf == NULL )
798 {
799 ast_log( LOG_ERROR, "unable to add member to NULL conference\n" ) ;
800 return ;
801 }
802
803 // acquire the conference lock
804 ast_mutex_lock( &conf->lock ) ;
805
806 if (member->id < 0)
807 {
808 // get an ID for this member
809 newid = get_new_id( conf );
810 member->id = newid;
811 } else
812 {
813 // boot anyone who has this id already
814 othermember = conf->memberlist;
815 while (othermember)
816 {
817 if (othermember->id == member->id)
818 othermember->id = -1;
819 othermember = othermember->next;
820 }
821 }
822
823 if ( member->mute_video )
824 {
825 send_text_message_to_member(member, AST_CONF_CONTROL_STOP_VIDEO);
826 }
827
828 // set a long term id
829 int new_initial_id = 0;
830 othermember = conf->memberlist;
831 while (othermember)
832 {
833 if (othermember->initial_id >= new_initial_id)
834 new_initial_id++;
835
836 othermember = othermember->next;
837 }
838 member->initial_id = new_initial_id;
839
840
841 ast_log( AST_CONF_DEBUG, "new video id %d\n", newid) ;
842
843 if (conf->memberlist) last_id = conf->memberlist->id;
844 else last_id = 0;
845
846 if (member->req_id < 0) // otherwise pre-selected in create_member
847 {
848 // want to watch the last person to 0 or 1 (for now)
849 if (member->id > 0) member->req_id = 0;
850 else member->req_id = 1;
851 }
852
853 member->next = conf->memberlist ; // next is now list
854 conf->memberlist = member ; // member is now at head of list
855
856 // update conference stats
857 count = count_member( member, conf, 1 ) ;
858
859 ast_log( AST_CONF_DEBUG, "member added to conference, name => %s\n", conf->name ) ;
860
861 // release the conference lock
862 ast_mutex_unlock( &conf->lock ) ;
863
864 return ;
865 }
866
867 int remove_member( struct ast_conf_member* member, struct ast_conference* conf )
868 {
869 // check for member
870 if ( member == NULL )
871 {
872 ast_log( LOG_WARNING, "unable to remove NULL member\n" ) ;
873 return -1 ;
874 }
875
876 // check for conference
877 if ( conf == NULL )
878 {
879 ast_log( LOG_WARNING, "unable to remove member from NULL conference\n" ) ;
880 return -1 ;
881 }
882
883 //
884 // loop through the member list looking
885 // for the requested member
886 //
887
888 ast_mutex_lock( &conf->lock );
889
890 struct ast_conf_member *member_list = conf->memberlist ;
891 struct ast_conf_member *member_temp = NULL ;
892
893 int count = -1 ; // default return code
894
895 while ( member_list != NULL )
896 {
897 // set conference to send no_video to anyone who was watching us
898 ast_mutex_lock( &member_list->lock ) ;
899 if (member_list->req_id == member->id)
900 {
901 member_list->conference = 1;
902 }
903 ast_mutex_unlock( &member_list->lock ) ;
904 member_list = member_list->next ;
905 }
906
907 member_list = conf->memberlist ;
908
909 int member_is_moderator = member->ismoderator;
910
911 while ( member_list != NULL )
912 {
913 // If member is driven by the currently visited member, break the association
914 if ( member_list->driven_member == member )
915 {
916 // Acquire member mutex
917 ast_mutex_lock(&member_list->lock);
918
919 member_list->driven_member = NULL;
920
921 // Release member mutex
922 ast_mutex_unlock(&member_list->lock);
923 }
924
925 if ( member_list == member )
926 {
927
928 //
929 // log some accounting information
930 //
931
932 // calculate time in conference (in seconds)
933 long tt = ast_tvdiff_ms(ast_tvnow(),
934 member->time_entered) / 1000;
935
936 if (conf->debug_flag)
937 {
938 ast_log(
939 LOG_NOTICE,
940 "member accounting, channel => %s, te => %ld, fi => %ld, fid => %ld, fo => %ld, fod => %ld, tt => %ld\n",
941 member->channel_name,
942 member->time_entered.tv_sec, member->frames_in, member->frames_in_dropped,
943 member->frames_out, member->frames_out_dropped, tt
944 ) ;
945 }
946
947 //
948 // if this is the first member in the linked-list,
949 // skip over the first member in the list, else
950 //
951 // point the previous 'next' to the current 'next',
952 // thus skipping the current member in the list
953 //
954 if ( member_temp == NULL )
955 conf->memberlist = member->next ;
956 else
957 member_temp->next = member->next ;
958
959 // update conference stats
960 count = count_member( member, conf, 0 ) ;
961
962 // Check if member is the default or current video source
963 if ( conf->current_video_source_id == member->id )
964 {
965 if ( conf->video_locked )
966 unlock_conference(conf->name);
967 do_video_switching(conf, conf->default_video_source_id, 0);
968 } else if ( conf->default_video_source_id == member->id )
969 {
970 conf->default_video_source_id = -1;
971 }
972
973 // output to manager...
974 manager_event(
975 EVENT_FLAG_CALL,
976 "ConferenceLeave",
977 "ConferenceName: %s\r\n"
978 "Member: %d\r\n"
979 "Channel: %s\r\n"
980 "CallerID: %s\r\n"
981 "CallerIDName: %s\r\n"
982 "Duration: %ld\r\n"
983 "Count: %d\r\n",
984 conf->name,
985 member->id,
986 member->channel_name,
987 member->callerid,
988 member->callername,
989 tt, count
990 ) ;
991
992 // save a pointer to the current member,
993 // and then point to the next member in the list
994 member_list = member_list->next ;
995
996 // leave member_temp alone.
997 // it already points to the previous (or NULL).
998 // it will still be the previous after member is deleted
999
1000 // delete the member
1001 delete_member( member ) ;
1002
1003 ast_log( AST_CONF_DEBUG, "removed member from conference, name => %s, remaining => %d\n",
1004 conf->name, conf->membercount ) ;
1005
1006 //break ;
1007 }
1008 else
1009 {
1010 // if member is a moderator, we end the conference when they leave
1011 if ( member_is_moderator )
1012 {
1013 ast_mutex_lock( &member_list->lock ) ;
1014 member_list->kick_flag = 1;
1015 ast_mutex_unlock( &member_list->lock ) ;
1016 }
1017
1018 // save a pointer to the current member,
1019 // and then point to the next member in the list
1020 member_temp = member_list ;
1021 member_list = member_list->next ;
1022 }
1023 }
1024 ast_mutex_unlock( &conf->lock );
1025
1026 // return -1 on error, or the number of members
1027 // remaining if the requested member was deleted
1028 return count ;
1029 }
1030
1031 int count_member( struct ast_conf_member* member, struct ast_conference* conf, short add_member )
1032 {
1033 if ( member == NULL || conf == NULL )
1034 {
1035 ast_log( LOG_WARNING, "unable to count member\n" ) ;
1036 return -1 ;
1037 }
1038
1039 short delta = ( add_member == 1 ) ? 1 : -1 ;
1040
1041 // increment member count
1042 conf->membercount += delta ;
1043
1044 return conf->membercount ;
1045 }
1046
1047 //
1048 // queue incoming frame functions
1049 //
1050
1051
1052
1053
1054 //
1055 // get conference stats
1056 //
1057
1058 //
1059 // returns: -1 => error, 0 => debugging off, 1 => debugging on
1060 // state: on => 1, off => 0, toggle => -1
1061 //
1062 int set_conference_debugging( const char* name, int state )
1063 {
1064 if ( name == NULL )
1065 return -1 ;
1066
1067 // acquire mutex
1068 ast_mutex_lock( &conflist_lock ) ;
1069
1070 struct ast_conference *conf = conflist ;
1071 int new_state = -1 ;
1072
1073 // loop through conf list
1074 while ( conf != NULL )
1075 {
1076 if ( strncasecmp( (const char*)&(conf->name), name, 80 ) == 0 )
1077 {
1078 // lock conference
1079 // ast_mutex_lock( &(conf->lock) ) ;
1080
1081 // toggle or set the state
1082 if ( state == -1 )
1083 conf->debug_flag = ( conf->debug_flag == 0 ) ? 1 : 0 ;
1084 else
1085 conf->debug_flag = ( state == 0 ) ? 0 : 1 ;
1086
1087 new_state = conf->debug_flag ;
1088
1089 // unlock conference
1090 // ast_mutex_unlock( &(conf->lock) ) ;
1091
1092 break ;
1093 }
1094
1095 conf = conf->next ;
1096 }
1097
1098 // release mutex
1099 ast_mutex_unlock( &conflist_lock ) ;
1100
1101 return new_state ;
1102 }
1103
1104
1105 int get_conference_count( void )
1106 {
1107 return conference_count ;
1108 }
1109
1110 int show_conference_stats ( int fd )
1111 {
1112 // no conferences exist
1113 if ( conflist == NULL )
1114 {
1115 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized.\n") ;
1116 return 0 ;
1117 }
1118
1119 // acquire mutex
1120 ast_mutex_lock( &conflist_lock ) ;
1121
1122 struct ast_conference *conf = conflist ;
1123
1124 ast_cli( fd, "%-20.20s %-40.40s\n", "Name", "Members") ;
1125
1126 // loop through conf list
1127 while ( conf != NULL )
1128 {
1129 ast_cli( fd, "%-20.20s %3d\n", conf->name, conf->membercount ) ;
1130 conf = conf->next ;
1131 }
1132
1133 // release mutex
1134 ast_mutex_unlock( &conflist_lock ) ;
1135
1136 return 1 ;
1137 }
1138
1139 int show_conference_list ( int fd, const char *name )
1140 {
1141 struct ast_conf_member *member;
1142
1143 // no conferences exist
1144 if ( conflist == NULL )
1145 {
1146 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", name ) ;
1147 return 0 ;
1148 }
1149
1150 // acquire mutex
1151 ast_mutex_lock( &conflist_lock ) ;
1152
1153 struct ast_conference *conf = conflist ;
1154
1155 // loop through conf list
1156 while ( conf != NULL )
1157 {
1158 if ( strncasecmp( (const char*)&(conf->name), name, 80 ) == 0 )
1159 {
1160 // acquire conference mutex
1161 ast_mutex_lock(&conf->lock);
1162
1163 // do the biz
1164 member = conf->memberlist ;
1165 while ( member != NULL )
1166 {
1167 ast_cli( fd, "User #: %d ", member->id ) ;
1168 ast_cli( fd, "Channel: %s ", member->channel_name ) ;
1169
1170 ast_cli( fd, "Flags:");
1171 if ( member->mute_video ) ast_cli( fd, "C");
1172 if ( member->norecv_video ) ast_cli( fd, "c");
1173 if ( member->mute_audio ) ast_cli( fd, "L");
1174 if ( member->norecv_audio ) ast_cli( fd, "l");
1175 if ( member->vad_flag ) ast_cli( fd, "V");
1176 if ( member->denoise_flag ) ast_cli( fd, "D");
1177 if ( member->agc_flag ) ast_cli( fd, "A");
1178 if ( member->dtmf_switch ) ast_cli( fd, "X");
1179 if ( member->dtmf_relay ) ast_cli( fd, "R");
1180 if ( member->vad_switch ) ast_cli( fd, "S");
1181 if ( member->ismoderator ) ast_cli( fd, "M");
1182 if ( member->no_camera ) ast_cli( fd, "N");
1183 if ( member->does_text ) ast_cli( fd, "t");
1184 if ( member->via_telephone ) ast_cli( fd, "T");
1185 ast_cli( fd, " " );
1186
1187 if ( member->id == conf->default_video_source_id )
1188 ast_cli(fd, "Default ");
1189 if ( member->id == conf->current_video_source_id )
1190 {
1191 ast_cli(fd, "Showing ");
1192 if ( conf->video_locked )
1193 ast_cli(fd, "Locked ");
1194 }
1195 if ( member->driven_member != NULL )
1196 {
1197 ast_cli(fd, "Driving:%s(%d) ", member->driven_member->channel_name, member->driven_member->id);
1198 }
1199
1200 ast_cli( fd, "\n");
1201 member = member->next;
1202 }
1203
1204 // release conference mutex
1205 ast_mutex_unlock(&conf->lock);
1206
1207 break ;
1208 }
1209
1210 conf = conf->next ;
1211 }
1212
1213 // release mutex
1214 ast_mutex_unlock( &conflist_lock ) ;
1215
1216 return 1 ;
1217 }
1218
1219 /* Dump list of conference info */
1220 int manager_conference_list( struct mansession *s, const struct message *m )
1221 {
1222 const char *id = astman_get_header(m,"ActionID");
1223 const char *conffilter = astman_get_header(m,"Conference");
1224 char idText[256] = "";
1225 struct ast_conf_member *member;
1226
1227 astman_send_ack(s, m, "Conference list will follow");
1228
1229 // no conferences exist
1230 if ( conflist == NULL )
1231 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", conffilter );;
1232
1233 if (!ast_strlen_zero(id)) {
1234 snprintf(idText,256,"ActionID: %s\r\n",id);
1235 }
1236
1237 // acquire mutex
1238 ast_mutex_lock( &conflist_lock ) ;
1239
1240 struct ast_conference *conf = conflist ;
1241
1242 // loop through conf list
1243 while ( conf != NULL )
1244 {
1245 if ( strncasecmp( (const char*)&(conf->name), conffilter, 80 ) == 0 )
1246 {
1247 // do the biz
1248 member = conf->memberlist ;
1249 while (member != NULL)
1250 {
1251 astman_append(s, "Event: ConferenceEntry\r\n"
1252 "ConferenceName: %s\r\n"
1253 "Member: %d\r\n"
1254 "Channel: %s\r\n"
1255 "CallerID: %s\r\n"
1256 "CallerIDName: %s\r\n"
1257 "Muted: %s\r\n"
1258 "VideoMuted: %s\r\n"
1259 "Default: %s\r\n"
1260 "Current: %s\r\n"
1261 "%s"
1262 "\r\n",
1263 conf->name,
1264 member->id,
1265 member->channel_name,
1266 member->chan->cid.cid_num ? member->chan->cid.cid_num : "unknown",
1267 member->chan->cid.cid_name ? member->chan->cid.cid_name : "unknown",
1268 member->mute_audio ? "YES" : "NO",
1269 member->mute_video ? "YES" : "NO",
1270 member->id == conf->default_video_source_id ? "YES" : "NO",
1271 member->id == conf->current_video_source_id ? "YES" : "NO",
1272 idText);
1273 member = member->next;
1274 }
1275 break ;
1276 }
1277
1278 conf = conf->next ;
1279 }
1280
1281 // release mutex
1282 ast_mutex_unlock( &conflist_lock ) ;
1283
1284 astman_append(s,
1285 "Event: ConferenceListComplete\r\n"
1286 "%s"
1287 "\r\n",idText);
1288
1289 return RESULT_SUCCESS;
1290 }
1291
1292 int kick_member ( const char* confname, int user_id)
1293 {
1294 struct ast_conf_member *member;
1295 int res = 0;
1296
1297 // no conferences exist
1298 if ( conflist == NULL )
1299 {
1300 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1301 return 0 ;
1302 }
1303
1304 // acquire mutex
1305 ast_mutex_lock( &conflist_lock ) ;
1306
1307 struct ast_conference *conf = conflist ;
1308
1309 // loop through conf list
1310 while ( conf != NULL )
1311 {
1312 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1313 {
1314 // do the biz
1315 ast_mutex_lock( &conf->lock ) ;
1316 member = conf->memberlist ;
1317 while (member != NULL)
1318 {
1319 if (member->id == user_id)
1320 {
1321 ast_mutex_lock( &member->lock ) ;
1322 member->kick_flag = 1;
1323 //ast_soft_hangup(member->chan);
1324 ast_mutex_unlock( &member->lock ) ;
1325
1326 res = 1;
1327 }
1328 member = member->next;
1329 }
1330 ast_mutex_unlock( &conf->lock ) ;
1331 break ;
1332 }
1333
1334 conf = conf->next ;
1335 }
1336
1337 // release mutex
1338 ast_mutex_unlock( &conflist_lock ) ;
1339
1340 return res ;
1341 }
1342
1343 int kick_channel ( const char *confname, const char *channel)
1344 {
1345 struct ast_conf_member *member;
1346 int res = 0;
1347
1348 // no conferences exist
1349 if ( conflist == NULL )
1350 {
1351 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1352 return 0 ;
1353 }
1354
1355 if ( confname == NULL || channel == NULL || strlen(confname) == 0 || strlen(channel) == 0 )
1356 return 0;
1357
1358 // acquire mutex
1359 ast_mutex_lock( &conflist_lock ) ;
1360
1361 struct ast_conference *conf = conflist ;
1362
1363 // loop through conf list
1364 while ( conf != NULL )
1365 {
1366 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1367 {
1368 // do the biz
1369 ast_mutex_lock( &conf->lock ) ;
1370 member = conf->memberlist ;
1371 while ( member != NULL )
1372 {
1373 if ( strncasecmp( member->channel_name, channel, 80 ) == 0 )
1374 {
1375 ast_mutex_lock( &member->lock ) ;
1376 member->kick_flag = 1;
1377 //ast_soft_hangup(member->chan);
1378 ast_mutex_unlock( &member->lock ) ;
1379
1380 res = 1;
1381 }
1382 member = member->next;
1383 }
1384 ast_mutex_unlock( &conf->lock ) ;
1385 break ;
1386 }
1387
1388 conf = conf->next ;
1389 }
1390
1391 // release mutex
1392 ast_mutex_unlock( &conflist_lock ) ;
1393
1394 return res ;
1395 }
1396
1397 int kick_all ( void )
1398 {
1399 struct ast_conf_member *member;
1400 int res = 0;
1401
1402 // no conferences exist
1403 if ( conflist == NULL )
1404 {
1405 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized\n" ) ;
1406 return 0 ;
1407 }
1408
1409 // acquire mutex
1410 ast_mutex_lock( &conflist_lock ) ;
1411
1412 struct ast_conference *conf = conflist ;
1413
1414 // loop through conf list
1415 while ( conf != NULL )
1416 {
1417 // do the biz
1418 ast_mutex_lock( &conf->lock ) ;
1419 member = conf->memberlist ;
1420 while (member != NULL)
1421 {
1422 ast_mutex_lock( &member->lock ) ;
1423 member->kick_flag = 1;
1424 ast_mutex_unlock( &member->lock ) ;
1425 member = member->next;
1426 }
1427 ast_mutex_unlock( &conf->lock ) ;
1428 break ;
1429
1430 conf = conf->next ;
1431 }
1432
1433 // release mutex
1434 ast_mutex_unlock( &conflist_lock ) ;
1435
1436 return res ;
1437 }
1438
1439 int mute_member ( const char* confname, int user_id)
1440 {
1441 struct ast_conf_member *member;
1442 int res = 0;
1443
1444 // no conferences exist
1445 if ( conflist == NULL )
1446 {
1447 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1448 return 0 ;
1449 }
1450
1451 // acquire mutex
1452 ast_mutex_lock( &conflist_lock ) ;
1453
1454 struct ast_conference *conf = conflist ;
1455
1456 // loop through conf list
1457 while ( conf != NULL )
1458 {
1459 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1460 {
1461 // do the biz
1462 ast_mutex_lock( &conf->lock ) ;
1463 member = conf->memberlist ;
1464 while (member != NULL)
1465 {
1466 if (member->id == user_id)
1467 {
1468 ast_mutex_lock( &member->lock ) ;
1469 member->mute_audio = 1;
1470 ast_mutex_unlock( &member->lock ) ;
1471 res = 1;
1472 }
1473 member = member->next;
1474 }
1475 ast_mutex_unlock( &conf->lock ) ;
1476 break ;
1477 }
1478
1479 conf = conf->next ;
1480 }
1481
1482 // release mutex
1483 ast_mutex_unlock( &conflist_lock ) ;
1484
1485 return res ;
1486 }
1487
1488 int mute_channel ( const char* confname, const char* user_chan)
1489 {
1490 struct ast_conf_member *member;
1491 int res = 0;
1492
1493 // no conferences exist
1494 if ( conflist == NULL )
1495 {
1496 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1497 return 0 ;
1498 }
1499
1500 // acquire mutex
1501 ast_mutex_lock( &conflist_lock ) ;
1502
1503 struct ast_conference *conf = conflist ;
1504
1505 // loop through conf list
1506 while ( conf != NULL )
1507 {
1508 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1509 {
1510 // do the biz
1511 ast_mutex_lock( &conf->lock ) ;
1512 member = conf->memberlist ;
1513 while (member != NULL)
1514 {
1515 if (strncasecmp( member->channel_name, user_chan, 80 ) == 0)
1516 {
1517 ast_mutex_lock( &member->lock ) ;
1518 member->mute_audio = 1;
1519 ast_mutex_unlock( &member->lock ) ;
1520 res = 1;
1521 }
1522 member = member->next;
1523 }
1524 ast_mutex_unlock( &conf->lock ) ;
1525 break ;
1526 }
1527
1528 conf = conf->next ;
1529 }
1530
1531 // release mutex
1532 ast_mutex_unlock( &conflist_lock ) ;
1533
1534 return res ;
1535 }
1536
1537 int unmute_member ( const char* confname, int user_id)
1538 {
1539 struct ast_conf_member *member;
1540 int res = 0;
1541
1542 // no conferences exist
1543 if ( conflist == NULL )
1544 {
1545 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1546 return 0 ;
1547 }
1548
1549 // acquire mutex
1550 ast_mutex_lock( &conflist_lock ) ;
1551
1552 struct ast_conference *conf = conflist ;
1553
1554 // loop through conf list
1555 while ( conf != NULL )
1556 {
1557 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1558 {
1559 // do the biz
1560 ast_mutex_lock( &conf->lock ) ;
1561 member = conf->memberlist ;
1562 while (member != NULL)
1563 {
1564 if (member->id == user_id)
1565 {
1566 ast_mutex_lock( &member->lock ) ;
1567 member->mute_audio = 0;
1568 ast_mutex_unlock( &member->lock ) ;
1569 res = 1;
1570 }
1571 member = member->next;
1572 }
1573 ast_mutex_unlock( &conf->lock ) ;
1574 break ;
1575 }
1576
1577 conf = conf->next ;
1578 }
1579
1580 // release mutex
1581 ast_mutex_unlock( &conflist_lock ) ;
1582
1583 return res ;
1584 }
1585
1586 int unmute_channel (const char* confname, const char* user_chan)
1587 {
1588 struct ast_conf_member *member;
1589 int res = 0;
1590
1591 // no conferences exist
1592 if ( conflist == NULL )
1593 {
1594 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1595 return 0 ;
1596 }
1597
1598 // acquire mutex
1599 ast_mutex_lock( &conflist_lock ) ;
1600
1601 struct ast_conference *conf = conflist ;
1602
1603 // loop through conf list
1604 while ( conf != NULL )
1605 {
1606 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1607 {
1608 // do the biz
1609 ast_mutex_lock( &conf->lock ) ;
1610 member = conf->memberlist ;
1611 while (member != NULL)
1612 {
1613 if (strncasecmp( member->channel_name, user_chan, 80 ) == 0)
1614 {
1615 ast_mutex_lock( &member->lock ) ;
1616 member->mute_audio = 0;
1617 ast_mutex_unlock( &member->lock ) ;
1618 res = 1;
1619 }
1620 member = member->next;
1621 }
1622 ast_mutex_unlock( &conf->lock ) ;
1623 break ;
1624 }
1625
1626 conf = conf->next ;
1627 }
1628
1629 // release mutex
1630 ast_mutex_unlock( &conflist_lock ) ;
1631
1632 return res ;
1633 }
1634
1635 int viewstream_switch ( const char* confname, int user_id, int stream_id )
1636 {
1637 struct ast_conf_member *member;
1638 int res = 0;
1639
1640 // no conferences exist
1641 if ( conflist == NULL )
1642 {
1643 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1644 return 0 ;
1645 }
1646
1647 // acquire mutex
1648 ast_mutex_lock( &conflist_lock ) ;
1649
1650 struct ast_conference *conf = conflist ;
1651
1652 // loop through conf list
1653 while ( conf != NULL )
1654 {
1655 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1656 {
1657 // do the biz
1658 ast_mutex_lock( &conf->lock ) ;
1659 member = conf->memberlist ;
1660 while (member != NULL)
1661 {
1662 if (member->id == user_id)
1663 {
1664 // switch the video
1665 ast_mutex_lock( &member->lock ) ;
1666
1667 member->req_id = stream_id;
1668 member->conference = 1;
1669
1670 ast_mutex_unlock( &member->lock ) ;
1671 res = 1;
1672 }
1673 member = member->next;
1674 }
1675 ast_mutex_unlock( &conf->lock ) ;
1676 break ;
1677 }
1678
1679 conf = conf->next ;
1680 }
1681
1682 // release mutex
1683 ast_mutex_unlock( &conflist_lock ) ;
1684
1685 return res ;
1686 }
1687
1688 int viewchannel_switch ( const char* confname, const char* userchan, const char* streamchan )
1689 {
1690 struct ast_conf_member *member;
1691 int res = 0;
1692 int stream_id = -1;
1693
1694 // no conferences exist
1695 if ( conflist == NULL )
1696 {
1697 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", confname ) ;
1698 return 0 ;
1699 }
1700
1701 // acquire mutex
1702 ast_mutex_lock( &conflist_lock ) ;
1703
1704 struct ast_conference *conf = conflist ;
1705
1706 // loop through conf list
1707 while ( conf != NULL )
1708 {
1709 if ( strncasecmp( (const char*)&(conf->name), confname, 80 ) == 0 )
1710 {
1711 // do the biz
1712 ast_mutex_lock( &conf->lock ) ;
1713 member = conf->memberlist ;
1714 while (member != NULL)
1715 {
1716 if (strncasecmp( member->channel_name, streamchan, 80 ) == 0)
1717 {
1718 stream_id = member->id;
1719 }
1720 member = member->next;
1721 }
1722 ast_mutex_unlock( &conf->lock ) ;
1723 if (stream_id >= 0)
1724 {
1725 // do the biz
1726 ast_mutex_lock( &conf->lock ) ;
1727 member = conf->memberlist ;
1728 while (member != NULL)
1729 {
1730 if (strncasecmp( member->channel_name, userchan, 80 ) == 0)
1731 {
1732 // switch the video
1733 ast_mutex_lock( &member->lock ) ;
1734
1735 member->req_id = stream_id;
1736 member->conference = 1;
1737
1738 ast_mutex_unlock( &member->lock ) ;
1739 res = 1;
1740 }
1741 member = member->next;
1742 }
1743 ast_mutex_unlock( &conf->lock ) ;
1744 }
1745 break ;
1746 }
1747
1748 conf = conf->next ;
1749 }
1750
1751 // release mutex
1752 ast_mutex_unlock( &conflist_lock ) ;
1753
1754 return res ;
1755 }
1756
1757 int get_conference_stats( ast_conference_stats* stats, int requested )
1758 {
1759 // no conferences exist
1760 if ( conflist == NULL )
1761 {
1762 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialize\n" ) ;
1763 return 0 ;
1764 }
1765
1766 // acquire mutex
1767 ast_mutex_lock( &conflist_lock ) ;
1768
1769 // compare the number of requested to the number of available conferences
1770 requested = ( get_conference_count() < requested ) ? get_conference_count() : requested ;
1771
1772 //
1773 // loop through conf list
1774 //
1775
1776 struct ast_conference* conf = conflist ;
1777 int count = 0 ;
1778
1779 while ( count <= requested && conf != NULL )
1780 {
1781 // copy stats struct to array
1782 stats[ count ] = conf->stats ;
1783
1784 conf = conf->next ;
1785 ++count ;
1786 }
1787
1788 // release mutex
1789 ast_mutex_unlock( &conflist_lock ) ;
1790
1791 return count ;
1792 }
1793
1794 int get_conference_stats_by_name( ast_conference_stats* stats, const char* name )
1795 {
1796 // no conferences exist
1797 if ( conflist == NULL )
1798 {
1799 ast_log( AST_CONF_DEBUG, "conflist has not yet been initialized, name => %s\n", name ) ;
1800 return 0 ;
1801 }
1802
1803 // make sure stats is null
1804 stats = NULL ;
1805
1806 // acquire mutex
1807 ast_mutex_lock( &conflist_lock ) ;
1808
1809 struct ast_conference *conf = conflist ;
1810
1811 // loop through conf list
1812 while ( conf != NULL )
1813 {
1814 if ( strncasecmp( (const char*)&(conf->name), name, 80 ) == 0 )
1815 {
1816 // copy stats for found conference
1817 *stats = conf->stats ;
1818 break ;
1819 }
1820
1821 conf = conf->next ;
1822 }
1823
1824 // release mutex
1825 ast_mutex_unlock( &conflist_lock ) ;
1826
1827 return ( stats == NULL ) ? 0 : 1 ;
1828 }
1829
1830 struct ast_conf_member *find_member (const char *chan, int lock)
1831 {
1832 struct ast_conf_member *found = NULL;
1833 struct ast_conf_member *member;
1834 struct ast_conference *conf;
1835
1836 ast_mutex_lock( &conflist_lock ) ;
1837
1838 conf = conflist;
1839
1840 // loop through conf list
1841 while ( conf != NULL && !found )
1842 {
1843 // lock conference
1844 ast_mutex_lock( &conf->lock );
1845
1846 member = conf->memberlist ;
1847
1848 while (member != NULL)
1849 {
1850 if(!strcmp(member->channel_name, chan)) {
1851 found = member;
1852 if(lock)
1853 ast_mutex_lock(&member->lock);
1854 break;
1855 }
1856 member = member->next;
1857 }
1858
1859 // unlock conference
1860 ast_mutex_unlock( &conf->lock );
1861
1862 conf = conf->next ;
1863 }
1864
1865 // release mutex
1866 ast_mutex_unlock( &conflist_lock ) ;
1867
1868 return found;
1869 }
1870
1871 // All the VAD-based video switching magic happens here
1872 // This function should be called inside conference_exec
1873 // The conference mutex should be locked, we don't have to do it here
1874 void do_VAD_switching(struct ast_conference *conf)
1875 {
1876 struct ast_conf_member *member;
1877 struct timeval current_time;
1878 long longest_speaking;
1879 struct ast_conf_member *longest_speaking_member;
1880 int current_silent, current_no_camera, current_video_mute;
1881 int default_no_camera, default_video_mute;
1882
1883 current_time = ast_tvnow();
1884
1885 // Scan the member list looking for the longest speaking member
1886 // We also check if the currently speaking member has been silent for a while
1887 // Also, we check for camera disabled or video muted members
1888 // We say that a member is speaking after his speaking state has been on for
1889 // at least AST_CONF_VIDEO_START_TIMEOUT ms
1890 // We say that a member is silent after his speaking state has been off for
1891 // at least AST_CONF_VIDEO_STOP_TIMEOUT ms
1892 longest_speaking = 0;
1893 longest_speaking_member = NULL;
1894 current_silent = 0;
1895 current_no_camera = 0;
1896 current_video_mute = 0;
1897 default_no_camera = 0;
1898 default_video_mute = 0;
1899 for ( member = conf->memberlist ;
1900 member != NULL ;
1901 member = member->next )
1902 {
1903 // Has the state changed since last time through this loop? Notify!
1904 if ( member->speaking_state_notify )
1905 {
1906 /* fprintf(stderr, "Mihai: member %d, channel %s has changed state to %s\n",
1907 member->id,
1908 member->channel_name,
1909 ((member->speaking_state == 1 ) ? "speaking" : "silent")
1910 ); */
1911 }
1912
1913 // If a member connects via telephone, they don't have video
1914 if ( member->via_telephone )
1915 continue;
1916
1917 // We check for no VAD switching, video-muted or camera disabled
1918 // If yes, this member will not be considered as a candidate for switching
1919 // If this is the currently speaking member, then mark it so we force a switch
1920 if ( !member->vad_switch )
1921 continue;
1922
1923 if ( member->mute_video )
1924 {
1925 if ( member->id == conf->default_video_source_id )
1926 default_video_mute = 1;
1927 if ( member->id == conf->current_video_source_id )
1928 current_video_mute = 1;
1929 else
1930 continue;
1931 }
1932
1933 if ( member->no_camera )
1934 {
1935 if ( member->id == conf->default_video_source_id )
1936 default_no_camera = 1;
1937 if ( member->id == conf->current_video_source_id )
1938 current_no_camera = 1;
1939 else
1940 continue;
1941 }
1942
1943 // Check if current speaker has been silent for a while
1944 if ( member->id == conf->current_video_source_id &&
1945 member->speaking_state == 0 &&
1946 ast_tvdiff_ms(current_time, member->last_state_change) > AST_CONF_VIDEO_STOP_TIMEOUT )
1947 {
1948 current_silent = 1;
1949 }
1950
1951 // Find a candidate to switch to by looking for the longest speaking member
1952 // We exclude the current video source from the search
1953 if ( member->id != conf->current_video_source_id && member->speaking_state == 1 )
1954 {
1955 long tmp = ast_tvdiff_ms(current_time, member->last_state_change);
1956 if ( tmp > AST_CONF_VIDEO_START_TIMEOUT && tmp > longest_speaking )
1957 {
1958 longest_speaking = tmp;
1959 longest_speaking_member = member;
1960 }
1961 }
1962 }
1963
1964 // We got our results, now let's make a decision
1965 // If the currently speaking member has been marked as silent, then we take the longest
1966 // speaking member. If no member is speaking, we go to default
1967 // As a policy we don't want to switch away from a member that is speaking
1968 // however, we might need to refine this to avoid a situation when a member has a
1969 // low noise threshold or its VAD is simply stuck
1970 if ( current_silent || current_no_camera || current_video_mute || conf->current_video_source_id < 0 )
1971 {
1972 if ( longest_speaking_member != NULL )
1973 {
1974 do_video_switching(conf, longest_speaking_member->id, 0);
1975 } else
1976 {
1977 // If there's nobody speaking and we have a default that can send video, switch to it
1978 // If not, then switch to empty (-1)
1979 if ( conf->default_video_source_id >= 0 &&
1980 !default_no_camera &&
1981 !default_video_mute
1982 )
1983 do_video_switching(conf, conf->default_video_source_id, 0);
1984 else
1985 do_video_switching(conf, -1, 0);
1986 }
1987 }
1988 }
1989
1990 int lock_conference(const char *conference, int member_id)
1991 {
1992 struct ast_conference *conf;
1993 struct ast_conf_member *member;
1994 int res;
1995
1996 if ( conference == NULL || member_id < 0 )
1997 return -1 ;
1998
1999 // acquire mutex
2000 ast_mutex_lock( &conflist_lock ) ;
2001
2002 // Look for conference
2003 res = 0;
2004 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2005 {
2006 if ( strcmp(conference, conf->name) == 0 )
2007 {
2008 // Search member list for our member
2009 // acquire conference mutex
2010 ast_mutex_lock( &conf->lock );
2011
2012 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2013 {
2014 if ( member->id == member_id && !member->mute_video )
2015 {
2016 do_video_switching(conf, member_id, 0);
2017 conf->video_locked = 1;
2018 res = 1;
2019
2020 manager_event(EVENT_FLAG_CALL, "ConferenceLock", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2021 break;
2022 }
2023 }
2024
2025 // Release conference mutex
2026 ast_mutex_unlock( &conf->lock );
2027 break;
2028 }
2029 }
2030
2031 // release mutex
2032 ast_mutex_unlock( &conflist_lock ) ;
2033
2034 return res;
2035 }
2036
2037 int lock_conference_channel(const char *conference, const char *channel)
2038 {
2039 struct ast_conference *conf;
2040 struct ast_conf_member *member;
2041 int res;
2042
2043 if ( conference == NULL || channel == NULL )
2044 return -1 ;
2045
2046 // acquire mutex
2047 ast_mutex_lock( &conflist_lock ) ;
2048
2049 // Look for conference
2050 res = 0;
2051 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2052 {
2053 if ( strcmp(conference, conf->name) == 0 )
2054 {
2055 // Search member list for our member
2056 // acquire conference mutex
2057 ast_mutex_lock( &conf->lock );
2058
2059 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2060 {
2061 if ( strcmp(channel, member->channel_name) == 0 && !member->mute_video )
2062 {
2063 do_video_switching(conf, member->id, 0);
2064 conf->video_locked = 1;
2065 res = 1;
2066
2067 manager_event(EVENT_FLAG_CALL, "ConferenceLock", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2068 break;
2069 }
2070 }
2071
2072 // Release conference mutex
2073 ast_mutex_unlock( &conf->lock );
2074 break;
2075 }
2076 }
2077
2078 // release mutex
2079 ast_mutex_unlock( &conflist_lock ) ;
2080
2081 return res;
2082 }
2083
2084 int unlock_conference(const char *conference)
2085 {
2086 struct ast_conference *conf;
2087 int res;
2088
2089 if ( conference == NULL )
2090 return -1;
2091
2092 // acquire conference list mutex
2093 ast_mutex_lock( &conflist_lock ) ;
2094
2095 // Look for conference
2096 res = 0;
2097 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2098 {
2099 if ( strcmp(conference, conf->name) == 0 )
2100 {
2101 conf->video_locked = 0;
2102 manager_event(EVENT_FLAG_CALL, "ConferenceUnlock", "ConferenceName: %s\r\n", conf->name);
2103 do_video_switching(conf, conf->default_video_source_id, 0);
2104 res = 1;
2105
2106 break;
2107 }
2108 }
2109
2110 // release conference list mutex
2111 ast_mutex_unlock( &conflist_lock ) ;
2112
2113 return res;
2114 }
2115
2116 int set_default_id(const char *conference, int member_id)
2117 {
2118 struct ast_conference *conf;
2119 struct ast_conf_member *member;
2120 int res;
2121
2122 if ( conference == NULL )
2123 return -1 ;
2124
2125 // acquire conference list mutex
2126 ast_mutex_lock( &conflist_lock ) ;
2127
2128 // Look for conference
2129 res = 0;
2130 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2131 {
2132 if ( strcmp(conference, conf->name) == 0 )
2133 {
2134 if ( member_id < 0 )
2135 {
2136 conf->default_video_source_id = -1;
2137 manager_event(EVENT_FLAG_CALL, "ConferenceDefault", "ConferenceName: %s\r\nChannel: empty\r\n", conf->name);
2138 res = 1;
2139 break;
2140 } else
2141 {
2142 // Search member list for our member
2143 // acquire conference mutex
2144 ast_mutex_lock( &conf->lock );
2145
2146 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2147 {
2148 // We do not allow video muted members or members that do not support
2149 // VAD switching to become defaults
2150 if ( member->id == member_id &&
2151 !member->mute_video &&
2152 member->vad_switch
2153 )
2154 {
2155 conf->default_video_source_id = member_id;
2156 res = 1;
2157
2158 manager_event(EVENT_FLAG_CALL, "ConferenceDefault", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2159 break;
2160 }
2161 }
2162
2163 // Release conference mutex
2164 ast_mutex_unlock( &conf->lock );
2165 break;
2166 }
2167 }
2168 }
2169
2170 // release conference list mutex
2171 ast_mutex_unlock( &conflist_lock ) ;
2172
2173 return res;
2174
2175 }
2176
2177 int set_default_channel(const char *conference, const char *channel)
2178 {
2179 struct ast_conference *conf;
2180 struct ast_conf_member *member;
2181 int res;
2182
2183 if ( conference == NULL || channel == NULL )
2184 return -1 ;
2185
2186 // acquire conference list mutex
2187 ast_mutex_lock( &conflist_lock ) ;
2188
2189 // Look for conference
2190 res = 0;
2191 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2192 {
2193 if ( strcmp(conference, conf->name) == 0 )
2194 {
2195 // Search member list for our member
2196 // acquire conference mutex
2197 ast_mutex_lock( &conf->lock );
2198
2199 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2200 {
2201 // We do not allow video muted members or members that do not support
2202 // VAD switching to become defaults
2203 if ( strcmp(channel, member->channel_name) == 0 &&
2204 !member->mute_video &&
2205 member->vad_switch
2206 )
2207 {
2208 conf->default_video_source_id = member->id;
2209 res = 1;
2210
2211 manager_event(EVENT_FLAG_CALL, "ConferenceDefault", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2212 break;
2213 }
2214 }
2215
2216 // Release conference mutex
2217 ast_mutex_unlock( &conf->lock );
2218 break;
2219 }
2220 }
2221
2222 // release conference list mutex
2223 ast_mutex_unlock( &conflist_lock ) ;
2224
2225 return res;
2226 }
2227
2228 int video_mute_member(const char *conference, int member_id)
2229 {
2230 struct ast_conference *conf;
2231 struct ast_conf_member *member;
2232 int res;
2233
2234 if ( conference == NULL || member_id < 0 )
2235 return -1;
2236
2237 res = 0;
2238
2239 // acquire conference list mutex
2240 ast_mutex_lock( &conflist_lock ) ;
2241
2242 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2243 {
2244 if ( strcmp(conference, conf->name) == 0 )
2245 {
2246 // acquire conference mutex
2247 ast_mutex_lock( &conf->lock );
2248
2249 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2250 {
2251 if ( member->id == member_id )
2252 {
2253 // acquire member mutex
2254 ast_mutex_lock( &member->lock );
2255
2256 member->mute_video = 1;
2257
2258 // release member mutex
2259 ast_mutex_unlock( &member->lock );
2260
2261 manager_event(EVENT_FLAG_CALL, "ConferenceVideoMute", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2262
2263 if ( member->id == conf->current_video_source_id )
2264 {
2265 do_video_switching(conf, conf->default_video_source_id, 0);
2266 }
2267
2268 res = 1;
2269 break;
2270 }
2271 }
2272
2273 // release conference mutex
2274 ast_mutex_unlock( &conf->lock );
2275
2276 break;
2277 }
2278 }
2279
2280 // release conference list mutex
2281 ast_mutex_unlock( &conflist_lock ) ;
2282
2283 return res;
2284 }
2285
2286 int video_unmute_member(const char *conference, int member_id)
2287 {
2288 struct ast_conference *conf;
2289 struct ast_conf_member *member;
2290 int res;
2291
2292 if ( conference == NULL || member_id < 0 )
2293 return -1;
2294
2295 res = 0;
2296
2297 // acquire conference list mutex
2298 ast_mutex_lock( &conflist_lock ) ;
2299
2300 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2301 {
2302 if ( strcmp(conference, conf->name) == 0 )
2303 {
2304 // acquire conference mutex
2305 ast_mutex_lock( &conf->lock );
2306
2307 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2308 {
2309 if ( member->id == member_id )
2310 {
2311 // acquire member mutex
2312 ast_mutex_lock( &member->lock );
2313
2314 member->mute_video = 0;
2315
2316 // release member mutex
2317 ast_mutex_unlock( &member->lock );
2318
2319 manager_event(EVENT_FLAG_CALL, "ConferenceVideoUnmute", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2320
2321 res = 1;
2322 break;
2323 }
2324 }
2325
2326 // release conference mutex
2327 ast_mutex_unlock( &conf->lock );
2328
2329 break;
2330 }
2331 }
2332
2333 // release conference list mutex
2334 ast_mutex_unlock( &conflist_lock ) ;
2335
2336 return res;
2337 }
2338
2339 int video_mute_channel(const char *conference, const char *channel)
2340 {
2341 struct ast_conference *conf;
2342 struct ast_conf_member *member;
2343 int res;
2344
2345 if ( conference == NULL || channel == NULL )
2346 return -1;
2347
2348 res = 0;
2349
2350 // acquire conference list mutex
2351 ast_mutex_lock( &conflist_lock ) ;
2352
2353 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2354 {
2355 if ( strcmp(conference, conf->name) == 0 )
2356 {
2357 // acquire conference mutex
2358 ast_mutex_lock( &conf->lock );
2359
2360 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2361 {
2362 if ( strcmp(channel, member->channel_name) == 0 )
2363 {
2364 // acquire member mutex
2365 ast_mutex_lock( &member->lock );
2366
2367 member->mute_video = 1;
2368
2369 // release member mutex
2370 ast_mutex_unlock( &member->lock );
2371
2372 manager_event(EVENT_FLAG_CALL, "ConferenceVideoMute", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2373
2374 if ( member->id == conf->current_video_source_id )
2375 {
2376 do_video_switching(conf, conf->default_video_source_id, 0);
2377 }
2378
2379 res = 1;
2380 break;
2381 }
2382 }
2383
2384 // release conference mutex
2385 ast_mutex_unlock( &conf->lock );
2386
2387 break;
2388 }
2389 }
2390
2391 // release conference list mutex
2392 ast_mutex_unlock( &conflist_lock ) ;
2393
2394 return res;
2395 }
2396
2397 int video_unmute_channel(const char *conference, const char *channel)
2398 {
2399 struct ast_conference *conf;
2400 struct ast_conf_member *member;
2401 int res;
2402
2403 if ( conference == NULL || channel == NULL )
2404 return -1;
2405
2406 res = 0;
2407
2408 // acquire conference list mutex
2409 ast_mutex_lock( &conflist_lock ) ;
2410
2411 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2412 {
2413 if ( strcmp(conference, conf->name) == 0 )
2414 {
2415 // acquire conference mutex
2416 ast_mutex_lock( &conf->lock );
2417
2418 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2419 {
2420 if ( strcmp(channel, member->channel_name) == 0 )
2421 {
2422 // acquire member mutex
2423 ast_mutex_lock( &member->lock );
2424
2425 member->mute_video = 0;
2426
2427 // release member mutex
2428 ast_mutex_unlock( &member->lock );
2429
2430 manager_event(EVENT_FLAG_CALL, "ConferenceVideoUnmute", "ConferenceName: %s\r\nChannel: %s\r\n", conf->name, member->channel_name);
2431
2432 res = 1;
2433 break;
2434 }
2435 }
2436
2437 // release conference mutex
2438 ast_mutex_unlock( &conf->lock );
2439
2440 break;
2441 }
2442 }
2443
2444 // release conference list mutex
2445 ast_mutex_unlock( &conflist_lock ) ;
2446
2447 return res;
2448 }
2449
2450 //
2451 // Text message functions
2452 //
2453 int send_text(const char *conference, int member_id, const char *text)
2454 {
2455 struct ast_conference *conf;
2456 struct ast_conf_member *member;
2457 int res;
2458
2459 if ( conference == NULL || member_id < 0 || text == NULL )
2460 return -1;
2461
2462 res = 0;
2463
2464 // acquire conference list mutex
2465 ast_mutex_lock( &conflist_lock ) ;
2466
2467 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2468 {
2469 if ( strcmp(conference, conf->name) == 0 )
2470 {
2471 // acquire conference mutex
2472 ast_mutex_lock( &conf->lock );
2473
2474 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2475 {
2476 if ( member->id == member_id )
2477 {
2478 res = send_text_message_to_member(member, text) == 0;
2479 break;
2480 }
2481 }
2482
2483 // release conference mutex
2484 ast_mutex_unlock( &conf->lock );
2485
2486 break;
2487 }
2488 }
2489
2490 // release conference list mutex
2491 ast_mutex_unlock( &conflist_lock ) ;
2492 return res;
2493 }
2494
2495 int send_text_channel(const char *conference, const char *channel, const char *text)
2496 {
2497 struct ast_conference *conf;
2498 struct ast_conf_member *member;
2499 int res;
2500
2501 if ( conference == NULL || channel == NULL || text == NULL )
2502 return -1;
2503
2504 res = 0;
2505
2506 // acquire conference list mutex
2507 ast_mutex_lock( &conflist_lock ) ;
2508
2509 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2510 {
2511 if ( strcmp(conference, conf->name) == 0 )
2512 {
2513 // acquire conference mutex
2514 ast_mutex_lock( &conf->lock );
2515
2516 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2517 {
2518 if ( strcmp(member->channel_name, channel) == 0 )
2519 {
2520 res = send_text_message_to_member(member, text) == 0;
2521 break;
2522 }
2523 }
2524
2525 // release conference mutex
2526 ast_mutex_unlock( &conf->lock );
2527
2528 break;
2529 }
2530 }
2531
2532 // release conference list mutex
2533 ast_mutex_unlock( &conflist_lock ) ;
2534
2535 return res;
2536 }
2537
2538 int send_text_broadcast(const char *conference, const char *text)
2539 {
2540 struct ast_conference *conf;
2541 struct ast_conf_member *member;
2542 int res;
2543
2544 if ( conference == NULL || text == NULL )
2545 return -1;
2546
2547 res = 0;
2548
2549 // acquire conference list mutex
2550 ast_mutex_lock( &conflist_lock ) ;
2551
2552 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2553 {
2554 if ( strcmp(conference, conf->name) == 0 )
2555 {
2556 // acquire conference mutex
2557 ast_mutex_lock( &conf->lock );
2558
2559 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2560 {
2561 if ( send_text_message_to_member(member, text) == 0 )
2562 res = res || 1;
2563 }
2564
2565 // release conference mutex
2566 ast_mutex_unlock( &conf->lock );
2567
2568 break;
2569 }
2570 }
2571
2572 // release conference list mutex
2573 ast_mutex_unlock( &conflist_lock ) ;
2574
2575 return res;
2576 }
2577
2578 // Creates a text frame and sends it to a given member
2579 // Returns 0 on success, -1 on failure
2580 int send_text_message_to_member(struct ast_conf_member *member, const char *text)
2581 {
2582 struct ast_frame *f;
2583
2584 if ( member == NULL || text == NULL ) return -1;
2585
2586 if ( member->does_text )
2587 {
2588 f = create_text_frame(text, 1);
2589 if ( f == NULL || queue_outgoing_text_frame(member, f) != 0) return -1;
2590 ast_frfree(f);
2591 }
2592
2593 return 0;
2594 }
2595
2596 // Associates two members
2597 // Drives VAD-based video switching of dst_member from audio from src_member
2598 // This can be used when a member participates in a video conference but
2599 // talks using a telephone (simulcast) connection
2600 int drive(const char *conference, int src_member_id, int dst_member_id)
2601 {
2602 int res;
2603 struct ast_conference *conf;
2604 struct ast_conf_member *member;
2605 struct ast_conf_member *src;
2606 struct ast_conf_member *dst;
2607
2608 if ( conference == NULL || src_member_id < 0 )
2609 return -1;
2610
2611 res = 0;
2612
2613 // acquire conference list mutex
2614 ast_mutex_lock( &conflist_lock ) ;
2615
2616 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2617 {
2618 if ( strcmp(conference, conf->name) == 0 )
2619 {
2620 // acquire conference mutex
2621 ast_mutex_lock( &conf->lock );
2622
2623 src = NULL;
2624 dst = NULL;
2625 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2626 {
2627 if ( member->id == src_member_id )
2628 src = member;
2629 if ( member->id == dst_member_id )
2630 dst = member;
2631 }
2632 if ( src != NULL )
2633 {
2634 // acquire member mutex
2635 ast_mutex_lock(&src->lock);
2636
2637 if ( dst != NULL )
2638 {
2639 src->driven_member = dst;
2640 // Make sure the driven member's speaker count is correct
2641 if ( src->speaking_state == 1 )
2642 increment_speaker_count(src->driven_member, 1);
2643 res = 1;
2644 } else
2645 {
2646 if ( dst_member_id < 0 )
2647 {
2648 // Make sure the driven member's speaker count is correct
2649 if ( src->speaking_state == 1 )
2650 decrement_speaker_count(src->driven_member, 1);
2651 src->driven_member = NULL;
2652 res = 1;
2653 }
2654 }
2655
2656 // release member mutex
2657 ast_mutex_unlock(&src->lock);
2658 }
2659
2660 // release conference mutex
2661 ast_mutex_unlock( &conf->lock );
2662
2663 break;
2664 }
2665 }
2666
2667 // release conference list mutex
2668 ast_mutex_unlock( &conflist_lock ) ;
2669
2670 return res;
2671 }
2672
2673 // Associates two channels
2674 // Drives VAD-based video switching of dst_channel from audio from src_channel
2675 // This can be used when a member participates in a video conference but
2676 // talks using a telephone (simulcast) connection
2677 int drive_channel(const char *conference, const char *src_channel, const char *dst_channel)
2678 {
2679 int res;
2680 struct ast_conference *conf;
2681 struct ast_conf_member *member;
2682 struct ast_conf_member *src;
2683 struct ast_conf_member *dst;
2684
2685 if ( conference == NULL || src_channel == NULL )
2686 return -1;
2687
2688 res = 0;
2689
2690 // acquire conference list mutex
2691 ast_mutex_lock( &conflist_lock ) ;
2692
2693 for ( conf = conflist ; conf != NULL ; conf = conf->next )
2694 {
2695 if ( strcmp(conference, conf->name) == 0 )
2696 {
2697 // acquire conference mutex
2698 ast_mutex_lock( &conf->lock );
2699
2700 src = NULL;
2701 dst = NULL;
2702 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2703 {
2704 if ( strcmp(src_channel, member->channel_name) == 0 )
2705 src = member;
2706 if ( dst_channel != NULL && strcmp(dst_channel, member->channel_name) == 0 )
2707 dst = member;
2708 }
2709 if ( src != NULL )
2710 {
2711 // acquire member mutex
2712 ast_mutex_lock(&src->lock);
2713
2714 if ( dst != NULL )
2715 {
2716 src->driven_member = dst;
2717 // Make sure the driven member's speaker count is correct
2718 if ( src->speaking_state == 1 )
2719 increment_speaker_count(src->driven_member, 1);
2720 res = 1;
2721 } else
2722 {
2723 if ( dst_channel == NULL )
2724 {
2725 // Make sure the driven member's speaker count is correct
2726 if ( src->speaking_state == 1 )
2727 decrement_speaker_count(src->driven_member, 1);
2728 src->driven_member = NULL;
2729 res = 1;
2730 }
2731 }
2732
2733 // release member mutex
2734 ast_mutex_unlock(&src->lock);
2735 }
2736
2737 // release conference mutex
2738 ast_mutex_unlock( &conf->lock );
2739
2740 break;
2741 }
2742 }
2743
2744 // release conference list mutex
2745 ast_mutex_unlock( &conflist_lock ) ;
2746
2747 return res;
2748 }
2749
2750 // Switches video source
2751 // Sends a manager event as well as
2752 // a text message notifying members of a video switch
2753 // The notification is sent to the current member and to the new member
2754 // The function locks the conference mutex as required
2755 void do_video_switching(struct ast_conference *conf, int new_id, int lock)
2756 {
2757 struct ast_conf_member *member;
2758 struct ast_conf_member *new_member = NULL;
2759
2760 if ( conf == NULL ) return;
2761
2762 if ( lock )
2763 {
2764 // acquire conference mutex
2765 ast_mutex_lock( &conf->lock );
2766 }
2767
2768 //fprintf(stderr, "Mihai: video switch from %d to %d\n", conf->current_video_source_id, new_id);
2769
2770 // No need to do anything if the current member is the same as the new member
2771 if ( new_id != conf->current_video_source_id )
2772 {
2773 for ( member = conf->memberlist ; member != NULL ; member = member->next )
2774 {
2775 if ( member->id == conf->current_video_source_id )
2776 {
2777 send_text_message_to_member(member, AST_CONF_CONTROL_STOP_VIDEO);
2778 }
2779 if ( member->id == new_id )
2780 {
2781 send_text_message_to_member(member, AST_CONF_CONTROL_START_VIDEO);
2782 new_member = member;
2783 }
2784 }
2785
2786 conf->current_video_source_id = new_id;
2787
2788 if ( new_member != NULL )
2789 {
2790 manager_event(EVENT_FLAG_CALL,
2791 "ConferenceVideoSwitch",
2792 "ConferenceName: %s\r\nChannel: %s\r\n",
2793 conf->name,
2794 new_member->channel_name);
2795 } else
2796 {
2797 manager_event(EVENT_FLAG_CALL,
2798 "ConferenceVideoSwitch",
2799 "ConferenceName: %s\r\nChannel: empty\r\n",
2800 conf->name);
2801 }
2802 }
2803
2804 if ( lock )
2805 {
2806 // release conference mutex
2807 ast_mutex_unlock( &conf->lock );
2808 }
2809 }
2810
2811 int play_sound_channel(int fd, const char *channel, const char *file, int mute)
2812 {
2813 struct ast_conf_member *member;
2814 struct ast_conf_soundq *newsound;
2815 struct ast_conf_soundq **q;
2816
2817 member = find_member(channel, 1);
2818 if( !member )
2819 {
2820 ast_cli(fd, "Member %s not found\n", channel);
2821 return 0;
2822 }
2823
2824 newsound = calloc(1, sizeof(struct ast_conf_soundq));
2825 newsound->stream = ast_openstream(member->chan, file, member->chan->language);
2826 if( !newsound->stream )
2827 {
2828 ast_cli(fd, "Sound %s not found\n", file);
2829 free(newsound);
2830 ast_mutex_unlock(&member->lock);
2831 return 0;
2832 }
2833 member->chan->stream = NULL;
2834
2835 newsound->muted = mute;
2836 ast_copy_string(newsound->name, file, sizeof(newsound->name));
2837
2838 // append sound to the end of the list.
2839 for ( q=&member->soundq; *q; q = &((*q)->next) ) ;
2840 *q = newsound;
2841
2842 ast_mutex_unlock(&member->lock);
2843
2844 ast_cli(fd, "Playing sound %s to member %s %s\n",
2845 file, channel, mute ? "with mute" : "");
2846
2847 return 1 ;
2848 }
2849
2850 int stop_sound_channel(int fd, const char *channel)
2851 {
2852 struct ast_conf_member *member;
2853 struct ast_conf_soundq *sound;
2854 struct ast_conf_soundq *next;
2855
2856 member = find_member(channel, 1);
2857 if ( !member )
2858 {
2859 ast_cli(fd, "Member %s not found\n", channel);
2860 return 0;
2861 }
2862
2863 // clear all sounds
2864 sound = member->soundq;
2865 member->soundq = NULL;
2866
2867 while ( sound )
2868 {
2869 next = sound->next;
2870 ast_closestream(sound->stream);
2871 free(sound);
2872 sound = next;
2873 }
2874
2875 // reset write format, since we're done playing the sound
2876 if ( ast_set_write_format( member->chan, member->write_format ) < 0 )
2877 {
2878 ast_log( LOG_ERROR, "unable to set write format to %d\n",
2879 member->write_format ) ;
2880 }
2881
2882 ast_mutex_unlock(&member->lock);
2883
2884 ast_cli( fd, "Stopped sounds to member %s\n", channel);
2885 return 1;
2886 }