Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc2fb720 authored by Wei Jia's avatar Wei Jia
Browse files

Add support of audio offloading for NuPlayer.

Change-Id: Ic83973339fb46a83b48382e6097925f45d200867
parent 0dba9b17
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
        HTTPLiveSource.cpp              \
        NuPlayer.cpp                    \
        NuPlayerDecoder.cpp             \
        NuPlayerDecoderPassThrough.cpp  \
        NuPlayerDriver.cpp              \
        NuPlayerRenderer.cpp            \
        NuPlayerStreamListener.cpp      \
+114 −14
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include "HTTPLiveSource.h"
#include "NuPlayerDecoder.h"
#include "NuPlayerDecoderPassThrough.h"
#include "NuPlayerDriver.h"
#include "NuPlayerRenderer.h"
#include "NuPlayerSource.h"
@@ -143,6 +144,7 @@ NuPlayer::NuPlayer()
    : mUIDValid(false),
      mSourceFlags(0),
      mVideoIsAVC(false),
      mOffloadAudio(false),
      mAudioEOS(false),
      mVideoEOS(false),
      mScanSourcesPending(false),
@@ -500,6 +502,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
            ALOGV("kWhatStart");

            mVideoIsAVC = false;
            mOffloadAudio = false;
            mAudioEOS = false;
            mVideoEOS = false;
            mSkipRenderingAudioUntilMediaTimeUs = -1;
@@ -517,6 +520,21 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                flags |= Renderer::FLAG_REAL_TIME;
            }

            sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
            audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
            if (mAudioSink != NULL) {
                streamType = mAudioSink->getAudioStreamType();
            }

            sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);

            mOffloadAudio =
                canOffloadStream(audioMeta, (videoFormat != NULL),
                                 true /* is_streaming */, streamType);
            if (mOffloadAudio) {
                flags |= Renderer::FLAG_OFFLOAD_AUDIO;
            }

            mRenderer = new Renderer(
                    mAudioSink,
                    new AMessage(kWhatRendererNotify, id()),
@@ -661,7 +679,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {

                    mAudioSink->close();

                    audio_output_flags_t flags;
                    uint32_t flags;
                    int64_t durationUs;
                    // FIXME: we should handle the case where the video decoder
                    // is created after we receive the format change indication.
@@ -682,6 +700,80 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                        channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
                    }

                    if (mOffloadAudio) {
                        audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
                        audio_offload_info_t offloadInfo =
                                AUDIO_INFO_INITIALIZER;

                        AString mime;
                        CHECK(format->findString("mime", &mime));

                        status_t err =
                            mapMimeToAudioFormat(audioFormat, mime.c_str());
                        if (err != OK) {
                            ALOGE("Couldn't map mime \"%s\" to a valid "
                                    "audio_format", mime.c_str());
                            mOffloadAudio = false;
                        } else {
                            ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
                                    mime.c_str(), audioFormat);

                            flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;

                            offloadInfo.duration_us = -1;
                            format->findInt64(
                                    "durationUs", &offloadInfo.duration_us);

                            int avgBitRate = -1;
                            format->findInt32("bit-rate", &avgBitRate);

                            offloadInfo.sample_rate = sampleRate;
                            offloadInfo.channel_mask = channelMask;
                            offloadInfo.format = audioFormat;
                            offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
                            offloadInfo.bit_rate = avgBitRate;
                            offloadInfo.has_video = (mVideoDecoder != NULL);
                            offloadInfo.is_streaming = true;

                            err = mAudioSink->open(
                                    sampleRate,
                                    numChannels,
                                    (audio_channel_mask_t)channelMask,
                                    audioFormat,
                                    8 /* bufferCount */,
                                    &NuPlayer::Renderer::AudioSinkCallback,
                                    mRenderer.get(),
                                    (audio_output_flags_t)flags,
                                    &offloadInfo);

                            if (err == OK) {
                                // If the playback is offloaded to h/w, we pass
                                // the HAL some metadata information.
                                // We don't want to do this for PCM because it
                                // will be going through the AudioFlinger mixer
                                // before reaching the hardware.
                                sp<MetaData> audioMeta =
                                    mSource->getFormatMeta(true /* audio */);
                                sendMetaDataToHal(mAudioSink, audioMeta);

                                err = mAudioSink->start();
                            }
                        }

                        if (err != OK) {
                            // Clean up, fall back to non offload mode.
                            mAudioSink->close();
                            mAudioDecoder.clear();
                            mRenderer->signalDisableOffloadAudio();
                            mOffloadAudio = false;

                            instantiateDecoder(
                                    true /* audio */, &mAudioDecoder);
                        }
                    }

                    if (!mOffloadAudio) {
                        flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
                        CHECK_EQ(mAudioSink->open(
                                    sampleRate,
                                    numChannels,
@@ -690,9 +782,10 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                                    8 /* bufferCount */,
                                    NULL,
                                    NULL,
                                flags),
                                    (audio_output_flags_t)flags),
                                 (status_t)OK);
                        mAudioSink->start();
                    }

                    mRenderer->signalAudioSinkChanged();
                } else {
@@ -968,8 +1061,15 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
        new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
                     id());

    *decoder = audio ? new Decoder(notify) :
                       new Decoder(notify, mNativeWindow);
    if (audio) {
        if (mOffloadAudio) {
            *decoder = new DecoderPassThrough(notify);
        } else {
            *decoder = new Decoder(notify);
        }
    } else {
        *decoder = new Decoder(notify, mNativeWindow);
    }
    (*decoder)->init();
    (*decoder)->configure(format);

+2 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ public:

private:
    struct Decoder;
    struct DecoderPassThrough;
    struct CCDecoder;
    struct GenericSource;
    struct HTTPLiveSource;
@@ -120,6 +121,7 @@ private:
    sp<MediaPlayerBase::AudioSink> mAudioSink;
    sp<Decoder> mVideoDecoder;
    bool mVideoIsAVC;
    bool mOffloadAudio;
    sp<Decoder> mAudioDecoder;
    sp<CCDecoder> mCCDecoder;
    sp<Renderer> mRenderer;
+6 −6
Original line number Diff line number Diff line
@@ -31,14 +31,14 @@ struct NuPlayer::Decoder : public AHandler {
    Decoder(const sp<AMessage> &notify,
            const sp<NativeWindowWrapper> &nativeWindow = NULL);

    void configure(const sp<AMessage> &format);
    void init();
    virtual void configure(const sp<AMessage> &format);
    virtual void init();

    void signalFlush();
    void signalResume();
    void initiateShutdown();
    virtual void signalFlush();
    virtual void signalResume();
    virtual void initiateShutdown();

    bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
    virtual bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;

    enum {
        kWhatFillThisBuffer      = 'flTB',
+237 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "NuPlayerDecoderPassThrough"
#include <utils/Log.h>
#include <inttypes.h>

#include "NuPlayerDecoderPassThrough.h"

#include <media/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>

namespace android {

static const int kMaxPendingBuffers = 10;

NuPlayer::DecoderPassThrough::DecoderPassThrough(
        const sp<AMessage> &notify)
    : Decoder(notify),
      mNotify(notify),
      mBufferGeneration(0),
      mReachedEOS(true),
      mPendingBuffers(0),
      mComponentName("pass through decoder") {
    mDecoderLooper = new ALooper;
    mDecoderLooper->setName("NuPlayerDecoderPassThrough");
    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
}

NuPlayer::DecoderPassThrough::~DecoderPassThrough() {
}

void NuPlayer::DecoderPassThrough::configure(const sp<AMessage> &format) {
    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
    msg->setMessage("format", format);
    msg->post();
}

void NuPlayer::DecoderPassThrough::init() {
    mDecoderLooper->registerHandler(this);
}

void NuPlayer::DecoderPassThrough::signalFlush() {
    (new AMessage(kWhatFlush, id()))->post();
}

void NuPlayer::DecoderPassThrough::signalResume() {
    (new AMessage(kWhatResume, id()))->post();
}

void NuPlayer::DecoderPassThrough::initiateShutdown() {
    (new AMessage(kWhatShutdown, id()))->post();
}

bool NuPlayer::DecoderPassThrough::supportsSeamlessFormatChange(
        const sp<AMessage> & /* targetFormat */) const {
    return true;
}

void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
    ALOGV("[%s] onConfigure", mComponentName.c_str());
    mPendingBuffers = 0;
    mReachedEOS = false;
    ++mBufferGeneration;

    requestABuffer();

    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatOutputFormatChanged);
    notify->setMessage("format", format);
    notify->post();
}

bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
    int32_t generation;
    CHECK(msg->findInt32("generation", &generation));
    return generation != mBufferGeneration;
}

void NuPlayer::DecoderPassThrough::requestABuffer() {
    if (mPendingBuffers >= kMaxPendingBuffers || mReachedEOS) {
        ALOGV("[%s] mReachedEOS=%d, max pending buffers(%d:%d)",
                mComponentName.c_str(), (mReachedEOS ? 1 : 0),
                mPendingBuffers, kMaxPendingBuffers);
        return;
    }

    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
    reply->setInt32("generation", mBufferGeneration);

    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatFillThisBuffer);
    notify->setMessage("reply", reply);
    notify->post();
    mPendingBuffers++;

    sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
    message->setInt32("generation", mBufferGeneration);
    message->post();
    return;
}

void android::NuPlayer::DecoderPassThrough::onInputBufferFilled(
        const sp<AMessage> &msg) {
    if (mReachedEOS) {
        return;
    }

    sp<ABuffer> buffer;
    msg->findBuffer("buffer", &buffer);
    if (buffer == NULL) {
        mReachedEOS = true;

        sp<AMessage> notify = mNotify->dup();
        notify->setInt32("what", kWhatEOS);
        notify->setInt32("err", ERROR_END_OF_STREAM);
        notify->post();
        return;
    }

    sp<AMessage> reply = new AMessage(kWhatBufferConsumed, id());
    reply->setInt32("generation", mBufferGeneration);

    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatDrainThisBuffer);
    notify->setBuffer("buffer", buffer);
    notify->setMessage("reply", reply);
    notify->post();
}

void NuPlayer::DecoderPassThrough::onBufferConsumed() {
    mPendingBuffers--;
    sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
    message->setInt32("generation", mBufferGeneration);
    message->post();
}

void NuPlayer::DecoderPassThrough::onFlush() {
    ++mBufferGeneration;

    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatFlushCompleted);
    notify->post();
    mPendingBuffers = 0;
    mReachedEOS = false;
}

void NuPlayer::DecoderPassThrough::onShutdown() {
    ++mBufferGeneration;

    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatShutdownCompleted);
    notify->post();
    mReachedEOS = true;
}

void NuPlayer::DecoderPassThrough::onMessageReceived(const sp<AMessage> &msg) {
    ALOGV("[%s] onMessage: %s", mComponentName.c_str(),
            msg->debugString().c_str());

    switch (msg->what()) {
        case kWhatConfigure:
        {
            sp<AMessage> format;
            CHECK(msg->findMessage("format", &format));
            onConfigure(format);
            break;
        }

        case kWhatRequestABuffer:
        {
            if (!isStaleReply(msg)) {
                requestABuffer();
            }

            break;
        }

        case kWhatInputBufferFilled:
        {
            if (!isStaleReply(msg)) {
                onInputBufferFilled(msg);
            }
            break;
        }

        case kWhatBufferConsumed:
        {
            if (!isStaleReply(msg)) {
                onBufferConsumed();
            }
            break;
        }

        case kWhatFlush:
        {
            onFlush();
            break;
        }

        case kWhatResume:
        {
            requestABuffer();
            break;
        }

        case kWhatShutdown:
        {
            onShutdown();
            break;
        }

        default:
            TRESPASS();
            break;
    }
}

}  // namespace android
Loading