tenfourfox/dom/media/omx/AudioOffloadPlayer.h
Cameron Kaiser c9b2922b70 hello FPR
2017-04-19 00:56:45 -07:00

266 lines
9.4 KiB
C++

/* -*- 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) 2009 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.
*/
#ifndef AUDIO_OFFLOAD_PLAYER_H_
#define AUDIO_OFFLOAD_PLAYER_H_
#include <stagefright/MediaBuffer.h>
#include <stagefright/MediaSource.h>
#include <stagefright/TimeSource.h>
#include <utils/threads.h>
#include <utils/RefBase.h>
#include "AudioOutput.h"
#include "AudioOffloadPlayerBase.h"
#include "MediaDecoderOwner.h"
#include "MediaOmxCommonDecoder.h"
namespace mozilla {
namespace dom {
class WakeLock;
}
/**
* AudioOffloadPlayer adds support for audio tunneling to a digital signal
* processor (DSP) in the device chipset. With tunneling, audio decoding is
* off-loaded to the DSP, waking the application processor less often and using
* less battery
*
* This depends on offloading capability provided by Android KK AudioTrack class
*
* Audio playback is based on pull mechanism, whenever audio sink needs
* data, FillBuffer() will read data from compressed audio source and provide
* it to the sink
*
* Also this class passes state changes (play/pause/seek) from
* MediaOmxCommonDecoder to GonkAudioSink as well as provide GonkAudioSink status
* (position changed, playback ended, seek complete, audio tear down) back to
* MediaOmxCommonDecoder
*
* It acts as a bridge between MediaOmxCommonDecoder and GonkAudioSink during
* offload playback
*/
class AudioOffloadPlayer : public AudioOffloadPlayerBase
{
typedef android::Mutex Mutex;
typedef android::MetaData MetaData;
typedef android::status_t status_t;
typedef android::AudioTrack AudioTrack;
typedef android::MediaBuffer MediaBuffer;
typedef android::MediaSource MediaSource;
public:
enum {
REACHED_EOS,
SEEK_COMPLETE
};
AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder = nullptr);
~AudioOffloadPlayer();
// Caller retains ownership of "aSource".
virtual void SetSource(const android::sp<MediaSource> &aSource) override;
// Start the source if it's not already started and open the GonkAudioSink to
// create an offloaded audio track
virtual status_t Start(bool aSourceAlreadyStarted = false) override;
virtual status_t ChangeState(MediaDecoder::PlayState aState) override;
virtual void SetVolume(double aVolume) override;
virtual int64_t GetMediaTimeUs() override;
// To update progress bar when the element is visible
virtual void SetElementVisibility(bool aIsVisible) override;;
// Update ready state based on current play state. Not checking data
// availability since offloading is currently done only when whole compressed
// data is available
virtual MediaDecoderOwner::NextFrameStatus GetNextFrameStatus() override;
virtual RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget) override;
void TimeUpdate();
// Close the audio sink, stop time updates, frees the input buffers
void Reset();
private:
// Set when audio source is started and GonkAudioSink is initialized
// Used only in main thread
bool mStarted;
// Set when audio sink is started. i.e. playback started
// Used only in main thread
bool mPlaying;
// Once playback reached end of stream (last ~100ms), position provided by DSP
// may be reset/corrupted. This bool is used to avoid that.
// Used in main thread and offload callback thread, protected by Mutex
// mLock
bool mReachedEOS;
// Set when the HTML Audio Element is visible to the user.
// Used only in main thread
bool mIsElementVisible;
// Session id given by Android::AudioSystem and used while creating audio sink
// Used only in main thread
int mSessionId;
// Sample rate of current audio track. Used only in main thread
int mSampleRate;
// After seeking, positions returned by offlaoded tracks (DSP) will be
// relative to the seeked position. And seeked position may be slightly
// different than given mSeekTimeUs, if audio source cannot find a frame at
// that position. Store seeked position in mStartPosUs and provide
// mStartPosUs + GetPosition() (i.e. absolute position) to
// MediaOmxCommonDecoder
// Used in main thread and offload callback thread, protected by Mutex
// mLock
int64_t mStartPosUs;
// The target of current seek when there is a request to seek
// Used in main thread and offload callback thread, protected by Mutex
// mLock
SeekTarget mSeekTarget;
// MozPromise of current seek.
// Used in main thread and offload callback thread, protected by Mutex
// mLock
MozPromiseHolder<MediaDecoder::SeekPromise> mSeekPromise;
// Positions obtained from offlaoded tracks (DSP)
// Used in main thread and offload callback thread, protected by Mutex
// mLock
int64_t mPositionTimeMediaUs;
// State obtained from MediaOmxCommonDecoder. Used only in main thread
MediaDecoder::PlayState mPlayState;
// Protect accessing audio position related variables between main thread and
// offload callback thread
Mutex mLock;
// Compressed audio source.
// Used in main thread first and later in offload callback thread
android::sp<MediaSource> mSource;
// Audio sink wrapper to access offloaded audio tracks
// Used in main thread and offload callback thread
// Race conditions are protected in underlying Android::AudioTrack class
android::sp<GonkAudioSink> mAudioSink;
// Buffer used to get date from audio source. Used in offload callback thread
MediaBuffer* mInputBuffer;
// MediaOmxCommonDecoder object used mainly to notify the audio sink status
MediaOmxCommonDecoder* mObserver;
TimeStamp mLastFireUpdateTime;
// Timer to trigger position changed events
nsCOMPtr<nsITimer> mTimeUpdateTimer;
// Timer to reset GonkAudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
// It is triggered in Pause() and canceled when there is a Play() within
// OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed.
nsCOMPtr<nsITimer> mResetTimer;
// To avoid device suspend when mResetTimer is going to be triggered.
// Used only from main thread so no lock is needed.
RefPtr<mozilla::dom::WakeLock> mWakeLock;
// Provide the playback position in microseconds from total number of
// frames played by audio track
int64_t GetOutputPlayPositionUs_l() const;
// Fill the buffer given by audio sink with data from compressed audio
// source. Also handles the seek by seeking audio source and stop the sink in
// case of error
size_t FillBuffer(void *aData, size_t aSize);
// Called by GonkAudioSink when it needs data, to notify EOS or tear down event
static size_t AudioSinkCallback(GonkAudioSink *aAudioSink,
void *aData,
size_t aSize,
void *aMe,
GonkAudioSink::cb_event_t aEvent);
bool IsSeeking();
// Set mSeekTarget to the given position and restart the sink. Actual seek
// happens in FillBuffer(). If mSeekPromise is not empty, send
// SeekingStarted event always and SeekingStopped event when the play state is
// paused to MediaDecoder.
// When decoding and playing happens separately, if there is a seek during
// pause, we can decode and keep data ready.
// In case of offload player, no way to seek during pause. So just fake that
// seek is done.
status_t DoSeek();
// Start/Resume the audio sink so that callback will start being called to get
// compressed data
status_t Play();
// Stop the audio sink if we need to play till we drain the current buffer.
// or Pause the sink in case we should stop playing immediately
void Pause(bool aPlayPendingSamples = false);
// When audio is offloaded, application processor wakes up less frequently
// (>1sec) But when Player UI is visible we need to update progress bar
// atleast once in 250ms. Start a timer when player UI becomes visible or
// audio starts playing to send UpdateLogicalPosition events once in 250ms.
// Stop the timer when UI goes invisible or play state is not playing.
// Also make sure timer functions are always called from main thread
nsresult StartTimeUpdate();
nsresult StopTimeUpdate();
void WakeLockCreate();
void WakeLockRelease();
// Notify end of stream by sending PlaybackEnded event to observer
// (i.e.MediaDecoder)
void NotifyAudioEOS();
// Notify position changed event by sending UpdateLogicalPosition event to
// observer
void NotifyPositionChanged();
// Offloaded audio track is invalidated due to usecase change. Notify
// MediaDecoder to re-evaluate offloading options
void NotifyAudioTearDown();
// Send information from MetaData to the HAL via GonkAudioSink
void SendMetaDataToHal(android::sp<GonkAudioSink>& aSink,
const android::sp<MetaData>& aMeta);
AudioOffloadPlayer(const AudioOffloadPlayer &);
AudioOffloadPlayer &operator=(const AudioOffloadPlayer &);
};
} // namespace mozilla
#endif // AUDIO_OFFLOAD_PLAYER_H_