syedhali / EZAudio

An iOS and macOS audio visualization framework built upon Core Audio useful for anyone doing real-time, low-latency audio processing and visualizations.
Other
4.95k stars 822 forks source link

Custom ABSD ignored when using EZMicrophone init methods #27

Closed chrisballinger closed 9 years ago

chrisballinger commented 10 years ago

initWithMicrophoneDelegate:withAudioStreamBasicDescription: and its "instant" counterpart ignore the ABSD passed into the method because _createInputUnit is called in the call to initWithMicrophoneDelegate:.

When trying to work around the issue doesn't seem to work either because no audio frames are delivered.

int preferredSampleRate = 48000;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setPreferredSampleRate:preferredSampleRate error:&error];
AudioStreamBasicDescription absd = [EZAudio monoCanonicalFormatWithSampleRate: preferredSampleRate];
self.microphone = [[EZMicrophone alloc] initWithMicrophoneDelegate:self];
[self.microphone setAudioStreamBasicDescription:absd];
[self.microphone startFetchingAudio];
chrisballinger commented 10 years ago

Looks like #19 is the same issue

syedhali commented 10 years ago

@chrisballinger,

Thanks for the heads up, were you able to patch it up? If so, I'd gladly accept a pull request, and, if not, I'll add it to my todos :)

chrisballinger commented 10 years ago

The patch will require a bit of refactoring so that the init methods don't duplicate code and that the majority of the init is done in the one with the most parameters, if that makes sense

On Thursday, February 20, 2014, Syed Haris Ali notifications@github.com wrote:

@chrisballinger https://github.com/chrisballinger,

Thanks for the heads up, were you able to patch it up? If so, I'd gladly accept a pull request, and, if not, I'll add it to my todos :)

— Reply to this email directly or view it on GitHubhttps://github.com/syedhali/EZAudio/issues/27#issuecomment-35702241 .

tylerstillwater commented 10 years ago

I am experiencing this same issue.

tylerstillwater commented 10 years ago

I am currently working on this. The refactor is complete, but the system just fails now. I've changed the code so it sets the hardware to the given sample rate, then sets up all the streams using that same sample rate. When the callback is called and AudioUnitRender runs, it returns -10863 (kAudioUnitErr_CannotDoInCurrentContext ) as an error. I read that this could be caused by a mismatch between the hardware sample rate and stream sample rate, but I think I've set them up appropriately:

if (_customASBD){
    Float64 sampleRate = streamFormat.mSampleRate;
    UInt32 sampleRateSize = sizeof(sampleRate);
    // Set the sample rate of the input device
    [EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
                                              kAudioUnitProperty_SampleRate,
                                              kAudioUnitScope_Input,
                                              kEZAudioMicrophoneOutputBus,
                                              &sampleRate,
                                              sampleRateSize)
               operation:"Could not set microphone's sample rate bus 0"];
    [EZAudio checkResult:AudioUnitSetProperty(microphoneInput,
                                              kAudioUnitProperty_SampleRate,
                                              kAudioUnitScope_Output,
                                              kEZAudioMicrophoneInputBus,
                                              &sampleRate,
                                              sampleRateSize)
               operation:"Could not set microphone's sample rate bus 1"];
  }

Anyone have an idea on what could be happening? When I use the Audio MIDI Setup program, it shows that the sample rate is 44100. So perhaps it isn't actually changing the sample rate of the hardware?

Additionally, changing the sample rate to 48000 in Audio MIDI Setup does not resolve the issue.

tylerstillwater commented 10 years ago

Reading further, it seems the sample rate conversion must be done with a separate Audio Unit - an AudioConverter. Is this correct? I'm afraid I don't know too much about Core Audio.

tylerstillwater commented 10 years ago

It seems attempting to shoehorn the conversion and whatnot into this framework is a bad idea. I'm going with a custom solution.

orkenstein commented 9 years ago

Hi everybody! So any solution is available now? I need custom sample rate. Cause EZAudioPlot freezes the whole app when using EZMicrophone.

Ronileco commented 9 years ago

I believe I have the same issue. I can't set the mic sample rate, it overrides my configuration no matter how I try it.

Should I just move to the core audio session? or is there something I'm missing. Thanks.

ogoldfinger commented 9 years ago

The problem is the everything gets initialized BEFORE the custom absd is applied. What worked for me is just reinitializing. You can refactor this a bit more but what worked for me is calling _createInputUnit again after my absd is set:

-(EZMicrophone *)initWithMicrophoneDelegate:(id<EZMicrophoneDelegate>)microphoneDelegate
        withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription {
  self = [self initWithMicrophoneDelegate:microphoneDelegate];
  if(self){
    _customASBD  = YES;
    streamFormat = audioStreamBasicDescription;
    [self _createInputUnit]; // ADD THIS LINE TO RE-INITIALIZE
  }
  return self;

}

chenjishi commented 9 years ago

@ogoldfinger your method worked for me also!

syedhali commented 9 years ago

As of 0.1.0 release the EZMicrophone was rewritten to better support custom AudioStreamBasicDescription so you should just be able to use the initializer:

/**
 Creates an instance of the EZMicrophone with a delegate to respond to the audioReceived callback. This will not start fetching the audio until startFetchingAudio has been called. Use microphoneWithDelegate:startsImmediately: to instantiate this class and immediately start fetching audio data.
 @param     delegate    A EZMicrophoneDelegate delegate that will receive the audioReceived callback.
 @param     audioStreamBasicDescription A custom AudioStreamBasicFormat for the microphone input.
 @return    An instance of the EZMicrophone class. This should be declared as a strong property!
 */
+ (EZMicrophone *)microphoneWithDelegate:(id<EZMicrophoneDelegate>)delegate
         withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;