From 5a0aabb06a8c15fdd1bb479047694028ffd5eb1c Mon Sep 17 00:00:00 2001 From: marc-sabeh <67316184+marc-sabeh@users.noreply.github.com> Date: Wed, 9 Jun 2021 18:10:58 +0300 Subject: [PATCH 1/3] commiting --- sampleQueueIphone/ViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sampleQueueIphone/ViewController.m b/sampleQueueIphone/ViewController.m index a30c806..f40daee 100644 --- a/sampleQueueIphone/ViewController.m +++ b/sampleQueueIphone/ViewController.m @@ -20,7 +20,7 @@ - (void)viewDidLoad // Do any additional setup after loading the view, typically from a nib. } -- (void)viewDidUnload +- (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. From 6890dcee051a515bcf5ea74adafd2f022e7d1f4e Mon Sep 17 00:00:00 2001 From: Abdullah Bakhach Date: Thu, 6 Sep 2012 10:54:54 +0300 Subject: [PATCH 2/3] first commit --- README.md | 0 sampleQueueIphone/Player.h | 34 ++++++++++++++++++++++++++++++++++ sampleQueueIphone/Player.m | 22 ++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 README.md create mode 100644 sampleQueueIphone/Player.h create mode 100644 sampleQueueIphone/Player.m diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/sampleQueueIphone/Player.h b/sampleQueueIphone/Player.h new file mode 100644 index 0000000..3a6e4f1 --- /dev/null +++ b/sampleQueueIphone/Player.h @@ -0,0 +1,34 @@ +// +// Player.h +// AudioConverterCoacoa +// +// Created by Abdullah Bakhach on 9/2/12. +// Copyright (c) 2012 Amazon. All rights reserved. +// + +#import +#include +#include + + +@interface Player : NSObject +{ + + @public + // AudioQueueRef queue; // the audio queue object + // AudioStreamBasicDescription dataFormat; // file's data stream description + AudioFileID playbackFile; // reference to your output file + SInt64 packetPosition; // current packet index in output file + UInt32 numPacketsToRead; // number of packets to read from file + AudioStreamPacketDescription *packetDescs; // array of packet descriptions for read buffer + // AudioQueueBufferRef buffers[kNumberPlaybackBuffers]; + Boolean isDone; // playback has completed +} + +@property (readwrite) AudioFileID playbackFile; +@property (readwrite) SInt64 packetPosition; +@property (readwrite) UInt32 numPacketsToRead; +@property (readwrite) AudioStreamPacketDescription *packetDescs; +@property (readwrite) Boolean isDone; + +@end \ No newline at end of file diff --git a/sampleQueueIphone/Player.m b/sampleQueueIphone/Player.m new file mode 100644 index 0000000..f86f94a --- /dev/null +++ b/sampleQueueIphone/Player.m @@ -0,0 +1,22 @@ +// +// Player.m +// AudioConverterCoacoa +// +// Created by Abdullah Bakhach on 9/2/12. +// Copyright (c) 2012 Amazon. All rights reserved. +// + +#import "Player.h" + +@implementation Player + +@synthesize playbackFile; +@synthesize packetPosition; +@synthesize numPacketsToRead; +@synthesize packetDescs; +@synthesize isDone; + + + + +@end From 113a353dbfac7aa31495fb7a2f578d0d4c905c64 Mon Sep 17 00:00:00 2001 From: Abdullah Bakhach Date: Sun, 3 Feb 2013 21:46:30 +0200 Subject: [PATCH 3/3] remove log statement that chokes audio # Conflicts: # sampleQueueIphone/AppDelegate.m --- .../UserInterfaceState.xcuserstate | Bin 0 -> 10148 bytes .../xcschemes/sampleQueueIphone.xcscheme | 86 +++ .../xcschemes/xcschememanagement.plist | 22 + sampleQueueIphone/AppDelegate.m | 579 +++++++++++++++++- 4 files changed, 674 insertions(+), 13 deletions(-) create mode 100644 sampleQueueIphone.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/sampleQueueIphone.xcscheme create mode 100644 sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/sampleQueueIphone.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate b/sampleQueueIphone.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..386b1167bfa74797088b4593538b818658eaba0d GIT binary patch literal 10148 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 Fe*h%Mrgs1U literal 0 HcmV?d00001 diff --git a/sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/sampleQueueIphone.xcscheme b/sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/sampleQueueIphone.xcscheme new file mode 100644 index 0000000..dac2a3b --- /dev/null +++ b/sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/sampleQueueIphone.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist b/sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..31f0bf3 --- /dev/null +++ b/sampleQueueIphone.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + sampleQueueIphone.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + D7A036D715F5D65300B98E91 + + primary + + + + + diff --git a/sampleQueueIphone/AppDelegate.m b/sampleQueueIphone/AppDelegate.m index 9e45e8e..7212956 100644 --- a/sampleQueueIphone/AppDelegate.m +++ b/sampleQueueIphone/AppDelegate.m @@ -7,7 +7,6 @@ // #import "AppDelegate.h" - #import "ViewController.h" @implementation AppDelegate @@ -15,6 +14,7 @@ @implementation AppDelegate @synthesize window = _window; @synthesize viewController = _viewController; + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; @@ -22,34 +22,587 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; + // Insert code here to initialize your application + + player = [[Player alloc] init]; + + + [self setupReader]; + [self setupQueue]; + + + // initialize reader in a new thread + internalThread =[[NSThread alloc] + initWithTarget:self + selector:@selector(readVBRPackets) + object:nil]; + + [internalThread start]; + + + // start the queue. this function returns immedatly and begins + // invoking the callback, as needed, asynchronously. + //CheckError(AudioQueueStart(queue, NULL), "AudioQueueStart failed"); + + // and wait + printf("Playing...\n"); + do + { + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false); + } while (!player.isDone /*|| gIsRunning*/); + + // isDone represents the state of the Audio File enqueuing. This does not mean the + // Audio Queue is actually done playing yet. Since we have 3 half-second buffers in-flight + // run for continue to run for a short additional time so they can be processed + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 2, false); + + // end playback + player.isDone = true; + CheckError(AudioQueueStop(queue, TRUE), "AudioQueueStop failed"); + +cleanup: + AudioQueueDispose(queue, TRUE); + AudioFileClose(player.playbackFile); + return YES; + +} + + +- (NSDictionary *)getPCMaSBD +{ + // Set the read settings + NSDictionary *PCMaSBD = [[NSMutableDictionary alloc] init]; + + [PCMaSBD setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] + forKey:AVFormatIDKey]; + [PCMaSBD setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey]; + [PCMaSBD setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey]; + [PCMaSBD setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey]; + [PCMaSBD setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsNonInterleaved]; + [PCMaSBD setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey]; + + return PCMaSBD; +} + +-(AudioStreamBasicDescription)getPCMaSBDRaw +{ + // get the audio data format from the file + // we know that it is PCM.. since it's converted + AudioStreamBasicDescription dataFormat; + dataFormat.mSampleRate = 44100.0; + dataFormat.mFormatID = kAudioFormatLinearPCM; + dataFormat.mFormatFlags = kAudioFormatFlagsCanonical; + dataFormat.mBytesPerPacket = 4; + dataFormat.mFramesPerPacket = 1; + dataFormat.mBytesPerFrame = 4; + dataFormat.mChannelsPerFrame = 2; + dataFormat.mBitsPerChannel = 16; + + return dataFormat; + +} + +-(AudioStreamBasicDescription)getTrackNativeSettings:(AVAssetTrack *) track +{ + + CMFormatDescriptionRef formDesc = (__bridge CMFormatDescriptionRef)[[track formatDescriptions] objectAtIndex:0]; + const AudioStreamBasicDescription* asbdPointer = CMAudioFormatDescriptionGetStreamBasicDescription(formDesc); + //because this is a pointer and not a struct we need to move the data into a struct so we can use it + AudioStreamBasicDescription asbd = {0}; + memcpy(&asbd, asbdPointer, sizeof(asbd)); + //asbd now contains a basic description for the track + return asbd; + +} + +- (void) setupReader +{ + + // this value represents the URL of an iPod music item, which was hardcoded to simplify this example + // to create UI to allow the user to manually pick their own music etc.. take a look at this tutorial + // 'Add Music' @ http://developer.apple.com/library/ios/#samplecode/AddMusic/Introduction/Intro.html + NSURL *assetURL = [NSURL URLWithString:@"ipod-library://item/item.m4a?id=1053020204400037178"]; + AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil]; + + // from AVAssetReader Class Reference: + // AVAssetReader is not intended for use with real-time sources, + // and its performance is not guaranteed for real-time operations. + // DON'T LISTEN TO THEM.. it seems to work fine for me + NSError * error = nil; + AVAssetReader* reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error]; + + AVAssetTrack* track = [songAsset.tracks objectAtIndex:0]; + nativeTrackASBD = [self getTrackNativeSettings:track]; + + readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track + outputSettings:nil]; + + [reader addOutput:readerOutput]; + [reader startReading]; + + +} + +- (void) setupQueue +{ + + AudioStreamBasicDescription asbd = nativeTrackASBD; + + // create a output (playback) queue + CheckError(AudioQueueNewOutput(&asbd, // ASBD + MyAQOutputCallback, // Callback + (__bridge void *)self, // user data + NULL, // run loop + NULL, // run loop mode + 0, // flags (always 0) + &queue), // output: reference to AudioQueue object + "AudioQueueNewOutput failed"); + + + // adjust buffer size to represent about a half second (0.5) of audio based on this format + CalculateBytesForTime(asbd, 0.5, &bufferByteSize, &player->numPacketsToRead); + bufferByteSize = 2048; + NSLog(@"this is buffer byte size %lu", bufferByteSize); + // bufferByteSize = 800; + + // check if we are dealing with a VBR file. ASBDs for VBR files always have + // mBytesPerPacket and mFramesPerPacket as 0 since they can fluctuate at any time. + // If we are dealing with a VBR file, we allocate memory to hold the packet descriptions + bool isFormatVBR = (asbd.mBytesPerPacket == 0 || asbd.mFramesPerPacket == 0); + if (isFormatVBR) + player.packetDescs = (AudioStreamPacketDescription*)malloc(sizeof(AudioStreamPacketDescription) * player.numPacketsToRead); + else + player.packetDescs = NULL; // we don't provide packet descriptions for constant bit rate formats (like linear PCM) + + // get magic cookie from file and set on queue + MyCopyEncoderCookieToQueue(player.playbackFile, queue); + + // allocate the buffers and prime the queue with some data before starting + player.isDone = false; + player.packetPosition = 0; + int i; + for (i = 0; i < kNumberPlaybackBuffers; ++i) + { + CheckError(AudioQueueAllocateBuffer(queue, bufferByteSize, &audioQueueBuffers[i]), "AudioQueueAllocateBuffer failed"); + + // EOF (the entire file's contents fit in the buffers) + if (player.isDone) + break; + } + + AudioSessionInitialize ( + NULL, // 'NULL' to use the default (main) run loop + NULL, // 'NULL' to use the default run loop mode + NULL, //ASAudioSessionInterruptionListenera reference to your interruption callback + NULL // data to pass to your interruption listener callback + ); + UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback; + AudioSessionSetProperty ( + kAudioSessionProperty_AudioCategory, + sizeof (sessionCategory), + &sessionCategory + ); + AudioSessionSetActive(true); + + +} + + +-(void)readVBRPackets +{ + // initialize a mutex and condition so that we can block on buffers in use. + pthread_mutex_init(&queueBuffersMutex, NULL); + pthread_cond_init(&queueBufferReadyCondition, NULL); + + state = AS_BUFFERING; + + while ((sample = [readerOutput copyNextSampleBuffer])) + { + + + Boolean isBufferDataReady = CMSampleBufferDataIsReady(sample); + + if (!isBufferDataReady) { + while (!isBufferDataReady) { + NSLog(@"buffer is not ready!"); + } + } + + CMBlockBufferRef CMBuffer = CMSampleBufferGetDataBuffer( sample ); + AudioBufferList audioBufferList; + + CheckError(CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( + sample, + NULL, + &audioBufferList, + sizeof(audioBufferList), + NULL, + NULL, + kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, + &CMBuffer + ), + "could not read sample data"); + + const AudioStreamPacketDescription * inPacketDescriptions; + size_t packetDescriptionsSizeOut; + size_t inNumberPackets; + + CheckError(CMSampleBufferGetAudioStreamPacketDescriptionsPtr(sample, + &inPacketDescriptions, + &packetDescriptionsSizeOut), + "could not read sample packet descriptions"); + + inNumberPackets = packetDescriptionsSizeOut/sizeof(AudioStreamPacketDescription); + + AudioBuffer audioBuffer = audioBufferList.mBuffers[0]; + + + for (int i = 0; i < inNumberPackets; ++i) + { + + SInt64 dataOffset = inPacketDescriptions[i].mStartOffset; + UInt32 packetSize = inPacketDescriptions[i].mDataByteSize; + + size_t packetSpaceRemaining; + packetSpaceRemaining = bufferByteSize - bytesFilled; + + // if the space remaining in the buffer is not enough for the data contained in this packet + // then just write it + if (packetSpaceRemaining < packetSize) + { + // NSLog(@"oops! packetSpaceRemaining (%zu) is smaller than datasize (%lu) SO WE WILL SHIP PACKET [%d]: (abs number %lu)", + // packetSpaceRemaining, dataSize, i, packetNumber); + + [self enqueueBuffer]; + + + // [self encapsulateAndShipPacket:packet packetDescriptions:packetDescriptions packetID:assetID]; + } + + + // copy data to the audio queue buffer + AudioQueueBufferRef fillBuf = audioQueueBuffers[fillBufferIndex]; + memcpy((char*)fillBuf->mAudioData + bytesFilled, + (const char*)(audioBuffer.mData + dataOffset), packetSize); + + + + // fill out packet description + packetDescs[packetsFilled] = inPacketDescriptions[i]; + packetDescs[packetsFilled].mStartOffset = bytesFilled; + + + bytesFilled += packetSize; + packetsFilled += 1; + + + // if this is the last packet, then ship it + size_t packetsDescsRemaining = kAQMaxPacketDescs - packetsFilled; + if (packetsDescsRemaining == 0) { + //NSLog(@"woooah! this is the last packet (%d).. so we will ship it!", i); + [self enqueueBuffer]; + // [self encapsulateAndShipPacket:packet packetDescriptions:packetDescriptions packetID:assetID]; + } + } + } + +} + +-(void)readCBRPackets +{ + + // initialize a mutex and condition so that we can block on buffers in use. + pthread_mutex_init(&queueBuffersMutex, NULL); + pthread_cond_init(&queueBufferReadyCondition, NULL); + + state = AS_BUFFERING; + + while ((sample = [readerOutput copyNextSampleBuffer])) { + + AudioBufferList audioBufferList; + CMBlockBufferRef CMBuffer = CMSampleBufferGetDataBuffer( sample ); + + CheckError(CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( + sample, + NULL, + &audioBufferList, + sizeof(audioBufferList), + NULL, + NULL, + kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, + &CMBuffer + ), + "could not read samples"); + + AudioBuffer audioBuffer = audioBufferList.mBuffers[0]; + + UInt32 inNumberBytes = audioBuffer.mDataByteSize; + /* NSData *bufContent = [NSData dataWithBytes:audioBuffer.mData length:audioBuffer.mDataByteSize]; + NSLog(@"this is bufcontent %@",bufContent); + NSLog(@"\n\n\n"); + NSLog(@":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"); + */ + + + size_t incomingDataOffset = 0; + + + while (inNumberBytes) { + size_t bufSpaceRemaining; + bufSpaceRemaining = bufferByteSize - bytesFilled; + + @synchronized(self) + { + bufSpaceRemaining = bufferByteSize - bytesFilled; + size_t copySize; + + if (bufSpaceRemaining < inNumberBytes) + { + copySize = bufSpaceRemaining; + } + else + { + copySize = inNumberBytes; + } + + + // copy data to the audio queue buffer + AudioQueueBufferRef fillBuf = audioQueueBuffers[fillBufferIndex]; + memcpy((char*)fillBuf->mAudioData + (bytesFilled), + (const char*)(audioBuffer.mData + (incomingDataOffset)), copySize); + + // keep track of bytes filled + bytesFilled +=copySize; + incomingDataOffset +=copySize; + inNumberBytes -=copySize; + } + + // if the space remaining in the buffer is not enough for this packet, then enqueue the buffer. + if (bufSpaceRemaining < inNumberBytes + bytesFilled) + { + [self enqueueBuffer]; + } + + } + } + + + + } -- (void)applicationWillResignActive:(UIApplication *)application +-(void)enqueueBuffer { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + @synchronized(self) + { + + inuse[fillBufferIndex] = true; // set in use flag + buffersUsed++; + + // enqueue buffer + AudioQueueBufferRef fillBuf = audioQueueBuffers[fillBufferIndex]; + fillBuf->mAudioDataByteSize = bytesFilled; + + + /*NSData *bufContent = [NSData dataWithBytes:fillBuf->mAudioData length:fillBuf->mAudioDataByteSize]; + NSLog(@"we are enquing the queue with buffer (length: %lu) %@",fillBuf->mAudioDataByteSize,bufContent); + NSLog(@"\n\n\n"); + NSLog(@":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::");*/ + + if (packetsFilled) + { + /* NSLog(@"\n\n\n\n\n\n"); + NSLog(@":::::: we are enqueuing buffer with %zu packtes!",packetsFilled); + NSLog(@"buffer data is %@",[NSData dataWithBytes:fillBuf->mAudioData length:fillBuf->mAudioDataByteSize]); + + for (int i = 0; i < packetsFilled; i++) + { + NSLog(@"\THIS IS THE PACKET WE ARE COPYING TO AUDIO BUFFER----------------\n"); + NSLog(@"this is packetDescriptionArray.mStartOffset: %lld", packetDescs[i].mStartOffset); + NSLog(@"this is packetDescriptionArray.mVariableFramesInPacket: %lu", packetDescs[i].mVariableFramesInPacket); + NSLog(@"this is packetDescriptionArray[.mDataByteSize: %lu", packetDescs[i].mDataByteSize); + NSLog(@"\n----------------\n"); + } + */ + + + err = AudioQueueEnqueueBuffer(queue, fillBuf, packetsFilled, packetDescs); + } + else + { + NSLog(@":::::: we are enqueuing buffer with fillBufIndex %d, and bytes %zu", fillBufferIndex, bytesFilled); + + //NSLog(@"enqueue buffer thread name %@", [NSThread currentThread].name); + err = AudioQueueEnqueueBuffer(queue, fillBuf, 0, NULL); + } + + if (err) + { + NSLog(@"could not enqueue queue with buffer"); + return; + } + + + if (state == AS_BUFFERING) + { + // + // Fill all the buffers before starting. This ensures that the + // AudioFileStream stays a small amount ahead of the AudioQueue to + // avoid an audio glitch playing streaming files on iPhone SDKs < 3.0 + // + if (buffersUsed == kNumberPlaybackBuffers - 1) + { + NSLog(@"STARTING THE QUEUE"); + err = AudioQueueStart(queue, NULL); + if (err) + { + NSLog(@"couldn't start queue"); + return; + } + state = AS_PLAYING; + } + } + + // go to next buffer + if (++fillBufferIndex >= kNumberPlaybackBuffers) fillBufferIndex = 0; + bytesFilled = 0; // reset bytes filled + packetsFilled = 0; // reset packets filled + + } + + // wait until next buffer is not in use + pthread_mutex_lock(&queueBuffersMutex); + while (inuse[fillBufferIndex]) + { + pthread_cond_wait(&queueBufferReadyCondition, &queueBuffersMutex); + } + pthread_mutex_unlock(&queueBuffersMutex); + + } -- (void)applicationDidEnterBackground:(UIApplication *)application + +#pragma mark - utility functions - + +// generic error handler - if err is nonzero, prints error message and exits program. +static void CheckError(OSStatus error, const char *operation) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + if (error == noErr) return; + + char str[20]; + // see if it appears to be a 4-char-code + *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error); + if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) { + str[0] = str[5] = '\''; + str[6] = '\0'; + } else + // no, format it as an integer + sprintf(str, "%d", (int)error); + + fprintf(stderr, "Error: %s (%s)\n", operation, str); + + exit(1); } -- (void)applicationWillEnterForeground:(UIApplication *)application +// we only use time here as a guideline +// we're really trying to get somewhere between 16K and 64K buffers, but not allocate too much if we don't need it/* +void CalculateBytesForTime(AudioStreamBasicDescription inDesc, Float64 inSeconds, UInt32 *outBufferSize, UInt32 *outNumPackets) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + + // we need to calculate how many packets we read at a time, and how big a buffer we need. + // we base this on the size of the packets in the file and an approximate duration for each buffer. + // + // first check to see what the max size of a packet is, if it is bigger than our default + // allocation size, that needs to become larger + + // we don't have access to file packet size, so we just default it to maxBufferSize + UInt32 maxPacketSize = 0x10000; + + static const int maxBufferSize = 0x10000; // limit size to 64K + static const int minBufferSize = 0x4000; // limit size to 16K + + if (inDesc.mFramesPerPacket) { + Float64 numPacketsForTime = inDesc.mSampleRate / inDesc.mFramesPerPacket * inSeconds; + *outBufferSize = numPacketsForTime * maxPacketSize; + } else { + // if frames per packet is zero, then the codec has no predictable packet == time + // so we can't tailor this (we don't know how many Packets represent a time period + // we'll just return a default buffer size + *outBufferSize = maxBufferSize > maxPacketSize ? maxBufferSize : maxPacketSize; + } + + // we're going to limit our size to our default + if (*outBufferSize > maxBufferSize && *outBufferSize > maxPacketSize) + *outBufferSize = maxBufferSize; + else { + // also make sure we're not too small - we don't want to go the disk for too small chunks + if (*outBufferSize < minBufferSize) + *outBufferSize = minBufferSize; + } + *outNumPackets = *outBufferSize / maxPacketSize; +} + +// many encoded formats require a 'magic cookie'. if the file has a cookie we get it +// and configure the queue with it +static void MyCopyEncoderCookieToQueue(AudioFileID theFile, AudioQueueRef queue ) { + UInt32 propertySize; + OSStatus result = AudioFileGetPropertyInfo (theFile, kAudioFilePropertyMagicCookieData, &propertySize, NULL); + if (result == noErr && propertySize > 0) + { + Byte* magicCookie = (UInt8*)malloc(sizeof(UInt8) * propertySize); + CheckError(AudioFileGetProperty (theFile, kAudioFilePropertyMagicCookieData, &propertySize, magicCookie), "get cookie from file failed"); + CheckError(AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, magicCookie, propertySize), "set cookie on queue failed"); + free(magicCookie); + } } -- (void)applicationDidBecomeActive:(UIApplication *)application + +#pragma mark - audio queue - + + +static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + AppDelegate *appDelegate = (__bridge AppDelegate *) inUserData; + [appDelegate myCallback:inUserData + inAudioQueue:inAQ + audioQueueBufferRef:inCompleteAQBuffer]; + } -- (void)applicationWillTerminate:(UIApplication *)application + +- (void)myCallback:(void *)userData + inAudioQueue:(AudioQueueRef)inAQ +audioQueueBufferRef:(AudioQueueBufferRef)inCompleteAQBuffer { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + + unsigned int bufIndex = -1; + for (unsigned int i = 0; i < kNumberPlaybackBuffers; ++i) + { + if (inCompleteAQBuffer == audioQueueBuffers[i]) + { + bufIndex = i; + break; + } + } + + if (bufIndex == -1) + { + NSLog(@"something went wrong at queue callback"); + return; + } + + // signal waiting thread that the buffer is free. + pthread_mutex_lock(&queueBuffersMutex); + + NSLog(@"in call back and we are freeing buf index %d", bufIndex); + inuse[bufIndex] = false; + buffersUsed--; + + pthread_cond_signal(&queueBufferReadyCondition); + pthread_mutex_unlock(&queueBuffersMutex); } + + @end