Аудио не записывается с помощью AVAssetWrite - PullRequest
0 голосов
/ 04 марта 2019

Я пытаюсь записать звук в файл в течение 14 дней.Я получаю аудиоданные в формате PCM через зеркальное отображение экрана, на котором принимается звук, и из этого я преобразую его в CMSampleBuffer, используя этот код

-(void)createAudioSampleBufferFromData:(uint8_t*)buf withSize:(uint32_t)buflen timeStamp:(double)timeStamp{
    OSStatus status;
    AudioStreamBasicDescription monoStreamFormat;

    memset(&monoStreamFormat, 0, sizeof(monoStreamFormat));
    monoStreamFormat.mFormatID         = kAudioFormatLinearPCM;
    monoStreamFormat.mSampleRate       = 44100;
    monoStreamFormat.mChannelsPerFrame = 2;
    monoStreamFormat.mBitsPerChannel   = 16;
    monoStreamFormat.mFramesPerPacket  = 1;  // uncompressed audio
    monoStreamFormat.mBytesPerFrame    =monoStreamFormat.mChannelsPerFrame * monoStreamFormat.mBitsPerChannel/8;
    monoStreamFormat.mBytesPerPacket   = monoStreamFormat.mBytesPerFrame * monoStreamFormat.mFramesPerPacket;
    monoStreamFormat.mFormatFlags      = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;

    CMFormatDescriptionRef format = NULL;
    status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &monoStreamFormat, 0, NULL, 0, NULL, NULL, &format);
    if (status != noErr) {
        // really shouldn't happen
        return;
    }

    long blockLength = buflen;

    CMSampleBufferRef sampleBuffer = NULL;
    CMBlockBufferRef blockBuffer = NULL;

    status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, buf,  // memoryBlock to hold buffered data
                                            blockLength,  // block length of the mem block in bytes.
                                            kCFAllocatorDefault, NULL,
                                            0, // offsetToData
                                            blockLength,   // dataLength of relevant bytes, starting at offsetToData
                                            0, &blockBuffer);


    if(status == noErr)
    {

        CMSampleTimingInfo timings = {CMTimeMake(1, 44100.0), CMClockGetTime(CMClockGetHostTimeClock()), kCMTimeInvalid };

        const size_t sampleSize = blockLength;
        status = CMSampleBufferCreate(kCFAllocatorDefault,
                                  NULL, true, NULL, NULL,
                                  format, 1, 0, &timings, 1,
                                  &sampleSize, &sampleBuffer);
         CMItemCount itemCount = CMSampleBufferGetNumSamples(sampleBuffer);

        [self notifyAudioBufferReceived:sampleBuffer];
//        if(blockBuffer)
//            CFRelease(blockBuffer);

    }
}

И в следующем методе это CMSampleBuffers получает:

- (void)airPlayServer:(id)server audioBufferReceived:(CMSampleBufferRef)buffer {
    if(recordingStarted){
        [decoderAndRecorder.recorder newAudioSample:buffer];
    }
//    CFRelease(buffer);
}

отсюда эти буферы переходят в класс AVAssetWriter, где я добавляю эти буферы для записи звука в файл.Класс AVAssetWriter выглядит следующим образом:

- (instancetype)init
{
    self = [super init];
    if (self) {
        // Create asset writer

        dateString = [self dateInString];

        NSString *documents = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
        filePath = [documents stringByAppendingPathComponent:[NSString stringWithFormat:@"screen recording - %@.caf",dateString]];

        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            [[NSFileManager defaultManager] removeItemAtPath:filePath
                                                   error:nil];
        }

    NSLog(@"%@", filePath);
        NSError *error = nil;

    _assetWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:filePath]
                                             fileType:AVFileTypeCoreAudioFormat
                                                error:&error];

        AudioChannelLayout acl;
        memset(&acl,0, sizeof(acl));
        acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;

        NSDictionary* audioOutputSettings = nil;

        audioOutputSettings = [ NSDictionary dictionaryWithObjectsAndKeys:
                              [ NSNumber numberWithInt: kAudioFormatLinearPCM ], AVFormatIDKey,
                              [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                              [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
                              [ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
                              [ NSNumber numberWithInt: 16 ], AVLinearPCMBitDepthKey,
                              [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                              [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
                              [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
                               nil ];


        _audioWriterInput = [[AVAssetWriterInput alloc]
                              initWithMediaType: AVMediaTypeAudio
                              outputSettings: audioOutputSettings ];

        _audioWriterInput.expectsMediaDataInRealTime = YES;
        NSParameterAssert(_audioWriterInput);
        NSParameterAssert([_assetWriter canAddInput:_audioWriterInput]);
        [_assetWriter addInput:_audioWriterInput];          
    }

}
return self;
}

-(void)startSession{
    //This is vedio recorder code
    _isStarted =[_assetWriter startWriting];
    if(_isStarted)
    {
        NSLog(@"======== Session started");
        [_assetWriter startSessionAtSourceTime:_startingTime];
    }
    else {
        NSLog(@"======== Session failed : %@", _assetWriter.error);
    }
}

-(void)endSession
{
    _isStarted = NO;

    [_audioWriterInput markAsFinished];
    [_assetWriter finishWritingWithCompletionHandler:^{
        NSLog(@"====== File Save Successfully =======");

    }];
}

- (void)newAudioSample:(CMSampleBufferRef)sampleBuffer
{
    if (_isStarted) {
        if (_videoWriter.status == AVAssetWriterStatusWriting) {
//            if(_audioWriterInput.readyForMoreMediaData){
            //NSLog(@"Warning: writer status is %d", _videoWriter.status)

                if(sampleBuffer){
                    if (![_audioWriterInput appendSampleBuffer:sampleBuffer]) {
                        NSLog(@"Unable to write to audio input");
                    }else{
                        NSLog(@"====Audio is being recorded===");
                    }

                }

//            }
        }else if(_videoWriter.status == AVAssetWriterStatusFailed){
            NSLog(@"<----- Appending failed ----->");
            NSLog(@"Error: %@", _videoWriter.error);

        }
    }
}

Вот и все.Файл создан, но с нулевыми байтами.В нем нет данных.Пожалуйста, помогите с этой проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...