You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.9 KiB
207 lines
5.9 KiB
#import "OpusBridge.h"
|
|
#import "opus.h"
|
|
|
|
// 编码器结构体
|
|
typedef struct {
|
|
OpusEncoder *encoder;
|
|
int channels;
|
|
int sampleRate;
|
|
int frameSize;
|
|
} OpusEncoderWrapper;
|
|
|
|
// 解码器结构体
|
|
typedef struct {
|
|
OpusDecoder *decoder;
|
|
int channels;
|
|
int sampleRate;
|
|
} OpusDecoderWrapper;
|
|
|
|
@implementation OpusBridge {
|
|
OpusEncoderWrapper *_encoderWrapper;
|
|
OpusDecoderWrapper *_decoderWrapper;
|
|
}
|
|
|
|
#pragma mark - 初始化和销毁
|
|
|
|
- (instancetype)init {
|
|
self = [super init];
|
|
if (self) {
|
|
_encoderWrapper = NULL;
|
|
_decoderWrapper = NULL;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[self disposeEncoder];
|
|
[self disposeDecoder];
|
|
}
|
|
|
|
#pragma mark - 编码器方法
|
|
|
|
- (BOOL)createEncoderWithSampleRate:(int)sampleRate
|
|
channels:(int)channels
|
|
application:(int)application
|
|
complexity:(int)complexity
|
|
frameSize:(int)frameSize {
|
|
// 先释放已有资源
|
|
[self disposeEncoder];
|
|
|
|
int error = OPUS_OK;
|
|
OpusEncoder *encoder = opus_encoder_create(sampleRate, channels, application, &error);
|
|
|
|
if (error != OPUS_OK || encoder == NULL) {
|
|
NSLog(@"[OpusBridge] Failed to create encoder: %s", opus_strerror(error));
|
|
return NO;
|
|
}
|
|
|
|
// 设置编码器参数
|
|
opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(complexity));
|
|
|
|
// 创建封装结构
|
|
_encoderWrapper = malloc(sizeof(OpusEncoderWrapper));
|
|
_encoderWrapper->encoder = encoder;
|
|
_encoderWrapper->channels = channels;
|
|
_encoderWrapper->sampleRate = sampleRate;
|
|
_encoderWrapper->frameSize = frameSize;
|
|
|
|
NSLog(@"[OpusBridge] Encoder created: sampleRate=%d, channels=%d", sampleRate, channels);
|
|
return YES;
|
|
}
|
|
|
|
- (NSData *)encodePCMData:(NSData *)pcmData {
|
|
if (_encoderWrapper == NULL || _encoderWrapper->encoder == NULL) {
|
|
NSLog(@"[OpusBridge] Encoder not initialized");
|
|
return nil;
|
|
}
|
|
|
|
// 检查PCM数据大小是否匹配
|
|
int frameSize = _encoderWrapper->frameSize;
|
|
int channels = _encoderWrapper->channels;
|
|
|
|
// PCM数据大小 = 帧大小 * 声道数 * 每样本字节数(2字节)
|
|
int frameBytes = frameSize * channels * 2;
|
|
|
|
if (pcmData.length < frameBytes) {
|
|
NSLog(@"[OpusBridge] PCM data too small: %lu bytes (need %d bytes)",
|
|
(unsigned long)pcmData.length, frameBytes);
|
|
return nil;
|
|
}
|
|
|
|
// 创建输出缓冲区 - 通常编码后的数据会小于PCM,可以用更小的缓冲区
|
|
// 但这里保守起见,使用相同大小的缓冲区
|
|
const int maxEncodedSize = (int)pcmData.length;
|
|
unsigned char *encodedData = malloc(maxEncodedSize);
|
|
|
|
// 编码
|
|
int encodedBytes = opus_encode(
|
|
_encoderWrapper->encoder,
|
|
(const opus_int16 *)[pcmData bytes],
|
|
frameSize,
|
|
encodedData,
|
|
maxEncodedSize
|
|
);
|
|
|
|
if (encodedBytes <= 0) {
|
|
NSLog(@"[OpusBridge] Encoding failed: %s", opus_strerror(encodedBytes));
|
|
free(encodedData);
|
|
return nil;
|
|
}
|
|
|
|
// 封装为NSData并返回
|
|
NSData *result = [NSData dataWithBytes:encodedData length:encodedBytes];
|
|
free(encodedData);
|
|
|
|
NSLog(@"[OpusBridge] Encoded %d bytes", encodedBytes);
|
|
return result;
|
|
}
|
|
|
|
- (void)disposeEncoder {
|
|
if (_encoderWrapper) {
|
|
if (_encoderWrapper->encoder) {
|
|
opus_encoder_destroy(_encoderWrapper->encoder);
|
|
_encoderWrapper->encoder = NULL;
|
|
}
|
|
free(_encoderWrapper);
|
|
_encoderWrapper = NULL;
|
|
NSLog(@"[OpusBridge] Encoder disposed");
|
|
}
|
|
}
|
|
|
|
#pragma mark - 解码器方法
|
|
|
|
- (BOOL)createDecoderWithSampleRate:(int)sampleRate channels:(int)channels {
|
|
// 先释放已有资源
|
|
[self disposeDecoder];
|
|
|
|
int error = OPUS_OK;
|
|
OpusDecoder *decoder = opus_decoder_create(sampleRate, channels, &error);
|
|
|
|
if (error != OPUS_OK || decoder == NULL) {
|
|
NSLog(@"[OpusBridge] Failed to create decoder: %s", opus_strerror(error));
|
|
return NO;
|
|
}
|
|
|
|
// 创建封装结构
|
|
_decoderWrapper = malloc(sizeof(OpusDecoderWrapper));
|
|
_decoderWrapper->decoder = decoder;
|
|
_decoderWrapper->channels = channels;
|
|
_decoderWrapper->sampleRate = sampleRate;
|
|
|
|
NSLog(@"[OpusBridge] Decoder created: sampleRate=%d, channels=%d", sampleRate, channels);
|
|
return YES;
|
|
}
|
|
|
|
- (NSData *)decodeOpusData:(NSData *)opusData frameSize:(int)frameSize {
|
|
if (_decoderWrapper == NULL || _decoderWrapper->decoder == NULL) {
|
|
NSLog(@"[OpusBridge] Decoder not initialized");
|
|
return nil;
|
|
}
|
|
|
|
// 准备输出缓冲区,frameSize * channels 个short类型
|
|
int outputSizeInSamples = frameSize * _decoderWrapper->channels;
|
|
int outputSizeInBytes = outputSizeInSamples * sizeof(opus_int16);
|
|
|
|
opus_int16 *outputBuffer = malloc(outputSizeInBytes);
|
|
|
|
// 解码
|
|
int samplesPerChannel = opus_decode(
|
|
_decoderWrapper->decoder,
|
|
[opusData bytes],
|
|
(int)[opusData length],
|
|
outputBuffer,
|
|
frameSize,
|
|
0 // 不使用FEC
|
|
);
|
|
|
|
if (samplesPerChannel <= 0) {
|
|
NSLog(@"[OpusBridge] Decoding failed: %s", opus_strerror(samplesPerChannel));
|
|
free(outputBuffer);
|
|
return nil;
|
|
}
|
|
|
|
// 实际输出大小
|
|
int actualSamples = samplesPerChannel * _decoderWrapper->channels;
|
|
int actualBytes = actualSamples * sizeof(opus_int16);
|
|
|
|
// 封装为NSData并返回
|
|
NSData *result = [NSData dataWithBytes:outputBuffer length:actualBytes];
|
|
free(outputBuffer);
|
|
|
|
NSLog(@"[OpusBridge] Decoded %d samples per channel", samplesPerChannel);
|
|
return result;
|
|
}
|
|
|
|
- (void)disposeDecoder {
|
|
if (_decoderWrapper) {
|
|
if (_decoderWrapper->decoder) {
|
|
opus_decoder_destroy(_decoderWrapper->decoder);
|
|
_decoderWrapper->decoder = NULL;
|
|
}
|
|
free(_decoderWrapper);
|
|
_decoderWrapper = NULL;
|
|
NSLog(@"[OpusBridge] Decoder disposed");
|
|
}
|
|
}
|
|
|
|
@end
|