audio - Opus for iOS, crashing with 16000 sample rate -
i developing voip application opus ios (objective-c , c++).
works fine 8000, 12000, 24000 , 48000 sampling rate except 16000, application crashes on opus_encode method.
here doing:
m_oaudiosession = [avaudiosession sharedinstance]; [m_oaudiosession setcategory:avaudiosessioncategoryplayandrecord error:&m_oerror]; [m_oaudiosession setmode:avaudiosessionmodevoicechat error:&m_oerror]; [m_oaudiosession setpreferredsamplerate:voip_audio_driver_default_sample_rate error:&m_oerror]; [m_oaudiosession setpreferredinputnumberofchannels:voip_audio_driver_default_input_channels error:&m_oerror]; [m_oaudiosession setpreferredoutputnumberofchannels:voip_audio_driver_default_output_channels error:&m_oerror]; [m_oaudiosession setpreferrediobufferduration:voip_audio_driver_default_buffer_duration error:&m_oerror]; [m_oaudiosession setactive:yes error:&m_oerror];
constants:
voip_audio_driver_default_sample_rate 16000 voip_audio_driver_default_input_channels 1 voip_audio_driver_default_output_channels 1 voip_audio_driver_default_buffer_duration 0.02 voip_audio_driver_frames_per_packet 1
after using real sampling rate , buffer duration m_oaudiosession.samplerate , m_oaudiosession.iobufferduration. set m_fsamplerate , m_fbufferduration variables.
the configurations are:
//describes audio component: m_saudiodescription.componenttype = kaudiounittype_output; m_saudiodescription.componentsubtype = kaudiounitsubtype_voiceprocessingio/*kaudiounitsubtype_remoteio*/; m_saudiodescription.componentflags = 0; m_saudiodescription.componentflagsmask = 0; m_saudiodescription.componentmanufacturer = kaudiounitmanufacturer_apple; m_saudioformat.msamplerate = m_fsamplerate; m_saudioformat.mformatid = kaudioformatlinearpcm; m_saudioformat.mformatflags = kaudioformatflagissignedinteger | kaudioformatflagispacked; m_saudioformat.mframesperpacket = voip_audio_driver_frames_per_packet; m_saudioformat.mchannelsperframe = voip_audio_driver_default_input_channels; m_saudioformat.mbitsperchannel = (uint32)(8 * m_ibytespersample); m_saudioformat.mbytesperframe = (uint32)((m_saudioformat.mbitsperchannel / 8) * m_saudioformat.mchannelsperframe); m_saudioformat.mbytesperpacket = m_saudioformat.mbytesperframe * m_saudioformat.mframesperpacket; m_saudioformat.mreserved = 0;
calculations make are:
m_ibytespersample = sizeof(/*audiosampletype*/sint16); //calculating buffer size: int samplesperframe = (int)(m_fbufferduration * m_fsamplerate) + 1; m_ibuffersizebytes = samplesperframe * m_ibytespersample; //allocating input buffer: uint32 inputbufferlistsize = offsetof(audiobufferlist, mbuffers[0]) + (sizeof(audiobuffer) * m_saudioformat.mchannelsperframe); m_sinputbuffer = (audiobufferlist *)voipalloc(inputbufferlistsize); m_sinputbuffer->mnumberbuffers = m_saudioformat.mchannelsperframe; //pre-mallocating buffers audiobufferlists for(voipuint32 tmp_int1 = 0; tmp_int1 < m_sinputbuffer->mnumberbuffers; tmp_int1++) { m_sinputbuffer->mbuffers[tmp_int1].mnumberchannels = voip_audio_driver_default_input_channels; m_sinputbuffer->mbuffers[tmp_int1].mdatabytesize = (uint32)m_ibuffersizebytes; m_sinputbuffer->mbuffers[tmp_int1].mdata = voipalloc(m_ibuffersizebytes); memset(m_sinputbuffer->mbuffers[tmp_int1].mdata, 0, m_ibuffersizebytes); }
reading , writing audio unit done using m_sinputbuffer.
here opus creation:
m_oencoder = opus_encoder_create(m_isamplerate, m_inumberofchannels, voip_audio_codecs_opus_application_type, &_error); if (_error < 0) { fprintf(stderr, "voipaudiocodecs error: failed create encoder: %s\n", opus_strerror(_error)); return; } _error = opus_encoder_ctl(m_oencoder, opus_set_bitrate(voip_audio_codecs_opus_bitrate)); if (_error < 0) { fprintf(stderr, "voipaudiocodecs error: failed set bitrate: %s\n", opus_strerror(_error)); return; } m_odecoder = opus_decoder_create(m_isamplerate, m_inumberofchannels, &_error); if (_error < 0) { fprintf(stderr, "voipaudiocodecs error: failed create decoder: %s\n", opus_strerror(_error)); return; }
opus configurations are:
voip_audio_codecs_opus_bitrate opus_bitrate_max //64000 //70400 //84800 //112000 voip_audio_codecs_opus_application_type opus_application_voip //opus_application_audio voip_audio_codecs_opus_max_frame_size 5760 //minimum: (120ms; 5760 48khz) voip_audio_codecs_opus_bytes_size 960 //120, 240, 480, 960, 1920, 2880
when encode , decode use these methods:
encode_opus(voipint16* rawsamples, int rawsamplessize) { unsigned char encodeddata[m_imaxpacketsize]; voipint32 bytesencoded; int framesize = rawsamplessize / m_ibytespersample; bytesencoded = opus_encode(m_oencoder, rawsamples, framesize, encodeddata, m_imaxpacketsize); if (bytesencoded < 0) { fprintf(stderr, "voipaudiocodecs error: encode failed: %s\n", opus_strerror(bytesencoded)); return nullptr; } svoipaudiocodecopusencoded* resultstruct = (svoipaudiocodecopusencoded* )voipalloc(sizeof(svoipaudiocodecopusencoded)); resultstruct->m_data = (unsigned char*)voipalloc(bytesencoded); memcpy(resultstruct->m_data, encodeddata, bytesencoded); resultstruct->m_datasize = bytesencoded; return resultstruct; } decode_opus(void* encodedsamples, voipint32 encodedsamplessize) { voipint16 decodedpacket[voip_audio_codecs_opus_max_frame_size]; int _framesize = opus_decode(m_odecoder, (const unsigned char*)encodedsamples, encodedsamplessize, decodedpacket, voip_audio_codecs_opus_max_frame_size, 0); if (_framesize < 0) { fprintf(stderr, "voipaudiocodecs error: decoder failed: %s\n", opus_strerror(_framesize)); return nullptr; } size_t framesize = (size_t)_framesize; svoipaudiocodecopusdecoded* resultstruct = (svoipaudiocodecopusdecoded* )voipalloc(sizeof(svoipaudiocodecopusdecoded)); resultstruct->m_data = (voipint16*)voipalloc(framesize * m_ibytespersample); memcpy(resultstruct->m_data, decodedpacket, (framesize * m_ibytespersample)); resultstruct->m_datasize = framesize * m_ibytespersample; return resultstruct; }
when app should send data:
voipuint32 itemsforprocess = inputaudioqueue->getitemcount(); (int tmp_queueitems = 0; tmp_queueitems < itemsforprocess; tmp_queueitems++) { svoipqueue* tmp_samples = inputaudioqueue->popitem(); m_ocirculartempinputbuffer->writedatatobuffer(tmp_samples->m_pdata, tmp_samples->m_idatasize); while (void* tmp_buffer = m_ocirculartempinputbuffer->readdatafrombuffer(voip_audio_codecs_opus_bytes_size)) { svoipaudiocodecopusencoded* encodedsamples = encode_opus((voipint16*)tmp_buffer, voip_audio_codecs_opus_bytes_size); //then packeting , real sending using tcp socket… } //rest of code… }
here reading:
svoipaudiocodecopusdecoded* decodedsamples = decode_opus(inputpacket->m_ppacketdata, (voipint32)inputpacket->m_ipacketsize); if (decodedsamples != nullptr) { m_ocirculartempoutputbuffer->writedatatobuffer(decodedsamples->m_data, decodedsamples->m_datasize); voipfree((void**)&decodedsamples->m_data); voipfree((void**)&decodedsamples); } while (void* tmp_buffer = m_ocirculartempoutputbuffer->readdatafrombuffer(m_ibuffersizebytes)) { outputaudioqueue->pushitem(tmp_buffer, m_ibuffersizebytes); }
inputaudioqueue queue recorded data audio unit’s callback.
outputaudioqueue queue used audio unit’s callback play sound.
m_imaxpacketsize same m_ibuffersizebytes.
questions are:
wondering, calculations correct?
, if not, how can improve them?
see mistake code?
have suggestion fixing crash bug on opus_encode method when sampling rate set 16000?
thank in advance.
ps. made tests sampling rate on 16000 , found this:
if use formula: frame_duration = frame_size / sample rate, , if set frame_duration preferediobufferduration:
120 / 16000 = 0.0075 //avaudiosession sets 0.008000 —— crashes
240 / 16000 = 0.015 //avaudiosession sets 0.016000 —— crashes
480 / 16000 = 0.03 //avaudiosession sets 0.032000 —— crashes
960 / 16000 = 0.06 //avaudiosession sets 0.064000 —— crashes
1920 / 16000 = 0.12 //avaudiosession sets 0.128000 —— works
2880 / 16000 = 0.18 //avaudiosession sets 0.128000 —— crashes
then found there no encoder crash sampling rate 16000 , preferrediobufferduration 0.12(1920), avaudiosession sets 0.128000. works in case.
ideas ?
Comments
Post a Comment