int AudioFormat::bytesPerFrame() const { if (!isValid()) return 0; return bytesPerSample() * channels(); }
static int ao_opensl_level(dtaudio_output_t *aout) { aout_sys_t *sys = (aout_sys_t *) aout->ao_priv; dt_lock(&sys->lock); int level = sys->samples * bytesPerSample(aout); const int unit_size = sys->samples_per_buf * bytesPerSample(aout); SLAndroidSimpleBufferQueueState st; if (!sys->started) goto END; SLresult res = GetState(sys->playerBufferQueue, &st); if (unlikely(res != SL_RESULT_SUCCESS)) { goto END; } level += st.count * unit_size; //__android_log_print(ANDROID_LOG_DEBUG,TAG, "opensl level:%d st.count:%d sample:%d:%d \n",level, (int)st.count, sys->samples); END: dt_unlock(&sys->lock); return level; }
/***************************************************************************** * Play: play a sound *****************************************************************************/ static int Play(dtaudio_output_t *aout, uint8_t *buf, int size) { aout_sys_t *sys = (aout_sys_t *) aout->ao_priv; int ret = 0; //__android_log_print(ANDROID_LOG_DEBUG,TAG, "space:%d level:%d size:%d \n",buf_space(&sys->dbt), buf_level(&sys->dbt), size); if (buf_space(&sys->dbt) > size) { ret = buf_put(&sys->dbt, buf, size); } sys->samples += ret / bytesPerSample(aout); //__android_log_print(ANDROID_LOG_DEBUG,TAG, "add sampels, %d add %d \n",sys->samples, ret / bytesPerSample(aout)); /* Fill OpenSL buffer */ WriteBuffer(aout); // will read data in callback return ret; }
static int WriteBuffer(dtaudio_output_t *aout) { aout_sys_t *sys = (aout_sys_t *) aout->ao_priv; const int unit_size = sys->samples_per_buf * bytesPerSample(aout); /* Check if we can fill at least one buffer unit by chaining blocks */ if (sys->dbt.level < unit_size) { return false; } SLAndroidSimpleBufferQueueState st; SLresult res = GetState(sys->playerBufferQueue, &st); if (unlikely(res != SL_RESULT_SUCCESS)) { return false; } if (st.count == OPENSLES_BUFFERS) return false; int done = 0; while (done < unit_size) { int cur = buf_level(&sys->dbt); if (cur > unit_size - done) cur = unit_size - done; //memcpy(&sys->buf[unit_size * sys->next_buf + done], b->p_buffer, cur); buf_get(&sys->dbt, &sys->buf[unit_size * sys->next_buf + done], cur); done += cur; if (done == unit_size) break; } SLresult r = Enqueue(sys->playerBufferQueue, &sys->buf[unit_size * sys->next_buf], unit_size); sys->samples -= sys->samples_per_buf; //__android_log_print(ANDROID_LOG_DEBUG,TAG, "minus sampels, %d minus %d \n",sys->samples, sys->samples_per_buf); if (r == SL_RESULT_SUCCESS) { if (++sys->next_buf == OPENSLES_BUFFERS) sys->next_buf = 0; return true; } else { /* XXX : if writing fails, we don't retry */ return false; } }
static int64_t ao_opensl_get_latency(dtaudio_output_t *aout) { int64_t latency; int ret = 0; int level = 0; aout_sys_t *sys = (aout_sys_t *) aout->ao_priv; #if 1 TimeGet(aout, &latency); if (latency == -1) return 0; latency = 9 * latency / 100; #else dtaudio_para_t *para = &aout->para; level = ao_opensl_level(aout); int sample_num; float pts_ratio = 0.0; pts_ratio = (double) 90000 / para->dst_samplerate; sample_num = level / bytesPerSample(aout); latency += (sample_num * pts_ratio); #endif //__android_log_print(ANDROID_LOG_DEBUG,TAG, "opensl latency, level:%d latency:%lld \n",level, latency); return latency; }
static int Start(dtaudio_output_t *aout) { SLresult result; aout_sys_t *sys = (aout_sys_t *) aout->ao_priv; dtaudio_para_t *para = &aout->para; // configure audio source - this defines the number of samples you can enqueue. SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, OPENSLES_BUFFERS }; int mask; if (para->dst_channels > 1) mask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; else mask = SL_SPEAKER_FRONT_CENTER; SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; format_pcm.numChannels = para->dst_channels; //format_pcm.samplesPerSec = ((SLuint32) para->dst_samplerate * 1000) ; format_pcm.samplesPerSec = ((SLuint32) convertSampleRate(para->dst_samplerate)); format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; format_pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; format_pcm.channelMask = mask; format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; SLDataSource audioSrc = {&loc_bufq, &format_pcm}; // configure audio sink SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, sys->outputMixObject }; SLDataSink audioSnk = {&loc_outmix, NULL}; //create audio player const SLInterfaceID ids2[] = {sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE, sys->SL_IID_VOLUME}; static const SLboolean req2[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; result = CreateAudioPlayer(sys->engineEngine, &sys->playerObject, &audioSrc, &audioSnk, sizeof(ids2) / sizeof(*ids2), ids2, req2); if (unlikely(result != SL_RESULT_SUCCESS)) { // error return -1; /* Try again with a more sensible samplerate */ #if 0 fmt->i_rate = 44100; format_pcm.samplesPerSec = ((SLuint32) 44100 * 1000) ; result = CreateAudioPlayer(sys->engineEngine, &sys->playerObject, &audioSrc, &audioSnk, sizeof(ids2) / sizeof(*ids2), ids2, req2); #endif } CHECK_OPENSL_ERROR("Failed to create audio player"); result = Realize(sys->playerObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR("Failed to realize player object."); result = GetInterface(sys->playerObject, sys->SL_IID_PLAY, &sys->playerPlay); CHECK_OPENSL_ERROR("Failed to get player interface."); result = GetInterface(sys->playerObject, sys->SL_IID_VOLUME, &sys->volumeItf); CHECK_OPENSL_ERROR("failed to get volume interface."); result = GetInterface(sys->playerObject, sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &sys->playerBufferQueue); CHECK_OPENSL_ERROR("Failed to get buff queue interface"); result = RegisterCallback(sys->playerBufferQueue, PlayedCallback, (void *) aout); CHECK_OPENSL_ERROR("Failed to register buff queue callback."); // set the player's state to playing result = SetPlayState(sys->playerPlay, SL_PLAYSTATE_PLAYING); CHECK_OPENSL_ERROR("Failed to switch to playing state"); /* XXX: rounding shouldn't affect us at normal sampling rate */ sys->rate = para->dst_samplerate; sys->samples_per_buf = OPENSLES_BUFLEN * para->dst_samplerate / 1000; sys->buf = malloc(OPENSLES_BUFFERS * sys->samples_per_buf * bytesPerSample(aout)); if (!sys->buf) goto error; sys->started = 0; sys->next_buf = 0; sys->samples = 0; SetPositionUpdatePeriod(sys->playerPlay, AOUT_MIN_PREPARE_TIME * 1000 / CLOCK_FREQ); return 0; error: if (sys->playerObject) { Destroy(sys->playerObject); sys->playerObject = NULL; } return -1; }
int DecoderAudio::decodeRender() { /* * Process some special Events * 1) BOS * 2) EOS */ AVPacket pkt; av_init_packet(&pkt); CHECK_POINTER_INT(mQueue, -1); LOGD("AudioQueue get start()"); if (mQueue -> get(&pkt, true) != PacketQueue::PQ_OP_SUCCESS) { LOGE("getAudio Packet error, thread exit!"); return -1; } LOGD("AudioQueue get end()"); if (&BOS_PKT == &pkt) { LOGI("Audio Decoder Received BOS PKT!"); /* update our clock */ pkt.pts; return 0; } else if (&EOS_PKT == &pkt) { LOGI("Audio Decoder Received EOS PKT!"); return 0; } if (pkt.pts != AV_NOPTS_VALUE) { mAudioClock = av_q2d(mStream -> time_base) * pkt.pts; } LOGD("after adjust 1 mAudioClock:%f!", mAudioClock); AVCodecContext * dec = mStream -> codec; CHECK_POINTER_INT(dec, -1); int remainBufSize = mSamplesSize, curOutputBufSize = mSamplesSize; int dataSize = 0; int16_t * outputBuf = mSamples; AVPacket dupPkt = pkt; while ((dupPkt.size > 0) && ((curOutputBufSize = remainBufSize) > 0)) { LOGD("Before avcodec_decode_audio3()"); int len = avcodec_decode_audio3(mStream -> codec, (int16_t *) outputBuf, &curOutputBufSize, &pkt); LOGD("after avcodec_decode_audio3() len:%d, curOutputBufSize:%d", len, curOutputBufSize); if ((len < 0) || (!curOutputBufSize)) { dupPkt.size = 0; break; } LOGD("After avcodec_decode_audio3()"); dupPkt.data += len; dupPkt.size -= len; remainBufSize -= curOutputBufSize; outputBuf += curOutputBufSize / (sizeof(int16_t)); dataSize += curOutputBufSize; LOGD("Audio Decoder Thread Processing"); } LOGD("Jump out of while loop"); double bytesPerSec = dec -> channels * bytesPerSample(dec -> sample_fmt) * dec -> sample_rate; mAudioClock += (double) dataSize / (double) (bytesPerSec); LOGD("after adjust 2 mAudioClock:%f, mLastClock:%f!", mAudioClock, mLastClock); // TODO: // update the delay time mTimer = (mAudioClock - mLastClock); // call handler for posting buffer to os audio driver LOGD("Before rendorHook() mTimer:%f", mTimer); rendorHook(mSamples, dataSize); long delta = now() - mLastAbsTime; LOGD("delta:%lld, mLastAbsTime:%lld, now():%lld", delta, mLastAbsTime, now()); mLastAbsTime = now(); usleep(mTimer * 1e6); mLastClock = mAudioClock; CHECK_POINTER_INT(mBuddy, -1); BuddyEvent evt; evt.type = AV_SYNC; evt.data.dData = mAudioClock; LOGD("Ready to call mBuddy's onBuddyEvent()"); mBuddy-> onBuddyEvent(this, evt); av_free_packet(&pkt); LOGD("Ready to call av_free_packet() called!"); return 0; }
/********************************* Fonction RecordFichier Permet d'enregistrer un fichier WAV *********************************/ void UAudioCaptureMic::mainLoop() { if(!_sound) { UERROR("Recorder is not initialized."); this->kill(); return; } FMOD_RESULT result; void *ptr1 = 0, *ptr2 = 0; int blockLength; unsigned int len1 = 0, len2 = 0; unsigned int recordPos = 0; result = UAudioSystem::getRecordPosition(_driver, &recordPos); UASSERT_MSG(result==FMOD_OK, FMOD_ErrorString(result)); if (recordPos != _lastRecordPos) { blockLength = (int)recordPos - (int)_lastRecordPos; if (blockLength < 0) { blockLength += _soundLength; } // * exinfo.numchannels * 2 = stereo 16bit. 1 sample = 4 bytes. // Lock the sound to get access to the raw data. FMOD_Sound_Lock(_sound, _lastRecordPos * channels() * bytesPerSample(), blockLength * channels() * bytesPerSample(), &ptr1, &ptr2, &len1, &len2); { if (ptr1 && len1) // Write it to disk. { if(_fp) { //write to file _dataLength += fwrite(ptr1, 1, len1, _fp); } // push back in the frames buffer pushBackSamples(ptr1, len1); } if (ptr2 && len2) // Write it to disk. { if(_fp) { //write to file _dataLength += fwrite(ptr2, 1, len2, _fp); } // push back in the frames buffer pushBackSamples(ptr2, len2); } } //Unlock the sound to allow FMOD to use it again. FMOD_Sound_Unlock(_sound, ptr1, ptr2, len1, len2); _lastRecordPos = recordPos; } UAudioSystem::update(); uSleep(10); // If we are recording to a file, make sure to stop // when the maximum file size is reached if (_fp && _maxFileSize != 0 && int(_dataLength) + frameLength()*bytesPerSample() > _maxFileSize) { UWARN("Recording max memory reached (%d Mb)... stopped", _maxFileSize/1000000); this->kill(); } }
bool UAudioCaptureMic::init() { this->close(); bool ok = UAudioCapture::init(); if(ok) { std::string::size_type loc; if(_fileName.size()) { loc = _fileName.find( ".mp3", 0 ); if( loc != std::string::npos ) { #ifdef BUILT_WITH_LAME _encodeToMp3 = true; #else _fileName.append(".wav"); UERROR("Cannot write to a mp3, saving to a wav instead (%s)", _fileName.c_str()); #endif } _fp = fopen(_fileName.c_str(), "wb"); } FMOD_RESULT result; FMOD_BOOL isRecording = false; result = UAudioSystem::isRecording(_driver, &isRecording); UASSERT_MSG(result==FMOD_OK, FMOD_ErrorString(result)); if(isRecording) { result = UAudioSystem::recordStop(_driver); UASSERT_MSG(result==FMOD_OK, FMOD_ErrorString(result)); } _dataLength = 0; _soundLength = 0; _lastRecordPos = 0; FMOD_CREATESOUNDEXINFO exinfo; memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = channels(); if(bytesPerSample() == 1) { exinfo.format = FMOD_SOUND_FORMAT_PCM8; } else if(bytesPerSample() == 2) { exinfo.format = FMOD_SOUND_FORMAT_PCM16; } else if(bytesPerSample() == 3) { exinfo.format = FMOD_SOUND_FORMAT_PCM24; } else if(bytesPerSample() == 4) { exinfo.format = FMOD_SOUND_FORMAT_PCM32; } exinfo.defaultfrequency = (int)fs(); exinfo.length = exinfo.defaultfrequency * bytesPerSample() * exinfo.numchannels * 2; // 2 -> pour deux secondes result = UAudioSystem::createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &_sound); UASSERT_MSG(result==FMOD_OK, FMOD_ErrorString(result)); if(_fp) { int channels, bits; float rate; FMOD_Sound_GetFormat(_sound, 0, 0, &channels, &bits); FMOD_Sound_GetDefaults(_sound, &rate, 0, 0, 0); UWav::writeWavHeader(_fp, _dataLength, rate, channels, bits); // Write out the wav header. La longueur sera de 0 puisqu'elle est incunnue pour l'instant. } result = FMOD_Sound_GetLength(_sound, &_soundLength, FMOD_TIMEUNIT_PCM); UASSERT_MSG(result==FMOD_OK, FMOD_ErrorString(result)); } return ok; }
int AudioFormat::bytesPerSecond() const { return channels() * bytesPerSample() * sampleRate(); }