| // |
| // DCAdaptiveJitterBuffer.m |
| // NexusVideoPlayer |
| // |
| // Created by Frank Huang on 11/18/13. |
| // Copyright (c) 2013 Dropcam. All rights reserved. |
| // |
| |
| #import "DCAdaptiveJitterBuffer.h" |
| #import "NSCondition+UnlockAfter.h" |
| |
| #include "AdaptiveJitterBuffer.hpp" |
| |
| @implementation Packet |
| @end |
| |
| @interface DCAdaptiveJitterBuffer () |
| @property (nonatomic, assign) AdaptiveJitterBuffer *buffer; |
| @property (nonatomic, strong) NSCondition *packetCondition; |
| @end |
| |
| @implementation DCAdaptiveJitterBuffer |
| |
| - (id)initWithTimebase:(int)timebase isLive:(BOOL)isLive isWifi:(BOOL)isWifi { |
| if ((self = [super init])) { |
| _buffer = new AdaptiveJitterBuffer(timebase, isLive == YES, isWifi == YES); |
| |
| _packetCondition = [[NSCondition alloc] init]; |
| } |
| |
| return self; |
| } |
| |
| - (void)dealloc { |
| delete _buffer; |
| } |
| |
| - (void)setAutoAdjust:(BOOL)adjust { |
| [self.packetCondition unlockAfter:^{ |
| _buffer->setAutoAdjust(adjust); |
| }]; |
| } |
| |
| - (int64_t)targetDelay { |
| __block int64_t rval; |
| [self.packetCondition unlockAfter:^{ |
| rval = _buffer->getTargetDelay(); |
| }]; |
| return rval; |
| } |
| |
| - (void)setTargetDelay:(int64_t)delay { |
| [self.packetCondition unlockAfter:^{ |
| _buffer->setTargetDelay(delay); |
| }]; |
| } |
| |
| - (void)addBias:(int64_t)bias { |
| [self.packetCondition unlockAfter:^{ |
| _buffer->addBias(bias); |
| }]; |
| } |
| |
| - (int)numPackets { |
| __block int rval; |
| [self.packetCondition unlockAfter:^{ |
| rval = _buffer->getNumPackets(); |
| }]; |
| return rval; |
| } |
| |
| - (int64_t)bufferLength { |
| __block int64_t rval; |
| [self.packetCondition unlockAfter:^{ |
| rval = _buffer->getBufferLength(); |
| }]; |
| return rval; |
| } |
| |
| - (BOOL)fullyBuffered { |
| __block BOOL rval; |
| [self.packetCondition unlockAfter:^{ |
| rval = _buffer->getFullyBuffered(); |
| }]; |
| return rval; |
| } |
| |
| - (void)addPacket:(Packet*)packet { |
| [self.packetCondition unlockAfter:^{ |
| JBPacket in_pkt = { |
| .seq_num = packet.sequenceNumber, |
| .PTS = packet.PTS, |
| .span = 0, |
| // transfer ownership of packet to JB |
| .payload_data = (__bridge_retained void*)packet |
| }; |
| _buffer->addPacket(in_pkt); |
| |
| [self.packetCondition signal]; |
| }]; |
| } |
| |
| - (void)addSlaveTiming:(int64_t)PTS { |
| [self.packetCondition unlockAfter:^{ |
| _buffer->addSlaveTiming(PTS); |
| }]; |
| } |
| |
| - (int64_t)peekPTS { |
| __block int64_t rval; |
| [self.packetCondition unlockAfter:^{ |
| rval = _buffer->peekPTS(); |
| }]; |
| return rval; |
| } |
| |
| - (Packet*)nextPacket { |
| __block Packet *packet = nil; |
| [self.packetCondition unlockAfter:^{ |
| JBPacket out_pkt; |
| bool has_pkt = _buffer->nextPacket(out_pkt); |
| if (!has_pkt) { |
| return; |
| } |
| |
| // Take ownership of packet back from JB |
| packet = (__bridge_transfer Packet*)out_pkt.payload_data; |
| }]; |
| return packet; |
| } |
| |
| - (BOOL)waitForPacket { |
| __block BOOL rval = NO; |
| [self.packetCondition unlockAfter:^{ |
| NSThread *thread = [NSThread currentThread]; |
| while (![thread isCancelled]) { |
| [self.packetCondition wait]; |
| if (_buffer->getNumPackets() == 0) { |
| continue; |
| } |
| else { |
| rval = YES; |
| return; |
| } |
| } |
| }]; |
| return rval; |
| } |
| |
| - (void)cancelWaiters { |
| [self.packetCondition unlockAfter:^{ |
| [self.packetCondition broadcast]; |
| }]; |
| } |
| |
| - (float)playSpeedForPTS:(int64_t)PTS { |
| __block float rval; |
| [self.packetCondition unlockAfter:^{ |
| rval = _buffer->getPlaySpeedForPTS(PTS); |
| }]; |
| return rval; |
| } |
| |
| @end |