使用OPUS库解码音频数据,但声音不清晰并拆分arraybytes,然后在Objective-c iOS中转换为shortbyte

问题描述 投票:0回答:1

我正在尝试使用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")
                      }
                  }
              }
ios arrays core-audio short opus
1个回答
0
投票

最后,我得到了使用OPUS库解码音频数据并将PCM转换为WAV然后播放的解决方案。

下面是更新的工作代码。

导入“ OpusAudioDecode.h”

@interface OpusAudioDecode : NSObject
+ (instancetype)shared;

-(void)opusInit;
-(NSMutableData*)decodeOpusData:(NSData*)data;
@end

导入“ OpusAudioDecode.m”

#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");
    }];
}
© www.soinside.com 2019 - 2024. All rights reserved.