示例#1
0
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;
}