1 /*
2  * Copyright (C) 2008 IPTEGO GmbH
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the sems software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 #include "AmAudioMixer.h"
29 
30 AmAudioMixer::AmAudioMixer(int external_sample_rate) {
31   sink_channel = mixer.addChannel(external_sample_rate);
32   sink_connector =
33     new AmAudioMixerConnector(mixer, sink_channel, NULL,
34 			      &srcsink_mut, &sinks);
35 }
36 
37 AmAudioMixer::~AmAudioMixer() {
38   mixer.removeChannel(sink_channel);
39   for (std::map<AmAudioMixerConnector*, unsigned int>::iterator
40 	 it=sources.begin(); it != sources.end(); it++) {
41     mixer.removeChannel(it->second);
42     delete it->first;
43   }
44   delete sink_connector;
45 }
46 
47 AmAudio* AmAudioMixer::addSource(int external_sample_rate) {
48   srcsink_mut.lock();
49   unsigned int src_channel = mixer.addChannel(external_sample_rate);
50   // the first source will process the media in the mixer channel
51   AmAudioMixerConnector* conn =
52     new AmAudioMixerConnector(mixer, src_channel,
53 			      sources.empty() ? sink_connector : NULL);
54   sources[conn] = src_channel;
55   srcsink_mut.unlock();
56   return conn;
57 }
58 
59 void AmAudioMixer::releaseSource(AmAudio* s) {
60   srcsink_mut.lock();
61   std::map<AmAudioMixerConnector*, unsigned int>::iterator it=
62     sources.find((AmAudioMixerConnector*)s);
63   if (it==sources.end()) {
64     srcsink_mut.unlock();
65     ERROR("source [%p] is not part of this mixer.\n", s);
66     return;
67   }
68   mixer.removeChannel(it->second);
69   delete s;
70   sources.erase(it);
71   srcsink_mut.unlock();
72 }
73 
74 void AmAudioMixer::addSink(AmAudio* s) {
75   srcsink_mut.lock();
76   sinks.insert(s);
77   srcsink_mut.unlock();
78 }
79 
80 void AmAudioMixer::releaseSink(AmAudio* s) {
81   srcsink_mut.lock();
82   sinks.erase(s);
83   srcsink_mut.unlock();
84 }
85 
86 int AmAudioMixerConnector::get(unsigned long long system_ts,
87 			       unsigned char* buffer,
88 			       int output_sample_rate,
89 			       unsigned int nb_samples)
90 {
91   // in fact GCP here only needed for the mixed channel
92   unsigned int mixer_sample_rate;
93   mixer.GetChannelPacket(channel, system_ts, buffer,
94 			 nb_samples, mixer_sample_rate);
95 
96   if ((audio_mut != NULL) && (sinks != NULL)) {
97     audio_mut->lock();
98     // write to all sinks
99     for (std::set<AmAudio*>::iterator it=sinks->begin();
100 	 it != sinks->end(); it++) {
101       (*it)->put(system_ts, buffer, output_sample_rate, nb_samples);
102     }
103     audio_mut->unlock();
104   }
105 
106   return nb_samples;
107 }
108 
109 int AmAudioMixerConnector::put(unsigned long long system_ts,
110 			       unsigned char* buffer,
111 			       int input_sample_rate,
112 			       unsigned int size)
113 {
114   mixer.PutChannelPacket(channel, system_ts, buffer, size);
115 
116   if (mix_channel != NULL) {
117     // we are processing the media of the mixed channel as well
118     ShortSample mix_buffer[SIZE_MIX_BUFFER];
119     mix_channel->get(system_ts, (unsigned char*)mix_buffer,
120 		     input_sample_rate, size);
121   }
122   return size;
123 }
124