diff -r 000000000000 -r 6474c204b198 content/media/omx/AudioOutput.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/omx/AudioOutput.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (C) 2008 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. + */ + +#include +#include "AudioOutput.h" + +namespace mozilla { + +#ifdef PR_LOGGING +extern PRLogModuleInfo* gAudioOffloadPlayerLog; +#define AUDIO_OFFLOAD_LOG(type, msg) \ + PR_LOG(gAudioOffloadPlayerLog, type, msg) +#else +#define AUDIO_OFFLOAD_LOG(type, msg) +#endif + +using namespace android; + +AudioOutput::AudioOutput(int aSessionId, int aUid) : + mCallback(nullptr), + mCallbackCookie(nullptr), + mCallbackData(nullptr), + mSessionId(aSessionId), + mUid(aUid) +{ +#ifdef PR_LOGGING + if (!gAudioOffloadPlayerLog) { + gAudioOffloadPlayerLog = PR_NewLogModule("AudioOffloadPlayer"); + } +#endif +} + +AudioOutput::~AudioOutput() +{ + Close(); +} + +ssize_t AudioOutput::FrameSize() const +{ + if (!mTrack.get()) { + return NO_INIT; + } + return mTrack->frameSize(); +} + +status_t AudioOutput::GetPosition(uint32_t *aPosition) const +{ + if (!mTrack.get()) { + return NO_INIT; + } + return mTrack->getPosition(aPosition); +} + +status_t AudioOutput::SetVolume(float aVolume) const +{ + if (!mTrack.get()) { + return NO_INIT; + } + return mTrack->setVolume(aVolume); +} + +status_t AudioOutput::SetParameters(const String8& aKeyValuePairs) +{ + if (!mTrack.get()) { + return NO_INIT; + } + return mTrack->setParameters(aKeyValuePairs); +} + +status_t AudioOutput::Open(uint32_t aSampleRate, + int aChannelCount, + audio_channel_mask_t aChannelMask, + audio_format_t aFormat, + AudioCallback aCb, + void* aCookie, + audio_output_flags_t aFlags, + const audio_offload_info_t *aOffloadInfo) +{ + mCallback = aCb; + mCallbackCookie = aCookie; + + if (((aFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || !aCb || + !aOffloadInfo) { + return BAD_VALUE; + } + + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", + aSampleRate, aChannelCount, aChannelMask, aFormat, mSessionId, aFlags)); + + if (aChannelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) { + aChannelMask = audio_channel_out_mask_from_count(aChannelCount); + if (0 == aChannelMask) { + AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("open() error, can\'t derive mask for" + " %d audio channels", aChannelCount)); + return NO_INIT; + } + } + + sp t; + CallbackData* newcbd = new CallbackData(this); + + t = new AudioTrack( + AUDIO_STREAM_MUSIC, + aSampleRate, + aFormat, + aChannelMask, + 0, // Offloaded tracks will get frame count from AudioFlinger + aFlags, + CallbackWrapper, + newcbd, + 0, // notification frames + mSessionId, + AudioTrack::TRANSFER_CALLBACK, + aOffloadInfo, + mUid); + + if ((!t.get()) || (t->initCheck() != NO_ERROR)) { + AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Unable to create audio track")); + delete newcbd; + return NO_INIT; + } + + mCallbackData = newcbd; + t->setVolume(1.0); + + mTrack = t; + return NO_ERROR; +} + +status_t AudioOutput::Start() +{ + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); + if (!mTrack.get()) { + return NO_INIT; + } + mTrack->setVolume(1.0); + return mTrack->start(); +} + +void AudioOutput::Stop() +{ + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); + if (mTrack.get()) { + mTrack->stop(); + } +} + +void AudioOutput::Flush() +{ + if (mTrack.get()) { + mTrack->flush(); + } +} + +void AudioOutput::Pause() +{ + if (mTrack.get()) { + mTrack->pause(); + } +} + +void AudioOutput::Close() +{ + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); + mTrack.clear(); + + delete mCallbackData; + mCallbackData = nullptr; +} + +// static +void AudioOutput::CallbackWrapper(int aEvent, void* aCookie, void* aInfo) +{ + CallbackData* data = (CallbackData*) aCookie; + data->Lock(); + AudioOutput* me = data->GetOutput(); + AudioTrack::Buffer* buffer = (AudioTrack::Buffer*) aInfo; + if (!me) { + // no output set, likely because the track was scheduled to be reused + // by another player, but the format turned out to be incompatible. + data->Unlock(); + if (buffer) { + buffer->size = 0; + } + return; + } + + switch(aEvent) { + + case AudioTrack::EVENT_MORE_DATA: { + + size_t actualSize = (*me->mCallback)(me, buffer->raw, buffer->size, + me->mCallbackCookie, CB_EVENT_FILL_BUFFER); + + if (actualSize == 0 && buffer->size > 0) { + // We've reached EOS but the audio track is not stopped yet, + // keep playing silence. + memset(buffer->raw, 0, buffer->size); + actualSize = buffer->size; + } + + buffer->size = actualSize; + } break; + + case AudioTrack::EVENT_STREAM_END: + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Callback wrapper: EVENT_STREAM_END")); + (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */, + me->mCallbackCookie, CB_EVENT_STREAM_END); + break; + + case AudioTrack::EVENT_NEW_IAUDIOTRACK : + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Callback wrapper: EVENT_TEAR_DOWN")); + (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */, + me->mCallbackCookie, CB_EVENT_TEAR_DOWN); + break; + + default: + AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("received unknown event type: %d in" + " Callback wrapper!", aEvent)); + break; + } + + data->Unlock(); +} + +} // namespace mozilla