//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// Teardown()
	//	This is invoked when the DAL is torn down by CMIOHardwareUnload().  If the process quits or crashes, the DAL just vanishes.
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	void PlugIn::Teardown()
	{
		// Grab the muxtex for the plugIn's state
		CAMutex::Locker locker(GetStateMutex());
		
		// Cancel the dispatch source for the device event notifications
		if (NULL != mDeviceEventDispatchSource)
		{
			dispatch_source_cancel(mDeviceEventDispatchSource);
			dispatch_release(mDeviceEventDispatchSource);
			mDeviceEventDispatchSource = NULL;
		}

		// Do the full teardown if this is outside of the process being torn down or this is the master process
		if (not DALA::System::IsInitingOrExiting() or DALA::System::IsMaster())
		{
			// Teardown all the devices currently being managed
			while (0 != GetNumberDevices())
				DeviceRemoved(*static_cast<Device*>(GetDeviceByIndex(0)));
			
			// Teardown the super class
			DP::PlugIn::Teardown();
		}
		else
		{
			// Iterate over the devices and suspend and finalize them
			for (UInt32 i = 0 ; i < GetNumberDevices() ; ++i)
			{
				Device* device = static_cast<Device*>(GetDeviceByIndex(i));
				
				// Suspend the device
				device->Unplug();
				
				// Finalize (rather than teardown) the device
				device->Finalize();
			}
			
			// Teardown the super class
			DP::PlugIn::Teardown();
			
			// And leave the rest to die with the process...
		}
	}
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// UpdateDeviceStates()
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	void PlugIn::UpdateDeviceStates() 
	{
		// Get the current state of all the devices plugged in from the SampleAssistant
		DPA::Sample::AutoFreeUnboundedArray<DPA::Sample::DeviceState> deviceStates;
		DPA::Sample::GetDeviceStates(mAssistantPort, mDeviceEventPort->GetMachPort(), deviceStates);
		
		// Determine how many devices have been removed (if any).
		// This will be done by iterating over all the devices the PlugIn knows about and making sure they are present in the deviceStates array
		{
			std::vector<Device*> removedDevices;

			for (UInt32 i = 0 ; i < GetNumberDevices() ; ++i)
			{
				Device* device = static_cast<Device*>(GetDeviceByIndex(i));
				bool found = false;
				
				// See if it can be located in the deviceStates array
				for (UInt32 ii = 0; ii < deviceStates.GetLength() ; ++ii)
				{
					if (deviceStates[ii].mGUID == device->GetDeviceGUID())
					{
						found = true;
						break;
					}
				}
				
				// If the device was not found, stick into the vector of unplugged devices
				if (not found)
					removedDevices.push_back(device);
			}
			
			// Remove all the unplugged devices
			for (std::vector<Device*>::iterator i = removedDevices.begin() ; i != removedDevices.end() ; ++i)
				DeviceRemoved(**i);
		}

		// Determine how many new devices are present
		{
			for (UInt32 i = 0; i < deviceStates.GetLength() ; ++i)
			{
				try
				{
					// This will throw an exception if the device is not found
					(void) GetDeviceByGUID(deviceStates[i].mGUID);
				}
				catch (...)
				{
					// No device was found with the indicated GUID, so it is a new device
					DeviceArrived(deviceStates[i].mGUID, deviceStates[i].mRegistryPath);
				}
			}
		}
	}
AudioDeviceID	CAAudioHardwareSystem::GetDeviceAtIndex(UInt32 inIndex)
{
	AudioDeviceID theAnswer = 0;
	UInt32 theNumberDevices = GetNumberDevices();
	if((theNumberDevices > 0) && (inIndex < theNumberDevices))
	{
		CAAutoArrayDelete<AudioDeviceID> theDeviceList(theNumberDevices);
		UInt32 theSize = theNumberDevices * sizeof(AudioDeviceID);
		GetPropertyData(kAudioHardwarePropertyDevices, theSize, theDeviceList);
		theAnswer = theDeviceList[inIndex];
	}
	return theAnswer;
}
UInt32	CAAudioHardwareSystem::GetIndexForDevice(const AudioDeviceID inDevice)
{
	UInt32 theAnswer = 0xFFFFFFFF;
	UInt32 theNumberDevices = GetNumberDevices();
	if(theNumberDevices > 0)
	{
		CAAutoArrayDelete<AudioDeviceID> theDeviceList(theNumberDevices);
		UInt32 theSize = theNumberDevices * sizeof(AudioDeviceID);
		GetPropertyData(kAudioHardwarePropertyDevices, theSize, theDeviceList);
		for(UInt32 theIndex = 0; theIndex < theNumberDevices; ++theIndex)
		{
			if(inDevice == theDeviceList[theIndex])
			{
				theAnswer = theIndex;
				break;
			}
		}
	}
	return theAnswer;
}
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// GetDeviceByGUID()
	//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	Device&	PlugIn::GetDeviceByGUID(UInt64 guid) const
	{
		Device* device = 0;
		bool found = false;

		// Iterate over the plugIn's devices and find the one whose guid matches
		for (UInt32 i = 0 ; i < GetNumberDevices() ; ++i)
		{
			device = static_cast<Device*>(GetDeviceByIndex(i));
			ThrowIfNULL(device, CAException(kCMIOHardwareBadDeviceError), "CMIO::DP::Sample::PlugIn::GetDeviceByGUID: no device for index");
			if (guid == device->GetDeviceGUID())
			{
				found = true;
				break;
			}
		}
		
		// Make sure that a device was actually found
		if (not found)
			throw CAException(kCMIOHardwareBadDeviceError);
		
		return *device;
	}