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

#include <VoIPStreamSender.h>

Inheritance diagram for inet::VoIPStreamSender:
inet::ILifecycle

Classes

class  Buffer
 

Public Member Functions

 VoIPStreamSender ()
 
 ~VoIPStreamSender ()
 
virtual bool handleOperationStage (LifecycleOperation *operation, int stage, IDoneCallback *doneCallback) override
 Perform one stage of a lifecycle operation. More...
 
- Public Member Functions inherited from inet::ILifecycle
virtual ~ILifecycle ()
 

Protected Member Functions

virtual void initialize (int stage) override
 
virtual int numInitStages () const override
 
virtual void handleMessage (cMessage *msg) override
 
virtual void finish () override
 
virtual void openSoundFile (const char *name)
 
virtual VoIPStreamPacket * generatePacket ()
 
virtual bool checkSilence (AVSampleFormat sampleFormat, void *_buf, int samples)
 
virtual void readFrame ()
 

Protected Attributes

int localPort = -1
 
int destPort = -1
 
L3Address destAddress
 
int voipHeaderSize = 0
 
int voipSilenceThreshold = 0
 
int voipSilencePacketSize = 0
 
int sampleRate = 0
 
const char * codec = nullptr
 
int compressedBitRate = 0
 
simtime_t packetTimeLength
 
const char * soundFile = nullptr
 
int repeatCount = 0
 
const char * traceFileName = nullptr
 
AudioOutFile outFile
 
AVFormatContext * pFormatCtx = nullptr
 
AVCodecContext * pCodecCtx = nullptr
 
AVCodec * pCodec = nullptr
 
AVAudioResampleContext * pReSampleCtx = nullptr
 
AVCodecContext * pEncoderCtx = nullptr
 
AVCodec * pCodecEncoder = nullptr
 
UDPSocket socket
 
int streamIndex = -1
 
uint32_t pktID = 0
 
int samplesPerPacket = 0
 
AVPacket packet
 
Buffer sampleBuffer
 
cMessage * timer = nullptr
 

Static Protected Attributes

static simsignal_t sentPkSignal = registerSignal("sentPk")
 

Constructor & Destructor Documentation

inet::VoIPStreamSender::VoIPStreamSender ( )
36 {
37 }
inet::VoIPStreamSender::~VoIPStreamSender ( )
40 {
41  if (pEncoderCtx) {
42  avcodec_close(pEncoderCtx);
43  avcodec_free_context(&pEncoderCtx);
44  }
45  cancelAndDelete(timer);
46  av_free_packet(&packet);
47 }
AVCodecContext * pEncoderCtx
Definition: VoIPStreamSender.h:130
AVPacket packet
Definition: VoIPStreamSender.h:138
cMessage * timer
Definition: VoIPStreamSender.h:141

Member Function Documentation

bool inet::VoIPStreamSender::checkSilence ( AVSampleFormat  sampleFormat,
void *  _buf,
int  samples 
)
protectedvirtual

Referenced by generatePacket().

378 {
379  int max = 0;
380  int i;
381 
382  switch (sampleFormat) {
383  case AV_SAMPLE_FMT_U8: {
384  uint8_t *buf = (uint8_t *)_buf;
385  for (i = 0; i < samples; ++i) {
386  int s = abs(int(buf[i]) - 0x80);
387  if (s > max)
388  max = s;
389  }
390  }
391  break;
392 
393  case AV_SAMPLE_FMT_S16: {
394  int16_t *buf = (int16_t *)_buf;
395  for (i = 0; i < samples; ++i) {
396  int s = abs(buf[i]);
397  if (s > max)
398  max = s;
399  }
400  }
401  break;
402 
403  case AV_SAMPLE_FMT_S32: {
404  int32_t *buf = (int32_t *)_buf;
405 
406  for (i = 0; i < samples; ++i) {
407  int s = abs(buf[i]);
408 
409  if (s > max)
410  max = s;
411  }
412  }
413  break;
414 
415  default:
416  throw cRuntimeError("Invalid sampleFormat: %d", sampleFormat);
417  }
418 
419  return max < voipSilenceThreshold;
420 }
double max(double a, double b)
Returns the greater of the given parameters.
Definition: INETMath.h:161
int voipSilenceThreshold
Definition: VoIPStreamSender.h:107
value< double, units::s > s
Definition: Units.h:1049
void inet::VoIPStreamSender::finish ( )
overrideprotectedvirtual
175 {
176  av_free_packet(&packet);
177  outFile.close();
178 
179  if (pCodecCtx) {
180  avcodec_close(pCodecCtx);
181  }
182  if (pReSampleCtx) {
183 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
184  avresample_close(pReSampleCtx);
185  avresample_free(&pReSampleCtx);
186 #else // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
187  audio_resample_close(pReSampleCtx);
188 #endif // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
189  pReSampleCtx = nullptr;
190  }
191 
192  if (pFormatCtx) {
193  avformat_close_input(&pFormatCtx);
194  }
195 }
bool close()
Definition: AudioOutFile.cc:149
AudioOutFile outFile
Definition: VoIPStreamSender.h:117
AVFormatContext * pFormatCtx
Definition: VoIPStreamSender.h:120
AVPacket packet
Definition: VoIPStreamSender.h:138
AVAudioResampleContext * pReSampleCtx
Definition: VoIPStreamSender.h:125
AVCodecContext * pCodecCtx
Definition: VoIPStreamSender.h:121
VoIPStreamPacket * inet::VoIPStreamSender::generatePacket ( )
protectedvirtual

Referenced by handleMessage().

305 {
306  readFrame();
307 
308  if (sampleBuffer.empty())
309  return nullptr;
310 
311  short int bytesPerInSample = av_get_bytes_per_sample(pEncoderCtx->sample_fmt);
312  int samples = std::min(sampleBuffer.length() / (bytesPerInSample), samplesPerPacket);
313  int inBytes = samples * bytesPerInSample;
314  bool isSilent = checkSilence(pEncoderCtx->sample_fmt, sampleBuffer.readPtr(), samples);
315  VoIPStreamPacket *vp = new VoIPStreamPacket();
316 
317  AVPacket opacket;
318  av_init_packet(&opacket);
319  opacket.data = nullptr;
320  opacket.size = 0;
321  AVFrame *frame = av_frame_alloc();
322 
323  frame->nb_samples = samples;
324 
325 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
326  frame->channel_layout = AV_CH_LAYOUT_MONO;
327  frame->sample_rate = pEncoderCtx->sample_rate;
328 #endif // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
329 
330  int ret = avcodec_fill_audio_frame(frame, /*channels*/ 1, pEncoderCtx->sample_fmt,
331  (const uint8_t *)(sampleBuffer.readPtr()), inBytes, 1);
332  if (ret < 0)
333  throw cRuntimeError("Error in avcodec_fill_audio_frame(): err=%d", ret);
334 
335  // The bitsPerOutSample is not 0 when codec is PCM.
336  int gotPacket;
337  ret = avcodec_encode_audio2(pEncoderCtx, &opacket, frame, &gotPacket);
338  if (ret < 0 || gotPacket != 1)
339  throw cRuntimeError("avcodec_encode_audio() error: %d gotPacket: %d", ret, gotPacket);
340 
341  if (outFile.isOpen())
342  outFile.write(sampleBuffer.readPtr(), inBytes);
343  sampleBuffer.notifyRead(inBytes);
344 
345  vp->getBytes().setDataFromBuffer(opacket.data, opacket.size);
346 
347  if (isSilent) {
348  vp->setName("SILENCE");
349  vp->setType(SILENCE);
350  vp->setByteLength(voipSilencePacketSize);
351  }
352  else {
353  vp->setName("VOICE");
354  vp->setType(VOICE);
355  vp->setByteLength(voipHeaderSize + opacket.size);
356  }
357 
358  vp->setTimeStamp(pktID);
359  vp->setSeqNo(pktID);
360  vp->setCodec(pEncoderCtx->codec_id);
361  vp->setSampleRate(sampleRate);
362  vp->setSampleBits(pEncoderCtx->bits_per_coded_sample);
363  vp->setSamplesPerPacket(samplesPerPacket);
364  vp->setTransmitBitrate(compressedBitRate);
365 
366  pktID++;
367 
368  av_free_packet(&opacket);
369 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
370  av_frame_free(&frame);
371 #else // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
372  av_freep(&frame);
373 #endif // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
374  return vp;
375 }
virtual bool checkSilence(AVSampleFormat sampleFormat, void *_buf, int samples)
Definition: VoIPStreamSender.cc:377
char * readPtr()
Definition: VoIPStreamSender.h:92
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SCTPAssociation.h:270
int samplesPerPacket
Definition: VoIPStreamSender.h:137
int voipHeaderSize
Definition: VoIPStreamSender.h:106
AVCodecContext * pEncoderCtx
Definition: VoIPStreamSender.h:130
AudioOutFile outFile
Definition: VoIPStreamSender.h:117
bool isOpen() const
Definition: AudioOutFile.h:46
int voipSilencePacketSize
Definition: VoIPStreamSender.h:108
void notifyRead(int length)
Definition: VoIPStreamSender.h:95
int length() const
Definition: VoIPStreamSender.h:90
int compressedBitRate
Definition: VoIPStreamSender.h:111
bool empty() const
Definition: VoIPStreamSender.h:91
uint32_t pktID
Definition: VoIPStreamSender.h:136
void write(void *inbuf, int inbytes)
Definition: AudioOutFile.cc:108
Buffer sampleBuffer
Definition: VoIPStreamSender.h:139
int sampleRate
Definition: VoIPStreamSender.h:109
virtual void readFrame()
Definition: VoIPStreamSender.cc:432
void inet::VoIPStreamSender::handleMessage ( cMessage *  msg)
overrideprotectedvirtual
143 {
144  if (msg->isSelfMessage()) {
145  VoIPStreamPacket *packet;
146 
147  if (msg == timer) {
148  packet = generatePacket();
149 
150  if (!packet) {
151  if (repeatCount > 1) {
152  repeatCount--;
153  av_seek_frame(pFormatCtx, streamIndex, 0, 0);
154  packet = generatePacket();
155  }
156  }
157 
158  if (packet) {
159  // reschedule trigger message
160  scheduleAt(simTime() + packetTimeLength, packet);
161  scheduleAt(simTime() + packetTimeLength, msg);
162  }
163  }
164  else {
165  packet = check_and_cast<VoIPStreamPacket *>(msg);
166  emit(sentPkSignal, packet);
167  socket.sendTo(packet, destAddress, destPort);
168  }
169  }
170  else
171  delete msg;
172 }
int streamIndex
Definition: VoIPStreamSender.h:135
void sendTo(cPacket *msg, L3Address destAddr, int destPort, const SendOptions *options=nullptr)
Sends a data packet to the given address and port.
Definition: UDPSocket.cc:88
simtime_t packetTimeLength
Definition: VoIPStreamSender.h:112
int repeatCount
Definition: VoIPStreamSender.h:114
static simsignal_t sentPkSignal
Definition: VoIPStreamSender.h:144
AVFormatContext * pFormatCtx
Definition: VoIPStreamSender.h:120
L3Address destAddress
Definition: VoIPStreamSender.h:104
int destPort
Definition: VoIPStreamSender.h:103
AVPacket packet
Definition: VoIPStreamSender.h:138
UDPSocket socket
Definition: VoIPStreamSender.h:134
cMessage * timer
Definition: VoIPStreamSender.h:141
virtual VoIPStreamPacket * generatePacket()
Definition: VoIPStreamSender.cc:304
virtual bool inet::VoIPStreamSender::handleOperationStage ( LifecycleOperation operation,
int  stage,
IDoneCallback doneCallback 
)
inlineoverridevirtual

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.

61  { Enter_Method_Silent(); throw cRuntimeError("Unsupported lifecycle operation '%s'", operation->getClassName()); return true; }
void inet::VoIPStreamSender::initialize ( int  stage)
overrideprotectedvirtual
75 {
76  if (stage == INITSTAGE_LOCAL) {
77  voipHeaderSize = par("voipHeaderSize");
78  voipSilenceThreshold = par("voipSilenceThreshold");
79  sampleRate = par("sampleRate");
80  codec = par("codec").stringValue();
81  compressedBitRate = par("compressedBitRate");
82  packetTimeLength = par("packetTimeLength");
83 
84  samplesPerPacket = (int)round(sampleRate * SIMTIME_DBL(packetTimeLength));
85  if (samplesPerPacket & 1)
87  EV_INFO << "The packetTimeLength parameter is " << packetTimeLength * 1000.0 << "ms, ";
89  EV_INFO << "adjusted to " << packetTimeLength * 1000.0 << "ms" << endl;
90 
91  soundFile = par("soundFile").stringValue();
92  repeatCount = par("repeatCount");
93  traceFileName = par("traceFileName").stringValue();
94 
95  pReSampleCtx = nullptr;
96  localPort = par("localPort");
97  destPort = par("destPort");
98  EV_DEBUG << "libavcodec: " << LIBAVCODEC_VERSION_MAJOR << "." << LIBAVCODEC_VERSION_MINOR << "." << LIBAVCODEC_VERSION_MICRO << endl;
99  EV_DEBUG << "libavformat: " << LIBAVFORMAT_VERSION_MAJOR << "." << LIBAVFORMAT_VERSION_MINOR << "." << LIBAVFORMAT_VERSION_MICRO << endl;
100  EV_DEBUG << "libavutil: " << LIBAVUTIL_VERSION_MAJOR << "." << LIBAVUTIL_VERSION_MINOR << "." << LIBAVUTIL_VERSION_MICRO << endl;
101  EV_DEBUG << "libavresample: " << LIBAVRESAMPLE_VERSION_MAJOR << "." << LIBAVRESAMPLE_VERSION_MINOR << "." << LIBAVRESAMPLE_VERSION_MICRO << endl;
102  }
103  else if (stage == INITSTAGE_APPLICATION_LAYER) {
104  bool isOperational;
105  NodeStatus *nodeStatus = dynamic_cast<NodeStatus *>(findContainingNode(this)->getSubmodule("status"));
106  isOperational = (!nodeStatus) || nodeStatus->getState() == NodeStatus::UP;
107  if (!isOperational)
108  throw cRuntimeError("This module doesn't support starting in node DOWN state");
109 
110  // say HELLO to the world
111  EV_TRACE << "VoIPSourceApp -> initialize(" << stage << ")" << endl;
112 
113  // Hack for create results folder
114  recordScalar("hackForCreateResultsFolder", 0);
115 
116  destAddress = L3AddressResolver().resolve(par("destAddress").stringValue());
117  socket.setOutputGate(gate("udpOut"));
119 
120  simtime_t startTime = par("startTime");
121 
122  sampleBuffer.clear(0);
123 
124  // initialize avcodec library
125  av_register_all();
126  avcodec_register_all();
127 
128  av_init_packet(&packet);
129 
131 
132  timer = new cMessage("sendVoIP");
133  scheduleAt(startTime, timer);
134 
136 
137  // initialize the sequence number
138  pktID = 1;
139  }
140 }
void clear(int framesize)
Definition: VoIPStreamSender.cc:62
const char * traceFileName
Definition: VoIPStreamSender.h:116
int samplesPerPacket
Definition: VoIPStreamSender.h:137
int voipHeaderSize
Definition: VoIPStreamSender.h:106
const char * soundFile
Definition: VoIPStreamSender.h:113
simtime_t packetTimeLength
Definition: VoIPStreamSender.h:112
virtual void openSoundFile(const char *name)
Definition: VoIPStreamSender.cc:197
int repeatCount
Definition: VoIPStreamSender.h:114
void setOutputGate(cGate *toUdp)
Sets the gate on which to send to UDP.
Definition: UDPSocket.h:110
int voipSilencePacketSize
Definition: VoIPStreamSender.h:108
L3Address destAddress
Definition: VoIPStreamSender.h:104
cModule * findContainingNode(const cModule *from)
Find the node containing the given module.
Definition: ModuleAccess.cc:56
Local initializations.
Definition: InitStages.h:35
int round(double d)
Returns an integer that corresponds to rounded double parameter.
Definition: INETMath.h:151
int destPort
Definition: VoIPStreamSender.h:103
int compressedBitRate
Definition: VoIPStreamSender.h:111
int voipSilenceThreshold
Definition: VoIPStreamSender.h:107
AVPacket packet
Definition: VoIPStreamSender.h:138
UDPSocket socket
Definition: VoIPStreamSender.h:134
uint32_t pktID
Definition: VoIPStreamSender.h:136
cMessage * timer
Definition: VoIPStreamSender.h:141
#define stringValue()
Definition: NedFunctions.cc:24
const char * codec
Definition: VoIPStreamSender.h:110
Buffer sampleBuffer
Definition: VoIPStreamSender.h:139
int sampleRate
Definition: VoIPStreamSender.h:109
int localPort
Definition: VoIPStreamSender.h:102
AVAudioResampleContext * pReSampleCtx
Definition: VoIPStreamSender.h:125
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::VoIPStreamSender::numInitStages ( ) const
inlineoverrideprotectedvirtual
65 { return NUM_INIT_STAGES; }
The number of initialization stages.
Definition: InitStages.h:116
void inet::VoIPStreamSender::openSoundFile ( const char *  name)
protectedvirtual

Referenced by initialize().

198 {
199  int ret;
200 
201  ret = avformat_open_input(&pFormatCtx, name, nullptr, nullptr);
202  if (ret < 0)
203  throw cRuntimeError("Audiofile '%s' open error: %d", name, ret);
204 
205  ret = avformat_find_stream_info(pFormatCtx, nullptr);
206  if (ret < 0)
207  throw cRuntimeError("Audiofile '%s' avformat_find_stream_info() error: %d", name, ret);
208 
209  //get stream number
210  streamIndex = -1;
211  for (unsigned int j = 0; j < pFormatCtx->nb_streams; j++) {
212  if (pFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
213  streamIndex = j;
214  break;
215  }
216  }
217 
218  if (streamIndex == -1)
219  throw cRuntimeError("The file '%s' not contains any audio stream.", name);
220 
221  pCodecCtx = pFormatCtx->streams[streamIndex]->codec;
222 
223  //find decoder and open the correct codec
224  pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
225  if (!pCodec)
226  throw cRuntimeError("Audiofile '%s' avcodec_find_decoder() error: decoder not found", name);
227 
228  ret = avcodec_open2(pCodecCtx, pCodec, nullptr);
229  if (ret < 0)
230  throw cRuntimeError("avcodec_open() error on file '%s': %d", name, ret);
231 
232  //allocate encoder
233  pEncoderCtx = avcodec_alloc_context3(nullptr);
234  if (!pEncoderCtx)
235  throw cRuntimeError("error occured in avcodec_alloc_context3()");
236  //set bitrate:
237  pEncoderCtx->bit_rate = compressedBitRate;
238 
239  pEncoderCtx->sample_rate = sampleRate;
240  pEncoderCtx->channels = 1;
241 
242  pCodecEncoder = avcodec_find_encoder_by_name(codec);
243  if (!pCodecEncoder)
244  throw cRuntimeError("Codec '%s' not found!", codec);
245 
246  pEncoderCtx->sample_fmt = pCodecCtx->sample_fmt; // FIXME hack!
247 
248  if (avcodec_open2(pEncoderCtx, pCodecEncoder, nullptr) < 0)
249  throw cRuntimeError("could not open %s encoding codec!", codec);
250 
251  if (pCodecCtx->sample_rate == sampleRate
252  && pCodecCtx->sample_fmt == pEncoderCtx->sample_fmt
253  && pCodecCtx->channels == 1)
254  {
255  pReSampleCtx = nullptr;
256  }
257  else {
258 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
259  pReSampleCtx = avresample_alloc_context();
260  if (!pReSampleCtx)
261  throw cRuntimeError("error in av_audio_resample_init()");
262 
263  int inChannelLayout = pCodecCtx->channel_layout == 0 ? av_get_default_channel_layout(pCodecCtx->channels) : pCodecCtx->channel_layout;
264  if (av_opt_set_int(pReSampleCtx, "in_channel_layout", inChannelLayout, 0))
265  throw cRuntimeError("error in option setting of 'in_channel_layout'");
266  if (av_opt_set_int(pReSampleCtx, "in_sample_fmt", pCodecCtx->sample_fmt, 0))
267  throw cRuntimeError("error in option setting of 'in_sample_fmt'");
268  if (av_opt_set_int(pReSampleCtx, "in_sample_rate", pCodecCtx->sample_rate, 0))
269  throw cRuntimeError("error in option setting of 'in_sample_rate'");
270  if (av_opt_set_int(pReSampleCtx, "out_channel_layout", AV_CH_LAYOUT_MONO, 0))
271  throw cRuntimeError("error in option setting of 'out_channel_layout'");
272  if (av_opt_set_int(pReSampleCtx, "out_sample_fmt", pEncoderCtx->sample_fmt, 0))
273  throw cRuntimeError("error in option setting of 'out_sample_fmt'");
274  if (av_opt_set_int(pReSampleCtx, "out_sample_rate", sampleRate, 0))
275  throw cRuntimeError("error in option setting of 'out_sample_rate'");
276  if (av_opt_set_int(pReSampleCtx, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0))
277  throw cRuntimeError("error in option setting of 'internal_sample_fmt'");
278 
279  ret = avresample_open(pReSampleCtx);
280  if (ret < 0)
281  throw cRuntimeError("Error opening context");
282 #else // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
283  pReSampleCtx = av_audio_resample_init(1, pCodecCtx->channels, sampleRate, pCodecCtx->sample_rate,
284  pEncoderCtx->sample_fmt, pCodecCtx->sample_fmt, 16, 10, 0, 0.8);
285  // parameters copied from the implementation of deprecated audio_resample_init()
286  // begin HACK
287  long int sec = 2;
288  short int *inb = new short int[sec * pCodecCtx->channels * pCodecCtx->sample_rate * av_get_bits_per_sample_format(pCodecCtx->sample_fmt) / (8 * sizeof(short int))];
289  short int *outb = new short int[sec * sampleRate * av_get_bits_per_sample_format(pEncoderCtx->sample_fmt) / (8 * sizeof(short int)) + 16];
290  int decoded = audio_resample(pReSampleCtx, outb, inb, sec * pCodecCtx->sample_rate);
291  EV_DEBUG << "decoded:" << decoded << endl;
292  delete[] inb;
293  delete[] outb;
294  // end HACK
295 #endif // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
296  }
297 
299  outFile.open(traceFileName, sampleRate, 8 * av_get_bytes_per_sample(pEncoderCtx->sample_fmt));
300 
301  sampleBuffer.clear(samplesPerPacket * av_get_bytes_per_sample(pEncoderCtx->sample_fmt));
302 }
int streamIndex
Definition: VoIPStreamSender.h:135
void clear(int framesize)
Definition: VoIPStreamSender.cc:62
const char * traceFileName
Definition: VoIPStreamSender.h:116
int samplesPerPacket
Definition: VoIPStreamSender.h:137
AVCodec * pCodecEncoder
Definition: VoIPStreamSender.h:131
AVCodecContext * pEncoderCtx
Definition: VoIPStreamSender.h:130
AudioOutFile outFile
Definition: VoIPStreamSender.h:117
AVFormatContext * pFormatCtx
Definition: VoIPStreamSender.h:120
int compressedBitRate
Definition: VoIPStreamSender.h:111
AVCodec * pCodec
Definition: VoIPStreamSender.h:122
const char * codec
Definition: VoIPStreamSender.h:110
Buffer sampleBuffer
Definition: VoIPStreamSender.h:139
void open(const char *resultFile, int sampleRate, short int sampleBits)
Definition: AudioOutFile.cc:52
int sampleRate
Definition: VoIPStreamSender.h:109
AVAudioResampleContext * pReSampleCtx
Definition: VoIPStreamSender.h:125
AVCodecContext * pCodecCtx
Definition: VoIPStreamSender.h:121
void inet::VoIPStreamSender::readFrame ( )
protectedvirtual

Referenced by generatePacket().

433 {
434  short int inBytesPerSample = av_get_bytes_per_sample(pEncoderCtx->sample_fmt);
435  short int outBytesPerSample = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
436  if (sampleBuffer.length() >= samplesPerPacket * inBytesPerSample)
437  return;
438 
440 
441  while (sampleBuffer.length() < samplesPerPacket * inBytesPerSample) {
442  //read one frame
443  int err = av_read_frame(pFormatCtx, &packet);
444  if (err < 0)
445  break;
446 
447  // if the frame doesn't belong to our audiostream, continue... is not supposed to happen,
448  // since .wav contain only one media stream
449  if (packet.stream_index != streamIndex)
450  continue;
451 
452  // packet length == 0 ? read next packet
453  if (packet.size == 0)
454  continue;
455 
456  AVPacket avpkt;
457  avpkt.data = nullptr;
458  avpkt.size = 0;
459  av_init_packet(&avpkt);
460  ASSERT(avpkt.data == nullptr && avpkt.size == 0);
461  avpkt.data = packet.data;
462  avpkt.size = packet.size;
463 
464  while (avpkt.size > 0) {
465 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
466  // decode audio and save the decoded samples in our buffer
467  AVFrame *frame = av_frame_alloc();
468  int gotFrame;
469  int decoded = avcodec_decode_audio4(pCodecCtx, frame, &gotFrame, &avpkt);
470  if (decoded < 0)
471  throw cRuntimeError("Error in avcodec_decode_audio4(), err=%d, gotFrame=%d", decoded, gotFrame);
472 
473  avpkt.data += decoded;
474  avpkt.size -= decoded;
475 
476  if (gotFrame) {
477  if (!pReSampleCtx) {
478  // copy frame to sampleBuffer
479  int dataSize = av_samples_get_buffer_size(nullptr, pCodecCtx->channels, frame->nb_samples, pCodecCtx->sample_fmt, 1);
480  memcpy(sampleBuffer.writePtr(), frame->data[0], dataSize);
481  sampleBuffer.notifyWrote(dataSize);
482  }
483  else {
484  uint8_t *tmpSamples = new uint8_t[Buffer::BUFSIZE];
485 
486  uint8_t **in_data = frame->extended_data;
487  int in_linesize = frame->linesize[0];
488  int in_nb_samples = frame->nb_samples;
489 
490  uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = {
491  nullptr
492  };
493  int maxOutSamples = sampleBuffer.availableSpace() / outBytesPerSample;
494  int out_linesize;
495  int ret;
496  ret = av_samples_fill_arrays(out_data, &out_linesize, tmpSamples,
497  1, maxOutSamples,
498  pEncoderCtx->sample_fmt, 0);
499  if (ret < 0)
500  throw cRuntimeError("failed out_data fill arrays");
501 
502  decoded = avresample_convert(pReSampleCtx, out_data, out_linesize, decoded,
503  in_data, in_linesize, in_nb_samples);
504  if (decoded <= 0 && avresample_get_delay(pReSampleCtx) == 0) {
505  throw cRuntimeError("audio_resample() returns error");
506  }
507  // if (avresample_get_delay(pReSampleCtx) > 0)
508  // throw cRuntimeError("%d delay samples not converted\n", avresample_get_delay(pReSampleCtx));
509  // if (avresample_available(pReSampleCtx) > 0)
510  // throw cRuntimeError("%d samples available for output\n", avresample_available(pReSampleCtx));
511  if (decoded > 0) {
512  memcpy(sampleBuffer.writePtr(), out_data[0], decoded * outBytesPerSample);
513  sampleBuffer.notifyWrote(decoded * outBytesPerSample);
514  }
515  delete[] tmpSamples;
516  }
517  }
518  av_frame_free(&frame);
519 #else // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
520  uint8_t *tmpSamples = new uint8_t[Buffer::BUFSIZE];
521 
522  int16_t *rbuf, *nbuf;
523  nbuf = (int16_t *)(sampleBuffer.writePtr());
524  rbuf = (pReSampleCtx) ? (int16_t *)tmpSamples : nbuf;
525 
526  int frame_size = (pReSampleCtx) ? Buffer::BUFSIZE : sampleBuffer.availableSpace();
527  memset(rbuf, 0, frame_size);
528  int decoded = avcodec_decode_audio3(pCodecCtx, rbuf, &frame_size, &avpkt);
529 
530  if (decoded < 0)
531  throw cRuntimeError("Error decoding frame, err=%d", decoded);
532 
533  avpkt.data += decoded;
534  avpkt.size -= decoded;
535 
536  if (frame_size == 0)
537  continue;
538 
539  decoded = frame_size / (inBytesPerSample * pCodecCtx->channels);
540  ASSERT(frame_size == decoded * inBytesPerSample * pCodecCtx->channels);
541 
542  if (pReSampleCtx)
543  decoded = audio_resample(pReSampleCtx, nbuf, rbuf, decoded);
544 
545  sampleBuffer.notifyWrote(decoded * inBytesPerSample);
546  delete[] tmpSamples;
547 #endif // if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
548  av_free_packet(&avpkt);
549  }
550  av_free_packet(&packet);
551  }
552 }
int availableSpace() const
Definition: VoIPStreamSender.h:94
void align()
Definition: VoIPStreamSender.cc:422
int streamIndex
Definition: VoIPStreamSender.h:135
int samplesPerPacket
Definition: VoIPStreamSender.h:137
Definition: VoIPStreamSender.h:78
AVCodecContext * pEncoderCtx
Definition: VoIPStreamSender.h:130
void notifyWrote(int length)
Definition: VoIPStreamSender.h:96
AVFormatContext * pFormatCtx
Definition: VoIPStreamSender.h:120
int length() const
Definition: VoIPStreamSender.h:90
AVPacket packet
Definition: VoIPStreamSender.h:138
char * writePtr()
Definition: VoIPStreamSender.h:93
Buffer sampleBuffer
Definition: VoIPStreamSender.h:139
AVAudioResampleContext * pReSampleCtx
Definition: VoIPStreamSender.h:125
AVCodecContext * pCodecCtx
Definition: VoIPStreamSender.h:121

Member Data Documentation

const char* inet::VoIPStreamSender::codec = nullptr
protected

Referenced by initialize(), and openSoundFile().

int inet::VoIPStreamSender::compressedBitRate = 0
protected
L3Address inet::VoIPStreamSender::destAddress
protected

Referenced by handleMessage(), and initialize().

int inet::VoIPStreamSender::destPort = -1
protected

Referenced by handleMessage(), and initialize().

int inet::VoIPStreamSender::localPort = -1
protected

Referenced by initialize().

AudioOutFile inet::VoIPStreamSender::outFile
protected
AVPacket inet::VoIPStreamSender::packet
protected
simtime_t inet::VoIPStreamSender::packetTimeLength
protected

Referenced by handleMessage(), and initialize().

AVCodec* inet::VoIPStreamSender::pCodec = nullptr
protected

Referenced by openSoundFile().

AVCodecContext* inet::VoIPStreamSender::pCodecCtx = nullptr
protected

Referenced by finish(), openSoundFile(), and readFrame().

AVCodec* inet::VoIPStreamSender::pCodecEncoder = nullptr
protected

Referenced by openSoundFile().

AVCodecContext* inet::VoIPStreamSender::pEncoderCtx = nullptr
protected
AVFormatContext* inet::VoIPStreamSender::pFormatCtx = nullptr
protected
uint32_t inet::VoIPStreamSender::pktID = 0
protected

Referenced by generatePacket(), and initialize().

AVAudioResampleContext* inet::VoIPStreamSender::pReSampleCtx = nullptr
protected
int inet::VoIPStreamSender::repeatCount = 0
protected

Referenced by handleMessage(), and initialize().

Buffer inet::VoIPStreamSender::sampleBuffer
protected
int inet::VoIPStreamSender::sampleRate = 0
protected
int inet::VoIPStreamSender::samplesPerPacket = 0
protected
simsignal_t inet::VoIPStreamSender::sentPkSignal = registerSignal("sentPk")
staticprotected

Referenced by handleMessage().

UDPSocket inet::VoIPStreamSender::socket
protected

Referenced by handleMessage(), and initialize().

const char* inet::VoIPStreamSender::soundFile = nullptr
protected

Referenced by initialize().

int inet::VoIPStreamSender::streamIndex = -1
protected
cMessage* inet::VoIPStreamSender::timer = nullptr
protected
const char* inet::VoIPStreamSender::traceFileName = nullptr
protected

Referenced by initialize(), and openSoundFile().

int inet::VoIPStreamSender::voipHeaderSize = 0
protected

Referenced by generatePacket(), and initialize().

int inet::VoIPStreamSender::voipSilencePacketSize = 0
protected

Referenced by generatePacket(), and initialize().

int inet::VoIPStreamSender::voipSilenceThreshold = 0
protected

Referenced by checkSilence(), and initialize().


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