I would like to implement volume and gain sliders in my Mac app. I already use code that sets the volume/gain to a specific level and tried to use it sample code with my sliders, but the volume/gain never adjusts, even though I can see the values from the sliders being passed to the routines. So what's the best to achieve continuous volume/gain levels using Code Audio?
Thanks
AudioObjectPropertyAddress address;
AudioDeviceID deviceID;
OSStatus err;
UInt32 size;
UInt32 channels[ 2 ];
Float32 volume;
SSAudioDevice * targetDevice = [self getTargetInputDevice];
address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
address.mScope = kAudioObjectPropertyScopeGlobal;
address.mElement = kAudioObjectPropertyElementMaster;
deviceID = targetDevice.deviceID;
if(!targetDevice.ioLevel){
volume = 0.5;
}
else{
volume = [targetDevice.ioLevel floatValue] / 100.0;
}
size = sizeof(deviceID);
err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &address, 0, nil, &size, &deviceID );
if ( ! err ) {
address.mSelector = kAudioDevicePropertyPreferredChannelsForStereo;
address.mScope = kAudioDevicePropertyScopeInput;
address.mElement = kAudioObjectPropertyElementWildcard;
size = sizeof(channels);
err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &channels );
}
if ( ! err ) {
Boolean hasProperty;
address.mSelector = kAudioDevicePropertyVolumeScalar;
address.mScope = kAudioDevicePropertyScopeInput;
address.mElement = kAudioObjectPropertyElementMaster;
hasProperty = AudioObjectHasProperty( deviceID, &address );
if(!hasProperty){
}
address.mElement = channels[ 0 ];
hasProperty = AudioObjectHasProperty( deviceID, &address );
if(!hasProperty){
}
address.mElement = channels[ 1 ];
// returns true, channel 1 has a VolumeScalar property
hasProperty = AudioObjectHasProperty( deviceID, &address );
if(!hasProperty){
}
}
if ( ! err ) {
address.mSelector = kAudioDevicePropertyVolumeScalar;
address.mScope = kAudioDevicePropertyScopeInput;
size = sizeof(volume);
address.mElement = kAudioObjectPropertyElementMaster;
err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
if(err){
address.mElement = channels[ 0 ];
err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
address.mElement = channels[ 1 ];
err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
}
}
Related
I'm getting unexpected values for the volume level using kAudioDevicePropertyVolumeScalarToDecibels on my laptop's built-in audio.
void volume_test()
{
AudioObjectPropertyAddress address = {
.mSelector = kAudioHardwarePropertyDefaultOutputDevice,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster
};
AudioObjectID deviceID = kAudioObjectUnknown;
UInt32 dataSize = sizeof(deviceID);
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, &dataSize, &deviceID);
assert(result == noErr);
address.mSelector = kAudioDevicePropertyVolumeScalar;
address.mScope = kAudioObjectPropertyScopeOutput;
Float32 volumeScalar = 0;
dataSize = sizeof(volumeScalar);
result = AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &dataSize, &volumeScalar);
assert(result == noErr);
address.mSelector = kAudioDevicePropertyVolumeDecibels;
Float32 volumeDecibels = 0;
dataSize = sizeof(volumeDecibels);
result = AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &dataSize, &volumeDecibels);
assert(result == noErr);
address.mSelector = kAudioDevicePropertyVolumeScalarToDecibels;
Float32 convertedVolumeDecibels = volumeScalar;
dataSize = sizeof(convertedVolumeDecibels);
result = AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &dataSize, &convertedVolumeDecibels);
assert(result == noErr);
address.mSelector = kAudioDevicePropertyVolumeDecibelsToScalar;
Float32 convertedVolumeScalar = volumeDecibels;
dataSize = sizeof(convertedVolumeScalar);
result = AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &dataSize, &convertedVolumeScalar);
assert(result == noErr);
NSLog(#"Direct = %.4f %+2.2f dB", volumeScalar, volumeDecibels);
NSLog(#"Converted = %.4f %+2.2f dB", convertedVolumeScalar, convertedVolumeDecibels);
address.mSelector = kAudioDevicePropertyVolumeRangeDecibels;
AudioValueRange decibelRange;
dataSize = sizeof(decibelRange);
result = AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &dataSize, &decibelRange);
assert(result == noErr);
NSLog(#"dB range %+2.2f ... %+2.2f", decibelRange.mMinimum, decibelRange.mMaximum);
}
The output is:
Direct = 0.0620 -47.69 dB
Converted = 0.0620 -59.56 dB
dB range -63.50 ... +0.00
The same thing occurs using the underlying AudioControl directly.
For reference, Audio MIDI setup shows:
Interestingly, using my external display's audio and the elements from kAudioDevicePropertyPreferredChannelsForStereo (since it has no master element), the values match.
Also of note, for the display audio kAudioDevicePropertyVolumeDecibelsToScalarTransferFunction is 5, or kAudioLevelControlTranferFunction2Over1. Attempting to retrieve kAudioDevicePropertyVolumeDecibelsToScalarTransferFunction for the laptop fails with the message
HALC_ShellObject::GetPropertyData: call to the proxy failed, Error: 2003332927 (who?)
HALPlugIn::ObjectGetPropertyData: got an error from the plug-in routine, Error: 2003332927 (who?)
which is not a "normal" error message for an unsupported property.
How should kAudioDevicePropertyVolumeScalarToDecibels be used?
I writed a file system demo most likely fast fat ,but when I use CreateFileA to call my dirver ,it gives an INVALID_HANDLE_VALUE result . I have checked the driver `s IRP dispatches and found no DbgPrint setting in the function entries triggered .
This is the user mode code:
public IntPtr LoadDriver(string lpFileName)
{
int error = 0;
string openName = string.Format("\\\\.\\{0}", EXE_DRIVER_NAME);
IntPtr hSCManager = WinAPI.OpenSCManager(null, null,
WinAPI.SC_MANAGER_CREATE_SERVICE);
if (IntPtr.Zero != hSCManager)
{
//创建服务
IntPtr hService = WinAPI.CreateService(hSCManager, EXE_DRIVER_NAME,
DISPLAY_NAME, WinAPI.SERVICE_START,
WinAPI.SERVICE_KERNEL_DRIVER, WinAPI.SERVICE_DEMAND_START,
WinAPI.SERVICE_ERROR_IGNORE, lpFileName, null, IntPtr.Zero, null, null, null);
if (WinAPI.ERROR_SERVICE_EXISTS == WinAPI.GetLastError())
{
hService = WinAPI.OpenService(hSCManager, EXE_DRIVER_NAME, WinAPI.SERVICE_START);
}
error = WinAPI.GetLastError();
if(error!=0)
{
dumpErrorCode("OpenService失败 ", error);
}
int startflag = WinAPI.StartService(hService, 0, 0);
if (startflag == 0)
{
error = WinAPI.GetLastError();
if (error != WinAPI.ERROR_SERVICE_ALREADY_RUNNING) //已经启动
{
dumpErrorCode("StartService失败", error);
}
else
{
MessageBox.Show("服务已经启动");
}
}
// WinAPI.CloseServiceHandle(hService);
// WinAPI.CloseServiceHandle(hSCManager);
MessageBox.Show(openName);
try
{
hDriver = WinAPI.CreateFileA(openName, WinAPI.GENERIC_READ , 0, IntPtr.Zero, WinAPI.OPEN_EXISTING, null, IntPtr.Zero);
if (hDriver == (IntPtr)(-1))
{
dumpErrorCode("获取文件句柄失败 ", error);
}
else
{
MessageBox.Show("成功创建驱动");
//his.OpenDriverEvent();
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
return hDriver;
}
This is the driver`s entry point code:
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status;
UNICODE_STRING UnicodeString;
FS_FILTER_CALLBACKS FilterCallbacks;
UNREFERENCED_PARAMETER( RegistryPath );
DbgPrint("\nThis is HRFS Driver Entry\n");
RtlInitUnicodeString(&UnicodeString, L"\\fastFatDemo");
gSFilterDriverObject = DriverObject;
Status = IoCreateDevice( DriverObject,
0,
&UnicodeString,
FILE_DEVICE_DISK_FILE_SYSTEM,
0,
FALSE,
&HrfsDiskFileSystemDeviceObject );
if (!NT_SUCCESS( Status )) {
return Status;
}
DbgPrint("HRFS device HRFS created\n ");
DriverObject->DriverUnload = FatUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)FatFsdCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)HrfsFsdClose;
DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)FatFsdRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)FatFsdWrite;
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)FatFsdQueryInformation;
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)FatFsdSetInformation;
DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)FatFsdQueryEa;
DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)FatFsdSetEa;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)FatFsdFlushBuffers;
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)FatFsdQueryVolumeInformation;
DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)FatFsdSetVolumeInformation;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)FatFsdCleanup;
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)FatFsdDirectoryControl;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)FatFsdFileSystemControl;
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)FatFsdLockControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)FatFsdDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)FatFsdShutdown;
DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)FatFsdPnp;
DbgPrint("HRFS device HRFS MajorFunction created\n ");
DriverObject->FastIoDispatch = NULL;
DbgPrint("HRFS device HRFS FatFastIoDispatch created\n ");
RtlZeroMemory(&FatFastIoDispatch, sizeof(FatFastIoDispatch));
FatFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
FatFastIoDispatch.FastIoCheckIfPossible = FALSE; // CheckForFastIo
FatFastIoDispatch.FastIoRead = FALSE; // Read
FatFastIoDispatch.FastIoWrite = FALSE; // Write
FatFastIoDispatch.FastIoQueryBasicInfo = FALSE; // QueryBasicInfo
FatFastIoDispatch.FastIoQueryStandardInfo = FALSE; // QueryStandardInfo
FatFastIoDispatch.FastIoLock = FALSE; // Lock
FatFastIoDispatch.FastIoUnlockSingle = FALSE; // UnlockSingle
FatFastIoDispatch.FastIoUnlockAll = FALSE; // UnlockAll
FatFastIoDispatch.FastIoUnlockAllByKey = FALSE; // UnlockAllByKey
FatFastIoDispatch.FastIoQueryNetworkOpenInfo = FALSE;
FatFastIoDispatch.AcquireForCcFlush = FALSE;
FatFastIoDispatch.ReleaseForCcFlush = FALSE;
FatFastIoDispatch.MdlRead = FALSE;
FatFastIoDispatch.MdlReadComplete = FALSE;
FatFastIoDispatch.PrepareMdlWrite = FALSE;
FatFastIoDispatch.MdlWriteComplete = FALSE;
//FatFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
//FatFastIoDispatch.FastIoCheckIfPossible = FatFastIoCheckIfPossible; // CheckForFastIo
//FatFastIoDispatch.FastIoRead = FsRtlCopyRead; // Read
//FatFastIoDispatch.FastIoWrite = FsRtlCopyWrite; // Write
//FatFastIoDispatch.FastIoQueryBasicInfo = FatFastQueryBasicInfo; // QueryBasicInfo
//FatFastIoDispatch.FastIoQueryStandardInfo = FatFastQueryStdInfo; // QueryStandardInfo
//FatFastIoDispatch.FastIoLock = FatFastLock; // Lock
//FatFastIoDispatch.FastIoUnlockSingle = FatFastUnlockSingle; // UnlockSingle
//FatFastIoDispatch.FastIoUnlockAll = FatFastUnlockAll; // UnlockAll
//FatFastIoDispatch.FastIoUnlockAllByKey = FatFastUnlockAllByKey; // UnlockAllByKey
//FatFastIoDispatch.FastIoQueryNetworkOpenInfo = FatFastQueryNetworkOpenInfo;
//FatFastIoDispatch.AcquireForCcFlush = HrfsAcquireForCcFlush;
//FatFastIoDispatch.ReleaseForCcFlush = HrfsReleaseForCcFlush;
//FatFastIoDispatch.MdlRead = FsRtlMdlReadDev;
//FatFastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
//FatFastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
//FatFastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
/* FsFilter通知回调例程在下层文件系统执行某些操作之前或之后调用。
如果需要获取更多有关于FsFilter回调例程相关信息,可参见FsRtlRegisterFileSystemFilterCallbacks例程
为了注册FsFilter的通知回调例程必须分配并初始化FS_FILTER_CALLBACKS结构体,然后向该结构体中促出FsFilter回调例程,
并将存储有Callbacks parameter到FsRtlRegisterFileSystemFilterCallbacks中。*/
RtlZeroMemory( &FilterCallbacks,
sizeof(FS_FILTER_CALLBACKS) );
FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
FilterCallbacks.PreAcquireForSectionSynchronization = HrfsFilterCallbackAcquireForCreateSection;
Status = FsRtlRegisterFileSystemFilterCallbacks( DriverObject,
&FilterCallbacks );
if (!NT_SUCCESS( Status )) {
IoDeleteDevice( HrfsDiskFileSystemDeviceObject );
return Status;
}
DbgPrint("HRFS device HRFS FilterCallbacks registed\n ");
RtlZeroMemory( &HrfsData, sizeof(FAT_DATA));
HrfsData.NodeTypeCode = HRFS_NTC_DATA_HEADER;
HrfsData.NodeByteSize = sizeof(FAT_DATA);
InitializeListHead(&HrfsData.VcbQueue);
pDriverObject = DriverObject;
HrfsData.DiskFileSystemDeviceObject = HrfsDiskFileSystemDeviceObject;
//
// This list head keeps track of closes yet to be done.
//
InitializeListHead( &HrfsData.AsyncCloseList );
InitializeListHead( &HrfsData.DelayedCloseList );
HrfsData.FatCloseItem = IoAllocateWorkItem( HrfsDiskFileSystemDeviceObject);
if (HrfsData.FatCloseItem == NULL) {
IoDeleteDevice (HrfsDiskFileSystemDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
DbgPrint("HRFS device HRFS workitem created\n ");
//
// Allocate the zero page
//
HrfsData.ZeroPage = ExAllocatePoolWithTag( NonPagedPoolNx, PAGE_SIZE, 'ZtaF' );
if (HrfsData.ZeroPage == NULL) {
IoDeleteDevice (HrfsDiskFileSystemDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( HrfsData.ZeroPage, PAGE_SIZE );
//
// Now initialize our general purpose spinlock (gag) and figure out how
// deep and wide we want our delayed lists (along with fooling ourselves
// about the lookaside depths).
//
KeInitializeSpinLock( &HrfsData.GeneralSpinLock );
HrfsData.CacheManagerCallbacks.AcquireForLazyWrite = &HrfsAcquireFcbForLazyWrite;
HrfsData.CacheManagerCallbacks.ReleaseFromLazyWrite = &HrfsReleaseFcbFromLazyWrite;
HrfsData.CacheManagerCallbacks.AcquireForReadAhead = &HrfsAcquireFcbForReadAhead;
HrfsData.CacheManagerCallbacks.ReleaseFromReadAhead = &HrfsReleaseFcbFromReadAhead;
HrfsData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = &HrfsNoOpAcquire;
HrfsData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &HrfsNoOpRelease;
HrfsData.CacheManagerNoOpCallbacks.AcquireForReadAhead = &HrfsNoOpAcquire;
HrfsData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &HrfsNoOpRelease;
//
// Set up global pointer to our process.
//
HrfsData.OurProcess = PsGetCurrentProcess();
DbgPrint("HRFS device HRFS our process getted\n ");
//
// Setup the number of processors we support for statistics as the current number
// running.
//
#if (NTDDI_VERSION >= NTDDI_VISTA)
HrfsData.NumberProcessors = KeQueryActiveProcessorCount( NULL );
#else
HrfsData.NumberProcessors = KeNumberProcessors;
#endif
DbgPrint("HrfsData.NumberProcessors :%d", HrfsData.NumberProcessors);
ExInitializeResourceLite( &HrfsData.Resource );
IoRegisterFileSystem(HrfsDiskFileSystemDeviceObject);
ObReferenceObject (HrfsDiskFileSystemDeviceObject);
DbgPrint("Device HRFS HrfsDiskFileSystemDeviceObject registed\n ");
return( STATUS_SUCCESS );
}
I'm trying to read the current volume level.
I moved from the waveOut* functions to the mixer* functions.
If I run the application under Windows XP the value are aligned with the system volume level.
If I run under Win8.1 and Win10 I always receive 0xFFFF.
My code is:
TCHAR msg[100];
g_uNumDevs = mixerGetNumDevs();
wsprintf( msg, L"N. mixer: %d", g_uNumDevs);
pInfo->Log(msg);
if (g_uNumDevs)
{
UINT i = 0;
while(i < g_uNumDevs)
{
MMRESULT mmRes = mixerOpen(&hMixer, i, 0, 0, MIXER_OBJECTF_MIXER);
if (mmRes != MMSYSERR_NOERROR)
{
wsprintf( msg, L"Errore openMixer i:%d err:%d", i, mmRes);
pInfo->Log(msg);
}
// Master line
MIXERLINE ml = {0};
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; // Volume master
mmRes = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
pInfo->Log( ml.szName);
if (mmRes != MMSYSERR_NOERROR)
{
wsprintf( msg, L"Errore mixerGetLineInfo err:%d", mmRes);
pInfo->Log(msg);
mixerClose(hMixer);
return FALSE;
}
// get the volume control of the speaker line.
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
mmRes = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmRes != MMSYSERR_NOERROR)
{
wsprintf( msg, L"Errore mixerGetLineControls err:%d", mmRes);
pInfo->Log(msg);
EnableWindow( g_hwndSlider, FALSE);
EnableWindow( g_hwndVerifBtn, FALSE);
}
else {
// GetVolume level
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdVolume;
mmRes = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(hMixer),
&mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);
if (mmRes != MMSYSERR_NOERROR)
{
EnableWindow( g_hwndSlider, FALSE);
EnableWindow( g_hwndVerifBtn, FALSE);
//return FALSE;
}
else {
DWORD dwVol = mxcdVolume.dwValue;
dwVol &= 0xFFFF;
DWORD perc = dwVol * 100 / 0xFFFF;
SendMessage( g_hwndSlider, TBM_SETPOS, 1, perc);
wsprintf( msg, L"Volume = %d %% [%d]", perc, dwVol);
pInfo->Log(msg);
}
}
mixerClose(hMixer);
++i;
} // while
}
else {
pInfo->Log(L"No audio device !!");
return FALSE;
}
guys! I have a trouble with using remote IO to playback a stream audio.I verified the PCM frame data before I put it in,it's correct.So I'm confused.Could you help me? Thanks a lot!
Below is my codes.
-
(void)initializeAudioPlay
{
OSStatus status;
// Describe audio component
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
// Get component
AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);
// Get audio units
status = AudioComponentInstanceNew(inputComponent, &audioPlayUnit);
[self checkStatus:status];
// Enable IO for playback
UInt32 flag = 1;
//kAUVoiceIOProperty_VoiceProcessingEnableAGC
status = AudioUnitSetProperty(audioPlayUnit, kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input, kOutputBus, &flag, sizeof(flag));
[self checkStatus:status];
// Describe format
AudioStreamBasicDescription audioFormat;
memset(&audioFormat, 0, sizeof(audioFormat));
audioFormat.mSampleRate = 8000;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagsCanonical;//kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagIsSignedInteger;
/*kAudioFormatFlagsCanonical
| (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift)*/
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerFrame = (audioFormat.mBitsPerChannel/8) * audioFormat.mChannelsPerFrame;
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
// Apply format
status = AudioUnitSetProperty(audioPlayUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus,
&audioFormat,
sizeof(audioFormat));
[self checkStatus:status];
float value = (float)10 / 255.0;
AudioUnitSetParameter(audioPlayUnit, kAudioUnitParameterUnit_LinearGain, kAudioUnitScope_Input, 0, value, 0);
AudioChannelLayout new_layout;
new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
AudioUnitSetProperty( audioPlayUnit,
kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Global,
0, &new_layout, sizeof(new_layout) );
UInt32 bypassEffect = kAudioUnitProperty_RenderQuality;
status = AudioUnitSetProperty(audioPlayUnit,
kAudioUnitProperty_RenderQuality,
kAudioUnitScope_Global,
0,
&bypassEffect,
sizeof(bypassEffect));
[self checkStatus:status];
// Set output callback
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = playCallback;
callbackStruct.inputProcRefCon = self;
status = AudioUnitSetProperty(audioPlayUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
kOutputBus,
&callbackStruct,
sizeof(callbackStruct));
[self checkStatus:status];
flag = 0;
// Initialize
status = AudioUnitInitialize(audioPlayUnit);
[self checkStatus:status];
DGLog(#"audio play unit initialize = %d", status);
circularBuf = [[CircularBuf alloc] initWithBufLen:kBufferLength];
/*
AudioSessionInitialize(NULL, NULL, NULL, NULL);
Float64 rate =32000.0;
AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, sizeof(rate), &rate);
Float32 volume=20.0;
UInt32 size = sizeof(Float32);
AudioSessionSetProperty(
kAudioSessionProperty_PreferredHardwareIOBufferDuration,
&size, &volume);
//float aBufferLength = 0.185759637188209;
//AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(aBufferLength), &aBufferLength);
AudioSessionSetActive(YES);
*/
AudioSessionInitialize(NULL, NULL, NULL, nil);
AudioSessionSetActive(true);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback ;
/* for Iphone we need to do this to route the audio to speaker */
status= AudioSessionSetProperty (
kAudioSessionProperty_AudioCategory,
sizeof (sessionCategory),
&sessionCategory
);
//NSLog(#"Error: %d", status);
//
// UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
// status = AudioSessionSetProperty (
// kAudioSessionProperty_OverrideAudioRoute,
// sizeof (audioRouteOverride),
// &audioRouteOverride);
UInt32 audioMixed = 1;
status = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (audioMixed),
&audioMixed);
}
- (void)processAudio:(AudioBuffer *)buffer
{
short pcmTemp[160];
unsigned char * amrBuffer=NULL;
AudioUnitSampleType sample;
int i = 0;
int j = 0;
if ([circularBuf isReadTwoRegion]) {
amrBuffer = [circularBuf ReadData];
} else {
amrBuffer = [circularBuf ReadData];
i = [circularBuf ReadPos];
}
j = i + circularBuf.Length;
if (j - i >= 320) {
memcpy((void*)pcmTemp, (void*)amrBuffer, 320);
for(i=0; i<160; i++)
{
sample = 3.162277*pcmTemp[i];//10db
if(sample > 32767)sample = 32767;
else if(sample < -32768)sample = -32768;
buffData[i] = sample;
}
memcpy(buffer->mData, buffData, buffer->mDataByteSize);
[circularBuf AdvanceReadPos:320];
}
else
{
memset(buffer->mData, 0, buffer->mDataByteSize);
}
}
/**
This callback is called when the audioUnit needs new data to play through the
speakers. If you don't have any, just don't write anything in the buffers
*/
static OSStatus playCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
// Notes: ioData contains buffers (may be more than one!)
// Fill them up as much as you can. Remember to set the size value in each buffer to match how
// much data is in the buffer.
AudioPlay *audioPlay = (AudioPlay *)inRefCon;
for ( int i=0; i < ioData->mNumberBuffers; i++ ) {
memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
}
ioData->mBuffers[0].mNumberChannels = 1;
[audioPlay processAudio:&ioData->mBuffers[0]];
return noErr;
}
How can i get audio device UID (USB speaker) to pass into NSSound's setPlaybackDeviceIdentifier: method
Thanks
To avoid the deprecated AudioHardwareGetProperty and AudioDeviceGetProperty calls replace them with something like this:
AudioObjectPropertyAddress propertyAddress;
AudioObjectID *deviceIDs;
UInt32 propertySize;
NSInteger numDevices;
propertyAddress.mSelector = kAudioHardwarePropertyDevices;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize) == noErr) {
numDevices = propertySize / sizeof(AudioDeviceID);
deviceIDs = (AudioDeviceID *)calloc(numDevices, sizeof(AudioDeviceID));
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, deviceIDs) == noErr) {
AudioObjectPropertyAddress deviceAddress;
char deviceName[64];
char manufacturerName[64];
for (NSInteger idx=0; idx<numDevices; idx++) {
propertySize = sizeof(deviceName);
deviceAddress.mSelector = kAudioDevicePropertyDeviceName;
deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
deviceAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, deviceName) == noErr) {
propertySize = sizeof(manufacturerName);
deviceAddress.mSelector = kAudioDevicePropertyDeviceManufacturer;
deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
deviceAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, manufacturerName) == noErr) {
CFStringRef uidString;
propertySize = sizeof(uidString);
deviceAddress.mSelector = kAudioDevicePropertyDeviceUID;
deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
deviceAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, &uidString) == noErr) {
NSLog(#"device %s by %s id %#", deviceName, manufacturerName, uidString);
CFRelease(uidString);
}
}
}
}
}
free(deviceIDs);
}
ok i got it myself...
the theCFString will contain the device UID
UInt32 theSize;
char theString[kMaxStringSize];
UInt32 theNumberDevices;
AudioDeviceID *theDeviceList = NULL;
UInt32 theDeviceIndex;
CFStringRef theCFString = NULL;
OSStatus theStatus = noErr;
// this is our driver
const char *nameString = "Burr-Brown Japan PCM2702";
const char *manufacturerString = "Burr-Brown Japan";
// device list size
theSize = 0;
theStatus = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &theSize, NULL);
theNumberDevices = theSize / sizeof(AudioDeviceID);
// allocate the device list
theDeviceList = (AudioDeviceID*)malloc(theNumberDevices * sizeof(AudioDeviceID));
// get the device list
theSize = theNumberDevices * sizeof(AudioDeviceID);
theStatus = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &theSize, theDeviceList);
// iterate through the device list, find our device and return the UID
for(theDeviceIndex = 0; theDeviceIndex < theNumberDevices; ++theDeviceIndex)
{
// get name
theSize = kMaxStringSize;
theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex],
0, 0, kAudioDevicePropertyDeviceName, &theSize, theString);
NSLog(#"%s",theString);
// is it me?
if (strncmp(theString, nameString, strlen(nameString)) == 0) {
// get manufacturer
theSize = kMaxStringSize;
theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex], 0, 0,
kAudioDevicePropertyDeviceManufacturer, &theSize, theString);
NSLog(#"%s",theString);
// is it really me?
if (strncmp(theString, manufacturerString, strlen(manufacturerString)) == 0) {
// get device UID
theSize = sizeof(CFStringRef);
theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex],
0, 0, kAudioDevicePropertyDeviceUID, &theSize, &theCFString);
NSLog(#"%s",theCFString);
break;
}
}
}
AudioHardwareGetProperty is deprecated in snow leopard.