iOS AVCaptureSession Stream Micro Audio Переполнение стека объектов

Я в настоящее время возиться с iOS и Objective-C ++. Я пришел из C / C ++, поэтому, пожалуйста, извините за плохое кодирование в следующих примерах.

Я пытаюсь транслировать звук с микрофона моего устройства iOS через tcp, устройство iOS действует как сервер и отправляет данные всем подключенным клиентам.

  1. Для этого я сначала использую AVCaptureDevice а также requestAccessForMediaType:AVMediaTypeAudio запросить доступ к микрофону (вместе с необходимой записью в Info.plist).

  2. Затем я создаю AVCaptureSession* используя следующую функцию:

    AVCaptureSession* createBasicARecordingSession(aReceiver* ObjectReceivingAudioFrames){
    
    AVCaptureSession* s = [[AVCaptureSession alloc] init];
    
    AVCaptureDevice* aDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    AVCaptureDeviceInput* aInput = NULL;
    if([aDevice lockForConfiguration:NULL] == YES && aDevice){
    aInput = [AVCaptureDeviceInput deviceInputWithDevice:aDevice error:nil];
    [aDevice unlockForConfiguration];
    }
    else if(!aDevice){
    fprintf(stderr, "[d] could not create device. (%p)\n", aDevice);
    return NULL;
    }
    else{
    fprintf(stderr, "[d] could not lock device.\n");
    return NULL;
    }
    
    if(!aInput){
    fprintf(stderr, "[d] could not create input.\n");
    return NULL;
    }
    
    AVCaptureAudioDataOutput* aOutput = [[AVCaptureAudioDataOutput alloc] init];
    dispatch_queue_t aQueue = dispatch_queue_create("aQueue", NULL);
    
    if(!aOutput){
    fprintf(stderr, "[d] could not create output.\n");
    return NULL;
    }
    
    [aOutput setSampleBufferDelegate:ObjectReceivingAudioFrames queue:aQueue];
    // the below line does only work on macOS
    //aOutput.audioSettings = settings;
    
    [s beginConfiguration];
    if([s canAddInput:aInput]){
    [s addInput:aInput];
    }
    else{
    fprintf(stderr, "[d] could not add input.\n");
    return NULL;
    }
    if([s canAddOutput:aOutput]){
    [s addOutput:aOutput];
    }
    else{
    fprintf(stderr, "[d] could not add output.\n");
    return NULL;
    }
    [s commitConfiguration];
    
    return s;
    
    }
    
  3. aReceiver* класс (?) определен ниже и получает аудио кадры, предоставленные AVCaptureAudioDataOutput* объект. Кадры хранятся внутри std::vector,

(Я добавляю код в виде изображения, так как я не смог правильно его отформатировать …)
введите описание изображения здесь
введите описание изображения здесь

  1. Тогда я начинаю AVCaptureSession* с помощью [audioSession start]

  2. Когда клиент TCP подключается, я сначала создаю AudioConverterRef и два AudioStreamBasicDescription чтобы преобразовать аудио кадры в AAC, см. ниже:

    AudioStreamBasicDescription asbdIn, asbdOut;
    AudioConverterRef converter;
    
    asbdIn.mFormatID = kAudioFormatLinearPCM;
    //asbdIn.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    asbdIn.mFormatFlags = 12;
    asbdIn.mSampleRate = 44100;
    asbdIn.mChannelsPerFrame = 1;
    asbdIn.mFramesPerPacket = 1;
    asbdIn.mBitsPerChannel = 16;
    //asbdIn.mBytesPerFrame = (asbdIn.mBitsPerChannel / 8) * asbdIn.mBitsPerChannel;
    asbdIn.mBytesPerFrame = 2;
    asbdIn.mBytesPerPacket = asbdIn.mBytesPerFrame;
    asbdIn.mReserved = 0;
    
    asbdOut.mFormatID = kAudioFormatMPEG4AAC;
    asbdOut.mFormatFlags = 0;
    asbdOut.mSampleRate = 44100;
    asbdOut.mChannelsPerFrame = 1;
    asbdOut.mFramesPerPacket = 1024;
    asbdOut.mBitsPerChannel = 0;
    //asbdOut.mBytesPerFrame = (asbdOut.mBitsPerChannel / 8) * asbdOut.mBitsPerChannel;
    asbdOut.mBytesPerFrame = 0;
    asbdOut.mBytesPerPacket = asbdOut.mBytesPerFrame;
    asbdOut.mReserved = 0;
    
    OSStatus err = AudioConverterNew(&asbdIn, &asbdOut, &converter);
    
  3. Затем я создаю AudioBufferList* хранить закодированные кадры:

    while(audioInput.locked){ // audioInput is my aReceiver*
    usleep(0.2 * 1000000);
    }
    audioInput.locked = true;
    
    UInt32 RequestedPackets = 8192;
    //AudioBufferList* aBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList));
    AudioBufferList* aBufferList = static_cast<AudioBufferList*>(calloc(1, offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * 1)));
    aBufferList->mNumberBuffers = 1;
    
    aBufferList->mBuffers[0].mNumberChannels = asbdIn.mChannelsPerFrame;
    aBufferList->mBuffers[0].mData = static_cast<void*>(calloc(RequestedPackets, asbdIn.mBytesPerFrame));
    aBufferList->mBuffers[0].mDataByteSize = asbdIn.mBytesPerFrame * RequestedPackets;
    
  4. Затем я иду через кадры, хранящиеся в std::vector упоминалось ранее и передать их AudioConverterFillComplexBuffer(), После преобразования я объединяю все закодированные кадры в один NSMutableData который я тогда write() к сокету, подключенному к клиенту.

    long aBufferListSize = audioInput.aBufferList.size();
    
    while(aBufferListSize > 0){
    
    err = AudioConverterFillComplexBuffer(converter, feedAFrames, static_cast<void*>(&audioInput.aBufferList[audioInput.aBufferList.size() - aBufferListSize]), &RequestedPackets, aBufferList, NULL);
    
    NSMutableData* encodedData = [[NSMutableData alloc] init];
    long encodedDataLen = 0;
    
    for(int i = 0; i < aBufferList->mNumberBuffers; i++){
    
    Float32* frame = (Float32*)aBufferList->mBuffers[i].mData;
    [encodedData appendBytes:frame length:aBufferList->mBuffers[i].mDataByteSize];
    encodedDataLen += aBufferList->mBuffers[i].mDataByteSize;
    
    }
    
    unsigned char* encodedDataBytes = (unsigned char*)[encodedData bytes];
    
    fprintf(stderr, "[d] got %li encoded bytes to send...\n", encodedDataLen);
    long bytes = write(Client->GetFD(), encodedDataBytes, encodedDataLen);
    fprintf(stderr, "[d] written %li of %li bytes.\n", bytes, encodedDataLen);
    
    usleep(0.2 * 1000000);
    
    aBufferListSize--;
    
    }
    
    audioInput.aBufferList.clear();
    
    audioInput.locked = false;
    
  5. Ниже feedAFrames() обратный вызов, используемый в AudioConverterFillComplexBuffer() вызов:

(опять же это изображение кода, та же причина, что и выше)
введите описание изображения здесь

Шаги с 5 по 7 повторяются до тех пор, пока соединение TCP не будет закрыто.


Каждый шаг выполняется без какой-либо заметной ошибки (я знаю, что я мог бы включить сюда более эффективную обработку ошибок), и я получаю данные из шагов 3 и 7. Однако, похоже, что в конце не получается AAC.

Поскольку я довольно новичок во всем этом, я действительно не уверен, в чем моя ошибка, я уверен, что есть несколько вещей, которые я сделал неправильно. Довольно сложно найти подходящий пример кода того, что я пытаюсь сделать, и вышеизложенное — лучшее, что я мог придумать до сих пор со всем, что я нашел, в паре с документацией на Apple Dev.

Я надеюсь, что кто-то может занять некоторое время, чтобы объяснить мне, что я сделал неправильно и как я могу заставить это работать. Спасибо за чтение, пока здесь!

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …