osx - Crackling audio due to wrong audio data -
i'm using coreaudio low level api audio capturing. app target mac osx, not ios.
during testing it, time time got annoying noise modulate real audio. phenomena develops time, started barely noticeable , become more , more dominant.
analyze captured audio under audacity indicate end part of audio packet wrong.
the intrusion repeat every 40 ms configured packetization time (in terms of buffer samples)
update: on time gap became larger, here snapshot same captured file 10 minutes later. gap contains 1460 samples 33ms total 40ms of packet!!
code snippests:
capture callback
osstatus macos_audiodevice::capturecallback(void *inrefcon, audiounitrenderactionflags *ioactionflags, const audiotimestamp *intimestamp, uint32 inbusnumber, uint32 innumberframes, audiobufferlist *iodata) { macos_audiodevice* _this = static_cast<macos_audiodevice*>(inrefcon); // new audio data osstatus err = audiounitrender(_this->m_auhal, ioactionflags, intimestamp, inbusnumber, innumberframes, _this->m_inputbuffer); if (err != noerr) { ... return err; } // ignore callback on unexpected buffer size if (_this->m_params.buffersizesamples != innumberframes) { ... return noerr; } // deliver audio data deviceiomessage message; message.buffersizebytes = _this->m_devicebuffersizebytes; message.buffer = _this->m_inputbuffer->mbuffers[0].mdata; if (_this->m_callbackfunc) { _this->m_callbackfunc(_this, message); } }
open , start capture device:
void macos_audiodevice::openauhalcapture() { uint32 enableio; audiostreambasicdescription streamformat; uint32 size; sint32 *channelarr; std::stringstream ss; audioobjectpropertyaddress devicebufsizeproperty = { kaudiodevicepropertybufferframesize, kaudiodevicepropertyscopeinput, kaudioobjectpropertyelementmaster }; // auhal audiocomponentdescription cd = {kaudiounittype_output, kaudiounitsubtype_haloutput, kaudiounitmanufacturer_apple, 0, 0}; audiocomponent haloutput = audiocomponentfindnext(null, &cd); verify_macosapi(audiocomponentinstancenew(haloutput, &m_auhal)); verify_macosapi(audiounitinitialize(m_auhal)); // enable input io enableio = 1; verify_macosapi(audiounitsetproperty(m_auhal, kaudiooutputunitproperty_enableio, kaudiounitscope_input, 1, &enableio, sizeof(enableio))); // disable output io enableio = 0; verify_macosapi(audiounitsetproperty(m_auhal, kaudiooutputunitproperty_enableio, kaudiounitscope_output, 0, &enableio, sizeof(enableio))); // setup current device size = sizeof(audiodeviceid); verify_macosapi(audiounitsetproperty(m_auhal, kaudiooutputunitproperty_currentdevice, kaudiounitscope_global, 0, &m_macdeviceid, sizeof(audiodeviceid))); // set device native buffer length before setting auhal stream size = sizeof(m_originaldevicebuffertimeframes); verify_macosapi(audioobjectsetpropertydata(m_macdeviceid, &devicebufsizeproperty, 0, null, size, &m_originaldevicebuffertimeframes)); // device format size = sizeof(audiostreambasicdescription); verify_macosapi(audiounitgetproperty(m_auhal, kaudiounitproperty_streamformat, kaudiounitscope_input, 1, &streamformat, &size)); // setup channel map assert(m_params.numofchannels <= streamformat.mchannelsperframe); channelarr = new sint32[streamformat.mchannelsperframe]; (int = 0; < streamformat.mchannelsperframe; i++) channelarr[i] = -1; (int = 0; < m_params.numofchannels; i++) channelarr[i] = i; verify_macosapi(audiounitsetproperty(m_auhal, kaudiooutputunitproperty_channelmap, kaudiounitscope_input, 1, channelarr, sizeof(sint32) * streamformat.mchannelsperframe)); delete [] channelarr; // setup stream converters streamformat.mformatid = kaudioformatlinearpcm; streamformat.mformatflags = kaudioformatflagissignedinteger; streamformat.mframesperpacket = m_samplesperpacket; streamformat.mbitsperchannel = m_params.sampledepthbits; streamformat.msamplerate = m_devicesamplerate; streamformat.mchannelsperframe = 1; streamformat.mbytesperframe = 2; streamformat.mbytesperpacket = streamformat.mframesperpacket * streamformat.mbytesperframe; verify_macosapi(audiounitsetproperty(m_auhal, kaudiounitproperty_streamformat, kaudiounitscope_output, 1, &streamformat, size)); // setup callbacks aurendercallbackstruct input; input.inputproc = capturecallback; input.inputprocrefcon = this; verify_macosapi(audiounitsetproperty(m_auhal, kaudiooutputunitproperty_setinputcallback, kaudiounitscope_global, 0, &input, sizeof(input))); // calculate size of io buffer (in samples) if (m_params.buffersizems != -1) { unsigned int desiredsignalsinbuffer = (m_params.buffersizems / (double)1000) * m_devicesamplerate; // making sure value stay in device's supported range desiredsignalsinbuffer = std::min<unsigned int>(desiredsignalsinbuffer, m_devicebufferframesrange.mmaximum); desiredsignalsinbuffer = std::max<unsigned int>(m_devicebufferframesrange.mminimum, desiredsignalsinbuffer); m_devicebufferframes = desiredsignalsinbuffer; } // set device buffer length size = sizeof(m_devicebufferframes); verify_macosapi(audioobjectsetpropertydata(m_macdeviceid, &devicebufsizeproperty, 0, null, size, &m_devicebufferframes)); m_devicebuffersizebytes = m_devicebufferframes * streamformat.mbytesperframe; m_devicebuffertimems = 1000 * m_devicebufferframes/m_devicesamplerate; // calculate number of buffers channels size = offsetof(audiobufferlist, mbuffers[0]) + (sizeof(audiobuffer) * m_params.numofchannels); // allocate input buffer m_inputbuffer = (audiobufferlist *)malloc(size); m_inputbuffer->mnumberbuffers = m_params.numofchannels; // pre-malloc buffers audiobufferlists for(uint32 = 0; i< m_inputbuffer->mnumberbuffers ; i++) { m_inputbuffer->mbuffers[i].mnumberchannels = 1; m_inputbuffer->mbuffers[i].mdatabytesize = m_devicebuffersizebytes; m_inputbuffer->mbuffers[i].mdata = malloc(m_devicebuffersizebytes); } // update class properties m_params.sampleratehz = streamformat.msamplerate; m_params.buffersizesamples = m_devicebufferframes; m_params.buffersizebytes = m_params.buffersizesamples * streamformat.mbytesperframe; } eadmreturncode macos_audiodevice::start() { eadmreturncode ret = ok; logapi(ret); if (!m_isstarted && m_isopen) { osstatus err = audiooutputunitstart(m_auhal); if (err == noerr) m_isstarted = true; else ret = error; } return ret; }
any idea cause , how solve?
thanks in advance!
periodic glitches or dropouts can caused not paying attention or not processing number of frames sent each audio callback. valid buffers don't contain expected or same number of samples (innumberframes might not equal buffersizesamples or previous innumberframes in valid audio buffer).
it possible these types of glitches might caused attempting record @ 44.1k on models of ios devices support 48k audio in hardware.
some types of glitch might caused non-hard-real-time code within m_callbackfunc function (such synchronous file reads/writes, os calls, objective c message dispatch, gc, or memory allocation/deallocation).
Comments
Post a Comment