IOAudioManager.cpp [plain text]
#include <IOKit/audio/IOAudioManager.h>
#include <IOKit/audio/IOAudioDevice.h>
#include <IOKit/audio/IOAudioTypes.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/IOLib.h>
#include <libkern/c++/OSSet.h>
#include <libkern/c++/OSCollectionIterator.h>
#include <IOKit/hidsystem/IOHIDShared.h>
#include <IOKit/audio/IOAudioDMAEngineUserClient.h>
#define DEFAULT_INITIAL_VOLUME MASTER_VOLUME_MAX
#define DEFAULT_INITIAL_MUTE false
#define DEFAULT_INITIAL_INCREMENT 4096
static MasterAudioFunctions masterFunctions;
IOAudioManager *IOAudioManager::amInstance = 0;
extern bool (*playBeep)(IOService *outputDMAEngine);
bool IOBeep(IOService *outputDMAEngine)
{
return true;
}
UInt16 sharedIncrementMasterVolume()
{
UInt16 result = 0;
IOAudioManager *am = IOAudioManager::sharedInstance();
if (am) {
result = am->incrementMasterVolume();
}
return result;
}
UInt16 sharedDecrementMasterVolume()
{
UInt16 result = 0;
IOAudioManager *am = IOAudioManager::sharedInstance();
if (am) {
result = am->decrementMasterVolume();
}
return result;
}
bool sharedToggleMasterMute()
{
bool result = false;
IOAudioManager *am = IOAudioManager::sharedInstance();
if (am) {
result = am->toggleMasterMute();
}
return result;
}
OSDefineMetaClassAndStructors(IOAudioManager, IOService);
IOAudioManager *IOAudioManager::sharedInstance()
{
return amInstance;
}
kern_return_t IOAudioClientIOTrap(IOAudioDMAEngineUserClient *userClient, UInt32 firstSampleFrame, UInt32 inputIO)
{
kern_return_t result = kIOReturnBadArgument;
#ifdef DEBUGLOG
IOLog("IOAudioClientIOTrap(0x%x, 0x%x, %d)\n", userClient, firstSampleFrame, inputIO);
#endif
if (userClient) {
result = userClient->performClientIO(firstSampleFrame, (inputIO != 0));
}
return result;
}
bool IOAudioManager::init(OSDictionary *properties)
{
if (!IOService::init(properties)) {
return false;
}
masterVolumeLeft = DEFAULT_INITIAL_VOLUME;
masterVolumeRight = DEFAULT_INITIAL_VOLUME;
masterMute = DEFAULT_INITIAL_MUTE;
masterVolumeIncrement = DEFAULT_INITIAL_INCREMENT;
setProperty(kMasterVolumeLeft, (unsigned long long)masterVolumeLeft, sizeof(masterVolumeLeft)*8);
setProperty(kMasterVolumeRight, (unsigned long long)masterVolumeRight, sizeof(masterVolumeRight)*8);
setProperty(kMasterMute, (unsigned long long)masterMute, sizeof(masterMute)*8);
setProperty(kMasterVolumeIncrement, (unsigned long long)masterVolumeIncrement, sizeof(masterVolumeIncrement)*8);
audioDevices = NULL;
publishNotify = NULL;
driverLock = NULL;
masterFunctions.incrementMasterVolume = &sharedIncrementMasterVolume;
masterFunctions.decrementMasterVolume = &sharedDecrementMasterVolume;
masterFunctions.toggleMasterMute = &sharedToggleMasterMute;
masterAudioFunctions = &masterFunctions;
playBeep = &IOBeep;
return true;
}
void IOAudioManager::free()
{
if (audioDevices) {
audioDevices->release();
audioDevices = 0;
}
if (publishNotify) {
publishNotify->remove();
publishNotify = 0;
}
if (driverLock) {
IOLockFree(driverLock);
driverLock = 0;
}
IOService::free();
}
bool IOAudioManager::start(IOService *provider)
{
bool success = false;
amInstance = this;
do {
if (!IOService::start(provider)) {
break;
}
audioDevices = OSSet::withCapacity(1);
driverLock = IOLockAlloc();
publishNotify = addNotification(gIOPublishNotification,
serviceMatching("IOAudioDevice"),
(IOServiceNotificationHandler) &audioPublishNotificationHandler,
this,
0);
if (!publishNotify || !driverLock) {
break;
}
IOLockInit(driverLock);
success = true;
} while (false);
if (!success) {
amInstance = NULL;
}
return success;
}
IOReturn IOAudioManager::setProperties( OSObject * properties )
{
OSDictionary *props;
IOReturn result = kIOReturnSuccess;
if (properties && (props = OSDynamicCast(OSDictionary, properties))) {
OSCollectionIterator *iterator;
OSObject *iteratorKey;
iterator = OSCollectionIterator::withCollection(props);
while ((iteratorKey = iterator->getNextObject())) {
OSSymbol *key;
key = OSDynamicCast(OSSymbol, iteratorKey);
if (key) {
OSNumber *value;
value = OSDynamicCast(OSNumber, props->getObject(key));
if (value) {
if (key->isEqualTo(kMasterVolumeLeft)) {
setMasterVolumeLeft(value->unsigned16BitValue());
} else if (key->isEqualTo(kMasterVolumeRight)) {
setMasterVolumeRight(value->unsigned16BitValue());
} else if (key->isEqualTo(kMasterMute)) {
setMasterMute(value->unsigned8BitValue());
} else if (key->isEqualTo(kMasterVolumeIncrement)) {
setMasterVolumeIncrement(value->unsigned16BitValue());
}
} else {
result = kIOReturnBadArgument;
break;
}
} else {
result = kIOReturnBadArgument;
break;
}
}
} else {
result = kIOReturnBadArgument;
}
return result;
}
bool IOAudioManager::audioPublishNotificationHandler(IOAudioManager *self,
void *ref,
IOService *newService)
{
if (OSDynamicCast(IOAudioDevice, newService)) {
self->registerAudioDevice((IOAudioDevice *)newService);
}
return true;
}
bool IOAudioManager::registerAudioDevice(IOAudioDevice *device)
{
this->attach(device);
IOTakeLock(driverLock);
audioDevices->setObject(device);
device->setMasterMute(masterMute);
device->setMasterVolumeLeft(masterVolumeLeft);
device->setMasterVolumeRight(masterVolumeRight);
IOUnlock(driverLock);
return true;
}
void IOAudioManager::removeAudioDevice(IOAudioDevice *device)
{
IOTakeLock(driverLock);
audioDevices->removeObject(device);
IOUnlock(driverLock);
this->detach(device);
}
UInt16 IOAudioManager::getMasterVolumeLeft()
{
return masterVolumeLeft;
}
UInt16 IOAudioManager::getMasterVolumeRight()
{
return masterVolumeRight;
}
UInt16 IOAudioManager::setMasterVolumeLeft(UInt16 newMasterVolumeLeft)
{
UInt16 oldMasterVolumeLeft;
oldMasterVolumeLeft = masterVolumeLeft;
masterVolumeLeft = newMasterVolumeLeft;
if (masterVolumeLeft != oldMasterVolumeLeft) {
OSCollectionIterator *iter;
setProperty(kMasterVolumeLeft, (unsigned long long)masterVolumeLeft, sizeof(masterVolumeLeft)*8);
IOTakeLock(driverLock);
iter = OSCollectionIterator::withCollection(audioDevices);
if (iter) {
IOAudioDevice *device;
while ((device = (IOAudioDevice *)iter->getNextObject()) != NULL) {
device->setMasterVolumeLeft(masterVolumeLeft);
}
iter->release();
}
IOUnlock(driverLock);
}
return oldMasterVolumeLeft;
}
UInt16 IOAudioManager::setMasterVolumeRight(UInt16 newMasterVolumeRight)
{
UInt16 oldMasterVolumeRight;
oldMasterVolumeRight = masterVolumeRight;
masterVolumeRight = newMasterVolumeRight;
if (masterVolumeRight != oldMasterVolumeRight) {
OSCollectionIterator *iter;
setProperty(kMasterVolumeRight, (unsigned long long)masterVolumeRight, sizeof(masterVolumeRight)*8);
IOTakeLock(driverLock);
iter = OSCollectionIterator::withCollection(audioDevices);
if (iter) {
IOAudioDevice *device;
while ((device = (IOAudioDevice *)iter->getNextObject()) != NULL) {
device->setMasterVolumeRight(masterVolumeRight);
}
iter->release();
}
IOUnlock(driverLock);
}
return oldMasterVolumeRight;
}
bool IOAudioManager::getMasterMute()
{
return masterMute;
}
bool IOAudioManager::setMasterMute(bool newMasterMute)
{
bool oldMasterMute;
oldMasterMute = masterMute;
masterMute = newMasterMute;
if (masterMute != oldMasterMute) {
OSCollectionIterator *iter;
setProperty(kMasterMute, (unsigned long long)masterMute, sizeof(masterMute)*8);
IOTakeLock(driverLock);
iter = OSCollectionIterator::withCollection(audioDevices);
if (iter) {
IOAudioDevice *device;
while ((device = (IOAudioDevice *)iter->getNextObject()) != NULL) {
device->setMasterMute(masterMute);
}
iter->release();
}
IOUnlock(driverLock);
}
return oldMasterMute;
}
UInt16 IOAudioManager::getMasterVolumeIncrement()
{
return masterVolumeIncrement;
}
UInt16 IOAudioManager::setMasterVolumeIncrement(UInt16 newMasterVolumeIncrement)
{
UInt16 oldMasterVolumeIncrement;
oldMasterVolumeIncrement = masterVolumeIncrement;
masterVolumeIncrement = newMasterVolumeIncrement;
setProperty(kMasterVolumeIncrement, (unsigned long long)masterVolumeIncrement, sizeof(masterVolumeIncrement)*8);
return oldMasterVolumeIncrement;
}
UInt16 IOAudioManager::incrementMasterVolume()
{
SInt32 newMasterVolumeLeft;
SInt32 newMasterVolumeRight;
newMasterVolumeLeft = masterVolumeLeft + masterVolumeIncrement;
newMasterVolumeRight = masterVolumeRight + masterVolumeIncrement;
if (newMasterVolumeLeft > MASTER_VOLUME_MAX) {
newMasterVolumeRight = newMasterVolumeRight - (newMasterVolumeLeft - MASTER_VOLUME_MAX);
newMasterVolumeLeft = MASTER_VOLUME_MAX;
}
if (newMasterVolumeRight > MASTER_VOLUME_MAX) {
newMasterVolumeLeft = newMasterVolumeLeft - (newMasterVolumeRight - MASTER_VOLUME_MAX);
newMasterVolumeRight = MASTER_VOLUME_MAX;
}
setMasterVolumeLeft(newMasterVolumeLeft);
setMasterVolumeRight(newMasterVolumeRight);
return masterVolumeLeft > masterVolumeRight ? masterVolumeLeft : masterVolumeRight;
}
UInt16 IOAudioManager::decrementMasterVolume()
{
SInt32 newMasterVolumeLeft;
SInt32 newMasterVolumeRight;
newMasterVolumeLeft = masterVolumeLeft - masterVolumeIncrement;
newMasterVolumeRight = masterVolumeRight - masterVolumeIncrement;
if (newMasterVolumeLeft < MASTER_VOLUME_MIN) {
newMasterVolumeRight = newMasterVolumeRight + (MASTER_VOLUME_MIN - newMasterVolumeLeft);
newMasterVolumeLeft = MASTER_VOLUME_MIN;
}
if (newMasterVolumeRight < MASTER_VOLUME_MIN) {
newMasterVolumeLeft = newMasterVolumeLeft + (MASTER_VOLUME_MIN - newMasterVolumeRight);
newMasterVolumeRight = MASTER_VOLUME_MIN;
}
setMasterVolumeLeft(newMasterVolumeLeft);
setMasterVolumeRight(newMasterVolumeRight);
return masterVolumeLeft > masterVolumeRight ? masterVolumeLeft : masterVolumeRight;
}
bool IOAudioManager::toggleMasterMute()
{
setMasterMute(!masterMute);
return masterMute;
}