Ejemplo n.º 1
0
//	Actions
	void Start()
	{
		if(mPThread != 0)
		{
			printf("OpenALThread::Start: can't start because the thread is already running\n");
			return;
		}

		OSStatus			result;
		pthread_attr_t		theThreadAttributes;
		
		result = pthread_attr_init(&theThreadAttributes);
			AssertNoError("Error initializing thread", end);
		
		result = pthread_attr_setdetachstate(&theThreadAttributes, PTHREAD_CREATE_DETACHED);
			AssertNoError("Error setting thread detach state", end);
				
		result = pthread_create(&mPThread, &theThreadAttributes, (ThreadRoutine)OpenALThread::Entry, this);
			AssertNoError("Error creating thread", end);
		
		pthread_attr_destroy(&theThreadAttributes);
			AssertNoError("Error destroying thread attributes", end);
end:
		return;
	}
Ejemplo n.º 2
0
		OSStatus LoadTrack(const char* inFilePath, Boolean inAddToQueue, Boolean inLoadAtOnce)
		{
			BG_FileInfo *fileInfo = new BG_FileInfo;
			fileInfo->mFilePath = inFilePath;
			OSStatus result = LoadFileDataInfo(fileInfo->mFilePath, fileInfo->mAFID, fileInfo->mFileFormat, fileInfo->mFileDataSize);
				AssertNoError("Error getting file data info", fail);
			fileInfo->mLoadAtOnce = inLoadAtOnce;
			fileInfo->mFileDataInQueue = false;
			// if not adding to the queue, clear the current file vector
			if (!inAddToQueue)
				mBGFileInfo.clear();
				
			mBGFileInfo.push_back(fileInfo);
			
			// setup the queue if this is the first (or only) file
			if (mBGFileInfo.size() == 1)
			{
				result = SetupQueue(fileInfo);
					AssertNoError("Error setting up queue", fail);
				result = SetupBuffers(fileInfo);
					AssertNoError("Error setting up queue buffers", fail);					
			}
			// if this is just part of the playlist, close the file for now
			else
			{
				result = AudioFileClose(fileInfo->mAFID);
					AssertNoError("Error closing file", fail);
			}	
			return result;
		
		fail:
			if (fileInfo)
				delete fileInfo;
			return result;
		}
Ejemplo n.º 3
0
		OSStatus SetupBuffers(BG_FileInfo *inFileInfo)
		{
			int numBuffersToQueue = kNumberBuffers;
			UInt32 maxPacketSize;
			UInt32 size = sizeof(maxPacketSize);
			// 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 allocation default size, that needs to become larger
			OSStatus result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
				AssertNoError("Error getting packet upper bound size", end);
			bool isFormatVBR = (inFileInfo->mFileFormat.mBytesPerPacket == 0 || inFileInfo->mFileFormat.mFramesPerPacket == 0);

			CalculateBytesForTime(inFileInfo->mFileFormat, maxPacketSize, 0.5/*seconds*/, &mBufferByteSize, &mNumPacketsToRead);
			
			// if the file is smaller than the capacity of all the buffer queues, always load it at once
			if ((mBufferByteSize * numBuffersToQueue) > inFileInfo->mFileDataSize)
				inFileInfo->mLoadAtOnce = true;
				
			if (inFileInfo->mLoadAtOnce)
			{
				UInt64 theFileNumPackets;
				size = sizeof(UInt64);
				result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyAudioDataPacketCount, &size, &theFileNumPackets);
					AssertNoError("Error getting packet count for file", end);
				
				mNumPacketsToRead = (UInt32)theFileNumPackets;
				mBufferByteSize = inFileInfo->mFileDataSize;
				numBuffersToQueue = 1;
			}	
			else
			{
				mNumPacketsToRead = mBufferByteSize / maxPacketSize;
			}
			
			if (isFormatVBR)
				mPacketDescs = new AudioStreamPacketDescription [mNumPacketsToRead];
			else
				mPacketDescs = NULL; // we don't provide packet descriptions for constant bit rate formats (like linear PCM)	
				
			// allocate the queue's buffers
			for (int i = 0; i < numBuffersToQueue; ++i) 
			{
				result = AudioQueueAllocateBuffer(mQueue, mBufferByteSize, &mBuffers[i]);
					AssertNoError("Error allocating buffer for queue", end);
				QueueCallback (this, mQueue, mBuffers[i]);
				if (inFileInfo->mLoadAtOnce)
					inFileInfo->mFileDataInQueue = true;
			}
		
		//end:
			return result;
		}
Ejemplo n.º 4
0
void	HP_Stream::PropertiesChanged(UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[]) const
{
	//	note that we need to be sure that the object state mutex is not held while we call the listeners
	bool ownsStateMutex = false;
	CAMutex* theObjectStateMutex = const_cast<HP_Object*>(this)->GetObjectStateMutex();
	if(theObjectStateMutex != NULL)
	{
		ownsStateMutex = theObjectStateMutex->IsOwnedByCurrentThread();
		if(ownsStateMutex)
		{
			theObjectStateMutex->Unlock();
		}
	}
		
	for(UInt32 theIndex = 0; theIndex < inNumberAddresses; ++theIndex)
	{
		OSStatus theError = AudioHardwareStreamPropertyChanged(mPlugIn->GetInterface(), mOwningDevice->GetObjectID(), mObjectID, inAddresses[theIndex].mElement, inAddresses[theIndex].mSelector);
		AssertNoError(theError, "HP_Stream::PropertiesChanged: got an error calling the input listeners");
	}
		
	//	re-lock the mutex
	if((theObjectStateMutex != NULL) && ownsStateMutex)
	{
		theObjectStateMutex->Lock();
	}
}
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// DeviceRemoved()
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	void PlugIn::DeviceRemoved(Device& device)
	{
		// Suspend the device
		device.Unplug();

		// Save it's settings if necessary
		if (DALA::System::IsMaster())
			DP::DeviceSettings::SaveToPrefs(device, DP::DeviceSettings::sStandardControlsToSave, DP::DeviceSettings::kStandardNumberControlsToSave);

		{
			// Unlock the mutex since CMIOObjectsPublishedAndDied() can callout to property listeners
			CAMutex::Unlocker unlocker(GetStateMutex());

			// Tell the DAL that the device has gone away
			CMIOObjectID objectID = device.GetObjectID();
			OSStatus err = CMIOObjectsPublishedAndDied(GetInterface(), kCMIOObjectSystemObject, 0, 0, 1, &objectID);
			AssertNoError(err, "CMIO::DP::Sample::PlugIn::Teardown: got an error telling the DAL a device died");
		}
						
		// Remove it from the device list
		RemoveDevice(device);

		// Get rid of the device object
		device.Teardown();
		delete &device;
	}
Ejemplo n.º 6
0
OSStatus LoadFileDataInfo(const char *inFilePath, AudioFileID &outAFID, AudioStreamBasicDescription &outFormat, UInt64 &outDataSize)
{
	UInt32 thePropSize = sizeof(outFormat);				
	OSStatus result = OpenFile(inFilePath, outAFID);
		AssertNoError("Error opening file", end);

	result = AudioFileGetProperty(outAFID, kAudioFilePropertyDataFormat, &thePropSize, &outFormat);
		AssertNoError("Error getting file format", end);
	
	thePropSize = sizeof(UInt64);
	result = AudioFileGetProperty(outAFID, kAudioFilePropertyAudioDataByteCount, &thePropSize, &outDataSize);
		AssertNoError("Error getting file data size", end);

end:
	return result;
}
Ejemplo n.º 7
0
void	SHP_PlugIn::Teardown()
{
	//  first figure out if this is being done as part of the process being torn down
	UInt32 isInitingOrExiting = 0;
	UInt32 theSize = sizeof(UInt32);
	AudioHardwareGetProperty(kAudioHardwarePropertyIsInitingOrExiting, &theSize, &isInitingOrExiting);

	//  next figure out if this is the master process
	UInt32 isMaster = 0;
	theSize = sizeof(UInt32);
	AudioHardwareGetProperty(kAudioHardwarePropertyProcessIsMaster, &theSize, &isMaster);

	//  do the full teardown if this is outside of the process being torn down or this is the master process
	if((isInitingOrExiting == 0) || (isMaster != 0))
	{
		//	stop all IO on the device
		mDevice->Do_StopAllIOProcs();
		
		//	send the necessary IsAlive notifications
		CAPropertyAddress theIsAliveAddress(kAudioDevicePropertyDeviceIsAlive);
		mDevice->PropertiesChanged(1, &theIsAliveAddress);
		
		//	save it's settings if necessary
		if(isMaster != 0)
		{
			HP_DeviceSettings::SaveToPrefs(*mDevice, HP_DeviceSettings::sStandardControlsToSave, HP_DeviceSettings::kStandardNumberControlsToSave);
		}

		//	tell the HAL that the device has gone away
		AudioObjectID theObjectID = mDevice->GetObjectID();
#if	(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4)
		OSStatus theError = AudioHardwareDevicesDied(GetInterface(), 1, &theObjectID);
#else
		OSStatus theError = AudioObjectsPublishedAndDied(GetInterface(), kAudioObjectSystemObject, 0, NULL, 1, &theObjectID);
#endif
		AssertNoError(theError, "SHP_PlugIn::Teardown: got an error telling the HAL a device died");
		
		//	remove the object state mutex
		HP_Object::SetObjectStateMutexForID(theObjectID, NULL);

		//  toss it
		mDevice->Teardown();
		delete mDevice;
		mDevice = NULL;

		//	teardown the super class
		HP_HardwarePlugIn::Teardown();
	}
	else
	{
		//  otherwise, only stop the IOProcs
		mDevice->Do_StopAllIOProcs();
		
		//	finalize (rather than tear down) the devices
		mDevice->Finalize();
		
		//	and leave the rest to die with the process
	}
}
Ejemplo n.º 8
0
		static OSStatus AttachNewCookie(AudioQueueRef inQueue, BackgroundTrackMgr::BG_FileInfo *inFileInfo)
		{
			OSStatus result = noErr;
			UInt32 size = sizeof(UInt32);
			result = AudioFileGetPropertyInfo (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, NULL);
			if (!result && size) 
			{
				char* cookie = new char [size];		
				result = AudioFileGetProperty (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, cookie);
					AssertNoError("Error getting cookie data", end);
				result = AudioQueueSetProperty(inQueue, kAudioQueueProperty_MagicCookie, cookie, size);
				delete [] cookie;
					AssertNoError("Error setting cookie data for queue", end);
			}
			return noErr;
		
		end:
			return noErr;
		}
Ejemplo n.º 9
0
		static void QueueStoppedProc(	void *                  inUserData,
										AudioQueueRef           inAQ,
										AudioQueuePropertyID    inID)
		{
			UInt32 isRunning;
			UInt32 propSize = sizeof(isRunning);

			BackgroundTrackMgr *THIS = (BackgroundTrackMgr*)inUserData;
			OSStatus result = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &isRunning, &propSize);
				
			if ((!isRunning) && (THIS->mMakeNewQueueWhenStopped))
			{
				result = AudioQueueDispose(inAQ, true);
					AssertNoError("Error disposing queue", end);
				result = THIS->SetupQueue(CurFileInfo);
					AssertNoError("Error setting up new queue", end);
				result = THIS->SetupBuffers(CurFileInfo);
					AssertNoError("Error setting up new queue buffers", end);
				result = THIS->Start();
					AssertNoError("Error starting queue", end);
			}
		end:
			return;
		}
Ejemplo n.º 10
0
void	ZKMORHP_ForeignThread::SetPriority(UInt32 inPriority, bool inFixedPriority)
{
	mPriority = inPriority;
	mTimeConstraintSet = false;
	mFixedPriority = inFixedPriority;
#if TARGET_OS_MAC
	if(mPThread != 0)
	{
		
		if (mFixedPriority)
		{
			thread_extended_policy_data_t		theFixedPolicy;
			theFixedPolicy.timeshare = false;	// set to true for a non-fixed thread
			AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT), "ZKMORHP_ForeignThread::SetPriority: failed to set the fixed-priority policy");
		}
        // We keep a reference to the spawning thread's priority around (initialized in the constructor), 
        // and set the importance of the child thread relative to the spawning thread's priority.
        thread_precedence_policy_data_t		thePrecedencePolicy;
        
        thePrecedencePolicy.importance = mPriority - mSpawningThreadPriority;
        AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT), "ZKMORHP_ForeignThread::SetPriority: failed to set the precedence policy");
    } 
#endif
}
Ejemplo n.º 11
0
//==================================================================================================
//	Helper functions
//==================================================================================================
OSStatus OpenFile(const char *inFilePath, AudioFileID &outAFID)
{
	
	CFURLRef theURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)inFilePath, strlen(inFilePath), false);
	if (theURL == NULL)
		return kSoundEngineErrFileNotFound;

#if TARGET_OS_IPHONE
	OSStatus result = AudioFileOpenURL(theURL, kAudioFileReadPermission, 0, &outAFID);
#else
	OSStatus result = AudioFileOpenURL(theURL, fsRdPerm, 0, &outAFID);
#endif
	CFRelease(theURL);
		AssertNoError("Error opening file", end);
	end:
		return result;
}
Ejemplo n.º 12
0
void	ZKMORHP_ForeignThread::SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible)
{
	mPeriod = inPeriod;
	mComputation = inComputation;
	mConstraint = inConstraint;
	mIsPreemptible = inIsPreemptible;
	mTimeConstraintSet = true;
#if TARGET_OS_MAC
	if(mPThread != 0)
	{
		thread_time_constraint_policy_data_t thePolicy;
		thePolicy.period = mPeriod;
		thePolicy.computation = mComputation;
		thePolicy.constraint = mConstraint;
		thePolicy.preemptible = mIsPreemptible;
		AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&thePolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT), "ZKMORHP_ForeignThread::SetTimeConstraints: thread_policy_set failed");
	}
#endif
}
Ejemplo n.º 13
0
void	SHP_PlugIn::InitializeWithObjectID(AudioObjectID inObjectID)
{
	//	initialize the super class
	HP_HardwarePlugIn::InitializeWithObjectID(inObjectID);
	
	//	instantiate a new AudioDevice object in the HAL
	AudioDeviceID theNewDeviceID = 0;
#if	(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4)
	OSStatus theError = AudioHardwareClaimAudioDeviceID(GetInterface(), &theNewDeviceID);
#else
	OSStatus theError = AudioObjectCreate(GetInterface(), kAudioObjectSystemObject, kAudioDeviceClassID, &theNewDeviceID);
#endif
	ThrowIfError(theError, CAException(theError), "SHP_PlugIn::InitializeWithObjectID: couldn't instantiate the AudioDevice object");
	
	//	make a device object
	mDevice = new SHP_Device(theNewDeviceID, this);
	mDevice->Initialize();
	
	//	restore it's settings if necessary
	UInt32 isMaster = 0;
	UInt32 theSize = sizeof(UInt32);
	AudioHardwareGetProperty(kAudioHardwarePropertyProcessIsMaster, &theSize, &isMaster);
	if(isMaster != 0)
	{
		HP_DeviceSettings::RestoreFromPrefs(*mDevice, HP_DeviceSettings::sStandardControlsToSave, HP_DeviceSettings::kStandardNumberControlsToSave);
	}

	//	set the object state mutex
	HP_Object::SetObjectStateMutexForID(theNewDeviceID, mDevice->GetObjectStateMutex());

	//	tell the HAL about the device
#if	(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4)
	theError = AudioHardwareDevicesCreated(GetInterface(), 1, &theNewDeviceID);
#else
	theError = AudioObjectsPublishedAndDied(GetInterface(), kAudioObjectSystemObject, 1, &theNewDeviceID, 0, NULL);
#endif
	AssertNoError(theError, "SHP_PlugIn::InitializeWithObjectID: got an error telling the HAL a device died");
}
Ejemplo n.º 14
0
		OSStatus LoadFileData(const char *inFilePath, void* &outData, UInt32 &outDataSize, ALuint &outBufferID)
		{
			AudioFileID theAFID = 0;
			OSStatus result = noErr;
			UInt64 theFileSize = 0;
			AudioStreamBasicDescription theFileFormat;
			
			result = LoadFileDataInfo(inFilePath, theAFID, theFileFormat, theFileSize);
			outDataSize = (UInt32)theFileSize;
				AssertNoError("Error loading file info", fail)

			outData = malloc(outDataSize);

			result = AudioFileReadBytes(theAFID, false, 0, &outDataSize, outData);
				AssertNoError("Error reading file data", fail)
				
			if (!TestAudioFormatNativeEndian(theFileFormat) && (theFileFormat.mBitsPerChannel > 8)) 
				return kSoundEngineErrInvalidFileFormat;
		
			alGenBuffers(1, &outBufferID);
				AssertNoOALError("Error generating buffer\n", fail);
			
			alBufferDataStaticProc(outBufferID, GetALFormat(theFileFormat), outData, outDataSize, theFileFormat.mSampleRate);
				AssertNoOALError("Error attaching data to buffer\n", fail);

			AudioFileClose(theAFID);
			return result;
			
		fail:			
			if (theAFID)
				AudioFileClose(theAFID);
			if (outData)
			{
				free(outData);
				outData = NULL;
			}
			return result;
		}
Ejemplo n.º 15
0
void	HP_Object::PropertiesChanged(UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[]) const
{
	//	note that we need to be sure that the object state mutex is not held while we call the listeners
	bool ownsStateMutex = false;
	CAMutex* theObjectStateMutex = const_cast<HP_Object*>(this)->GetObjectStateMutex();
	if(theObjectStateMutex != NULL)
	{
		ownsStateMutex = theObjectStateMutex->IsOwnedByCurrentThread();
		if(ownsStateMutex)
		{
			theObjectStateMutex->Unlock();
		}
	}
		
	OSStatus theError = AudioObjectPropertiesChanged(mPlugIn->GetInterface(), mObjectID, inNumberAddresses, inAddresses);
	AssertNoError(theError, "HP_Object::PropertiesChanged: got an error calling the listeners");
		
	//	re-lock the mutex
	if((theObjectStateMutex != NULL) && ownsStateMutex)
	{
		theObjectStateMutex->Lock();
	}
}
Ejemplo n.º 16
0
void	CAPThread::SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible)
{
	mPeriod = inPeriod;
	mComputation = inComputation;
	mConstraint = inConstraint;
	mIsPreemptible = inIsPreemptible;
	mTimeConstraintSet = true;
#if TARGET_OS_MAC
	if(mPThread != 0)
	{
		thread_time_constraint_policy_data_t thePolicy;
		thePolicy.period = mPeriod;
		thePolicy.computation = mComputation;
		thePolicy.constraint = mConstraint;
		thePolicy.preemptible = mIsPreemptible;
		AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&thePolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT), "CAPThread::SetTimeConstraints: thread_policy_set failed");
	}
#elif TARGET_OS_WIN32
	if(mThreadHandle != NULL)
	{
		SetThreadPriority(mThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
	}
#endif
}
Ejemplo n.º 17
0
		OSStatus SetupQueue(BG_FileInfo *inFileInfo)
		{
			UInt32 size = 0;
			OSStatus result = AudioQueueNewOutput(&inFileInfo->mFileFormat, QueueCallback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue);
					AssertNoError("Error creating queue", end);

			// (2) If the file has a cookie, we should get it and set it on the AQ
			size = sizeof(UInt32);
			result = AudioFileGetPropertyInfo (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, NULL);

			if (!result && size) {
				char* cookie = new char [size];		
				result = AudioFileGetProperty (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, cookie);
					AssertNoError("Error getting magic cookie", end);
				result = AudioQueueSetProperty(mQueue, kAudioQueueProperty_MagicCookie, cookie, size);
				delete [] cookie;
					AssertNoError("Error setting magic cookie", end);
			}

			// channel layout
			OSStatus err = AudioFileGetPropertyInfo(inFileInfo->mAFID, kAudioFilePropertyChannelLayout, &size, NULL);
			if (err == noErr && size > 0) {
				AudioChannelLayout *acl = (AudioChannelLayout *)malloc(size);
				result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyChannelLayout, &size, acl);
					AssertNoError("Error getting channel layout from file", end);
				result = AudioQueueSetProperty(mQueue, kAudioQueueProperty_ChannelLayout, acl, size);
				free(acl);
					AssertNoError("Error setting channel layout on queue", end);
			}
			
			// add a notification proc for when the queue stops
			result = AudioQueueAddPropertyListener(mQueue, kAudioQueueProperty_IsRunning, QueueStoppedProc, this);
				AssertNoError("Error adding isRunning property listener to queue", end);
				
			// we need to reset this variable so that if the queue is stopped mid buffer we don't dispose it 
			mMakeNewQueueWhenStopped = false;
			
			// volume
			result = SetVolume(mVolume);
			
		//end:
			return result;
		}
Ejemplo n.º 18
0
		static void QueueCallback(	void *					inUserData,
									AudioQueueRef			inAQ,
									AudioQueueBufferRef		inCompleteAQBuffer) 
		{
			// dispose of the buffer if no longer in use
			OSStatus result = noErr;
			BackgroundTrackMgr *THIS = (BackgroundTrackMgr*)inUserData;
			if (DisposeBuffer(inAQ, THIS->mBuffersToDispose, inCompleteAQBuffer))
				return;
			
			UInt32 nPackets = 0;
			// loop the current buffer if the following:
			// 1. file was loaded into the buffer previously
			// 2. only one file in the queue
			// 3. we have not been told to stop at playlist completion
			if ((CurFileInfo->mFileDataInQueue) && (THIS->mBGFileInfo.size() == 1) && (!THIS->mStopAtEnd))
				nPackets = THIS->GetNumPacketsToRead(CurFileInfo);

			else
			{
				UInt32 numBytes;
				while (nPackets == 0)
				{
					// if loadAtOnce, get all packets in the file, otherwise ~.5 seconds of data
					nPackets = THIS->GetNumPacketsToRead(CurFileInfo);					
					result = AudioFileReadPackets(CurFileInfo->mAFID, false, &numBytes, THIS->mPacketDescs, THIS->mCurrentPacket, &nPackets, 
											inCompleteAQBuffer->mAudioData);
						AssertNoError("Error reading file data", end);
					
					inCompleteAQBuffer->mAudioDataByteSize = numBytes;	
											
					if (nPackets == 0) // no packets were read, this file has ended.
					{
						if (CurFileInfo->mLoadAtOnce)
							CurFileInfo->mFileDataInQueue = true;
						
						THIS->mCurrentPacket = 0;
						UInt32 theNextFileIndex = (THIS->mCurrentFileIndex < THIS->mBGFileInfo.size()-1) ? THIS->mCurrentFileIndex+1 : 0;
						
						// we have gone through the playlist. if mStopAtEnd, stop the queue here
						if (theNextFileIndex == 0 && THIS->mStopAtEnd)
						{
							result = AudioQueueStop(inAQ, false);
								AssertNoError("Error stopping queue", end);
							return;
						}
						
						SInt8 theQueueState = GetQueueStateForNextBuffer(CurFileInfo, THIS->mBGFileInfo[theNextFileIndex]);
						if (theNextFileIndex != THIS->mCurrentFileIndex)
						{
							// if were are not looping the same file. Close the old one and open the new
							result = AudioFileClose(CurFileInfo->mAFID);
								AssertNoError("Error closing file", end);
							THIS->mCurrentFileIndex = theNextFileIndex;

							result = LoadFileDataInfo(CurFileInfo->mFilePath, CurFileInfo->mAFID, CurFileInfo->mFileFormat, CurFileInfo->mFileDataSize);
								AssertNoError("Error opening file", end);
						}
						
						switch (theQueueState) 
						{							
							// if we need to resize the buffer, set the buffer's audio data size to the new file's size
							// we will also need to get the new file cookie
							case kQueueState_ResizeBuffer:
								inCompleteAQBuffer->mAudioDataByteSize = CurFileInfo->mFileDataSize;							
							// if the data format is the same but we just need a new cookie, attach a new cookie
							case kQueueState_NeedNewCookie:
								result = AttachNewCookie(inAQ, CurFileInfo);
									AssertNoError("Error attaching new file cookie data to queue", end);
								break;
							
							// we can keep the same queue, but not the same buffer(s)
							case kQueueState_NeedNewBuffers:
								THIS->mBuffersToDispose.push_back(inCompleteAQBuffer);
								THIS->SetupBuffers(CurFileInfo);
								break;
							
							// if the data formats are not the same, we need to dispose the current queue and create a new one
							case kQueueState_NeedNewQueue:
								THIS->mMakeNewQueueWhenStopped = true;
								result = AudioQueueStop(inAQ, false);
									AssertNoError("Error stopping queue", end);
								return;
								
							default:
								break;
						}
					}
				}
			}
			
			result = AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, (THIS->mPacketDescs ? nPackets : 0), THIS->mPacketDescs);
				AssertNoError("Error enqueuing new buffer", end);
			if (CurFileInfo->mLoadAtOnce)
				CurFileInfo->mFileDataInQueue = true;
				
			THIS->mCurrentPacket += nPackets;
		
		end:
			return;
		}