#include "WebRtcJitterBuffer.h" #include #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; pthread_mutex_lock(&lock); neteq = webrtc::NetEq::Create(config); pthread_mutex_unlock(&lock); 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; } pthread_create(&stats, NULL, &WebRtcJitterBuffer::collectStats, this); 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() { pthread_mutex_lock(&lock); running = 0; pthread_cond_signal(&condition); pthread_mutex_unlock(&lock); pthread_join(stats, NULL); } void WebRtcJitterBuffer::collectStats() { while (running) { webrtc::NetEqNetworkStatistics stats; pthread_mutex_lock(&lock); neteq->NetworkStatistics(&stats); pthread_mutex_unlock(&lock); __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); 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); } } void* WebRtcJitterBuffer::collectStats(void *context) { WebRtcJitterBuffer* jitterBuffer = static_cast(context); jitterBuffer->collectStats(); return 0; }