bool AudioDecoder::start() { auto oldTime = clockNow(); auto nowTime = oldTime; bool ret; do { ret = decodeToPcm(); if (!ret) { ALOGE("decodeToPcm (%s) failed!", _url.c_str()); break; } nowTime = clockNow(); ALOGD("Decoding (%s) to pcm data wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); oldTime = nowTime; ret = resample(); if (!ret) { ALOGE("resample (%s) failed!", _url.c_str()); break; } nowTime = clockNow(); ALOGD("Resampling (%s) wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); oldTime = nowTime; ret = interleave(); if (!ret) { ALOGE("interleave (%s) failed!", _url.c_str()); break; } nowTime = clockNow(); ALOGD("Interleave (%s) wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); } while(false); ALOGV_IF(!ret, "%s returns false, decode (%s)", __FUNCTION__, _url.c_str()); return ret; }
void AudioMixerController::mixOneFrame() { _isMixingFrame = true; _activeTracksMutex.lock(); auto mixStart = clockNow(); std::vector<Track*> tracksToRemove; tracksToRemove.reserve(_activeTracks.size()); // FOR TESTING BEGIN // Track* track = _activeTracks[0]; // // AudioBufferProvider::Buffer buffer; // buffer.frameCount = _bufferSizeInFrames; // status_t r = track->getNextBuffer(&buffer); //// ALOG_ASSERT(buffer.frameCount == _mixing->size / 2, "buffer.frameCount:%d, _mixing->size/2:%d", buffer.frameCount, _mixing->size/2); // if (r == NO_ERROR) // { // ALOGV("getNextBuffer succeed ..."); // memcpy(_mixing->buf, buffer.raw, _mixing->size); // } // if (buffer.raw == nullptr) // { // ALOGV("Play over ..."); // tracksToRemove.push_back(track); // } // else // { // track->releaseBuffer(&buffer); // } // // _mixing->state = BufferState::FULL; // _activeTracksMutex.unlock(); // FOR TESTING END Track::State state; // set up the tracks. for (auto&& track : _activeTracks) { state = track->getState(); if (state == Track::State::IDLE) { initTrack(track, tracksToRemove); } else if (state == Track::State::PLAYING) { if (!track->isInitialized()) { initTrack(track, tracksToRemove); } int name = track->getName(); ALOG_ASSERT(name >= 0); std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex); if (track->isVolumeDirty()) { gain_minifloat_packed_t volume = track->getVolumeLR(); float lVolume = float_from_gain(gain_minifloat_unpack_left(volume)); float rVolume = float_from_gain(gain_minifloat_unpack_right(volume)); ALOGV("Track (name: %d)'s volume is dirty, update volume to L: %f, R: %f", name, lVolume, rVolume); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume); track->setVolumeDirty(false); } } else if (state == Track::State::RESUMED) { if (!track->isInitialized()) { initTrack(track, tracksToRemove); } if (track->getPrevState() == Track::State::PAUSED) { _mixer->enable(track->getName()); track->setState(Track::State::PLAYING); } else { ALOGW("Previous state (%d) isn't PAUSED, couldn't resume!", static_cast<int>(track->getPrevState())); } } else if (state == Track::State::PAUSED) { if (!track->isInitialized()) { initTrack(track, tracksToRemove); } if (track->getPrevState() == Track::State::PLAYING || track->getPrevState() == Track::State::RESUMED) { _mixer->disable(track->getName()); } else { ALOGW("Previous state (%d) isn't PLAYING, couldn't pause!", static_cast<int>(track->getPrevState())); } } else if (state == Track::State::STOPPED) { if (track->isInitialized()) { if (track->getPrevState() != Track::State::IDLE) { _mixer->deleteTrackName(track->getName()); } else { ALOGV("Stop track (%p) while it's in IDLE state!", track); } } else { ALOGV("Track (%p) hasn't been initialized yet!", track); } tracksToRemove.push_back(track); } if (track->isPlayOver()) { if (track->isLoop()) { track->reset(); } else { ALOGV("Play over ..."); _mixer->deleteTrackName(track->getName()); tracksToRemove.push_back(track); track->setState(Track::State::OVER); } } } bool hasAvailableTracks = _activeTracks.size() - tracksToRemove.size() > 0; if (hasAvailableTracks) { ALOGV_IF(_activeTracks.size() > 8, "More than 8 active tracks: %d", (int) _activeTracks.size()); _mixer->process(AudioBufferProvider::kInvalidPTS); } else { ALOGV("Doesn't have enough tracks: %d, %d", (int) _activeTracks.size(), (int) tracksToRemove.size()); } // Remove stopped or playover tracks for active tracks container for (auto&& track : tracksToRemove) { removeItemFromVector(_activeTracks, track); if (track != nullptr && track->onStateChanged != nullptr) { track->onStateChanged(Track::State::DESTROYED); } else { ALOGE("track (%p) was released ...", track); } } _activeTracksMutex.unlock(); auto mixEnd = clockNow(); float mixInterval = intervalInMS(mixStart, mixEnd); ALOGV_IF(mixInterval > 1.0f, "Mix a frame waste: %fms", mixInterval); _isMixingFrame = false; }