2015-09-09 20:54:29 +00:00
|
|
|
#include "WebRtcJitterBuffer.h"
|
2015-11-05 01:30:09 +00:00
|
|
|
#include <time.h>
|
2015-09-09 20:54:29 +00:00
|
|
|
|
|
|
|
#define TAG "WebRtcJitterBuffer"
|
|
|
|
|
|
|
|
static volatile int running = 0;
|
|
|
|
|
|
|
|
WebRtcJitterBuffer::WebRtcJitterBuffer(AudioCodec &codec) :
|
|
|
|
neteq(NULL), webRtcCodec(codec)
|
|
|
|
{
|
|
|
|
running = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WebRtcJitterBuffer::init() {
|
|
|
|
webrtc::NetEq::Config config;
|
|
|
|
config.sample_rate_hz = 8000;
|
|
|
|
|
2015-11-05 01:30:09 +00:00
|
|
|
pthread_mutex_lock(&lock);
|
2015-09-09 20:54:29 +00:00
|
|
|
neteq = webrtc::NetEq::Create(config);
|
2015-11-05 01:30:09 +00:00
|
|
|
pthread_mutex_unlock(&lock);
|
2015-09-09 20:54:29 +00:00
|
|
|
|
|
|
|
if (neteq == NULL) {
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, TAG, "Failed to construct NetEq!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (neteq->RegisterExternalDecoder(&webRtcCodec, webrtc::kDecoderPCMu, 0) != 0) {
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, TAG, "Failed to register external codec!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-11-05 01:30:09 +00:00
|
|
|
pthread_create(&stats, NULL, &WebRtcJitterBuffer::collectStats, this);
|
2015-09-09 20:54:29 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
WebRtcJitterBuffer::~WebRtcJitterBuffer() {
|
|
|
|
if (neteq != NULL) {
|
|
|
|
delete neteq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebRtcJitterBuffer::addAudio(RtpPacket *packet, uint32_t tick) {
|
|
|
|
webrtc::WebRtcRTPHeader header;
|
|
|
|
header.header.payloadType = packet->getPayloadType();
|
|
|
|
header.header.sequenceNumber = packet->getSequenceNumber();
|
|
|
|
header.header.timestamp = packet->getTimestamp();
|
|
|
|
header.header.ssrc = packet->getSsrc();
|
|
|
|
|
|
|
|
uint8_t *payload = (uint8_t*)malloc(packet->getPayloadLen());
|
|
|
|
memcpy(payload, packet->getPayload(), packet->getPayloadLen());
|
|
|
|
|
|
|
|
if (neteq->InsertPacket(header, payload, packet->getPayloadLen(), tick) != 0) {
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, TAG, "neteq->InsertPacket() failed!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WebRtcJitterBuffer::getAudio(short *rawData, int maxRawData) {
|
|
|
|
int samplesPerChannel = 0;
|
|
|
|
int numChannels = 0;
|
|
|
|
|
|
|
|
if (neteq->GetAudio(maxRawData, rawData, &samplesPerChannel, &numChannels, NULL) != 0) {
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, TAG, "neteq->GetAudio() failed!");
|
|
|
|
}
|
|
|
|
|
|
|
|
return samplesPerChannel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebRtcJitterBuffer::stop() {
|
2015-11-05 01:30:09 +00:00
|
|
|
pthread_mutex_lock(&lock);
|
2015-09-09 20:54:29 +00:00
|
|
|
running = 0;
|
2015-11-05 01:30:09 +00:00
|
|
|
pthread_cond_signal(&condition);
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
|
|
|
|
pthread_join(stats, NULL);
|
2015-09-09 20:54:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WebRtcJitterBuffer::collectStats() {
|
|
|
|
while (running) {
|
|
|
|
webrtc::NetEqNetworkStatistics stats;
|
2015-11-05 01:30:09 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&lock);
|
2015-09-09 20:54:29 +00:00
|
|
|
neteq->NetworkStatistics(&stats);
|
2015-11-05 01:30:09 +00:00
|
|
|
pthread_mutex_unlock(&lock);
|
2015-09-09 20:54:29 +00:00
|
|
|
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, "WebRtcJitterBuffer",
|
|
|
|
"Jitter Stats:\n{\n" \
|
|
|
|
" current_buffer_size_ms: %d,\n" \
|
|
|
|
" preferred_buffer_size_ms: %d\n" \
|
|
|
|
" jitter_peaks_found: %d\n" \
|
|
|
|
" packet_loss_rate: %d\n" \
|
|
|
|
" packet_discard_rate: %d\n" \
|
|
|
|
" expand_rate: %d\n" \
|
|
|
|
" preemptive_rate: %d\n" \
|
|
|
|
" accelerate_rate: %d\n" \
|
|
|
|
" clockdrift_ppm: %d\n" \
|
|
|
|
" added_zero_samples: %d\n" \
|
|
|
|
"}",
|
|
|
|
stats.current_buffer_size_ms,
|
|
|
|
stats.preferred_buffer_size_ms,
|
|
|
|
stats.jitter_peaks_found,
|
|
|
|
stats.packet_loss_rate,
|
|
|
|
stats.packet_discard_rate,
|
|
|
|
stats.expand_rate,
|
|
|
|
stats.preemptive_rate,
|
|
|
|
stats.accelerate_rate,
|
|
|
|
stats.clockdrift_ppm,
|
|
|
|
stats.added_zero_samples);
|
2015-11-05 01:30:09 +00:00
|
|
|
|
|
|
|
struct timespec timeToWait;
|
|
|
|
struct timeval now;
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
|
|
|
|
timeToWait.tv_sec = now.tv_sec;
|
|
|
|
timeToWait.tv_nsec = now.tv_usec * 1000;
|
|
|
|
timeToWait.tv_sec += 30;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&lock);
|
|
|
|
|
|
|
|
if (running) {
|
|
|
|
pthread_cond_timedwait(&condition, &lock, &timeToWait);
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&lock);
|
2015-09-09 20:54:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void* WebRtcJitterBuffer::collectStats(void *context) {
|
|
|
|
WebRtcJitterBuffer* jitterBuffer = static_cast<WebRtcJitterBuffer*>(context);
|
|
|
|
jitterBuffer->collectStats();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|