mirror of
https://github.com/morgan9e/VolumeControl
synced 2026-04-14 00:04:05 +09:00
Initial commit
This commit is contained in:
410
driver/VC_AbstractDevice.cpp
Normal file
410
driver/VC_AbstractDevice.cpp
Normal file
@@ -0,0 +1,410 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_AbstractDevice.cpp
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VC_AbstractDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Utils.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CAException.h"
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
VC_AbstractDevice::VC_AbstractDevice(AudioObjectID inObjectID, AudioObjectID inOwnerObjectID)
|
||||
:
|
||||
VC_Object(inObjectID, kAudioDeviceClassID, kAudioObjectClassID, inOwnerObjectID)
|
||||
{
|
||||
}
|
||||
|
||||
VC_AbstractDevice::~VC_AbstractDevice()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
bool VC_AbstractDevice::HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
case kAudioDevicePropertyModelUID:
|
||||
case kAudioDevicePropertyTransportType:
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
case kAudioDevicePropertyLatency:
|
||||
case kAudioDevicePropertyStreams:
|
||||
case kAudioObjectPropertyControlList:
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
theAnswer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::HasProperty(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool VC_AbstractDevice::IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
case kAudioDevicePropertyModelUID:
|
||||
case kAudioDevicePropertyTransportType:
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
case kAudioDevicePropertyLatency:
|
||||
case kAudioDevicePropertyStreams:
|
||||
case kAudioObjectPropertyControlList:
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
theAnswer = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::IsPropertySettable(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
UInt32 VC_AbstractDevice::GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* __nullable inQualifierData) const
|
||||
{
|
||||
UInt32 theAnswer = 0;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyModelUID:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyTransportType:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
theAnswer = sizeof(AudioObjectID);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
theAnswer = sizeof(AudioClassID);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyLatency:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyStreams:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyControlList:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
theAnswer = sizeof(Float64);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::GetPropertyDataSize(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void VC_AbstractDevice::GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* __nullable inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const
|
||||
{
|
||||
UInt32 theNumberItemsToFetch;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
case kAudioDevicePropertyModelUID:
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
// Should be unreachable. Reaching this point would mean a concrete device has delegated
|
||||
// a required property that can't be handled by this class or its parent, VC_Object.
|
||||
//
|
||||
// See VC_Device for info about these properties.
|
||||
//
|
||||
// TODO: Write a test that checks all required properties for each subclass.
|
||||
VCAssert(false,
|
||||
"VC_AbstractDevice::GetPropertyData: Property %u not handled in subclass",
|
||||
inAddress.mSelector);
|
||||
// Throw in release builds.
|
||||
Throw(CAException(kAudioHardwareIllegalOperationError));
|
||||
|
||||
case kAudioDevicePropertyTransportType:
|
||||
// This value represents how the device is attached to the system. This can be
|
||||
// any 32 bit integer, but common values for this property are defined in
|
||||
// <CoreAudio/AudioHardwareBase.h>.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyTransportType for the device");
|
||||
// Default to virtual device.
|
||||
*reinterpret_cast<UInt32*>(outData) = kAudioDeviceTransportTypeVirtual;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
// The related devices property identifies device objects that are very closely
|
||||
// related. Generally, this is for relating devices that are packaged together
|
||||
// in the hardware such as when the input side and the output side of a piece
|
||||
// of hardware can be clocked separately and therefore need to be represented
|
||||
// as separate AudioDevice objects. In such case, both devices would report
|
||||
// that they are related to each other. Note that at minimum, a device is
|
||||
// related to itself, so this list will always be at least one item long.
|
||||
|
||||
// Calculate the number of items that have been requested. Note that this
|
||||
// number is allowed to be smaller than the actual size of the list. In such
|
||||
// case, only that number of items will be returned
|
||||
theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID);
|
||||
|
||||
// Default to only have the one device.
|
||||
if(theNumberItemsToFetch > 1)
|
||||
{
|
||||
theNumberItemsToFetch = 1;
|
||||
}
|
||||
|
||||
// Write the devices' object IDs into the return value.
|
||||
if(theNumberItemsToFetch > 0)
|
||||
{
|
||||
reinterpret_cast<AudioObjectID*>(outData)[0] = GetObjectID();
|
||||
}
|
||||
|
||||
// Report how much we wrote.
|
||||
outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
// This property allows the device to declare what other devices it is
|
||||
// synchronized with in hardware. The way it works is that if two devices have
|
||||
// the same value for this property and the value is not zero, then the two
|
||||
// devices are synchronized in hardware. Note that a device that either can't
|
||||
// be synchronized with others or doesn't know should return 0 for this
|
||||
// property.
|
||||
//
|
||||
// Default to 0.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyClockDomain for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
// Default to alive.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyDeviceIsAlive for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
// This property returns whether or not the device wants to be able to be the
|
||||
// default device for content. This is the device that iTunes and QuickTime
|
||||
// will use to play their content on and FaceTime will use as it's microphone.
|
||||
// Nearly all devices should allow for this.
|
||||
//
|
||||
// Default to true.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyDeviceCanBeDefaultDevice for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
// This property returns whether or not the device wants to be the system
|
||||
// default device. This is the device that is used to play interface sounds and
|
||||
// other incidental or UI-related sounds on. Most devices should allow this
|
||||
// although devices with lots of latency may not want to.
|
||||
//
|
||||
// Default to true.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyDeviceCanBeDefaultSystemDevice for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyLatency:
|
||||
// This property returns the presentation latency of the device. Default to 0.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyLatency for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyStreams:
|
||||
// Default to not having any streams.
|
||||
outDataSize = 0;
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyControlList:
|
||||
// Default to not having any controls.
|
||||
outDataSize = 0;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
// This property returns the how close to now the HAL can read and write. Default to 0.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertySafetyOffset for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
// This returns whether or not the device is visible to clients. Default to not hidden.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyIsHidden for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
default:
|
||||
VC_Object::GetPropertyData(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData,
|
||||
inDataSize,
|
||||
outDataSize,
|
||||
outData);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
Reference in New Issue
Block a user