Add example code for sending Opus

This commit is contained in:
Aaro Altonen 2019-05-15 09:46:48 +03:00
parent eccc414bcf
commit d56b70beaf
3 changed files with 119 additions and 0 deletions

20
examples/README.md Normal file
View File

@ -0,0 +1,20 @@
# Opus sender
Extract signed 16-bit little endian PCM from input.mp4 and start ffplay
```
ffmpeg -i input.mp4 -f s16le -acodec pcm_s16le -ac 2 -ar 48000 output.raw
ffplay -acodec libopus -protocol_whitelist "file,rtp,udp" sdp/opus.sdp
```
Compile the RTP Library and opus_sender.cc and start the sender
```
cd ..
make all -j8
cd examples
g++ -o main opus_sender.cc -lrtp -L .. -lpthread -lopus
./main
```

90
examples/opus_sender.cc Normal file
View File

@ -0,0 +1,90 @@
#include "../src/debug.hh"
#include "../src/lib.hh"
#include "../src/util.hh"
#include "../src/rtp_opus.hh"
#include <iostream>
#include <thread>
#include <cstdlib>
#include <cstring>
#include <kvazaar.h>
#include <opus/opus.h>
#include <stdint.h>
#define OPUS_BITRATE 64000
// 20 ms for 48 000Hz
#define FRAME_SIZE 960
bool done = false;
void audioSender(RTPContext *ctx, int samplerate, int channels)
{
/* input has to PCM audio in signed 16-bit little endian format */
FILE *inFile = fopen("output.raw", "r");
int error = 0;
OpusEncoder* opusEnc = opus_encoder_create(samplerate, channels, OPUS_APPLICATION_VOIP, &error);
opus_encoder_ctl(opusEnc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
opus_encoder_ctl(opusEnc, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
if (!opusEnc) {
std::cerr << "opus_encoder_create failed: " << error << std::endl;
return;
}
RTPOpus::OpusConfig *config = new RTPOpus::OpusConfig;
config->channels = channels;
config->samplerate = samplerate;
config->configurationNumber = 15; // Hydrib | FB | 20 ms
RTPWriter *writer = ctx->createWriter("127.0.0.1", 8890, RTP_FORMAT_OPUS);
writer->start();
writer->setConfig(config);
uint32_t dataLenPerFrame = FRAME_SIZE * channels * sizeof(uint16_t);
uint8_t *inFrame = (uint8_t *)malloc(dataLenPerFrame);
uint32_t outputSize = 25000;
uint8_t *outData = (uint8_t *)malloc(outputSize);
int frame = 0;
opus_int16 in[FRAME_SIZE * channels];
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point end;
while (!done) {
if (!fread(inFrame, dataLenPerFrame, 1, inFile)) {
done = true;
} else {
/* convert from little endian ordering */
for (int i = 0; i < channels * FRAME_SIZE; ++i) {
in[i] = inFrame[2 * i + 1] << 8 | inFrame[2 * i];
}
int32_t len = opus_encode(opusEnc, in, FRAME_SIZE, outData, outputSize);
// 20 ms per frame
if (writer->pushFrame(outData, len, RTP_FORMAT_OPUS, 960 * frame) < 0) {
std::cerr << "Failed to push Opus frame!" << std::endl;
}
frame++;
end = std::chrono::high_resolution_clock::now();
auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
double diff = 20.0 - (elapsed_time / (double)frame);
std::this_thread::sleep_for(std::chrono::milliseconds((int)diff));
}
}
opus_encoder_destroy(opusEnc);
return;
}
int main(void)
{
RTPContext rtp_ctx;
std::thread *t = new std::thread(audioSender, &rtp_ctx, 48000, 2);
t->join();
std::cerr << "here" << std::endl;
}

9
examples/sdp/opus.sdp Normal file
View File

@ -0,0 +1,9 @@
o=User 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
m=audio 8890 RTP/AVP 97
a=rtpmap:97 opus/48000/2
a=fmtp:97 stereo=1; useinbandfec=1; usedtx=0
a=ptime:20
a=maxptime:20