lundi 29 juin 2015

AURemoteIO EXC_BAD_ACCESS


In my iOS app I use open-source code (a mix of C++ and Objective-C) in a .mm file to find the max frequency of sound recorded by the mic. However, I'm getting a bad access error about 10% of the time and have no idea how to deal with it, as I'm using a language I'm not familiar with.

The NSLog output is as follows:

ERROR:     [0x19932f310] >aurioc> 806: failed: -50 (enable 3, outf< 2 ch,  44100 Hz, Int8.24, non-inter> inf< 2 ch,  44100 Hz, Int8.24, non-inter>)
2015-06-29 12:31:15.396 XXX[547:138175]  error = couldn't setup remote i/o unit

Here is where the error occurs:

AudioToolbox`AUInputElement::PullInput:
    0x182a821ec <+0>:   stp    x24, x23, [sp, #-64]!
    0x182a821f0 <+4>:   stp    x22, x21, [sp, #16]
    0x182a821f4 <+8>:   stp    x20, x19, [sp, #32]
    0x182a821f8 <+12>:  stp    x29, x30, [sp, #48]
    0x182a821fc <+16>:  add    x29, sp, #48
    0x182a82200 <+20>:  mov    x20, x4
    0x182a82204 <+24>:  mov    x23, x3
    0x182a82208 <+28>:  mov    x21, x2
    0x182a8220c <+32>:  mov    x22, x1
    0x182a82210 <+36>:  mov    x19, x0
    0x182a82214 <+40>:  ldr    w8, [x19, #164]
    0x182a82218 <+44>:  cbnz   w8, 0x182a82224           ; <+56>
    0x182a8221c <+48>:  movn   w0, #0x2a7b
    0x182a82220 <+52>:  b      0x182a822ac               ; <+192>
    0x182a82224 <+56>:  cmp    w8, #1
    0x182a82228 <+60>:  b.eq   0x182a82248               ; <+92>
    0x182a8222c <+64>:  ldrb   w8, [x19, #160]
    0x182a82230 <+68>:  cbz    w8, 0x182a82248           ; <+92>
    0x182a82234 <+72>:  add    x0, x19, #120
    0x182a82238 <+76>:  add    x1, x19, #80
    0x182a8223c <+80>:  mov    x2, x20
    0x182a82240 <+84>:  bl     0x182a810e4               ; AUBufferList::PrepareBuffer(CAStreamBasicDescription const&, unsigned int)
    0x182a82244 <+88>:  b      0x182a82258               ; <+108>
    0x182a82248 <+92>:  add    x0, x19, #120
    0x182a8224c <+96>:  add    x1, x19, #80
    0x182a82250 <+100>: mov    x2, x20
    0x182a82254 <+104>: bl     0x182a811e4               ; AUBufferList::PrepareNullBuffer(CAStreamBasicDescription const&, unsigned int)
    0x182a82258 <+108>: mov    x5, x0
    0x182a8225c <+112>: ldr    w8, [x19, #164]
    0x182a82260 <+116>: cmp    w8, #1
    0x182a82264 <+120>: b.ne   0x182a82284               ; <+152>
    0x182a82268 <+124>: ldr    x0, [x19, #184]
    0x182a8226c <+128>: ldr    w3, [x19, #192]
    0x182a82270 <+132>: mov    x1, x22
    0x182a82274 <+136>: mov    x2, x21
    0x182a82278 <+140>: mov    x4, x20
    0x182a8227c <+144>: bl     0x18298f0ec               ; AudioUnitRender
    0x182a82280 <+148>: b      0x182a8229c               ; <+176>
    0x182a82284 <+152>: ldp    x8, x0, [x19, #168]
    0x182a82288 <+156>: mov    x1, x22
    0x182a8228c <+160>: mov    x2, x21
    0x182a82290 <+164>: mov    x3, x23
    0x182a82294 <+168>: mov    x4, x20
    0x182a82298 <+172>: blr    x8
    0x182a8229c <+176>: ldr    w8, [x19, #164] // EXC_BAD_ACCESS HERE
    0x182a822a0 <+180>: cmp    w8, #0
    0x182a822a4 <+184>: movn   w8, #0x2a7b
    0x182a822a8 <+188>: csel   w0, w8, w0, eq
    0x182a822ac <+192>: ldp    x29, x30, [sp, #48]
    0x182a822b0 <+196>: ldp    x20, x19, [sp, #32]
    0x182a822b4 <+200>: ldp    x22, x21, [sp, #16]
    0x182a822b8 <+204>: ldp    x24, x23, [sp], #64
    0x182a822bc <+208>: ret    

The thing is, this error does not happen in the demo app using the open-source code, so I figure it must be something I added. The only code I added was to the view controller, the code between the three asterisks (***) in here:

#import "LightsViewController.h"

#import "mo_audio.h" //stuff that helps set up low-level audio
#import "FFTHelper.h"


#define SAMPLE_RATE 44100 //22050 //44100
#define FRAMESIZE  512
#define NUMCHANNELS 2

#define kOutputBus 0
#define kInputBus 1



/// Nyquist Maximum Frequency
const Float32 NyquistMaxFreq = SAMPLE_RATE/2.0;

/// caculates HZ value for specified index from a FFT bins vector
Float32 frequencyHerzValue(long frequencyIndex, long fftVectorSize, Float32 nyquistFrequency ) {
    return ((Float32)frequencyIndex/(Float32)fftVectorSize) * nyquistFrequency;
}



// The Main FFT Helper
FFTHelperRef *fftConverter = NULL;



//Accumulator Buffer=====================

// CHANGE "SAMPLE RATE" (?) HERE, I.E., HOW OFTEN THE METHOD IS RUN THAT SAMPLES THE MAX HZ
const UInt32 accumulatorDataLenght = 2048;  //16384; //32768; 65536; 131072;
UInt32 accumulatorFillIndex = 0;
Float32 *dataAccumulator = nil;
static void initializeAccumulator() {
    dataAccumulator = (Float32*) malloc(sizeof(Float32)*accumulatorDataLenght);
    accumulatorFillIndex = 0;
}
static void destroyAccumulator() {
    if (dataAccumulator!=NULL) {
        free(dataAccumulator);
        dataAccumulator = NULL;
    }
    accumulatorFillIndex = 0;
}

static BOOL accumulateFrames(Float32 *frames, UInt32 lenght) { //returned YES if full, NO otherwise.
    //    float zero = 0.0;
    //    vDSP_vsmul(frames, 1, &zero, frames, 1, lenght);

    if (accumulatorFillIndex>=accumulatorDataLenght) { return YES; } else {
        memmove(dataAccumulator+accumulatorFillIndex, frames, sizeof(Float32)*lenght);
        accumulatorFillIndex = accumulatorFillIndex+lenght;
        if (accumulatorFillIndex>=accumulatorDataLenght) { return YES; }
    }
    return NO;
}

static void emptyAccumulator() {
    accumulatorFillIndex = 0;
    memset(dataAccumulator, 0, sizeof(Float32)*accumulatorDataLenght);
}
//=======================================


//==========================Window Buffer
const UInt32 windowLength = accumulatorDataLenght;
Float32 *windowBuffer= NULL;
//=======================================



/// max value from vector with value index (using Accelerate Framework)
static Float32 vectorMaxValueACC32_index(Float32 *vector, unsigned long size, long step, unsigned long *outIndex) {
    Float32 maxVal;
    vDSP_maxvi(vector, step, &maxVal, outIndex, size);
    return maxVal;
}




///returns HZ of the strongest frequency.
static Float32 strongestFrequencyHZ(Float32 *buffer, FFTHelperRef *fftHelper, UInt32 frameSize, Float32 *freqValue) {
    Float32 *fftData = computeFFT(fftHelper, buffer, frameSize);
    fftData[0] = 0.0;
    unsigned long length = frameSize/2.0;
    Float32 max = 0;
    unsigned long maxIndex = 0;
    max = vectorMaxValueACC32_index(fftData, length, 1, &maxIndex);
    if (freqValue!=NULL) { *freqValue = max; }
    Float32 HZ = frequencyHerzValue(maxIndex, length, NyquistMaxFreq);
    return HZ;
}



__weak UILabel *labelToUpdate = nil;
int value;



#pragma mark MAIN CALLBACK
void AudioCallback( Float32 * buffer, UInt32 frameSize, void * userData )
{


    //take only data from 1 channel
    Float32 zero = 0.0;
    vDSP_vsadd(buffer, 2, &zero, buffer, 1, frameSize*NUMCHANNELS);



    if (accumulateFrames(buffer, frameSize)==YES) { //if full

        //windowing the time domain data before FFT (using Blackman Window)
        if (windowBuffer==NULL) { windowBuffer = (Float32*) malloc(sizeof(Float32)*windowLength); }
        vDSP_blkman_window(windowBuffer, windowLength, 0);
        vDSP_vmul(dataAccumulator, 1, windowBuffer, 1, dataAccumulator, 1, accumulatorDataLenght);
        //=========================================


        Float32 maxHZValue = 0;
        Float32 maxHZ = strongestFrequencyHZ(dataAccumulator, fftConverter, accumulatorDataLenght, &maxHZValue);

        //NSLog(@" max HZ = %0.3f ", maxHZ);
        dispatch_async(dispatch_get_main_queue(), ^{ //update UI only on main thread

            ***//labelToUpdate.text = [NSString stringWithFormat:@"%0.3f HZ",maxHZ];

            if (maxHZ > 18950.0f) {
                if (maxHZ < 19050.0f) {
                    value = 0;
                } else if (maxHZ < 19150.0f) {
                    value = 1;
                } else if (maxHZ < 19450.0f) {
                    value = 2;
                }
            }
        });***

        emptyAccumulator(); //empty the accumulator when finished
    }
    memset(buffer, 0, sizeof(Float32)*frameSize*NUMCHANNELS);
}













@interface LightsViewController ()
@property int hzValue;
@property NSTimer *timerWhiteAndOrage;
@property NSTimer *timerRedAndBlue;
@property NSTimer *methodTimer;
@end

@implementation LightsViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    //labelToUpdate = HZValueLabel;
    _hzValue = value;


    //initialize stuff
    fftConverter = FFTHelperCreate(accumulatorDataLenght);
    initializeAccumulator();
    [self initMomuAudio];

    NSTimer *timer = [NSTimer
                      scheduledTimerWithTimeInterval:(NSTimeInterval)(0.05f)
                      target:self
                      selector:@selector(didReceiveNewMaxHz)
                      userInfo:nil
                      repeats:TRUE];

    timer.fireDate = [NSDate dateWithTimeIntervalSinceNow:(NSTimeInterval) 0.1f];
    _methodTimer = timer;
}

-(void) initMomuAudio {
    bool result = false;
    result = MoAudio::init( SAMPLE_RATE, FRAMESIZE, NUMCHANNELS, false);
    if (!result) { NSLog(@" MoAudio init ERROR"); }
    result = MoAudio::start( AudioCallback, NULL );
    if (!result) { NSLog(@" MoAudio start ERROR"); }
}

-(void) dealloc {
    destroyAccumulator();
    FFTHelperRelease(fftConverter);
}

@end


Aucun commentaire:

Enregistrer un commentaire