Some chunking/paging buffering data source work

This commit is contained in:
Thong Nguyen 2014-02-24 17:05:54 +00:00
parent 7540045361
commit d7d583c3ba
4 changed files with 143 additions and 73 deletions

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
A1682FA318B3903900F29FEC /* STKBufferingDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1682FA218B3903900F29FEC /* STKBufferingDataSource.m */; };
A168C6F118BB67DC003D170D /* STKBufferChunk.m in Sources */ = {isa = PBXBuildFile; fileRef = A168C6F018BB67DC003D170D /* STKBufferChunk.m */; };
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4996A189E744400E2A2E2 /* Cocoa.framework */; };
A1A49975189E744500E2A2E2 /* StreamingKitMac.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A49974189E744500E2A2E2 /* StreamingKitMac.m */; };
A1A4997B189E744500E2A2E2 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4D9188D57F60010896F /* XCTest.framework */; };
@ -86,6 +87,8 @@
/* Begin PBXFileReference section */
A1682FA118B3903900F29FEC /* STKBufferingDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKBufferingDataSource.h; sourceTree = "<group>"; };
A1682FA218B3903900F29FEC /* STKBufferingDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKBufferingDataSource.m; sourceTree = "<group>"; };
A168C6EF18BB67DC003D170D /* STKBufferChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKBufferChunk.h; sourceTree = "<group>"; };
A168C6F018BB67DC003D170D /* STKBufferChunk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKBufferChunk.m; sourceTree = "<group>"; };
A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStreamingKitMac.a; sourceTree = BUILT_PRODUCTS_DIR; };
A1A4996A189E744400E2A2E2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; };
A1A4996D189E744500E2A2E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@ -269,6 +272,8 @@
A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */,
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */,
A1E7C4F4188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m */,
A168C6EF18BB67DC003D170D /* STKBufferChunk.h */,
A168C6F018BB67DC003D170D /* STKBufferChunk.m */,
A1682FA118B3903900F29FEC /* STKBufferingDataSource.h */,
A1682FA218B3903900F29FEC /* STKBufferingDataSource.m */,
A1E7C4F5188D5E550010896F /* STKCoreFoundationDataSource.h */,
@ -509,6 +514,7 @@
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */,
A1682FA318B3903900F29FEC /* STKBufferingDataSource.m in Sources */,
A1E7C502188D5E550010896F /* STKDataSource.m in Sources */,
A168C6F118BB67DC003D170D /* STKBufferChunk.m in Sources */,
A1BF65D5189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m in Sources */,
A1E7C500188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m in Sources */,
);

View File

@ -0,0 +1,22 @@
//
// STKBufferChunk.h
// StreamingKit
//
// Created by Thong Nguyen on 24/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface STKBufferChunk : NSObject
{
@public
UInt32 key;
UInt32 size;
UInt32 position;
UInt8* buffer;
}
-(id) initWithBufferSize:(UInt32)sizeIn;
@end

View File

@ -0,0 +1,30 @@
//
// STKBufferChunk.m
// StreamingKit
//
// Created by Thong Nguyen on 24/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "STKBufferChunk.h"
@implementation STKBufferChunk
-(id) initWithBufferSize:(UInt32)sizeIn
{
if (self = [super init])
{
self->size = sizeIn;
self->buffer = calloc(sizeof(UInt8), sizeIn);
}
return self;
}
-(void) dealloc
{
free(self->buffer);
}
@end

View File

@ -33,17 +33,22 @@
**********************************************************************************/
#import "STKBufferingDataSource.h"
#import "STKBufferChunk.h"
#import <pthread.h>
#define STK_BUFFER_CHUNK_SIZE (128 * 1024)
@interface STKBufferingDataSource()
{
@private
NSRunLoop* runLoop;
int bufferStartIndex;
int bufferStartFileOffset;
int bufferBytesUsed;
int bufferBytesTotal;
SInt32 maxSize;
UInt32 chunkSize;
UInt32 chunkCount;
SInt64 position;
uint8_t* buffer;
pthread_mutex_t mutex;
pthread_cond_t condition;
STKBufferChunk* __strong * bufferChunks;
STKDataSource* dataSource;
}
@end
@ -63,7 +68,7 @@
if (self = [super init])
{
threadStartedLock = [[NSConditionLock alloc] initWithCondition:0];
}
}
return self;
}
@ -110,12 +115,21 @@ static STKBufferingDataSourceThread* thread;
{
if (self = [super init])
{
self->maxSize = maxSizeIn;
self->dataSource = dataSourceIn;
self->bufferBytesTotal = maxSizeIn;
self->chunkSize = STK_BUFFER_CHUNK_SIZE;
self->dataSource.delegate = self.delegate;
[self->dataSource registerForEvents:[thread runLoop]];
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&self->mutex, &attr);
pthread_cond_init(&self->condition, NULL);
}
return self;
@ -125,20 +139,40 @@ static STKBufferingDataSourceThread* thread;
{
self->dataSource.delegate = nil;
free(self->buffer);
for (int i = 0; i < self->chunkCount; i++)
{
self->bufferChunks[i] = nil;
}
free(self->bufferChunks);
pthread_mutex_destroy(&self->mutex);
pthread_cond_destroy(&self->condition);
}
-(void) createBuffer
{
if (self->buffer == nil)
if (self->bufferChunks == nil)
{
self->bufferBytesTotal = MIN((int)self.length, self->bufferBytesTotal);
self->bufferBytesTotal = MAX(self->bufferBytesTotal, 1024);
int length = (int)MIN(self.length == 0? 1024 * 1024 : self.length, self->maxSize);
self->buffer = malloc(self->bufferBytesTotal);
self->chunkCount = (int)((length / self->chunkSize) + 1);
self->bufferChunks = (__strong STKBufferChunk**)calloc(sizeof(STKBufferChunk*), self->chunkCount);
}
}
-(STKBufferChunk*) chunkForPosition:(SInt64)positionIn createIfNotExist:(BOOL)createIfNotExist
{
int chunkIndex = (int)(positionIn / chunkCount);
if (self->bufferChunks[chunkIndex] == nil && createIfNotExist)
{
self->bufferChunks[chunkIndex] = [[STKBufferChunk alloc] initWithBufferSize:STK_BUFFER_CHUNK_SIZE];
}
return self->bufferChunks[chunkIndex];
}
-(SInt64) length
{
return self->dataSource.length;
@ -146,33 +180,21 @@ static STKBufferingDataSourceThread* thread;
-(void) seekToOffset:(SInt64)offset
{
pthread_mutex_lock(&mutex);
[self seekToNextGap];
pthread_mutex_unlock(&mutex);
}
-(BOOL) hasBytesAvailable
{
return bufferBytesUsed > 0;
return NO;
}
-(int) readIntoBuffer:(UInt8*)bufferIn withSize:(int)size
{
SInt64 bytesAlreadyReadInBuffer = (position - bufferStartFileOffset);
SInt64 bytesAvailable = bufferBytesUsed - bytesAlreadyReadInBuffer;
if (bytesAvailable < 0)
{
return 0;
}
int start = (bufferStartIndex + bytesAlreadyReadInBuffer) % bufferBytesTotal;
int end = (start + bufferBytesUsed) % bufferBytesTotal;
int bytesToRead = MIN(end - start, size);
memcpy(self->buffer, bufferIn, bytesToRead);
self->bufferBytesUsed -= bytesToRead;
self->bufferStartFileOffset += bytesToRead;
return bytesToRead;
return 0;
}
-(BOOL) registerForEvents:(NSRunLoop*)runLoopIn
@ -197,60 +219,50 @@ static STKBufferingDataSourceThread* thread;
[dataSource close];
}
-(void) seekToNextGap
{
}
-(void) dataSourceDataAvailable:(STKDataSource*)dataSourceIn
{
if (self->buffer == nil)
if (![dataSourceIn hasBytesAvailable])
{
return;
}
pthread_mutex_lock(&mutex);
if (self->bufferChunks == nil)
{
[self createBuffer];
}
UInt32 start = (bufferStartIndex + bufferBytesUsed) % bufferBytesTotal;
UInt32 end = (position - bufferStartFileOffset + bufferStartIndex) % bufferBytesTotal;
if (start >= end)
SInt64 sourcePosition = dataSourceIn.position;
STKBufferChunk* chunk = [self chunkForPosition:sourcePosition createIfNotExist:YES];
if (chunk->position >= chunk->size)
{
int bytesRead;
int bufferStartFileOffsetDelta = 0;
int bytesToRead = bufferBytesTotal - start;
[self seekToNextGap];
if (bytesToRead > 0)
{
bytesRead = [dataSource readIntoBuffer:self->buffer + bufferStartIndex withSize:bytesToRead];
}
else
{
bytesToRead = end;
bytesRead = [dataSource readIntoBuffer:self->buffer withSize:bytesToRead];
bufferStartFileOffsetDelta = bytesRead - bufferStartIndex;
}
if (bytesRead < 0)
{
return;
}
bufferBytesUsed += bytesRead;
bufferStartFileOffset += bufferStartFileOffsetDelta;
return;
}
else
int offset = dataSourceIn.position % self->chunkSize;
if (offset > chunk->position)
{
int bytesToRead = end - start;
[self seekToNextGap];
int bytesRead = [dataSource readIntoBuffer:self->buffer + start withSize:bytesToRead];
if (bytesToRead < 0)
{
return;
}
int bufferStartFileOffsetDelta = (bytesRead + start) - bufferStartIndex;
bufferStartIndex += bytesRead;
bufferBytesUsed += bytesRead;
bufferStartFileOffset += bufferStartFileOffsetDelta;
return;
}
int bytesToRead = self->chunkSize - offset;
int bytesRead = [dataSourceIn readIntoBuffer:(chunk->buffer + offset) withSize:bytesToRead];
chunk->position = offset + bytesRead;
pthread_mutex_unlock(&mutex);
}
-(void) dataSourceErrorOccured:(STKDataSource*)dataSourceIn