Как правильно читать декодированные образцы PCM на iOS с помощью AVAssetReader - в настоящее время некорректное декодирование

В настоящее время я работаю над приложением как часть моего бакалавра в области компьютерных наук. Приложение будет сопоставлять данные с аппаратного обеспечения iPhone (акселерометр, GPS) и музыку, которая воспроизводится.

Проект все еще находится в зачаточном состоянии, проработав над ним всего 2 месяца.

Момент, в котором я сейчас нахожусь и где мне нужна помощь, - это чтение сэмплов PCM из песен из библиотеки itunes и их воспроизведение с использованием аудиоустройства. В настоящее время реализация, над которой я бы хотел поработать, заключается в следующем: выбирает случайную песню из iTunes, читает сэмплы из нее, когда это необходимо, и сохраняет ее в буфере, назовем ее sampleBuffer. Позже в потребительской модели аудиоустройство (которое имеет микшер и выход RemoteIO) имеет обратный вызов, в котором я просто копирую необходимое количество выборок из sampleBuffer в буфер, указанный в обратном вызове. То, что я потом слышу через динамики, - это не совсем то, что я ожидаю; Я могу распознать, что она играет песню, но кажется, что она неправильно декодирована и в ней много шума! Я приложил изображение, которое показывает первые ~ полсекунды (24576 сэмплов при 44,1 кГц), и это не похоже на нормальный вид вывода. Прежде чем попасть в список, я проверил, что файл не поврежден, аналогично я написал тестовые примеры для буфера (поэтому я знаю, что буфер не изменяет образцы), и хотя это может быть не лучшим способом сделать это (некоторые поспорили бы пойти по пути аудио-очереди), я хочу выполнить различные манипуляции с семплами, а также изменить песню до ее завершения, изменить порядок воспроизведения песни и т. д. Кроме того, возможно, в аудиосистеме есть некоторые неправильные настройки Однако, блок, который отображает сэмплы (которые показывают, что сэмплы некорректно декодируются) берется прямо из буфера, поэтому я только сейчас смотрю, чтобы решить, почему чтение с диска и декодирование не работают правильно. Прямо сейчас я просто хочу сыграть на работе. Не могу опубликовать изображения, потому что новичок в stackoverflow, поэтому вот ссылка на изображение:http://i.stack.imgur.com/RHjlv.jpg

Листинг:

Здесь я настраиваю audioReadSettigns, который будет использоваться для AVAssetReaderAudioMixOutput

// Set the read settings
    audioReadSettings = [[NSMutableDictionary alloc] init];
    [audioReadSettings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM]
                         forKey:AVFormatIDKey];
    [audioReadSettings setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
    [audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
    [audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
    [audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsNonInterleaved];
    [audioReadSettings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];

Теперь следующий листинг кода представляет собой метод, который получает NSString с persistant_id песни:

-(BOOL)setNextSongID:(NSString*)persistand_id {

assert(persistand_id != nil);

MPMediaItem *song = [self getMediaItemForPersistantID:persistand_id];
NSURL *assetUrl = [song valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetUrl 
                                            options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] 
                                                                                forKey:AVURLAssetPreferPreciseDurationAndTimingKey]];


NSError *assetError = nil;

assetReader = [[AVAssetReader assetReaderWithAsset:songAsset error:&assetError] retain];

if (assetError) {
    NSLog(@"error: %@", assetError);
    return NO;
}

CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, songAsset.duration);
[assetReader setTimeRange:timeRange];

track = [[songAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];

assetReaderOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:[NSArray arrayWithObject:track]
                                                                            audioSettings:audioReadSettings];

if (![assetReader canAddOutput:assetReaderOutput]) {
    NSLog(@"cant add reader output... die!");
    return NO;
}

[assetReader addOutput:assetReaderOutput];
[assetReader startReading];

// just getting some basic information about the track to print
NSArray *formatDesc = ((AVAssetTrack*)[[assetReaderOutput audioTracks] objectAtIndex:0]).formatDescriptions;
for (unsigned int i = 0; i < [formatDesc count]; ++i) {
    CMAudioFormatDescriptionRef item = (CMAudioFormatDescriptionRef)[formatDesc objectAtIndex:i];
    const CAStreamBasicDescription *asDesc = (CAStreamBasicDescription*)CMAudioFormatDescriptionGetStreamBasicDescription(item);
    if (asDesc) {
        // get data
        numChannels = asDesc->mChannelsPerFrame;
        sampleRate = asDesc->mSampleRate;
        asDesc->Print();
    }
}
[self copyEnoughSamplesToBufferForLength:24000];
return YES;
}

Ниже представлена функция - (void) copyEnoughSamplesToBufferForLength:

-(void)copyEnoughSamplesToBufferForLength:(UInt32)samples_count {

[w_lock lock];
int stillToCopy = 0;
if (sampleBuffer->numSamples() < samples_count) {
    stillToCopy = samples_count;
}

NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];


CMSampleBufferRef sampleBufferRef;
SInt16 *dataBuffer = (SInt16*)malloc(8192 * sizeof(SInt16));

int a = 0;

while (stillToCopy > 0) {

    sampleBufferRef = [assetReaderOutput copyNextSampleBuffer];
    if (!sampleBufferRef) {
        // end of song or no more samples
        return;
    }

    CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBufferRef);
    CMItemCount numSamplesInBuffer = CMSampleBufferGetNumSamples(sampleBufferRef);
    AudioBufferList audioBufferList;

    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBufferRef,
                                                            NULL,
                                                            &audioBufferList,
                                                            sizeof(audioBufferList),
                                                            NULL,
                                                            NULL,
                                                            0,
                                                            &blockBuffer);

    int data_length = floorf(numSamplesInBuffer * 1.0f);

    int j = 0;

    for (int bufferCount=0; bufferCount < audioBufferList.mNumberBuffers; bufferCount++) {
        SInt16* samples = (SInt16 *)audioBufferList.mBuffers[bufferCount].mData;
        for (int i=0; i < numSamplesInBuffer; i++) {
            dataBuffer[j] = samples[i];
            j++;
        }
    }

    CFRelease(sampleBufferRef);
    sampleBuffer->putSamples(dataBuffer, j);
    stillToCopy = stillToCopy - data_length;
}

free(dataBuffer);
[w_lock unlock];
[apool release];
}

Теперь sampleBuffer будет иметь неправильно декодированные сэмплы. Кто-нибудь может мне помочь, почему это так? Это происходит для разных файлов в моей медиатеке iTunes (mp3, aac, wav и т. Д.). Любая помощь будет принята с благодарностью, кроме того, если вам понадобится какой-либо другой список моего кода или, возможно, как будет звучать вывод, я приложу его к каждому запросу. Я сидел на этом в течение прошлой недели, пытаясь отладить это и не нашел никакой помощи онлайн - все, кажется, обдумывают это в моем пути, все же кажется, что только у меня есть эта проблема.

Спасибо за любую помощь!

Питер

Ответы на вопрос(3)

Ваш ответ на вопрос