INET Framework for OMNeT++/OMNEST
inet::SimpleVoIPReceiver Class Reference

Implements a simple VoIP source. More...

#include <SimpleVoIPReceiver.h>

Inheritance diagram for inet::SimpleVoIPReceiver:
inet::ILifecycle

Classes

class  TalkspurtInfo
 
class  VoIPPacketInfo
 

Public Member Functions

 SimpleVoIPReceiver ()
 
 ~SimpleVoIPReceiver ()
 
- Public Member Functions inherited from inet::ILifecycle
virtual ~ILifecycle ()
 

Protected Member Functions

virtual int numInitStages () const override
 
void initialize (int stage) override
 
void handleMessage (cMessage *msg) override
 
virtual void finish () override
 
virtual bool handleOperationStage (LifecycleOperation *operation, int stage, IDoneCallback *doneCallback) override
 Perform one stage of a lifecycle operation. More...
 

Private Types

typedef std::list< VoIPPacketInfo * > PacketsList
 
typedef std::vector< VoIPPacketInfoPacketsVector
 

Private Member Functions

double eModel (double delay, double loss)
 
void evaluateTalkspurt (bool finish)
 
void startTalkspurt (SimpleVoIPPacket *packet)
 

Private Attributes

double emodelRo = NaN
 
unsigned int bufferSpace = 0
 
int emodelIe = -1
 
int emodelBpl = -1
 
int emodelA = -1
 
simtime_t playoutDelay
 
simtime_t mosSpareTime
 
UDPSocket socket
 
cMessage * selfTalkspurtFinished = nullptr
 
TalkspurtInfo currentTalkspurt
 

Static Private Attributes

static simsignal_t packetLossRateSignal = registerSignal("VoIPPacketLossRate")
 
static simsignal_t packetDelaySignal = registerSignal("VoIPPacketDelay")
 
static simsignal_t playoutDelaySignal = registerSignal("VoIPPlayoutDelay")
 
static simsignal_t playoutLossRateSignal = registerSignal("VoIPPlayoutLossRate")
 
static simsignal_t mosSignal = registerSignal("VoIPMosSignal")
 
static simsignal_t taildropLossRateSignal = registerSignal("VoIPTaildropLossRate")
 

Detailed Description

Implements a simple VoIP source.

See the NED file for more information.

Member Typedef Documentation

Constructor & Destructor Documentation

inet::SimpleVoIPReceiver::SimpleVoIPReceiver ( )
64 {
65 }
inet::SimpleVoIPReceiver::~SimpleVoIPReceiver ( )
68 {
69  cancelAndDelete(selfTalkspurtFinished);
70 }
cMessage * selfTalkspurtFinished
Definition: SimpleVoIPReceiver.h:89

Member Function Documentation

double inet::SimpleVoIPReceiver::eModel ( double  delay,
double  loss 
)
private

Referenced by evaluateTalkspurt().

290 {
291  static const double alpha3 = 177.3; //ms
292  double delayms = 1000.0 * delay;
293 
294  // Compute the Id parameter
295  int u = (delayms - alpha3) > 0 ? 1 : 0;
296  double id = 0.024 * delayms + 0.11 * (delayms - alpha3) * u;
297 
298  // p: Packet loss rate in %
299  double p = lossRate * 100;
300  // Compute the Ie,eff parameter
301  double ie_eff = emodelIe + (95 - emodelIe) * p / (p + emodelBpl);
302 
303  // Compute the R factor
304  double Rfactor = emodelRo - id - ie_eff + emodelA;
305 
306  // Compute the MOS value
307  double mos = 0.0;
308 
309  if (Rfactor < 0.0) {
310  mos = 1.0;
311  }
312  else if (Rfactor > 100.0) {
313  mos = 4.5;
314  }
315  else {
316  mos = 1.0 + 0.035 * Rfactor + 7.0 * 1E-6 * Rfactor * (Rfactor - 60.0) * (100.0 - Rfactor);
317  }
318 
319  mos = (mos < 1.0) ? 1.0 : mos;
320 
321  return mos;
322 }
int emodelIe
Definition: SimpleVoIPReceiver.h:81
int emodelBpl
Definition: SimpleVoIPReceiver.h:82
int emodelA
Definition: SimpleVoIPReceiver.h:83
double emodelRo
Definition: SimpleVoIPReceiver.h:79
void inet::SimpleVoIPReceiver::evaluateTalkspurt ( bool  finish)
private

Referenced by finish(), and handleMessage().

163 {
164  ASSERT(!currentTalkspurt.packets.empty());
165  ASSERT(currentTalkspurt.isActive());
166 
167  VoIPPacketInfo firstPacket = currentTalkspurt.packets.front();
168 
169  simtime_t firstPlayoutTime = firstPacket.arrivalTime + playoutDelay;
170  simtime_t mouthToEarDelay = firstPlayoutTime - firstPacket.creationTime;
171  unsigned int firstPacketId = firstPacket.packetID;
172  unsigned int talkspurtNumPackets = currentTalkspurt.talkspurtNumPackets;
173  unsigned int playoutLoss = 0;
174  unsigned int tailDropLoss = 0;
175  unsigned int channelLoss;
176 
177  if (finish) {
178  unsigned int maxId = 0;
179  for (auto & elem : currentTalkspurt.packets)
180  maxId = std::max(maxId, (elem).packetID);
181  channelLoss = maxId + 1 - currentTalkspurt.packets.size();
182  }
183  else
185 
186  // Note: duplicate packets may shadow lost packets in the above channel loss calculation,
187  // we'll correct that in the code below when we detect duplicates.
188 
189  double packetLossRate = ((double)channelLoss / (double)talkspurtNumPackets);
190  emit(packetLossRateSignal, packetLossRate);
191 
192  // vector to manage duplicated packets
193  bool *isArrived = new bool[talkspurtNumPackets];
194  for (unsigned int y = 0; y < talkspurtNumPackets; y++)
195  isArrived[y] = false;
196 
197  simtime_t lastLateness = -playoutDelay; // arrival time - playout time
198  simtime_t maxLateness = -playoutDelay;
199 
200  // compute channelLoss, playoutLoss and tailDropLoss, needed for MOS and statistics
201  PacketsList playoutQueue;
202  for (auto & elem : currentTalkspurt.packets) {
203  elem.playoutTime = (firstPlayoutTime + ((int)elem.packetID - (int)firstPacketId) * currentTalkspurt.voiceDuration);
204 
205  lastLateness = elem.arrivalTime - elem.playoutTime; // >0: packet is too late (missed its playout time)
206  if (maxLateness < lastLateness)
207  maxLateness = lastLateness;
208 
209  EV_DEBUG << "MEASURED PACKET LATENESS: " << lastLateness << " TALK " << currentTalkspurt.talkspurtID << " PACKET " << elem.packetID << "\n\n";
210 
211  // Management of duplicated packets
212  if (isArrived[elem.packetID]) {
213  ++channelLoss; // duplicate packets may shadow lost packets in the channel loss calculation above, we correct that here.
214  EV_DEBUG << "DUPLICATED PACKET: TALK " << currentTalkspurt.talkspurtID << " PACKET " << elem.packetID << "\n\n";
215  }
216  else if (lastLateness > 0.0) {
217  ++playoutLoss;
218  EV_DEBUG << "REMOVED LATE PACKET: TALK " << currentTalkspurt.talkspurtID << " PACKET " << elem.packetID << ", LATENESS " << lastLateness * 1000.0 << "ms\n\n";
219  }
220  else {
221  // insert packet into playout buffer (if there is room in it)
222 
223  // remove packets from queue
224  auto qi = playoutQueue.begin();
225  while (qi != playoutQueue.end()) {
226  if ((*qi)->playoutTime < elem.arrivalTime) {
227  // EV_DEBUG << "REPRODUCED AND EXTRACT FROM BUFFER: TALK " << currentTalkspurt.talkspurtID << " PACKET " << (*qi)->packetID << "\n";
228  qi = playoutQueue.erase(qi);
229  }
230  else
231  ++qi;
232  }
233 
234  if (playoutQueue.size() < bufferSpace) {
235  EV_DEBUG << "PACKET INSERTED INTO PLAYOUT BUFFER: TALK "
236  << currentTalkspurt.talkspurtID << " PACKET " << elem.packetID << ", "
237  << "ARRIVAL TIME " << elem.arrivalTime << "s, "
238  << "PLAYOUT TIME " << elem.playoutTime << "s\n\n";
239 
240  isArrived[elem.packetID] = true; // isArrived[] is needed for detecting duplicate packets
241 
242  playoutQueue.push_back(&(elem));
243  }
244  else {
245  // buffer full
246  ++tailDropLoss;
247  EV_DEBUG << "BUFFER FULL, PACKET DISCARDED: TALK " << currentTalkspurt.talkspurtID << " PACKET "
248  << elem.packetID << " ARRIVAL TIME " << elem.arrivalTime << "s\n\n";
249  }
250  }
251  }
252 
253  double proportionalLossRate = (double)(tailDropLoss + playoutLoss + channelLoss) / (double)talkspurtNumPackets;
254  EV_DEBUG << "proportionalLossRate " << proportionalLossRate << "(tailDropLoss=" << tailDropLoss
255  << " - playoutLoss=" << playoutLoss << " - channelLoss=" << channelLoss << ")\n\n";
256 
257  double mos = eModel(SIMTIME_DBL(mouthToEarDelay), proportionalLossRate);
258 
260  double lossRate = ((double)playoutLoss / (double)talkspurtNumPackets);
261  emit(playoutLossRateSignal, lossRate);
262  emit(mosSignal, mos);
263 
264  // add calculated MOS value to fingerprint
266 
267  double tailDropRate = ((double)tailDropLoss / (double)talkspurtNumPackets);
268  emit(taildropLossRateSignal, tailDropRate);
269 
270  EV_DEBUG << "CALCULATED MOS: eModel( " << playoutDelay << " , " << tailDropLoss << "+" << playoutLoss << "+" << channelLoss << " ) = " << mos << "\n\n";
271 
272  EV_DEBUG << "PLAYOUT DELAY ADAPTATION \n" << "OLD PLAYOUT DELAY: " << playoutDelay << "\nMAX LATENESS MEASURED: " << maxLateness << "\n\n";
273 
274  if (par("adaptivePlayoutDelay").boolValue()) {
275  playoutDelay += maxLateness;
276  if (playoutDelay < 0.0)
277  playoutDelay = 0.0;
278  EV_DEBUG << "NEW PLAYOUT DELAY: " << playoutDelay << "\n\n";
279  }
280 
281  delete[] isArrived;
283 }
std::list< VoIPPacketInfo * > PacketsList
Definition: SimpleVoIPReceiver.h:52
static simsignal_t taildropLossRateSignal
Definition: SimpleVoIPReceiver.h:97
simtime_t voiceDuration
Definition: SimpleVoIPReceiver.h:66
double max(double a, double b)
Returns the greater of the given parameters.
Definition: INETMath.h:161
bool isActive()
Definition: SimpleVoIPReceiver.h:75
unsigned int talkspurtNumPackets
Definition: SimpleVoIPReceiver.h:65
simtime_t playoutDelay
Definition: SimpleVoIPReceiver.h:84
void finishTalkspurt()
Definition: SimpleVoIPReceiver.h:72
static simsignal_t playoutDelaySignal
Definition: SimpleVoIPReceiver.h:94
static simsignal_t playoutLossRateSignal
Definition: SimpleVoIPReceiver.h:95
TalkspurtInfo currentTalkspurt
Definition: SimpleVoIPReceiver.h:90
unsigned int bufferSpace
Definition: SimpleVoIPReceiver.h:80
PacketsVector packets
Definition: SimpleVoIPReceiver.h:67
double eModel(double delay, double loss)
Definition: SimpleVoIPReceiver.cc:289
static simsignal_t mosSignal
Definition: SimpleVoIPReceiver.h:96
virtual void finish() override
Definition: SimpleVoIPReceiver.cc:324
static simsignal_t packetLossRateSignal
Definition: SimpleVoIPReceiver.h:92
#define FINGERPRINT_ADD_EXTRA_DATA(x)
Definition: INETDefs.h:87
unsigned int talkspurtID
Definition: SimpleVoIPReceiver.h:64
void inet::SimpleVoIPReceiver::finish ( )
overrideprotectedvirtual
325 {
326  // evaluate last talkspurt
327  cancelEvent(selfTalkspurtFinished);
329  evaluateTalkspurt(true);
330 }
bool isActive()
Definition: SimpleVoIPReceiver.h:75
TalkspurtInfo currentTalkspurt
Definition: SimpleVoIPReceiver.h:90
cMessage * selfTalkspurtFinished
Definition: SimpleVoIPReceiver.h:89
void evaluateTalkspurt(bool finish)
Definition: SimpleVoIPReceiver.cc:162
void inet::SimpleVoIPReceiver::handleMessage ( cMessage *  msg)
overrideprotected
114 {
115  if (msg->isSelfMessage()) {
116  // selfTalkspurtFinished
117  evaluateTalkspurt(false);
118  return;
119  }
120 
121  SimpleVoIPPacket *packet = dynamic_cast<SimpleVoIPPacket *>(msg);
122  if (packet == nullptr) {
123  // TODO: throw exception instead?
124  EV_ERROR << "VoIPReceiver: Unknown incoming message: " << msg->getClassName() << endl;
125  delete msg;
126  return;
127  }
128 
130  // first talkspurt
131  startTalkspurt(packet);
132  }
133  else if (packet->getTalkspurtID() > currentTalkspurt.talkspurtID) {
134  // old talkspurt finished, new talkspurt started
135  if (currentTalkspurt.isActive()) {
136  cancelEvent(selfTalkspurtFinished);
137  evaluateTalkspurt(false);
138  }
139  startTalkspurt(packet);
140  }
141  else if (currentTalkspurt.talkspurtID == packet->getTalkspurtID() && currentTalkspurt.status == TalkspurtInfo::ACTIVE) {
142  // talkspurt continued
143  if (!currentTalkspurt.checkPacket(packet))
144  throw cRuntimeError("Talkspurt parameters not equals");
145  currentTalkspurt.addPacket(packet);
146  }
147  else {
148  // packet from older talkspurt, ignore
149  EV_DEBUG << "PACKET ARRIVED TOO LATE: TALKSPURT " << packet->getTalkspurtID() << " PACKET " << packet->getPacketID() << ", IGNORED\n\n";
150  delete msg;
151  return;
152  }
153 
154  EV_DEBUG << "PACKET ARRIVED: TALKSPURT " << packet->getTalkspurtID() << " PACKET " << packet->getPacketID() << "\n\n";
155 
156  simtime_t delay = packet->getArrivalTime() - packet->getVoipTimestamp();
157  emit(packetDelaySignal, delay);
158 
159  delete msg;
160 }
Status status
Definition: SimpleVoIPReceiver.h:63
void startTalkspurt(SimpleVoIPPacket *packet)
Definition: SimpleVoIPReceiver.cc:106
static simsignal_t packetDelaySignal
Definition: SimpleVoIPReceiver.h:93
bool isActive()
Definition: SimpleVoIPReceiver.h:75
void addPacket(SimpleVoIPPacket *pk)
Definition: SimpleVoIPReceiver.cc:54
Definition: SimpleVoIPReceiver.h:59
TalkspurtInfo currentTalkspurt
Definition: SimpleVoIPReceiver.h:90
cMessage * selfTalkspurtFinished
Definition: SimpleVoIPReceiver.h:89
bool checkPacket(SimpleVoIPPacket *pk)
Definition: SimpleVoIPReceiver.cc:47
Definition: SimpleVoIPReceiver.h:60
void evaluateTalkspurt(bool finish)
Definition: SimpleVoIPReceiver.cc:162
unsigned int talkspurtID
Definition: SimpleVoIPReceiver.h:64
virtual bool inet::SimpleVoIPReceiver::handleOperationStage ( LifecycleOperation operation,
int  stage,
IDoneCallback doneCallback 
)
inlineoverrideprotectedvirtual

Perform one stage of a lifecycle operation.

Processing may be done entirely within this method, or may be a longer process that involves nonzero simulation time or several events, and is triggered by this method call.

Return value: true = "done"; false = "not yet done, will invoke doneCallback when done"

Implements inet::ILifecycle.

110  { Enter_Method_Silent(); throw cRuntimeError("Unsupported lifecycle operation '%s'", operation->getClassName()); return true; }
void inet::SimpleVoIPReceiver::initialize ( int  stage)
overrideprotected
73 {
74  cSimpleModule::initialize(stage);
75 
76  if (stage == INITSTAGE_LOCAL) {
77  emodelIe = par("emodelIe");
78  emodelBpl = par("emodelBpl");
79  emodelA = par("emodelA");
80  emodelRo = par("emodelRo");
81 
82  bufferSpace = par("bufferSpace");
83  playoutDelay = par("playoutDelay");
84  mosSpareTime = par("mosSpareTime");
85 
87  }
88  else if (stage == INITSTAGE_APPLICATION_LAYER) {
89  bool isOperational;
90  NodeStatus *nodeStatus = dynamic_cast<NodeStatus *>(findContainingNode(this)->getSubmodule("status"));
91  isOperational = (!nodeStatus) || nodeStatus->getState() == NodeStatus::UP;
92  if (!isOperational)
93  throw cRuntimeError("This module doesn't support starting in node DOWN state");
94 
95  int port = par("localPort");
96  EV_INFO << "VoIPReceiver::initialize - binding to port: local:" << port << endl;
97  if (port != -1) {
98  socket.setOutputGate(gate("udpOut"));
99  socket.bind(port);
100  }
101 
102  selfTalkspurtFinished = new cMessage("selfTalkspurtFinished");
103  }
104 }
simtime_t mosSpareTime
Definition: SimpleVoIPReceiver.h:85
int emodelIe
Definition: SimpleVoIPReceiver.h:81
int emodelBpl
Definition: SimpleVoIPReceiver.h:82
void setOutputGate(cGate *toUdp)
Sets the gate on which to send to UDP.
Definition: UDPSocket.h:110
simtime_t playoutDelay
Definition: SimpleVoIPReceiver.h:84
cModule * findContainingNode(const cModule *from)
Find the node containing the given module.
Definition: ModuleAccess.cc:56
Local initializations.
Definition: InitStages.h:35
UDPSocket socket
Definition: SimpleVoIPReceiver.h:88
int emodelA
Definition: SimpleVoIPReceiver.h:83
TalkspurtInfo currentTalkspurt
Definition: SimpleVoIPReceiver.h:90
unsigned int bufferSpace
Definition: SimpleVoIPReceiver.h:80
double emodelRo
Definition: SimpleVoIPReceiver.h:79
cMessage * selfTalkspurtFinished
Definition: SimpleVoIPReceiver.h:89
unsigned int talkspurtID
Definition: SimpleVoIPReceiver.h:64
void bind(int localPort)
Bind the socket to a local port number.
Definition: UDPSocket.cc:53
Initialization of applications.
Definition: InitStages.h:106
Definition: NodeStatus.h:40
virtual int inet::SimpleVoIPReceiver::numInitStages ( ) const
inlineoverrideprotectedvirtual
104 { return NUM_INIT_STAGES; }
The number of initialization stages.
Definition: InitStages.h:116
void inet::SimpleVoIPReceiver::startTalkspurt ( SimpleVoIPPacket packet)
private
107 {
109  simtime_t endTime = simTime() + playoutDelay + (currentTalkspurt.talkspurtNumPackets - packet->getPacketID()) * currentTalkspurt.voiceDuration + mosSpareTime;
110  scheduleAt(endTime, selfTalkspurtFinished);
111 }
simtime_t mosSpareTime
Definition: SimpleVoIPReceiver.h:85
simtime_t voiceDuration
Definition: SimpleVoIPReceiver.h:66
unsigned int talkspurtNumPackets
Definition: SimpleVoIPReceiver.h:65
simtime_t playoutDelay
Definition: SimpleVoIPReceiver.h:84
TalkspurtInfo currentTalkspurt
Definition: SimpleVoIPReceiver.h:90
cMessage * selfTalkspurtFinished
Definition: SimpleVoIPReceiver.h:89
void startTalkspurt(SimpleVoIPPacket *pk)
Definition: SimpleVoIPReceiver.cc:36

Member Data Documentation

unsigned int inet::SimpleVoIPReceiver::bufferSpace = 0
private

Referenced by evaluateTalkspurt(), and initialize().

TalkspurtInfo inet::SimpleVoIPReceiver::currentTalkspurt
private
int inet::SimpleVoIPReceiver::emodelA = -1
private

Referenced by eModel(), and initialize().

int inet::SimpleVoIPReceiver::emodelBpl = -1
private

Referenced by eModel(), and initialize().

int inet::SimpleVoIPReceiver::emodelIe = -1
private

Referenced by eModel(), and initialize().

double inet::SimpleVoIPReceiver::emodelRo = NaN
private

Referenced by eModel(), and initialize().

simsignal_t inet::SimpleVoIPReceiver::mosSignal = registerSignal("VoIPMosSignal")
staticprivate

Referenced by evaluateTalkspurt().

simtime_t inet::SimpleVoIPReceiver::mosSpareTime
private

Referenced by initialize(), and startTalkspurt().

simsignal_t inet::SimpleVoIPReceiver::packetDelaySignal = registerSignal("VoIPPacketDelay")
staticprivate

Referenced by handleMessage().

simsignal_t inet::SimpleVoIPReceiver::packetLossRateSignal = registerSignal("VoIPPacketLossRate")
staticprivate

Referenced by evaluateTalkspurt().

simtime_t inet::SimpleVoIPReceiver::playoutDelay
private
simsignal_t inet::SimpleVoIPReceiver::playoutDelaySignal = registerSignal("VoIPPlayoutDelay")
staticprivate

Referenced by evaluateTalkspurt().

simsignal_t inet::SimpleVoIPReceiver::playoutLossRateSignal = registerSignal("VoIPPlayoutLossRate")
staticprivate

Referenced by evaluateTalkspurt().

cMessage* inet::SimpleVoIPReceiver::selfTalkspurtFinished = nullptr
private
UDPSocket inet::SimpleVoIPReceiver::socket
private

Referenced by initialize().

simsignal_t inet::SimpleVoIPReceiver::taildropLossRateSignal = registerSignal("VoIPTaildropLossRate")
staticprivate

Referenced by evaluateTalkspurt().


The documentation for this class was generated from the following files: