AudioQueue comment find la longueur de lecture des données en queue

J'utilise AudioQueue pour diffuser certaines chansons, ma question est comment puis-je dire la longueur de la lecture des tampons déjà mis en queue? Je veux diffuser deux secondes de données à la fois, le problème que j'ai est comment puis-je savoir combien d'octets correspondent réellement à deux secondes de musique (donc je peux toujours être en avance de deux secondes).

Merci

Daniel

Voici une class qui utilise Audio File Services pour get des données bitrate / packet / frame pour saisir la quantité d'octets d'un file musical correspondant à x secondes, l'exemple a été testé avec des files mp3 et m4a

Entête

#import <Foundation/Foundation.h> #import <AudioToolbox/AudioToolbox.h> @interface MusicChunker : NSObject { AudioFileID audioFile; int _sampleRate; int _totalFrames; UInt64 _framesPerPacket; UInt64 _totalPackets; UInt64 fileDataSize; AudioFilePacketTableInfo _packetInfo; int _fileLength; AudioStreamBasicDescription _fileDataFormat; NSFileHandle * _fileHandle; int _packetOffset; int _totalReadBytes; int _maxPacketSize; BOOL firstTime; BOOL _ism4a; } -(id)initWithURL:(NSURL*)url andFileType:(NSSsortingng*)ext; //gets next chunk that corresponds to seconds of audio -(NSData*)getNextDataChunk:(int)seconds; @end 

la mise en oeuvre

 #import "MusicChunker.h" void ReportAudioError(OSStatus statusCode); @implementation MusicChunker - (id)init { self = [super init]; if (self) { // Initialization code here. } return self; } void ReportAudioError(OSStatus statusCode) { switch (statusCode) { case noErr: break; case kAudioFileUnspecifiedError: [NSException raise:@"AudioFileUnspecifiedError" format:@"An unspecified error occured."]; break; case kAudioFileUnsupportedDataFormatError: [NSException raise:@"AudioFileUnsupportedDataFormatError" format:@"The data format is not supported by the output file type."]; break; case kAudioFileUnsupportedFileTypeError: [NSException raise:@"AudioFileUnsupportedFileTypeError" format:@"The file type is not supported."]; break; case kAudioFileUnsupportedPropertyError: [NSException raise:@"AudioFileUnsupportedPropertyError" format:@"A file property is not supported."]; break; case kAudioFilePermissionsError: [NSException raise:@"AudioFilePermissionsError" format:@"The operation violated the file permissions. For example, an attempt was made to write to a file opened with the kAudioFileReadPermission constant."]; break; case kAudioFileNotOptimizedError: [NSException raise:@"AudioFileNotOptimizedError" format:@"The chunks following the audio data chunk are preventing the extension of the audio data chunk. To write more data, you must optimize the file."]; break; case kAudioFileInvalidChunkError: [NSException raise:@"AudioFileInvalidChunkError" format:@"Either the chunk does not exist in the file or it is not supported by the file."]; break; case kAudioFileDoesNotAllow64BitDataSizeError: [NSException raise:@"AudioFileDoesNotAllow64BitDataSizeError" format:@"The file offset was too large for the file type. The AIFF and WAVE file format types have 32-bit file size limits."]; break; case kAudioFileInvalidPacketOffsetError: [NSException raise:@"AudioFileInvalidPacketOffsetError" format:@"A packet offset was past the end of the file, or not at the end of the file when a VBR format was written, or a corrupt packet size was read when the packet table was built."]; break; case kAudioFileInvalidFileError: [NSException raise:@"AudioFileInvalidFileError" format:@"The file is malformed, or otherwise not a valid instance of an audio file of its type."]; break; case kAudioFileOperationNotSupportedError: [NSException raise:@"AudioFileOperationNotSupportedError" format:@"The operation cannot be performed. For example, setting the kAudioFilePropertyAudioDataByteCount constant to increase the size of the audio data in a file is not a supported operation. Write the data instead."]; break; case -50: [NSException raise:@"AudioFileBadParameter" format:@"An invalid parameter was passed, possibly the current packet and/or the inNumberOfPackets."]; break; default: [NSException raise:@"AudioFileUknownError" format:@"An unknown error type %@ occured. [%s]", [NSNumber numberWithInteger:statusCode], (char*)&statusCode]; break; } } + (AudioFileTypeID)hintForFileExtension:(NSSsortingng *)fileExtension { AudioFileTypeID fileTypeHint = kAudioFileAAC_ADTSType; if ([fileExtension isEqual:@"mp3"]) { fileTypeHint = kAudioFileMP3Type; } else if ([fileExtension isEqual:@"wav"]) { fileTypeHint = kAudioFileWAVEType; } else if ([fileExtension isEqual:@"aifc"]) { fileTypeHint = kAudioFileAIFCType; } else if ([fileExtension isEqual:@"aiff"]) { fileTypeHint = kAudioFileAIFFType; } else if ([fileExtension isEqual:@"m4a"]) { fileTypeHint = kAudioFileM4AType; } else if ([fileExtension isEqual:@"mp4"]) { fileTypeHint = kAudioFileMPEG4Type; } else if ([fileExtension isEqual:@"caf"]) { fileTypeHint = kAudioFileCAFType; } else if ([fileExtension isEqual:@"aac"]) { fileTypeHint = kAudioFileAAC_ADTSType; } return fileTypeHint; } -(id)initWithURL:(NSURL*)url andFileType:(NSSsortingng*)ext { self = [super init]; if (self) { // Initialization code here. //OSStatus theErr = noErr; if([ext isEqualToSsortingng:@"mp3"]) { _ism4a=FALSE; } else _ism4a=TRUE; firstTime=TRUE; _packetOffset=0; AudioFileTypeID hint=[MusicChunker hintForFileExtension:ext]; OSStatus theErr = AudioFileOpenURL((CFURLRef)url, kAudioFileReadPermission, hint, &audioFile); if(theErr) { ReportAudioError(theErr); } UInt32 thePropertySize;// = sizeof(theFileFormat); thePropertySize = sizeof(fileDataSize); theErr = AudioFileGetProperty(audioFile, kAudioFilePropertyAudioDataByteCount, &thePropertySize, &fileDataSize); if(theErr) { ReportAudioError(theErr); } theErr = AudioFileGetProperty(audioFile, kAudioFilePropertyAudioDataPacketCount, &thePropertySize, &_totalPackets); if(theErr) { ReportAudioError(theErr); } /* UInt32 size; size= sizeof(_packetInfo); theErr= AudioFileGetProperty(audioFile, kAudioFilePropertyPacketTableInfo, &size, &_packetInfo); g(@"Key %@", key ); } if(theErr) { ReportAudioError(theErr); } */ UInt32 size; size=sizeof(_maxPacketSize); theErr=AudioFileGetProperty(audioFile, kAudioFilePropertyMaximumPacketSize , &size, &_maxPacketSize); size = sizeof( _fileDataFormat ); theErr=AudioFileGetProperty( audioFile, kAudioFilePropertyDataFormat, &size, &_fileDataFormat ); _framesPerPacket=_fileDataFormat.mFramesPerPacket; _totalFrames=_fileDataFormat.mFramesPerPacket*_totalPackets; _fileHandle=[[NSFileHandle fileHandleForReadingFromURL:url error:nil] retain]; _fileLength=[_fileHandle seekToEndOfFile]; _sampleRate=_fileDataFormat.mSampleRate; _totalReadBytes=0; /* AudioFramePacketTranslation tran;//= .mFrame = 0, .mPacket = packetCount - 1, .mFrameOffsetInPacket = 0 }; tran.mFrame=0; tran.mFrameOffsetInPacket=0; tran.mPacket=1; UInt32 size=sizeof(tran); theErr=AudioFileGetProperty(audioFile, kAudioFilePropertyPacketToFrame, &size, &tran); */ /* AudioBytePacketTranslation bt; bt.mPacket=4; bt.mByteOffsetInPacket=0; size=sizeof(bt); theErr=AudioFileGetProperty(audioFile, kAudioFilePropertyPacketToByte, &size, &bt); */ } return self; } //gets next chunk that corresponds to seconds of audio -(NSData*)getNextDataChunk:(int)seconds { //NSLog(@"%d, total packets",_totalPackets); if(_packetOffset>=_totalPackets) return nil; //sampleRate * seconds = number of wanted frames int framesWanted= _sampleRate*seconds; NSData *header=nil; int wantedPackets= framesWanted/_framesPerPacket; if(firstTime && _ism4a) { firstTime=false; //when we have a header that was ssortingpped off, we grab it from the original file int totallen= [_fileHandle seekToEndOfFile]; int dif=totallen-fileDataSize; [_fileHandle seekToFileOffset:0]; header= [_fileHandle readDataOfLength:dif]; } int packetOffset=_packetOffset+wantedPackets; //bound condition if(packetOffset>_totalPackets) { packetOffset=_totalPackets; } UInt32 outBytes; UInt32 packetCount = wantedPackets; int x=packetCount * _maxPacketSize; void *data = (void *)malloc(x); OSStatus theErr=AudioFileReadPackets(audioFile, false, &outBytes, NULL, _packetOffset, &packetCount, data); if(theErr) { ReportAudioError(theErr); } //calculate bytes to read int bytesRead=outBytes; //update read bytes _totalReadBytes+=bytesRead; // NSLog(@"total bytes read %d", _totalReadBytes); _packetOffset=packetOffset; NSData *subdata=[[NSData dataWithBytes:data length:outBytes] retain]; free(data); if(header) { NSMutableData *data=[[NSMutableData alloc]init]; [data appendData:header]; [data appendData:subdata]; [subdata release]; return [data autorelease]; } return [subdata autorelease]; } @end 

Si les morceaux sont dans des formats compressés arbitraires et que vous voulez exactement des coupures de 2 secondes, vous devrez peut-être convertir les morceaux en échantillons PCM bruts ou en données WAV en premier (AVAssetReader, et autres). Ensuite, vous pouvez countr les échantillons à une fréquence d'échantillonnage connue. par exemple 88200 images à un taux d'échantillonnage de 44,1k serait de 2 secondes.