0

I'm working on an application that plays sounds through the default audio device on a Mac. I want to change the output sampling rate and bit depth of the default output device but it always gives me a kAudioUnitErr_PropertyNotWritable error code.

Here is my test code:

    AudioStreamBasicDescription streamFormat;
    AudioStreamBasicDescription newStreamFormat;
    newStreamFormat.mSampleRate = 96000;        // the sample rate of the audio stream
    newStreamFormat.mFormatID = kAudioFormatLinearPCM;     // the specific encoding type of audio stream
    newStreamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger;//kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsNonMixable;
    newStreamFormat.mFramesPerPacket = 1;
    newStreamFormat.mChannelsPerFrame = 1;
    newStreamFormat.mBitsPerChannel = 24;
    newStreamFormat.mBytesPerPacket = 2;
    newStreamFormat.mBytesPerFrame = 2;
    
    UInt32 size = sizeof(AudioStreamBasicDescription);

    result = AudioUnitGetProperty(myUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
    
    result = AudioOutputUnitStop(myUnit);
    result = AudioUnitUninitialize(myUnit);
    
    result = AudioUnitSetProperty(myUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &newStreamFormat, size);
    result = AudioUnitInitialize(myUnit);
    result = AudioOutputUnitStart(myUnit);
    
    result = AudioUnitGetProperty(myUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
    result = AudioUnitGetProperty(myUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, &size);

When I make the call to set the stream format on kAudioUnitScope_Input I don't get any error but when I set it on kAudioUnitScope_Output if fails with the property not writable error.

It must be possible to do this programmatically (Audio MIDI Setup does it) but I have searched and searched but I haven't been able to find any solution.

I did find this post that implies that setting the input sampling rate of the device will update the output as well. I tried this but when I read back the property the output doesn't match what I set on the input.

act1292
  • 19
  • 6

1 Answers1

1

I'm pretty sure it's not the output AudioUnit's job to configure devices. It's more of an intermediary between clients and audio devices. Which means AudioUnitSetProperty() is the wrong API for the job.

So if you want to configure the device, try setting kAudioDevicePropertyNominalSampleRate on it using the AudioObjectSetPropertyData() function.

Then, unless you want a gratuitous rate conversion, you probably want to make sure your audio unit input format matches the new device sample rate by doing what you're already doing: calling AudioUnitSetProperty() on the input (data going into the audio unit) scope.

Rhythmic Fistman
  • 34,352
  • 5
  • 87
  • 159
  • Thanks for the reply. I'll give it a try today and see what I get. Per your last comment, that is exactly what I am trying to accomplish here - matching the input sampling rate to the hardware. My code I have shown is just testing so I understand how all of this works. I'll post back my results – act1292 Apr 04 '22 at 12:52
  • 1
    Yes - Setting the nominal rate through the AudioObjectSetPropertyData() works as you stated. The update is viewable through AudioMIDISetup application. Thanks for the answer. – act1292 Apr 04 '22 at 20:48