Cómo leer correctamente las muestras PCM decodificadas en iOS usando AVAssetReader - actualmente decodificación incorrecta

Actualmente estoy trabajando en una aplicación como parte de mi Licenciatura en Informática. La aplicación correlacionará los datos del hardware del iPhone (acelerómetro, gps) y la música que se está reproduciendo.

El proyecto todavía está en su infancia, después de haber trabajado en él durante solo 2 meses.

El momento en que estoy ahora, y donde necesito ayuda, es leer muestras de PCM de canciones de la biblioteca de iTunes, y reproducirlas usando una unidad de audio. Actualmente, la implementación en la que me gustaría trabajar hace lo siguiente: elige una canción aleatoria de iTunes, lee muestras de ella cuando es necesario y la almacena en un búfer, llamémosla sampleBuffer. Más adelante en el modelo de consumidor, la unidad de audio (que tiene un mezclador y una salida de control remoto) tiene una devolución de llamada donde simplemente copie el número requerido de muestras de sampleBuffer en el búfer especificado en la devolución de llamada. Lo que luego escucho a través de los altavoces es algo que no es exactamente lo que espero; Puedo reconocer que está reproduciendo la canción, sin embargo, parece que está decodificada incorrectamente y tiene mucho ruido. Adjunté una imagen que muestra el primer medio segundo (24576 muestras a 44,1 kHz), y esto no se parece a una salida de aspecto normal. Antes de entrar en la lista, verifiqué que el archivo no está dañado, de manera similar, he escrito casos de prueba para el búfer (por lo que sé que el búfer no altera las muestras), y aunque esta podría no ser la mejor manera de hacerlo (algunos argumentarían ir a la ruta de la cola de audio), quiero realizar varias manipulaciones en las muestras, así como cambiar la canción antes de que termine, reorganizar la canción que se reproduce, etc. Además, tal vez hay algunas configuraciones incorrectas en el audio Sin embargo, el gráfico que muestra las muestras (que muestra que las muestras están decodificadas incorrectamente) se toma directamente del búfer, por lo tanto, solo estoy buscando resolver por qué la lectura del disco y la decodificación no funcionan correctamente. En este momento, simplemente quiero jugar jugando. No puedo publicar imágenes porque es nuevo en stackoverflow, así que aquí está el enlace a la imagen:http: //i.stack.imgur.com/RHjlv.jp

Listado

quí es donde configuro el audioReadSettigns que se usará para 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];

Ahora la siguiente lista de códigos es un método que recibe un NSString con el persistant_id de la canción:

-(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;
}

Lo siguiente presenta la función - (vacío) 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];
}

Ahora el sampleBuffer tendrá decodificaciones incorrectamente decodificadas. ¿Alguien puede ayudarme por qué es así? Esto sucede para diferentes archivos en mi biblioteca de iTunes (mp3, aac, wav, etc.). Además, agradecería cualquier ayuda, si necesita alguna otra lista de mi código, o tal vez cómo suena la salida, la adjuntaré por solicitud. He estado sentado en esto durante la última semana tratando de depurarlo y no he encontrado ayuda en línea: todo el mundo parece estar haciéndolo a mi manera, pero parece que solo yo tengo este problema.

¡Gracias por cualquier ayuda de todas maneras

Peter

Respuestas a la pregunta(6)

Su respuesta a la pregunta