Noise occurs when iOS encodes pcm data into aac data through socket

21 Views Asked by At

What happened:

Establish socket communication using GCDAsyncSocket.

Implemented aac encoding using AudioToolbox:

#import "ConvertPcmToAACStreamTool.h"
#import <AudioToolbox/AudioToolbox.h>


typedef struct {
    char *     srcBuffer;
    UInt32     srcBufferSize;
} XXAudioInfo, *XXAudioInfoPtr;

#define kXXPCMMaxBufferSize 2048
#define kXXmSampleRate 16000
#define kXXmChannelsPerFrame 1

@interface ConvertPcmToAACStreamTool(){
    AudioConverterRef  _encodeConvertRef;
}

@end

@implementation ConvertPcmToAACStreamTool


- (instancetype)init{
    if (self = [super init]){
        [self createConverter];
    }
    return self;
}

- (void)startData:(NSData *)pcmData complete:(DataComplete)complete{
    if (pcmData.length == 0){return;}
    AudioBufferList bufferList = {};
    bufferList.mNumberBuffers              = 1;
    bufferList.mBuffers[0].mNumberChannels = kXXmChannelsPerFrame;
    bufferList.mBuffers[0].mDataByteSize   = kXXPCMMaxBufferSize;
    bufferList.mBuffers[0].mData           = malloc(kXXPCMMaxBufferSize * sizeof(char));
    
    AudioStreamPacketDescription outputPacketDescriptions;
    
    UInt32 inNumPackets = 1;
    XXAudioInfo audioInfo = {};
    audioInfo.srcBuffer = (void *)[pcmData bytes];
    audioInfo.srcBufferSize = (UInt32)[pcmData length];
    
    OSStatus status = AudioConverterFillComplexBuffer(_encodeConvertRef,
                                                      MyinInputDataProc,
                                             &audioInfo,
                                             &inNumPackets,
                                             &bufferList,
                                             &outputPacketDescriptions);

    if(status != noErr){
        free(bufferList.mBuffers[0].mData);
        AudioConverterDispose(_encodeConvertRef);
        NSLog(@"Converter fail:%d", (int)status);
        return;
    }
    NSMutableData *adtsData = [[self adtsDataWithChannels:kXXmChannelsPerFrame sampleRate:kXXmSampleRate rawDataLength:bufferList.mBuffers[0].mDataByteSize] mutableCopy];
    NSData *bufferData = [NSData dataWithBytes:bufferList.mBuffers[0].mData length:bufferList.mBuffers[0].mDataByteSize];
    [adtsData appendData:bufferData];
    complete(adtsData.copy);
}

-(void)createConverter{
    AudioStreamBasicDescription audioFormat; 
    AudioStreamBasicDescription outputFormat; 

    audioFormat.mSampleRate   = kXXmSampleRate;
    audioFormat.mFormatID   = kAudioFormatLinearPCM;
    audioFormat.mFormatFlags  = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioFormat.mFramesPerPacket = 1;
    audioFormat.mChannelsPerFrame = kXXmChannelsPerFrame;
    audioFormat.mBitsPerChannel  = 16;
    audioFormat.mBytesPerPacket  = 2;
    audioFormat.mBytesPerFrame  = 2;

    memset(&outputFormat, 0, sizeof(outputFormat));
    outputFormat.mSampleRate  = kXXmSampleRate;
    outputFormat.mFormatID   = kAudioFormatMPEG4AAC;
    outputFormat.mFormatFlags  = kMPEG4Object_AAC_Main;
    outputFormat.mFramesPerPacket = 1024;
    outputFormat.mChannelsPerFrame = kXXmChannelsPerFrame;
    outputFormat.mBitsPerChannel = 0;
    outputFormat.mBytesPerFrame = 0;
    outputFormat.mBytesPerPacket = 0;
    
    if (_encodeConvertRef == NULL){
        OSStatus result = AudioConverterNew(&audioFormat, &outputFormat, &_encodeConvertRef);
        if (result != noErr) {
            NSLog(@"Create AudioConverter Fail,error code:%d", (int)result);
            return;
        }
    }
}

#pragma mark - ADTS

- (NSData *)adtsDataWithChannels:(NSInteger)channels sampleRate:(NSInteger)sampleRate rawDataLength:(NSInteger)rawDataLength {
    int adtsLength = 7; 
    char *packet = malloc(sizeof(char) * adtsLength);
    
    int profile = 2; 
    NSInteger sampleRateIndex = [self sampleRateIndex:sampleRate]; 
    int channelCfg = (int) channels; 
    NSUInteger fullLength = adtsLength + rawDataLength; 
    
    packet[0] = (char) 0xFF; // 11111111     = syncword
    packet[1] = (char) 0xF9; // 1111 1 00 1  = syncword MPEG-2 Layer CRC
    packet[2] = (char) (((profile - 1) << 6) + (sampleRateIndex << 2) + (channelCfg >> 2));
    packet[3] = (char) (((channelCfg & 3) << 6) + (fullLength >> 11));
    packet[4] = (char) ((fullLength & 0x7FF) >> 3);
    packet[5] = (char) (((fullLength & 7) << 5) + 0x1F);
    packet[6] = (char) 0xFC;
    NSData *data = [NSData dataWithBytesNoCopy:packet length:adtsLength freeWhenDone:YES];
    
    return data;
}

- (NSInteger)sampleRateIndex:(NSInteger)frequencyInHz {
    NSInteger sampleRateIndex = 0;
    switch (frequencyInHz) {
        case 96000:
            sampleRateIndex = 0;
            break;
        case 88200:
            sampleRateIndex = 1;
            break;
        case 64000:
            sampleRateIndex = 2;
            break;
        case 48000:
            sampleRateIndex = 3;
            break;
        case 44100:
            sampleRateIndex = 4;
            break;
        case 32000:
            sampleRateIndex = 5;
            break;
        case 24000:
            sampleRateIndex = 6;
            break;
        case 22050:
            sampleRateIndex = 7;
            break;
        case 16000:
            sampleRateIndex = 8;
            break;
        case 12000:
            sampleRateIndex = 9;
            break;
        case 11025:
            sampleRateIndex = 10;
            break;
        case 8000:
            sampleRateIndex = 11;
            break;
        case 7350:
            sampleRateIndex = 12;
            break;
        default:
            sampleRateIndex = 15;
    }
    
    return sampleRateIndex;
}


- (void)dealloc{
    AudioConverterDispose(_encodeConvertRef);
}

OSStatus MyinInputDataProc(AudioConverterRef inAudioConverter,
                                           UInt32* ioNumberDataPackets,
                                           AudioBufferList* ioData,
                                           AudioStreamPacketDescription** ioDataPacketDescription,
                                           void* inUserData) {
    XXAudioInfoPtr info = (XXAudioInfoPtr)inUserData;
    ioData->mNumberBuffers              = 1;
    ioData->mBuffers[0].mData           = info->srcBuffer;
    ioData->mBuffers[0].mNumberChannels = 1;
    ioData->mBuffers[0].mDataByteSize   = kXXPCMMaxBufferSize;
    return noErr;
}

@end

Encoding pcm data to aac data works in some cases and does not work in some cases.

Can work:

Receive all the socket data, save it in the file, and then read the length of 2048 to the encoder through NSInputStream. The decoding can be successful and there is no noise.

Can not work:

During the process of receiving socket data, after receiving a piece of data, it is immediately sent to the encoder. It is also read according to the length of 2048. It can also be decoded successfully, but there is obvious noise.

socket.readData(toLength: 2048, withTimeout: -1, tag: 0)

I compared the input and output in the two cases. The input is the same and there is no data loss. When it works, if repeated multiple times, the output will be the same. If it doesn't work, repeat it multiple times, and the output will be different each time.

Current status:

I now suspect that it may be related to the speed of reading data. I am trying to receive the socket data myself, and then read the 2048 length data to the encoder, but there is an efficiency issue involved here. Anyone have any suggestions?

0

There are 0 best solutions below