我正在尝试使用OPUS库解码音频数据。我能够解码数据,但语音不清楚。实际上,我是从语音翻译设备获取编码的音频数据,只是我需要解码音频数据,而从设备获取的数据长度是160。现在我需要转换为Bytearray,然后需要分成40个length.4部分。然后每个40bytes然后转换为shortArray,然后我需要解码..然后需要发送到websocket。您能帮助我如何在下面编写此逻辑的是在android中正确解码的android逻辑吗。]
- (void)viewDidLoad{
[super viewDidLoad];
_decoder = opus_decoder_create(16000, 1, &error);
}
-(void)onGetData:(NSData *)getData{
if(self.isSocketOpen){
NSData *opus = [OpusConverter.shared decodeOpusData:getData];
[self.fileHandler writeData:opus];
self.filePath = [self getVoiceData];
NSInteger len = [opus length];
NSLog(@"123Data length===%ld",(long)len);
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [opus bytes], len);
NSData * audioData = [NSData dataWithBytes:byteData length:len ];
///////////SENDING START FRAME
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@{@"type": @"START",
@"data": @{
@"appid": @13432495,
@"appkey": @"sdfgdfgsdfgsdfsg",
@"dev_pid": @15372,
@"lm_id": @1235,
@"cuid": @"cuid-1",
@"format": @"pcm",
@"sample": @16000
}
} options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[[WebSocketManager shared] sendDataToServer:jsonString];
////////SENDING AUDIO FRAME
[[WebSocketManager shared] sendDataToServer:audioData];
/////////SENDING FINISH FRAME
NSData *finishjsonData = [NSJSONSerialization dataWithJSONObject:@{@"type": @"FINISH"
} options:NSJSONWritingPrettyPrinted error:&error];
NSString *finishJsonString = [[NSString alloc] initWithData:finishjsonData encoding:NSUTF8StringEncoding];
[[WebSocketManager shared] sendDataToServer:finishJsonString];
}
-(NSData*)decodeOpusData:(NSData*)data
{
int audioLength = (int)[data length];
Byte *byteData = (Byte*)malloc(sizeof(Byte)*audioLength);
memcpy(byteData, [data bytes], audioLength);
short decodedBuffer[960];
int nDecodedByte = sizeof(short) * [self decode:byteData length:audioLength output:decodedBuffer];
NSData* PCMData = [NSData dataWithBytes:(Byte *)decodedBuffer length:nDecodedByte];
return PCMData;
}
-(void)playbutton{
self.filePath = [self getVoiceData];
NSURL *url = [NSURL fileURLWithPath:self.filePath];
NSData *wavDATA = [NSData dataWithContentsOfURL:url];
[AudioManager.shared playAudioData:wavDATA completionHandler:^(BOOL successfully) {
NSLog(@"Playing");
}];
}
以下逻辑在android中工作正常。有人可以帮助您解决此问题吗下面是Android代码。
BUFFER_LENGTH = 40
public fun opusDataDecoder(data:ByteArray){
val tntOpusUtils = OpusUtils.getInstant()
val decoderHandler = tntOpusUtils.createDecoder(16000, 1)
for (i in 0..3){
val byteArray = ByteArray(BUFFER_LENGTH)
System.arraycopy(data,i * BUFFER_LENGTH,byteArray,0, BUFFER_LENGTH)
val decodeBufferArray = ShortArray(byteArray.size * 8)
val size = tntOpusUtils.decode(decoderHandler, byteArray, decodeBufferArray)
if (size > 0) {
val decodeArray = ShortArray(size)
System.arraycopy(decodeBufferArray, 0, decodeArray, 0, size)
opusDecode(decodeArray)//输出数据到接口
} else {
Log.e(TAG, "opusDecode error : $size")
}
}
}
最后,我得到了使用OPUS库解码音频数据并将PCM转换为WAV然后播放的解决方案。
下面是更新的工作代码。
@interface OpusAudioDecode : NSObject
+ (instancetype)shared;
-(void)opusInit;
-(NSMutableData*)decodeOpusData:(NSData*)data;
@end
#import "OpusAudioDecode.h"
#import "opus.h"
#define SAMPLE_RATE 16000
#define CHANNELS 1
#define WB_FRAME_SIZE 320
@implementation OpusAudioDecode
{
OpusDecoder *decoder;
int opus_num;
int pcm_num;
}
+ (instancetype)shared {
static id _instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone: NULL] init];
});
return _instance;
}
+ (id)allocWithZone:(struct _NSZone *)zone {
return [self shared];
}
- (id)copyWithZone:(struct _NSZone *)zone {
return [[self class] shared];
}
- (instancetype)init {
self = [super init];
if (self) {
[self opusInit];
}
return self;
}
-(void)opusInit
{
int error;
decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &error);
opus_decoder_ctl(decoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
}
////int decode(unsigned char* in_data, int len, short* out_data, int* out_len) {
-(int)decode:(unsigned char *)encodedBytes length:(int)lengthOfBytes output:(short*)decoded {
int frame_size = WB_FRAME_SIZE;
unsigned char cbits[frame_size + 1];
memcpy(cbits, encodedBytes, lengthOfBytes);
pcm_num = opus_decode(decoder,cbits,lengthOfBytes,decoded,frame_size,0);
return frame_size;
}
-(NSMutableData*)decodeOpusData:(NSData*)data
{
NSMutableData *audioData = [[NSMutableData alloc] init];
for (NSUInteger i = 0; i < 4; i ++)
{
int bufferLength = 40;
if([data length]>= 40){
NSData *subData = [data subdataWithRange:NSMakeRange(i*bufferLength, bufferLength)];
Byte *byteData = (Byte*)malloc(sizeof(Byte)*bufferLength);
memcpy(byteData, [subData bytes], bufferLength);
short decodedBuffer[WB_FRAME_SIZE];
int nDecodedByte = sizeof(short) * [self decode:byteData length:bufferLength output:decodedBuffer];
NSData *PCMData = [NSData dataWithBytes:(Byte *)decodedBuffer length:nDecodedByte ];
[audioData appendData:PCMData];
}
}
return audioData;
}
@end
import“ RecordingViewController.m”
#pragma mark - Reciving Audio Data from Deivce and DECODING with OPUS Library
-(void)recivedEncodedDatafromDevice:(NSData *)getData{
NSMutableData *opus = [OpusAudioDecode.shared decodeOpusData:getData];
[self.fileHandler writeData:opus];
}
#pragma mark - Save and Convert WAV From PCM
- (NSString *)getVoiceData{
if (![CommonUtils isEmptyString:self.pcmPath]) {
self.wavPath = [self createWavFromPcm:self.pcmPath];
}
return self.wavPath;
}
- (NSString *)createWavFromPcm:(NSString *)filePath {
NSString *wavFilePath = [NSString stringWithFormat:@"%@.wav", [filePath stringByDeletingPathExtension]];
long totalAudioLen = 0;
long totalDataLen = 0;
long longSampleRate = 16000;
int channels = 1;
long byteRate = 16 * 16000 * channels/8;
int numOfSamples = (int)[[NSData dataWithContentsOfFile:filePath] length];
NSData * wavData = [NSData dataWithContentsOfFile:filePath];
if(numOfSamples>0){
int wav1DataSize = (int)[[NSData dataWithContentsOfFile:filePath] length] - 44;
NSData *Wave= [NSMutableData dataWithData:[wavData subdataWithRange:NSMakeRange(44, wav1DataSize)]];
totalAudioLen=[Wave length];
totalDataLen = totalAudioLen + 44;
Byte *header = (Byte*)malloc(44);
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (Byte) (totalDataLen & 0xff);
header[5] = (Byte) ((totalDataLen >> 8) & 0xff);
header[6] = (Byte) ((totalDataLen >> 16) & 0xff);
header[7] = (Byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (Byte) channels;
header[23] = 0;
header[24] = (Byte) (longSampleRate & 0xff);
header[25] = (Byte) ((longSampleRate >> 8) & 0xff);
header[26] = (Byte) ((longSampleRate >> 16) & 0xff);
header[27] = (Byte) ((longSampleRate >> 24) & 0xff);
header[28] = (Byte) (byteRate & 0xff);
header[29] = (Byte) ((byteRate >> 8) & 0xff);
header[30] = (Byte) ((byteRate >> 16) & 0xff);
header[31] = (Byte) ((byteRate >> 24) & 0xff);
header[32] = (Byte) (2 * 8 / 8); // block align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (Byte) (totalAudioLen & 0xff);
header[41] = (Byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (Byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (Byte) ((totalAudioLen >> 24) & 0xff);
NSData *headerData = [NSData dataWithBytes:header length:44];
NSMutableData * soundFileData = [NSMutableData alloc];
[soundFileData appendData:[headerData subdataWithRange:NSMakeRange(0, 44)]];
[soundFileData appendData:Wave];
[[NSFileManager defaultManager] createFileAtPath:wavFilePath contents:soundFileData attributes:nil];
}
return wavFilePath;
}
#pragma mark - PLAYING DECODED DATA
-(void)playbutton{
self.filePath = [self getVoiceData];
NSURL *url = [NSURL fileURLWithPath:self.filePath];
NSData *wavDATA = [NSData dataWithContentsOfURL:url];
[AudioPlayerManager.shared playAudioData:wavDATA completionHandler:^(BOOL successfully) {
NSLog(@"Playing");
}];
}