169 lines
5.7 KiB
Objective-C
169 lines
5.7 KiB
Objective-C
#import "Environment.h"
|
|
#import "Constraints.h"
|
|
#import "SpeexCodec.h"
|
|
|
|
@implementation SpeexCodec
|
|
|
|
#define MAX_FRAMES 512
|
|
#define DECODED_SAMPLE_SIZE_IN_BYTES 2
|
|
#define FRAME_SIZE_IN_SAMPLES 160
|
|
#define NUMBER_OF_CHANNELS 1
|
|
#define PERPETUAL_ENHANCER_PARAMETER 1
|
|
#define VARIABLE_BIT_RATE_PARAMETER 0
|
|
#define QUALITY_PARAMETER 3
|
|
#define COMPLEXITY_PARAMETER 1
|
|
|
|
+(SpeexCodec*) speexCodec {
|
|
SpeexCodec* c = [SpeexCodec new];
|
|
c->logging = [[Environment logging] getConditionLoggerForSender:self];
|
|
[c openSpeex];
|
|
return c;
|
|
}
|
|
-(void) dealloc {
|
|
[self closeSpeex];
|
|
}
|
|
|
|
+(NSUInteger)frameSizeInSamples {
|
|
return FRAME_SIZE_IN_SAMPLES;
|
|
}
|
|
|
|
-(NSUInteger)encodedFrameSizeInBytes {
|
|
requireState(cachedEncodedLength != 0);
|
|
return cachedEncodedLength;
|
|
}
|
|
-(NSUInteger)decodedFrameSizeInBytes {
|
|
return FRAME_SIZE_IN_SAMPLES*DECODED_SAMPLE_SIZE_IN_BYTES;
|
|
}
|
|
|
|
-(void) determineDecodedLength {
|
|
NSData* encoded = [self encode:[NSMutableData dataWithLength:[self decodedFrameSizeInBytes]]];
|
|
cachedEncodedLength = encoded.length;
|
|
}
|
|
|
|
-(NSData*)encode:(NSData*)rawData {
|
|
require(rawData != nil);
|
|
require(rawData.length == FRAME_SIZE_IN_SAMPLES*DECODED_SAMPLE_SIZE_IN_BYTES);
|
|
speex_bits_reset(&encodingBits);
|
|
speex_encode_int(encodingState, (spx_int16_t*)[rawData bytes], &encodingBits);
|
|
|
|
NSMutableData* outputBuffer = [NSMutableData dataWithLength:encodingBufferSizeInBytes];
|
|
int outputSizeInBytes = speex_bits_write(&encodingBits, [outputBuffer mutableBytes], (int)encodingBufferSizeInBytes);
|
|
checkOperation(outputSizeInBytes > 0);
|
|
[outputBuffer setLength:(NSUInteger)outputSizeInBytes];
|
|
|
|
return outputBuffer;
|
|
}
|
|
|
|
-(NSData*)decode:(NSData*)potentiallyMissingEncodedData {
|
|
NSUInteger encodedDataLength = potentiallyMissingEncodedData.length;
|
|
if (potentiallyMissingEncodedData == nil) {
|
|
encodedDataLength = [self decodedFrameSizeInBytes]; // size for infering audio data
|
|
}
|
|
if(encodedDataLength == 0) return nil;
|
|
|
|
SpeexBits *dbits = [self getSpeexBitsFromData:potentiallyMissingEncodedData andDataLength:(int)encodedDataLength];
|
|
|
|
int decodedLength = [self decodeSpeexBits:dbits withLength:(int)encodedDataLength];
|
|
|
|
return [NSData dataWithBytes:decodingBuffer length:(NSUInteger)decodedLength*sizeof(spx_int16_t)];
|
|
}
|
|
|
|
-(NSUInteger) encodedDataLengthFromData:(NSData*)potentiallyMissingEncodedData{
|
|
if (potentiallyMissingEncodedData != nil) {
|
|
return potentiallyMissingEncodedData.length;
|
|
}
|
|
return [self decodedFrameSizeInBytes];
|
|
}
|
|
|
|
- (SpeexBits *)getSpeexBitsFromData:(NSData *)encodedData andDataLength:(int)encodedDataLength {
|
|
SpeexBits *dbits=NULL;
|
|
char* encodingStream;
|
|
if([encodedData bytes] != NULL){
|
|
encodingStream = (char*)[encodedData bytes];
|
|
speex_bits_read_from(&decodingBits, encodingStream, encodedDataLength);
|
|
dbits = &decodingBits;
|
|
}
|
|
return dbits;
|
|
}
|
|
|
|
- (int)decodeSpeexBits:(SpeexBits *)dbits withLength:(int)encodedDataLength {
|
|
int decodingBufferIndex = 0;
|
|
int decodingBufferLength = (int)[self decodedFrameSizeInBytes];
|
|
int count = 0;
|
|
while(0 == speex_decode_int(decodingState, dbits, decodingBuffer + decodingBufferIndex)){
|
|
count++;
|
|
decodingBufferIndex += decodingFrameSize;
|
|
if(decodingBufferIndex + decodingFrameSize > decodingBufferLength){
|
|
[logging logWarning:[NSString stringWithFormat:@"out of space in the decArr buffer, idx=%d, frameSize=%d, length=%d", decodingBufferIndex,decodingFrameSize,decodingBufferLength]];
|
|
break;
|
|
}
|
|
if(decodingBufferIndex + decodingFrameSize > decodingFrameSize * MAX_FRAMES){
|
|
[logging logWarning:[NSString stringWithFormat:@"out of space in the dec_buffer buffer, idx=%d", decodingBufferIndex]];
|
|
break;
|
|
}
|
|
if(dbits == NULL){
|
|
break;
|
|
}
|
|
}
|
|
return decodingBufferIndex;
|
|
}
|
|
|
|
-(void) openSpeex {
|
|
[self initiateEncoderAndDecoder];
|
|
[self applySpeexSettings];
|
|
[self initiateSpeexBuffers];
|
|
[self determineDecodedLength];
|
|
}
|
|
|
|
- (void)initiateEncoderAndDecoder {
|
|
|
|
encodingState = speex_encoder_init(&speex_nb_mode);
|
|
decodingState = speex_decoder_init(&speex_nb_mode);
|
|
|
|
checkOperationDescribe(encodingState != NULL, @"speex encoder init failed");
|
|
checkOperationDescribe(decodingState != NULL, @"speex decoder init failed");
|
|
}
|
|
|
|
-(void)applySpeexSettings{
|
|
spx_int32_t tmp;
|
|
tmp=PERPETUAL_ENHANCER_PARAMETER;
|
|
speex_decoder_ctl(decodingState, SPEEX_SET_ENH, &tmp);
|
|
tmp=VARIABLE_BIT_RATE_PARAMETER;
|
|
speex_encoder_ctl(encodingState, SPEEX_SET_VBR, &tmp);
|
|
tmp=QUALITY_PARAMETER;
|
|
speex_encoder_ctl(encodingState, SPEEX_SET_QUALITY, &tmp);
|
|
tmp=COMPLEXITY_PARAMETER;
|
|
speex_encoder_ctl(encodingState, SPEEX_SET_COMPLEXITY, &tmp);
|
|
|
|
speex_encoder_ctl(encodingState, SPEEX_GET_FRAME_SIZE, &encodingFrameSize);
|
|
speex_decoder_ctl(decodingState, SPEEX_GET_FRAME_SIZE, &decodingFrameSize);
|
|
|
|
int sampleRate = (int)SAMPLE_RATE;
|
|
speex_encoder_ctl(encodingState, SPEEX_SET_SAMPLING_RATE, &sampleRate);
|
|
speex_decoder_ctl(decodingState, SPEEX_SET_SAMPLING_RATE, &sampleRate);
|
|
}
|
|
|
|
- (void)initiateSpeexBuffers {
|
|
speex_bits_init(&encodingBits);
|
|
speex_bits_init(&decodingBits);
|
|
|
|
encodingBufferSizeInBytes = (NSUInteger)encodingFrameSize * MAX_FRAMES;
|
|
decodingBuffer = (spx_int16_t *) malloc( sizeof( spx_int16_t ) * (NSUInteger)decodingFrameSize*MAX_FRAMES );
|
|
|
|
checkOperationDescribe(decodingBuffer != NULL, @"buffer allocation failed");
|
|
}
|
|
|
|
-(void) closeSpeex {
|
|
terminated = true;
|
|
|
|
speex_encoder_destroy( encodingState );
|
|
speex_decoder_destroy( decodingState );
|
|
|
|
speex_bits_destroy( &encodingBits );
|
|
speex_bits_destroy( &decodingBits );
|
|
|
|
free(decodingBuffer);
|
|
}
|
|
|
|
@end
|