reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
SipXBridgeMixer.cxx
Go to the documentation of this file.
1#include "SipXBridgeMixer.hxx"
2#include "ReconSubsystem.hxx"
3#include "Participant.hxx"
5#include "Conversation.hxx"
6
7#include <rutil/Log.hxx>
8#include <rutil/Logger.hxx>
9
10#ifndef max
11#define max(x,y) (((x)>(y))?(x):(y))
12#endif
13
14using namespace recon;
15using namespace resip;
16using namespace std;
17
18#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
19
20SipXBridgeMixer::SipXBridgeMixer(CpTopologyGraphInterface& mediaInterface) :
21 mMediaInterface(mediaInterface)
22{
23 // Set default to 0 gain for entire matrix
24 memset(mMixMatrix, 0, sizeof(mMixMatrix));
25}
26
30
31void
33{
34 int bridgePort = participant->getConnectionPortOnBridge();
35 MpBridgeGain inputBridgeWeights[DEFAULT_BRIDGE_MAX_IN_OUTPUTS];
36
37 InfoLog( << "calculatingMixWeigthsForParticipant, handle=" << participant->getParticipantHandle() << ", bridgePort=" << bridgePort << ", hasInput=" << participant->hasInput() << ", hasOutput=" << participant->hasOutput());
38
39 if(bridgePort != -1)
40 {
41 bool processingMultiChannelRecorder = false;
42 if (participant->hasInput() && bridgePort == 0)
43 {
44 // If input bridgePort is 0, then this is the multichannel recorder.
45 processingMultiChannelRecorder = true;
46 }
47 // Default All Inputs/Outputs to 0, then calculate non-zero inputs/outputs
48 for(int i = 0; i < DEFAULT_BRIDGE_MAX_IN_OUTPUTS; i++)
49 {
50 // If we have input capabilities, then clear out other participants outputs to us
51 if (participant->hasInput())
52 {
53 mMixMatrix[bridgePort][i] = 0;
54 if (processingMultiChannelRecorder)
55 {
56 // BridgePort 0 is for the left channel. BridgePort 1 is for the right channel.
57 // Note: getConnectionPortOnBridge always only returns BridgePort 0 for the
58 // multichannel recorder.
59 mMixMatrix[1][i] = 0; // Clear out right channel (bridge port 1)
60 }
61 }
62 // If we have output capabilites, then clear out other participants inputs from us
63 if (participant->hasOutput())
64 {
65 mMixMatrix[i][bridgePort] = 0;
66 }
67 inputBridgeWeights[i] = 0;
68 }
69
70 // Walk through all Conversations this Participant is in
71 const Participant::ConversationMap& partConvs = participant->getConversations();
72
73 Participant::ConversationMap::const_iterator it1;
74 for(it1 = partConvs.begin(); it1 != partConvs.end(); it1++)
75 {
76 //InfoLog( << "calculateMixWeightsForParticipant: part=" << participant->getParticipantHandle() << ", conv=" << it1->second->getHandle());
77 // Walk through each participant in this Conversation
78 Conversation::ParticipantMap& convParts = it1->second->getParticipants();
79 Conversation::ParticipantMap::iterator it2;
80 it2 = convParts.find(participant->getParticipantHandle()); // Get the participants gain settings in this conversation
81 unsigned int participantOutputGain = 0;
82 unsigned int participantInputGain = 0;
83 if(it2 != convParts.end()) // if we are in the middle of removing a participant from a conversation then they may not exist in the conversation list any more
84 {
85 participantOutputGain = it2->second.getOutputGain();
86 participantInputGain = it2->second.getInputGain();
87 }
88 for(it2 = convParts.begin(); it2 != convParts.end(); it2++)
89 {
90 //InfoLog( << "calculateMixWeightsForParticipant: part=" << participant->getParticipantHandle() << ", conv=" << it1->second->getHandle() << ", otherpart=" << it2->second.getParticipant()->getParticipantHandle() << ", hasInput=" << it2->second.getParticipant()->hasInput() << ", hasOutput=" << it2->second.getParticipant()->hasOutput());
91 // If we found a participant that is not ourself
92 if(it2->second.getParticipant()->getParticipantHandle() != participant->getParticipantHandle())
93 {
94 int otherBridgePort = it2->second.getParticipant()->getConnectionPortOnBridge();
95 if (otherBridgePort != -1)
96 {
97 int bridgePortToUse = bridgePort;
98 if (participant->hasInput() && // Only look at outputs from other participants if we have an input, and
99 it2->second.getParticipant()->hasOutput()) // Only look at other participant if it has an output
100 {
101 // Calculate the mixed output gain from the other participant to us.
102 // getOutputGain()/participantInputGain are percentages (0..100). Their product
103 // over 100 is the combined percentage; scale that to the bridge's fixed-point
104 // unity (MP_BRIDGE_GAIN_PASSTHROUGH == 1<<MP_BRIDGE_FRAC_LENGTH == 1024) so that
105 // 100% maps to exact unity. The old "* 10" produced 1000, i.e. 1000/1024 = 0.98.
106 unsigned int outputGain = (it2->second.getOutputGain() * participantInputGain * MP_BRIDGE_GAIN_PASSTHROUGH) / (100 * 100);
107 if (processingMultiChannelRecorder)
108 {
109 // If other party is supposed to record to channel 2 then update
110 // bridgePortToUse from 0 to 1
111 if (it2->second.getParticipant()->getRecordChannelNum() == 2)
112 {
113 // Send audio to right channel
114 bridgePortToUse = 1;
115 }
116 }
117 mMixMatrix[bridgePortToUse][otherBridgePort] = max((int)outputGain, mMixMatrix[bridgePortToUse][otherBridgePort]);
118 }
119
120 if (participant->hasOutput() && // Only look at inputs to other participants if we have an output, and
121 it2->second.getParticipant()->hasInput()) // Only look at other participants that have an input and can accept our output
122 {
123 // Calculate the mixed input gain for the other participant.
124 // Scale combined percentage to fixed-point unity (1024) — see note above.
125 unsigned int inputGain = (it2->second.getInputGain() * participantOutputGain * MP_BRIDGE_GAIN_PASSTHROUGH) / (100 * 100);
126
127 // OtherParty has input and is bridgePort is 0, then other party is the multichannel recorder.
128 if (otherBridgePort == 0)
129 {
130 // If participant in question needs channel 2 recording then change otherBridgePort from 0 to 1.
131 if (participant->getRecordChannelNum() == 2)
132 {
133 // Send audio to right channel
134 otherBridgePort = 1;
135 }
136 }
137 inputBridgeWeights[otherBridgePort] = mMixMatrix[otherBridgePort][bridgePortToUse] = max((int)inputGain, mMixMatrix[otherBridgePort][bridgePortToUse]);
138 }
139 //InfoLog(<< "Setting mix level for bridge ports: " << bridgePortToUse << " and " << otherBridgePort << ": outputGain=" << mMixMatrix[bridgePortToUse][otherBridgePort]/10 << ", inputGain=" << inputBridgeWeights[otherBridgePort]/10);
140 }
141 }
142 }
143 }
144
145 //outputBridgeMixWeights();
146
147 // Apply new bridge weights
148 if (participant->hasInput())
149 {
150 // Apply mix outputs for other participants if we have an input
151 MprBridge::setMixWeightsForOutput(DEFAULT_BRIDGE_RESOURCE_NAME, *mMediaInterface.getMsgQ(), bridgePort, DEFAULT_BRIDGE_MAX_IN_OUTPUTS, mMixMatrix[bridgePort]);
152 if (processingMultiChannelRecorder)
153 {
154 // If processing the multichannel recorder than also update the secondary/right channel
155 MprBridge::setMixWeightsForOutput(DEFAULT_BRIDGE_RESOURCE_NAME, *mMediaInterface.getMsgQ(), 1, DEFAULT_BRIDGE_MAX_IN_OUTPUTS, mMixMatrix[1]);
156 }
157 }
158 if (participant->hasOutput())
159 {
160 // Apply mix inputs to other participants if we have an output
161 MprBridge::setMixWeightsForInput(DEFAULT_BRIDGE_RESOURCE_NAME, *mMediaInterface.getMsgQ(), bridgePort, DEFAULT_BRIDGE_MAX_IN_OUTPUTS, inputBridgeWeights);
162 }
163 }
164}
165
166void
168{
169 int i;
170 Data data;
171 data = " ";
172 for(i = 0; i < DEFAULT_BRIDGE_MAX_IN_OUTPUTS; i++)
173 {
174 if(i < 10)
175 {
176 data += " " + Data(i);
177 }
178 else
179 {
180 data += " " + Data(i);
181 }
182 }
183 InfoLog( << data);
184
185 data = "-";
186 for(i = 0; i < DEFAULT_BRIDGE_MAX_IN_OUTPUTS; i++)
187 {
188 data += "----";
189 }
190 InfoLog( << data);
191
192 for(i = 0; i < DEFAULT_BRIDGE_MAX_IN_OUTPUTS; i++)
193 {
194 if(i < 10)
195 {
196 data = Data(i) + " |";
197 }
198 else
199 {
200 data = Data(i) + "|";
201 }
202 for(int j = 0; j < DEFAULT_BRIDGE_MAX_IN_OUTPUTS; j++)
203 {
204 if(mMixMatrix[i][j]/10 < 10)
205 {
206 data += " " + Data(mMixMatrix[i][j]/10) + " ";
207 }
208 else if(mMixMatrix[i][j]/10 < 100)
209 {
210 data += Data(mMixMatrix[i][j]/10) + " ";
211 }
212 else
213 {
214 data += Data(mMixMatrix[i][j]/10) + " ";
215 }
216 }
217 InfoLog( << data);
218 }
219}
220
221
222/* ====================================================================
223
224 Copyright (c) 2021-2023, SIP Spectrum, Inc. http://www.sipspectrum.com
225 Copyright (c) 2021, Daniel Pocock https://danielpocock.com
226 Copyright (c) 2007-2008, Plantronics, Inc.
227 All rights reserved.
228
229 Redistribution and use in source and binary forms, with or without
230 modification, are permitted provided that the following conditions are
231 met:
232
233 1. Redistributions of source code must retain the above copyright
234 notice, this list of conditions and the following disclaimer.
235
236 2. Redistributions in binary form must reproduce the above copyright
237 notice, this list of conditions and the following disclaimer in the
238 documentation and/or other materials provided with the distribution.
239
240 3. Neither the name of Plantronics nor the names of its contributors
241 may be used to endorse or promote products derived from this
242 software without specific prior written permission.
243
244 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
246 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
247 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
248 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
249 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
250 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
254 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
255
256 ==================================================================== */
#define max(x, y)
#define InfoLog(args_)
Definition Logger.hxx:131
std::map< ParticipantHandle, ConversationParticipantAssignment > ParticipantMap
This is the base class for a RemoteParticipant, LocalParticipant and a MediaResourceParticipant.
virtual bool hasInput()=0
std::map< ConversationHandle, Conversation * > ConversationMap
virtual unsigned int getRecordChannelNum()
virtual bool hasOutput()=0
virtual ParticipantHandle getParticipantHandle()
const ConversationMap & getConversations()
virtual int getConnectionPortOnBridge()=0
void calculateMixWeightsForParticipant(Participant *participant)
Calculates all of the current mixer settings required for the passed in participant and applies them.
void outputBridgeMixWeights()
Logs a multiline representation of the current state of the mixing matrix.
SipXBridgeMixer(CpTopologyGraphInterface &mediaInterface)
Constructor.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
dcm! – add UnusedChecking(_enum) below;