This commit is contained in:
Wes Kocher 2014-06-13 17:12:04 -07:00
Родитель 1416242684 9511934161
Коммит ad99ae743a
64 изменённых файлов: 1261 добавлений и 1824 удалений

Просмотреть файл

@ -638,7 +638,7 @@ ContentSecurityPolicy.prototype = {
break;
}
var violationMessage = null;
if (blockedUri["asciiSpec"]) {
if (blockedUri && blockedUri["asciiSpec"]) {
let localizeString = policy._reportOnlyMode ? "CSPROViolationWithURI" : "CSPViolationWithURI";
violationMessage = CSPLocalizer.getFormatStr(localizeString, [violatedDirective, blockedUri.asciiSpec]);
} else {
@ -666,6 +666,10 @@ ContentSecurityPolicy.prototype = {
// to be triggered if any policy wants it.
var permitted = true;
for (let i = 0; i < this._policies.length; i++) {
// spec says don't check the policies that are report-only (monitored)
if (this._policies[i]._reportOnlyMode) {
continue;
}
if (!this._permitsAncestryInternal(docShell, this._policies[i], i)) {
permitted = false;
}
@ -715,7 +719,20 @@ ContentSecurityPolicy.prototype = {
let directive = policy._directives[cspContext];
let violatedPolicy = 'frame-ancestors ' + directive.toString();
this._asyncReportViolation(ancestors[i], null, violatedPolicy,
// spec says don't report ancestors for cross-origin violations (it is
// a violation of same-origin)
let ssm = Services.scriptSecurityManager;
let blockedURI = null;
try {
if (Services.scriptSecurityManager
.checkSameOriginURI(ancestors[i], this._requestOrigin, false)) {
blockedURI = ancestors[i];
}
} catch (ex) {
// cross-origin, don't send the ancestor
}
this._asyncReportViolation(blockedURI, null, violatedPolicy,
policyIndex);
// need to lie if we are testing in report-only mode

Просмотреть файл

@ -639,6 +639,8 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
csp_report.AppendASCII(reportBlockedURI.get());
}
else {
// this can happen for frame-ancestors violation where the violating
// ancestor is cross-origin.
NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
}
csp_report.AppendASCII("\", ");
@ -1036,6 +1038,13 @@ nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
// Now that we've got the ancestry chain in ancestorsArray, time to check
// them against any CSP.
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
// According to the W3C CSP spec, frame-ancestors checks are ignored for
// report-only policies (when "monitoring").
if (mPolicies[i]->getReportOnlyFlag()) {
continue;
}
for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
// TODO(sid) the mapping from frame-ancestors context to TYPE_DOCUMENT is
// forced. while this works for now, we will implement something in
@ -1052,7 +1061,11 @@ nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
EmptyString(), // no nonce
violatedDirective)) {
// Policy is violated
this->AsyncReportViolation(ancestorsArray[a],
// Send reports, but omit the ancestor URI if cross-origin as per spec
// (it is a violation of the same-origin policy).
bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
this->AsyncReportViolation((okToSendAncestor ? ancestorsArray[a] : nullptr),
mSelfURI,
violatedDirective,
i, /* policy index */
@ -1060,9 +1073,7 @@ nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
EmptyString(), /* no source file */
EmptyString(), /* no script sample */
0); /* no line number */
if (!mPolicies[i]->getReportOnlyFlag()) {
*outPermitsAncestry = false;
}
*outPermitsAncestry = false;
}
}
}

Просмотреть файл

@ -10,6 +10,13 @@ function logResult(str, passed) {
window._testResults = {};
// check values for return values from blocked timeout or intervals
var verifyZeroRetVal = (function(window) {
return function(val, details) {
logResult((val === 0 ? "PASS: " : "FAIL: ") + "Blocked interval/timeout should have zero return value; " + details, val === 0);
window.parent.verifyZeroRetVal(val, details);
};})(window);
// callback for when stuff is allowed by CSP
var onevalexecuted = (function(window) {
return function(shouldrun, what, data) {
@ -41,7 +48,28 @@ addEventListener('load', function() {
}
}
setTimeout(fcn_setTimeoutWithStringCheck.bind(window), 10);
setTimeout(str_setTimeoutWithStringRan, 10);
var res = setTimeout(str_setTimeoutWithStringRan, 10);
verifyZeroRetVal(res, "setTimeout(String)");
}
// setInterval(String) test -- mutate something in the window._testResults
// obj, then check it.
{
var str_setIntervalWithStringRan = 'onevalexecuted(false, "setInterval(String)", "setInterval with a string was enabled.");';
function fcn_setIntervalWithStringCheck() {
if (this._testResults["setInterval(String)"] !== "ran") {
onevalblocked(false, "setInterval(String)",
"setInterval with a string was blocked");
}
}
setTimeout(fcn_setIntervalWithStringCheck.bind(window), 10);
var res = setInterval(str_setIntervalWithStringRan, 10);
verifyZeroRetVal(res, "setInterval(String)");
// emergency cleanup, just in case.
if (res != 0) {
setTimeout(function () { clearInterval(res); }, 15);
}
}
// setTimeout(function) test -- mutate something in the window._testResults

Просмотреть файл

@ -15,7 +15,7 @@
var evalScriptsThatRan = 0;
var evalScriptsBlocked = 0;
var evalScriptsTotal = 16;
var evalScriptsTotal = 17;
// called by scripts that run
var scriptRan = function(shouldrun, testname, data) {
@ -31,6 +31,9 @@ var scriptBlocked = function(shouldrun, testname, data) {
checkTestResults();
}
var verifyZeroRetVal = function(val, testname) {
ok(val === 0, 'RETURN VALUE SHOULD BE ZERO, was ' + val + ': ' + testname);
}
// Check to see if all the tests have run
var checkTestResults = function() {

Просмотреть файл

@ -42,7 +42,16 @@ examiner.prototype = {
if (topic === "csp-on-violate-policy") {
//these were blocked... record that they were blocked
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
var asciiSpec = subject;
// Except CSP prohibits cross-origin URI reporting during frame ancestors
// checks so this URI could be null.
try {
asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
} catch (ex) {
// was not an nsIURI, so it was probably a cross-origin report.
}
window.frameBlocked(asciiSpec, data);
}
},

Просмотреть файл

@ -42,7 +42,16 @@ examiner.prototype = {
if (topic === "csp-on-violate-policy") {
//these were blocked... record that they were blocked
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
var asciiSpec = subject;
// Except CSP prohibits cross-origin URI reporting during frame ancestors
// checks so this may not be an nsIURI.
try {
asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
} catch (ex) {
// was not an nsIURI, so it was probably a cross-origin report.
}
window.frameBlocked(asciiSpec, data);
}
},

Просмотреть файл

@ -37,7 +37,6 @@ public:
, mOffset(aOffset)
, mTime(aTimestamp)
, mDuration(aDuration)
, mDiscontinuity(false)
{}
virtual ~MediaData() {}
@ -54,10 +53,6 @@ public:
// Duration of sample, in microseconds.
const int64_t mDuration;
// True if this is the first sample after a gap or discontinuity in
// the stream. This is true for the first sample in a stream after a seek.
bool mDiscontinuity;
int64_t GetEndTime() const { return mTime + mDuration; }
};

Просмотреть файл

@ -1,148 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MediaDataDecodedListener_h_
#define MediaDataDecodedListener_h_
#include "mozilla/Monitor.h"
#include "MediaDecoderReader.h"
namespace mozilla {
class MediaDecoderStateMachine;
class MediaData;
// A RequestSampleCallback implementation that forwards samples onto the
// MediaDecoderStateMachine via tasks that run on the supplied task queue.
template<class Target>
class MediaDataDecodedListener : public RequestSampleCallback {
public:
MediaDataDecodedListener(Target* aTarget,
MediaTaskQueue* aTaskQueue)
: mMonitor("MediaDataDecodedListener")
, mTaskQueue(aTaskQueue)
, mTarget(aTarget)
{
MOZ_ASSERT(aTarget);
MOZ_ASSERT(aTaskQueue);
}
virtual void OnAudioDecoded(AudioData* aSample) MOZ_OVERRIDE {
MonitorAutoLock lock(mMonitor);
nsAutoPtr<AudioData> sample(aSample);
if (!mTarget || !mTaskQueue) {
// We've been shutdown, abort.
return;
}
RefPtr<nsIRunnable> task(new DeliverAudioTask(sample.forget(), mTarget));
mTaskQueue->Dispatch(task);
}
virtual void OnAudioEOS() MOZ_OVERRIDE {
MonitorAutoLock lock(mMonitor);
if (!mTarget || !mTaskQueue) {
// We've been shutdown, abort.
return;
}
RefPtr<nsIRunnable> task(NS_NewRunnableMethod(mTarget, &Target::OnAudioEOS));
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
NS_WARNING("Failed to dispatch OnAudioEOS task");
}
}
virtual void OnVideoDecoded(VideoData* aSample) MOZ_OVERRIDE {
MonitorAutoLock lock(mMonitor);
nsAutoPtr<VideoData> sample(aSample);
if (!mTarget || !mTaskQueue) {
// We've been shutdown, abort.
return;
}
RefPtr<nsIRunnable> task(new DeliverVideoTask(sample.forget(), mTarget));
mTaskQueue->Dispatch(task);
}
virtual void OnVideoEOS() MOZ_OVERRIDE {
MonitorAutoLock lock(mMonitor);
if (!mTarget || !mTaskQueue) {
// We've been shutdown, abort.
return;
}
RefPtr<nsIRunnable> task(NS_NewRunnableMethod(mTarget, &Target::OnVideoEOS));
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
NS_WARNING("Failed to dispatch OnVideoEOS task");
}
}
virtual void OnDecodeError() MOZ_OVERRIDE {
MonitorAutoLock lock(mMonitor);
if (!mTarget || !mTaskQueue) {
// We've been shutdown, abort.
return;
}
RefPtr<nsIRunnable> task(NS_NewRunnableMethod(mTarget, &Target::OnDecodeError));
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
NS_WARNING("Failed to dispatch OnAudioDecoded task");
}
}
void BreakCycles() {
MonitorAutoLock lock(mMonitor);
mTarget = nullptr;
mTaskQueue = nullptr;
}
private:
class DeliverAudioTask : public nsRunnable {
public:
DeliverAudioTask(AudioData* aSample, Target* aTarget)
: mSample(aSample)
, mTarget(aTarget)
{
MOZ_COUNT_CTOR(DeliverAudioTask);
}
~DeliverAudioTask()
{
MOZ_COUNT_DTOR(DeliverAudioTask);
}
NS_METHOD Run() {
mTarget->OnAudioDecoded(mSample.forget());
return NS_OK;
}
private:
nsAutoPtr<AudioData> mSample;
RefPtr<Target> mTarget;
};
class DeliverVideoTask : public nsRunnable {
public:
DeliverVideoTask(VideoData* aSample, Target* aTarget)
: mSample(aSample)
, mTarget(aTarget)
{
MOZ_COUNT_CTOR(DeliverVideoTask);
}
~DeliverVideoTask()
{
MOZ_COUNT_DTOR(DeliverVideoTask);
}
NS_METHOD Run() {
mTarget->OnVideoDecoded(mSample.forget());
return NS_OK;
}
private:
nsAutoPtr<VideoData> mSample;
RefPtr<Target> mTarget;
};
Monitor mMonitor;
RefPtr<MediaTaskQueue> mTaskQueue;
RefPtr<Target> mTarget;
};
}
#endif // MediaDataDecodedListener_h_

Просмотреть файл

@ -1528,7 +1528,7 @@ int64_t MediaDecoder::GetEndMediaTime() const {
}
// Drop reference to state machine. Only called during shutdown dance.
void MediaDecoder::BreakCycles() {
void MediaDecoder::ReleaseStateMachine() {
mDecoderStateMachine = nullptr;
}

Просмотреть файл

@ -6,9 +6,9 @@
/*
Each video element based on MediaDecoder has a state machine to manage
its play state and keep the current frame up to date. All state machines
share time in a single shared thread. Each decoder also has a MediaTaskQueue
running in a SharedThreadPool to decode audio and video data.
Each decoder also has a thread to push decoded audio
share time in a single shared thread. Each decoder also has one thread
dedicated to decoding audio and video data. This thread is shutdown when
playback is paused. Each decoder also has a thread to push decoded audio
to the hardware. This thread is not created until playback starts, but
currently is not destroyed when paused, only when playback ends.
@ -234,11 +234,6 @@ struct SeekTarget {
, mType(aType)
{
}
SeekTarget(const SeekTarget& aOther)
: mTime(aOther.mTime)
, mType(aOther.mType)
{
}
bool IsValid() const {
return mType != SeekTarget::Invalid;
}
@ -829,7 +824,7 @@ public:
MediaDecoderStateMachine* GetStateMachine() const;
// Drop reference to state machine. Only called during shutdown dance.
virtual void BreakCycles();
virtual void ReleaseStateMachine();
// Notifies the element that decoding has failed.
virtual void DecodeError();

Просмотреть файл

@ -63,11 +63,9 @@ public:
};
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mAudioCompactor(mAudioQueue)
, mDecoder(aDecoder)
, mIgnoreAudioOutputFormat(false)
, mAudioDiscontinuity(false)
, mVideoDiscontinuity(false)
: mAudioCompactor(mAudioQueue),
mDecoder(aDecoder),
mIgnoreAudioOutputFormat(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
}
@ -99,9 +97,6 @@ nsresult MediaDecoderReader::ResetDecode()
VideoQueue().Reset();
AudioQueue().Reset();
mAudioDiscontinuity = true;
mVideoDiscontinuity = true;
return res;
}
@ -178,6 +173,169 @@ VideoData* MediaDecoderReader::FindStartTime(int64_t& aOutStartTime)
return videoData;
}
nsresult MediaDecoderReader::DecodeToTarget(int64_t aTarget)
{
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) Begin", aTarget));
// Decode forward to the target frame. Start with video, if we have it.
if (HasVideo()) {
// Note: when decoding hits the end of stream we must keep the last frame
// in the video queue so that we'll have something to display after the
// seek completes. This makes our logic a bit messy.
bool eof = false;
nsAutoPtr<VideoData> video;
while (HasVideo() && !eof) {
while (VideoQueue().GetSize() == 0 && !eof) {
bool skip = false;
eof = !DecodeVideoFrame(skip, 0);
{
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
return NS_ERROR_FAILURE;
}
}
}
if (eof) {
// Hit end of file, we want to display the last frame of the video.
if (video) {
DECODER_LOG(PR_LOG_DEBUG,
("MediaDecoderReader::DecodeToTarget(%lld) repushing video frame [%lld, %lld] at EOF",
aTarget, video->mTime, video->GetEndTime()));
VideoQueue().PushFront(video.forget());
}
VideoQueue().Finish();
break;
}
video = VideoQueue().PeekFront();
// If the frame end time is less than the seek target, we won't want
// to display this frame after the seek, so discard it.
if (video && video->GetEndTime() <= aTarget) {
DECODER_LOG(PR_LOG_DEBUG,
("MediaDecoderReader::DecodeToTarget(%lld) pop video frame [%lld, %lld]",
aTarget, video->mTime, video->GetEndTime()));
VideoQueue().PopFront();
} else {
// Found a frame after or encompasing the seek target.
if (aTarget >= video->mTime && video->GetEndTime() >= aTarget) {
// The seek target lies inside this frame's time slice. Adjust the frame's
// start time to match the seek target. We do this by replacing the
// first frame with a shallow copy which has the new timestamp.
VideoQueue().PopFront();
VideoData* temp = VideoData::ShallowCopyUpdateTimestamp(video, aTarget);
video = temp;
VideoQueue().PushFront(video);
}
DECODER_LOG(PR_LOG_DEBUG,
("MediaDecoderReader::DecodeToTarget(%lld) found target video frame [%lld,%lld]",
aTarget, video->mTime, video->GetEndTime()));
video.forget();
break;
}
}
{
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
return NS_ERROR_FAILURE;
}
}
#ifdef PR_LOGGING
const VideoData* front = VideoQueue().PeekFront();
DECODER_LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld",
front ? front->mTime : -1));
#endif
}
if (HasAudio()) {
// Decode audio forward to the seek target.
bool eof = false;
while (HasAudio() && !eof) {
while (!eof && AudioQueue().GetSize() == 0) {
eof = !DecodeAudioData();
{
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
return NS_ERROR_FAILURE;
}
}
}
const AudioData* audio = AudioQueue().PeekFront();
if (!audio || eof) {
AudioQueue().Finish();
break;
}
CheckedInt64 startFrame = UsecsToFrames(audio->mTime, mInfo.mAudio.mRate);
CheckedInt64 targetFrame = UsecsToFrames(aTarget, mInfo.mAudio.mRate);
if (!startFrame.isValid() || !targetFrame.isValid()) {
return NS_ERROR_FAILURE;
}
if (startFrame.value() + audio->mFrames <= targetFrame.value()) {
// Our seek target lies after the frames in this AudioData. Pop it
// off the queue, and keep decoding forwards.
delete AudioQueue().PopFront();
audio = nullptr;
continue;
}
if (startFrame.value() > targetFrame.value()) {
// The seek target doesn't lie in the audio block just after the last
// audio frames we've seen which were before the seek target. This
// could have been the first audio data we've seen after seek, i.e. the
// seek terminated after the seek target in the audio stream. Just
// abort the audio decode-to-target, the state machine will play
// silence to cover the gap. Typically this happens in poorly muxed
// files.
NS_WARNING("Audio not synced after seek, maybe a poorly muxed file?");
break;
}
// The seek target lies somewhere in this AudioData's frames, strip off
// any frames which lie before the seek target, so we'll begin playback
// exactly at the seek target.
NS_ASSERTION(targetFrame.value() >= startFrame.value(),
"Target must at or be after data start.");
NS_ASSERTION(targetFrame.value() < startFrame.value() + audio->mFrames,
"Data must end after target.");
int64_t framesToPrune = targetFrame.value() - startFrame.value();
if (framesToPrune > audio->mFrames) {
// We've messed up somehow. Don't try to trim frames, the |frames|
// variable below will overflow.
NS_WARNING("Can't prune more frames that we have!");
break;
}
uint32_t frames = audio->mFrames - static_cast<uint32_t>(framesToPrune);
uint32_t channels = audio->mChannels;
nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[frames * channels]);
memcpy(audioData.get(),
audio->mAudioData.get() + (framesToPrune * channels),
frames * channels * sizeof(AudioDataValue));
CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
if (!duration.isValid()) {
return NS_ERROR_FAILURE;
}
nsAutoPtr<AudioData> data(new AudioData(audio->mOffset,
aTarget,
duration.value(),
frames,
audioData.forget(),
channels));
delete AudioQueue().PopFront();
AudioQueue().PushFront(data.forget());
break;
}
}
#ifdef PR_LOGGING
const VideoData* v = VideoQueue().PeekFront();
const AudioData* a = AudioQueue().PeekFront();
DECODER_LOG(PR_LOG_DEBUG,
("MediaDecoderReader::DecodeToTarget(%lld) finished v=%lld a=%lld",
aTarget, v ? v->mTime : -1, a ? a->mTime : -1));
#endif
return NS_OK;
}
nsresult
MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
int64_t aStartTime)
@ -192,174 +350,4 @@ MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
return NS_OK;
}
class RequestVideoWithSkipTask : public nsRunnable {
public:
RequestVideoWithSkipTask(MediaDecoderReader* aReader,
int64_t aTimeThreshold)
: mReader(aReader)
, mTimeThreshold(aTimeThreshold)
{
}
NS_METHOD Run() {
bool skip = true;
mReader->RequestVideoData(skip, mTimeThreshold);
return NS_OK;
}
private:
nsRefPtr<MediaDecoderReader> mReader;
int64_t mTimeThreshold;
};
void
MediaDecoderReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
{
bool skip = aSkipToNextKeyframe;
while (VideoQueue().GetSize() == 0 &&
!VideoQueue().IsFinished()) {
if (!DecodeVideoFrame(skip, aTimeThreshold)) {
VideoQueue().Finish();
} else if (skip) {
// We still need to decode more data in order to skip to the next
// keyframe. Post another task to the decode task queue to decode
// again. We don't just decode straight in a loop here, as that
// would hog the decode task queue.
RefPtr<nsIRunnable> task(new RequestVideoWithSkipTask(this, aTimeThreshold));
mTaskQueue->Dispatch(task);
return;
}
}
if (VideoQueue().GetSize() > 0) {
VideoData* v = VideoQueue().PopFront();
if (v && mVideoDiscontinuity) {
v->mDiscontinuity = true;
mVideoDiscontinuity = false;
}
GetCallback()->OnVideoDecoded(v);
} else if (VideoQueue().IsFinished()) {
GetCallback()->OnVideoEOS();
}
}
void
MediaDecoderReader::RequestAudioData()
{
while (AudioQueue().GetSize() == 0 &&
!AudioQueue().IsFinished()) {
if (!DecodeAudioData()) {
AudioQueue().Finish();
}
}
if (AudioQueue().GetSize() > 0) {
AudioData* a = AudioQueue().PopFront();
if (mAudioDiscontinuity) {
a->mDiscontinuity = true;
mAudioDiscontinuity = false;
}
GetCallback()->OnAudioDecoded(a);
return;
} else if (AudioQueue().IsFinished()) {
GetCallback()->OnAudioEOS();
return;
}
}
void
MediaDecoderReader::SetCallback(RequestSampleCallback* aCallback)
{
mSampleDecodedCallback = aCallback;
}
void
MediaDecoderReader::SetTaskQueue(MediaTaskQueue* aTaskQueue)
{
mTaskQueue = aTaskQueue;
}
void
MediaDecoderReader::BreakCycles()
{
if (mSampleDecodedCallback) {
mSampleDecodedCallback->BreakCycles();
mSampleDecodedCallback = nullptr;
}
mTaskQueue = nullptr;
}
void
MediaDecoderReader::Shutdown()
{
ReleaseMediaResources();
}
AudioDecodeRendezvous::AudioDecodeRendezvous()
: mMonitor("AudioDecodeRendezvous")
, mHaveResult(false)
{
}
AudioDecodeRendezvous::~AudioDecodeRendezvous()
{
}
void
AudioDecodeRendezvous::OnAudioDecoded(AudioData* aSample)
{
MonitorAutoLock mon(mMonitor);
mSample = aSample;
mStatus = NS_OK;
mHaveResult = true;
mon.NotifyAll();
}
void
AudioDecodeRendezvous::OnAudioEOS()
{
MonitorAutoLock mon(mMonitor);
mSample = nullptr;
mStatus = NS_OK;
mHaveResult = true;
mon.NotifyAll();
}
void
AudioDecodeRendezvous::OnDecodeError()
{
MonitorAutoLock mon(mMonitor);
mSample = nullptr;
mStatus = NS_ERROR_FAILURE;
mHaveResult = true;
mon.NotifyAll();
}
void
AudioDecodeRendezvous::Reset()
{
MonitorAutoLock mon(mMonitor);
mHaveResult = false;
mStatus = NS_OK;
mSample = nullptr;
}
nsresult
AudioDecodeRendezvous::Await(nsAutoPtr<AudioData>& aSample)
{
MonitorAutoLock mon(mMonitor);
while (!mHaveResult) {
mon.Wait();
}
mHaveResult = false;
aSample = mSample;
return mStatus;
}
void
AudioDecodeRendezvous::Cancel()
{
MonitorAutoLock mon(mMonitor);
mStatus = NS_ERROR_ABORT;
mHaveResult = true;
mon.NotifyAll();
}
} // namespace mozilla

Просмотреть файл

@ -18,19 +18,12 @@ namespace dom {
class TimeRanges;
}
class RequestSampleCallback;
// Encapsulates the decoding and reading of media data. Reading can either
// synchronous and done on the calling "decode" thread, or asynchronous and
// performed on a background thread, with the result being returned by
// callback. Never hold the decoder monitor when calling into this class.
// Unless otherwise specified, methods and fields of this class can only
// be accessed on the decode task queue.
// Encapsulates the decoding and reading of media data. Reading can only be
// done on the decode thread. Never hold the decoder monitor when
// calling into this class. Unless otherwise specified, methods and fields of
// this class can only be accessed on the decode thread.
class MediaDecoderReader {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
MediaDecoderReader(AbstractMediaDecoder* aDecoder);
virtual ~MediaDecoderReader();
@ -43,48 +36,24 @@ public:
// True when this reader need to become dormant state
virtual bool IsDormantNeeded() { return false; }
// Release media resources they should be released in dormant state
// The reader can be made usable again by calling ReadMetadata().
virtual void ReleaseMediaResources() {};
// Breaks reference-counted cycles. Called during shutdown.
// WARNING: If you override this, you must call the base implementation
// in your override.
virtual void BreakCycles();
// Destroys the decoding state. The reader cannot be made usable again.
// This is different from ReleaseMediaResources() as it is irreversable,
// whereas ReleaseMediaResources() is.
virtual void Shutdown();
virtual void SetCallback(RequestSampleCallback* aDecodedSampleCallback);
virtual void SetTaskQueue(MediaTaskQueue* aTaskQueue);
// Release the decoder during shutdown
virtual void ReleaseDecoder() {};
// Resets all state related to decoding, emptying all buffers etc.
// Cancels all pending Request*Data() request callbacks, and flushes the
// decode pipeline. The decoder must not call any of the callbacks for
// outstanding Request*Data() calls after this is called. Calls to
// Request*Data() made after this should be processed as usual.
// Normally this call preceedes a Seek() call, or shutdown.
// The first samples of every stream produced after a ResetDecode() call
// *must* be marked as "discontinuities". If it's not, seeking work won't
// properly!
virtual nsresult ResetDecode();
// Requests the Reader to call OnAudioDecoded() on aCallback with one
// audio sample. The decode should be performed asynchronously, and
// the callback can be performed on any thread. Don't hold the decoder
// monitor while calling this, as the implementation may try to wait
// on something that needs the monitor and deadlock.
virtual void RequestAudioData();
// Decodes an unspecified amount of audio data, enqueuing the audio data
// in mAudioQueue. Returns true when there's more audio to decode,
// false if the audio is finished, end of file has been reached,
// or an un-recoverable read error has occured.
virtual bool DecodeAudioData() = 0;
// Requests the Reader to call OnVideoDecoded() on aCallback with one
// video sample. The decode should be performed asynchronously, and
// the callback can be performed on any thread. Don't hold the decoder
// monitor while calling this, as the implementation may try to wait
// on something that needs the monitor and deadlock.
// If aSkipToKeyframe is true, the decode should skip ahead to the
// the next keyframe at or after aTimeThreshold microseconds.
virtual void RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold);
// Reads and decodes one video frame. Packets with a timestamp less
// than aTimeThreshold will be decoded (unless they're not keyframes
// and aKeyframeSkip is true), but will not be added to the queue.
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold) = 0;
virtual bool HasAudio() = 0;
virtual bool HasVideo() = 0;
@ -96,7 +65,6 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) = 0;
// TODO: DEPRECATED. This uses synchronous decoding.
// Stores the presentation time of the first frame we'd be able to play if
// we started playback at the current position. Returns the first video
// frame, if we have video.
@ -130,6 +98,22 @@ public:
mIgnoreAudioOutputFormat = true;
}
protected:
// Queue of audio frames. This queue is threadsafe, and is accessed from
// the audio, decoder, state machine, and main threads.
MediaQueue<AudioData> mAudioQueue;
// Queue of video frames. This queue is threadsafe, and is accessed from
// the decoder, state machine, and main threads.
MediaQueue<VideoData> mVideoQueue;
// An adapter to the audio queue which first copies data to buffers with
// minimal allocation slop and then pushes them to the queue. This is
// useful for decoders working with formats that give awkward numbers of
// frames such as mp3.
AudioCompactor mAudioCompactor;
public:
// Populates aBuffered with the time ranges which are buffered. aStartTime
// must be the presentation time of the first frame in the media, e.g.
// the media time corresponding to playback time/position 0. This function
@ -172,51 +156,15 @@ public:
AudioData* DecodeToFirstAudioData();
VideoData* DecodeToFirstVideoData();
// Decodes samples until we reach frames required to play at time aTarget
// (usecs). This also trims the samples to start exactly at aTarget,
// by discarding audio samples and adjusting start times of video frames.
nsresult DecodeToTarget(int64_t aTarget);
MediaInfo GetMediaInfo() { return mInfo; }
protected:
// Overrides of this function should decodes an unspecified amount of
// audio data, enqueuing the audio data in mAudioQueue. Returns true
// when there's more audio to decode, false if the audio is finished,
// end of file has been reached, or an un-recoverable read error has
// occured. This function blocks until the decode is complete.
virtual bool DecodeAudioData() {
return false;
}
// Overrides of this function should read and decodes one video frame.
// Packets with a timestamp less than aTimeThreshold will be decoded
// (unless they're not keyframes and aKeyframeSkip is true), but will
// not be added to the queue. This function blocks until the decode
// is complete.
virtual bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) {
return false;
}
RequestSampleCallback* GetCallback() {
MOZ_ASSERT(mSampleDecodedCallback);
return mSampleDecodedCallback;
}
virtual MediaTaskQueue* GetTaskQueue() {
return mTaskQueue;
}
// Queue of audio frames. This queue is threadsafe, and is accessed from
// the audio, decoder, state machine, and main threads.
MediaQueue<AudioData> mAudioQueue;
// Queue of video frames. This queue is threadsafe, and is accessed from
// the decoder, state machine, and main threads.
MediaQueue<VideoData> mVideoQueue;
// An adapter to the audio queue which first copies data to buffers with
// minimal allocation slop and then pushes them to the queue. This is
// useful for decoders working with formats that give awkward numbers of
// frames such as mp3.
AudioCompactor mAudioCompactor;
// Reference to the owning decoder object.
AbstractMediaDecoder* mDecoder;
@ -227,82 +175,6 @@ protected:
// directly, because they have a number of channel higher than
// what we support.
bool mIgnoreAudioOutputFormat;
private:
nsRefPtr<RequestSampleCallback> mSampleDecodedCallback;
nsRefPtr<MediaTaskQueue> mTaskQueue;
// Flags whether a the next audio/video sample comes after a "gap" or
// "discontinuity" in the stream. For example after a seek.
bool mAudioDiscontinuity;
bool mVideoDiscontinuity;
};
// Interface that callers to MediaDecoderReader::Request{Audio,Video}Data()
// must implement to receive the requested samples asynchronously.
// This object is refcounted, and cycles must be broken by calling
// BreakCycles() during shutdown.
class RequestSampleCallback {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestSampleCallback)
// Receives the result of a RequestAudioData() call.
virtual void OnAudioDecoded(AudioData* aSample) = 0;
// Called when a RequestAudioData() call can't be fulfiled as we've
// reached the end of stream.
virtual void OnAudioEOS() = 0;
// Receives the result of a RequestVideoData() call.
virtual void OnVideoDecoded(VideoData* aSample) = 0;
// Called when a RequestVideoData() call can't be fulfiled as we've
// reached the end of stream.
virtual void OnVideoEOS() = 0;
// Called when there's a decode error. No more sample requests
// will succeed.
virtual void OnDecodeError() = 0;
// Called during shutdown to break any reference cycles.
virtual void BreakCycles() = 0;
virtual ~RequestSampleCallback() {}
};
// A RequestSampleCallback implementation that can be passed to the
// MediaDecoderReader to block the thread requesting an audio sample until
// the audio decode is complete. This is used to adapt the asynchronous
// model of the MediaDecoderReader to a synchronous model.
class AudioDecodeRendezvous : public RequestSampleCallback {
public:
AudioDecodeRendezvous();
~AudioDecodeRendezvous();
// RequestSampleCallback implementation. Called when decode is complete.
// Note: aSample is null at end of stream.
virtual void OnAudioDecoded(AudioData* aSample) MOZ_OVERRIDE;
virtual void OnAudioEOS() MOZ_OVERRIDE;
virtual void OnVideoDecoded(VideoData* aSample) MOZ_OVERRIDE {}
virtual void OnVideoEOS() MOZ_OVERRIDE {}
virtual void OnDecodeError() MOZ_OVERRIDE;
virtual void BreakCycles() MOZ_OVERRIDE {};
void Reset();
// Returns failure on error, or NS_OK.
// If *aSample is null, EOS has been reached.
nsresult Await(nsAutoPtr<AudioData>& aSample);
// Interrupts a call to Wait().
void Cancel();
private:
Monitor mMonitor;
nsresult mStatus;
nsAutoPtr<AudioData> mSample;
bool mHaveResult;
};
} // namespace mozilla

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -4,36 +4,29 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
Each video element for a media file has two threads:
Each media element for a media file has one thread called the "audio thread".
1) The Audio thread writes the decoded audio data to the audio
hardware. This is done in a separate thread to ensure that the
audio hardware gets a constant stream of data without
interruption due to decoding or display. At some point
AudioStream will be refactored to have a callback interface
where it asks for data and an extra thread will no longer be
needed.
The audio thread writes the decoded audio data to the audio
hardware. This is done in a separate thread to ensure that the
audio hardware gets a constant stream of data without
interruption due to decoding or display. At some point
AudioStream will be refactored to have a callback interface
where it asks for data and this thread will no longer be
needed.
The element/state machine also has a MediaTaskQueue which runs in a
SharedThreadPool that is shared with all other elements/decoders. The state
machine dispatches tasks to this to call into the MediaDecoderReader to
request decoded audio or video data. The Reader will callback with decoded
sampled when it has them available, and the state machine places the decoded
samples into its queues for the consuming threads to pull from.
The MediaDecoderReader can choose to decode asynchronously, or synchronously
and return requested samples synchronously inside it's Request*Data()
functions via callback. Asynchronous decoding is preferred, and should be
used for any new readers.
2) The decode thread. This thread reads from the media stream and
decodes the Theora and Vorbis data. It places the decoded data into
queues for the other threads to pull from.
All file reads, seeks, and all decoding must occur on the decode thread.
Synchronisation of state between the thread is done via a monitor owned
by MediaDecoder.
The lifetime of the audio thread is controlled by the state machine when
it runs on the shared state machine thread. When playback needs to occur
the audio thread is created and an event dispatched to run it. The audio
thread exits when audio playback is completed or no longer required.
The lifetime of the decode and audio threads is controlled by the state
machine when it runs on the shared state machine thread. When playback
needs to occur they are created and events dispatched to them to run
them. These events exit when decoding/audio playback is completed or
no longer required.
A/V synchronisation is handled by the state machine. It examines the audio
playback time and compares this to the next frame in the queue of video
@ -46,7 +39,7 @@ Frame skipping is done in the following ways:
display time is less than the current audio time. This ensures
the correct frame for the current time is always displayed.
2) The decode tasks will stop decoding interframes and read to the
2) The decode thread will stop decoding interframes and read to the
next keyframe if it determines that decoding the remaining
interframes will cause playback issues. It detects this by:
a) If the amount of audio data in the audio queue drops
@ -54,13 +47,11 @@ Frame skipping is done in the following ways:
b) If the video queue drops below a threshold where it
will be decoding video data that won't be displayed due
to the decode thread dropping the frame immediately.
TODO: In future we should only do this when the Reader is decoding
synchronously.
When hardware accelerated graphics is not available, YCbCr conversion
is done on the decode task queue when video frames are decoded.
is done on the decode thread when video frames are decoded.
The decode task queue pushes decoded audio and videos frames into two
The decode thread pushes decoded audio and videos frames into two
separate queues - one for audio and one for video. These are kept
separate to make it easy to constantly feed audio data to the audio
hardware while allowing frame skipping of video data. These queues are
@ -68,10 +59,13 @@ threadsafe, and neither the decode, audio, or state machine should
be able to monopolize them, and cause starvation of the other threads.
Both queues are bounded by a maximum size. When this size is reached
the decode tasks will no longer request video or audio depending on the
queue that has reached the threshold. If both queues are full, no more
decode tasks will be dispatched to the decode task queue, so other
decoders will have an opportunity to run.
the decode thread will no longer decode video or audio depending on the
queue that has reached the threshold. If both queues are full, the decode
thread will wait on the decoder monitor.
When the decode queues are full (they've reaced their maximum size) and
the decoder is not in PLAYING play state, the state machine may opt
to shut down the decode thread in order to conserve resources.
During playback the audio thread will be idle (via a Wait() on the
monitor) if the audio queue is empty. Otherwise it constantly pops
@ -89,7 +83,6 @@ hardware (via AudioStream).
#include "MediaDecoderReader.h"
#include "MediaDecoderOwner.h"
#include "MediaMetadataManager.h"
#include "MediaDataDecodedListener.h"
class nsITimer;
@ -109,7 +102,7 @@ class SharedThreadPool;
/*
The state machine class. This manages the decoding and seeking in the
MediaDecoderReader on the decode task queue, and A/V sync on the shared
MediaDecoderReader on the decode thread, and A/V sync on the shared
state machine thread, and controls the audio "push" thread.
All internal state is synchronised via the decoder monitor. State changes
@ -319,9 +312,10 @@ public:
void SetFragmentEndTime(int64_t aEndTime);
// Drop reference to decoder. Only called during shutdown dance.
void BreakCycles() {
void ReleaseDecoder() {
MOZ_ASSERT(mReader);
if (mReader) {
mReader->BreakCycles();
mReader->ReleaseDecoder();
}
mDecoder = nullptr;
}
@ -363,22 +357,11 @@ public:
// samples in advance of when they're needed for playback.
void SetMinimizePrerollUntilPlaybackStarts();
void OnAudioDecoded(AudioData* aSample);
void OnAudioEOS();
void OnVideoDecoded(VideoData* aSample);
void OnVideoEOS();
void OnDecodeError();
protected:
virtual ~MediaDecoderStateMachine();
void AssertCurrentThreadInMonitor() const { mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); }
// Inserts MediaData* samples into their respective MediaQueues.
// aSample must not be null.
void Push(AudioData* aSample);
void Push(VideoData* aSample);
class WakeDecoderRunnable : public nsRunnable {
public:
WakeDecoderRunnable(MediaDecoderStateMachine* aSM)
@ -414,14 +397,8 @@ protected:
};
WakeDecoderRunnable* GetWakeDecoderRunnable();
MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
nsresult FinishDecodeMetadata();
RefPtr<MediaDataDecodedListener<MediaDecoderStateMachine>> mMediaDecodedListener;
nsAutoPtr<MetadataTags> mMetadataTags;
MediaQueue<AudioData>& AudioQueue() { return mReader->AudioQueue(); }
MediaQueue<VideoData>& VideoQueue() { return mReader->VideoQueue(); }
// True if our buffers of decoded audio are not full, and we should
// decode more.
@ -491,10 +468,11 @@ protected:
// Called on the state machine thread.
int64_t GetClock();
nsresult DropAudioUpToSeekTarget(AudioData* aSample);
nsresult DropVideoUpToSeekTarget(VideoData* aSample);
void SetStartTime(int64_t aStartTimeUsecs);
// Returns the presentation time of the first audio or video frame in the
// media. If the media has video, it returns the first video frame. The
// decoder monitor must be held with exactly one lock count. Called on the
// state machine thread.
VideoData* FindStartTime();
// Update only the state machine's current playback position (and duration,
// if unknown). Does not update the playback position on the decoder or
@ -566,10 +544,6 @@ protected:
// The decoder monitor must be held.
nsresult EnqueueDecodeMetadataTask();
// Dispatches a task to the decode task queue to seek the decoder.
// The decoder monitor must be held.
nsresult EnqueueDecodeSeekTask();
nsresult DispatchAudioDecodeTaskIfNeeded();
// Ensures a to decode audio has been dispatched to the decode task queue.
@ -587,6 +561,10 @@ protected:
// The decoder monitor must be held.
nsresult EnsureVideoDecodeTaskQueued();
// Dispatches a task to the decode task queue to seek the decoder.
// The decoder monitor must be held.
nsresult EnqueueDecodeSeekTask();
// Calls the reader's SetIdle(). This is only called in a task dispatched to
// the decode task queue, don't call it directly.
void SetReaderIdle();
@ -597,6 +575,12 @@ protected:
// The decoder monitor must be held.
void DispatchDecodeTasksIfNeeded();
// Queries our state to see whether the decode has finished for all streams.
// If so, we move into DECODER_STATE_COMPLETED and schedule the state machine
// to run.
// The decoder monitor must be held.
void CheckIfDecodeComplete();
// Returns the "media time". This is the absolute time which the media
// playback has reached. i.e. this returns values in the range
// [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
@ -620,29 +604,15 @@ protected:
// must be held with exactly one lock count.
nsresult DecodeMetadata();
// Wraps the call to DecodeMetadata(), signals a DecodeError() on failure.
void CallDecodeMetadata();
// Checks whether we're finished decoding metadata, and switches to DECODING
// state if so.
void MaybeFinishDecodeMetadata();
// Seeks to mSeekTarget. Called on the decode thread. The decoder monitor
// must be held with exactly one lock count.
void DecodeSeek();
void CheckIfSeekComplete();
bool IsAudioSeekComplete();
bool IsVideoSeekComplete();
// Decode loop, decodes data until EOF or shutdown.
// Called on the decode thread.
void DecodeLoop();
// Completes the seek operation, moves onto the next appropriate state.
void SeekCompleted();
// Queries our state to see whether the decode has finished for all streams.
// If so, we move into DECODER_STATE_COMPLETED and schedule the state machine
// to run.
// The decoder monitor must be held.
void CheckIfDecodeComplete();
void CallDecodeMetadata();
// Copy audio from an AudioData packet to aOutput. This may require
// inserting silence depending on the timing of the audio packet.
@ -667,11 +637,6 @@ protected:
// case as it may not be needed again.
bool IsPausedAndDecoderWaiting();
// These return true if the respective stream's decode has not yet reached
// the end of stream.
bool IsAudioDecoding();
bool IsVideoDecoding();
// The decoder object that created this state machine. The state machine
// holds a strong reference to the decoder to ensure that the decoder stays
// alive once media element has started the decoder shutdown process, and has
@ -683,19 +648,6 @@ protected:
// state machine, audio and main threads.
nsRefPtr<MediaDecoder> mDecoder;
// Time at which the last video sample was requested. If it takes too long
// before the sample arrives, we will increase the amount of audio we buffer.
// This is necessary for legacy synchronous decoders to prevent underruns.
TimeStamp mVideoDecodeStartTime;
// Queue of audio frames. This queue is threadsafe, and is accessed from
// the audio, decoder, state machine, and main threads.
MediaQueue<AudioData> mAudioQueue;
// Queue of video frames. This queue is threadsafe, and is accessed from
// the decoder, state machine, and main threads.
MediaQueue<VideoData> mVideoQueue;
// The decoder monitor must be obtained before modifying this state.
// NotifyAll on the monitor must be called when the state is changed so
// that interested threads can wake up and alter behaviour if appropriate
@ -767,14 +719,6 @@ protected:
// this value. Accessed on main and decode thread.
SeekTarget mSeekTarget;
// The position that we're currently seeking to. This differs from
// mSeekTarget, as mSeekTarget is the target we'll seek to next, whereas
// mCurrentSeekTarget is the position that the decode is in the process
// of seeking to.
// The decoder monitor lock must be obtained before reading or writing
// this value.
SeekTarget mCurrentSeekTarget;
// Media Fragment end time in microseconds. Access controlled by decoder monitor.
int64_t mFragmentEndTime;
@ -785,8 +729,9 @@ protected:
RefPtr<AudioStream> mAudioStream;
// The reader, don't call its methods with the decoder monitor held.
// This is created in the state machine's constructor.
nsRefPtr<MediaDecoderReader> mReader;
// This is created in the play state machine's constructor, and destroyed
// in the play state machine's destructor.
nsAutoPtr<MediaDecoderReader> mReader;
// Accessed only on the state machine thread.
// Not an nsRevocableEventPtr since we must Revoke() it well before
@ -872,12 +817,6 @@ protected:
uint32_t mAudioPrerollUsecs;
uint32_t mVideoPrerollFrames;
// This temporarily stores the first frame we decode after we seek.
// This is so that if we hit end of stream while we're decoding to reach
// the seek target, we will still have a frame that we can display as the
// last frame in the media.
nsAutoPtr<VideoData> mFirstVideoFrameAfterSeek;
// When we start decoding (either for the first time, or after a pause)
// we may be low on decoded data. We don't want our "low data" logic to
// kick in and decide that we're low on decoded data because the download
@ -897,11 +836,19 @@ protected:
// yet decoded to end of stream.
bool mIsVideoDecoding;
// True when we have dispatched a task to the decode task queue to request
// decoded audio/video, and/or we are waiting for the requested sample to be
// returned by callback from the Reader.
bool mAudioRequestPending;
bool mVideoRequestPending;
// True when we have dispatched a task to the decode task queue to run
// the audio decode.
bool mDispatchedAudioDecodeTask;
// True when we have dispatched a task to the decode task queue to run
// the video decode.
bool mDispatchedVideoDecodeTask;
// If the video decode is falling behind the audio, we'll start dropping the
// inter-frames up until the next keyframe which is at or before the current
// playback position. skipToNextKeyframe is true if we're currently
// skipping up to the next keyframe.
bool mSkipToNextKeyFrame;
// True if we shouldn't play our audio (but still write it to any capturing
// streams). When this is true, mStopAudioThread is always true and
@ -977,16 +924,10 @@ protected:
// dispatch multiple tasks to re-do the metadata loading.
bool mDispatchedDecodeMetadataTask;
// These two flags are true when we need to drop decoded samples that
// we receive up to the next discontinuity. We do this when we seek;
// the first sample in each stream after the seek is marked as being
// a "discontinuity".
bool mDropAudioUntilNextDiscontinuity;
bool mDropVideoUntilNextDiscontinuity;
// True if we need to decode forwards to the seek target inside
// mCurrentSeekTarget.
bool mDecodeToSeekTarget;
// True if we've dispatched a task to the decode task queue to call
// Seek on the reader. We maintain a flag to ensure that we don't
// dispatch multiple tasks to re-do the seek.
bool mDispatchedDecodeSeekTask;
// Stores presentation info required for playback. The decoder monitor
// must be held when accessing this.

Просмотреть файл

@ -43,13 +43,11 @@ template <class T> class MediaQueue : private nsDeque {
inline void Push(T* aItem) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aItem);
nsDeque::Push(aItem);
}
inline void PushFront(T* aItem) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aItem);
nsDeque::PushFront(aItem);
}
@ -77,6 +75,11 @@ template <class T> class MediaQueue : private nsDeque {
nsDeque::Empty();
}
inline void Erase() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Erase();
}
void Reset() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (GetSize() > 0) {

Просмотреть файл

@ -9,8 +9,6 @@
#include "nsSize.h"
#include "VorbisUtils.h"
#include "ImageContainer.h"
#include "SharedThreadPool.h"
#include "mozilla/Preferences.h"
#include <stdint.h>
@ -192,10 +190,4 @@ IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
aDisplay.width * aDisplay.height != 0;
}
TemporaryRef<SharedThreadPool> GetMediaDecodeThreadPool()
{
return SharedThreadPool::Get(NS_LITERAL_CSTRING("Media Decode"),
Preferences::GetUint("media.num-decode-threads", 25));
}
} // end namespace mozilla

Просмотреть файл

@ -20,7 +20,6 @@
#include "nsThreadUtils.h"
#include "prtime.h"
#include "AudioSampleFormat.h"
#include "mozilla/RefPtr.h"
using mozilla::CheckedInt64;
using mozilla::CheckedUint64;
@ -209,12 +208,6 @@ private:
const T mValue;
};
class SharedThreadPool;
// Returns the thread pool that is shared amongst all decoder state machines
// for decoding streams.
TemporaryRef<SharedThreadPool> GetMediaDecodeThreadPool();
} // end namespace mozilla
#endif

Просмотреть файл

@ -43,8 +43,6 @@ class MediaSourceReader : public MediaDecoderReader
public:
MediaSourceReader(MediaSourceDecoder* aDecoder, dom::MediaSource* aSource)
: MediaDecoderReader(aDecoder)
, mTimeThreshold(-1)
, mDropVideoBeforeThreshold(false)
, mActiveVideoDecoder(-1)
, mActiveAudioDecoder(-1)
, mMediaSource(aSource)
@ -64,72 +62,53 @@ public:
return mDecoders.IsEmpty() && mPendingDecoders.IsEmpty();
}
void RequestAudioData() MOZ_OVERRIDE
bool DecodeAudioData() MOZ_OVERRIDE
{
if (!GetAudioReader()) {
MSE_DEBUG("%p DecodeAudioFrame called with no audio reader", this);
MOZ_ASSERT(mPendingDecoders.IsEmpty());
GetCallback()->OnDecodeError();
return;
return false;
}
GetAudioReader()->RequestAudioData();
bool rv = GetAudioReader()->DecodeAudioData();
nsAutoTArray<AudioData*, 10> audio;
GetAudioReader()->AudioQueue().GetElementsAfter(-1, &audio);
for (uint32_t i = 0; i < audio.Length(); ++i) {
AudioQueue().Push(audio[i]);
}
GetAudioReader()->AudioQueue().Empty();
return rv;
}
void OnAudioDecoded(AudioData* aSample)
{
GetCallback()->OnAudioDecoded(aSample);
}
void OnAudioEOS()
{
GetCallback()->OnAudioEOS();
}
void RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) MOZ_OVERRIDE
bool DecodeVideoFrame(bool& aKeyFrameSkip, int64_t aTimeThreshold) MOZ_OVERRIDE
{
if (!GetVideoReader()) {
MSE_DEBUG("%p DecodeVideoFrame called with no video reader", this);
MOZ_ASSERT(mPendingDecoders.IsEmpty());
GetCallback()->OnDecodeError();
return;
return false;
}
mTimeThreshold = aTimeThreshold;
GetVideoReader()->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
}
void OnVideoDecoded(VideoData* aSample)
{
if (mDropVideoBeforeThreshold) {
if (aSample->mTime < mTimeThreshold) {
delete aSample;
GetVideoReader()->RequestVideoData(false, mTimeThreshold);
} else {
mDropVideoBeforeThreshold = false;
GetCallback()->OnVideoDecoded(aSample);
}
} else {
GetCallback()->OnVideoDecoded(aSample);
if (MaybeSwitchVideoReaders(aTimeThreshold)) {
GetVideoReader()->DecodeToTarget(aTimeThreshold);
}
bool rv = GetVideoReader()->DecodeVideoFrame(aKeyFrameSkip, aTimeThreshold);
nsAutoTArray<VideoData*, 10> video;
GetVideoReader()->VideoQueue().GetElementsAfter(-1, &video);
for (uint32_t i = 0; i < video.Length(); ++i) {
VideoQueue().Push(video[i]);
}
GetVideoReader()->VideoQueue().Empty();
if (rv) {
return true;
}
}
void OnVideoEOS()
{
// End of stream. See if we can switch to another video decoder.
MSE_DEBUG("%p MSR::DecodeVF %d (%p) returned false (readers=%u)",
this, mActiveVideoDecoder, mDecoders[mActiveVideoDecoder].get(), mDecoders.Length());
if (MaybeSwitchVideoReaders()) {
// Success! Resume decoding with next video decoder.
RequestVideoData(false, mTimeThreshold);
} else {
// End of stream.
MSE_DEBUG("%p MSR::DecodeVF %d (%p) EOS (readers=%u)",
this, mActiveVideoDecoder, mDecoders[mActiveVideoDecoder].get(), mDecoders.Length());
GetCallback()->OnVideoEOS();
}
}
void OnDecodeError() {
GetCallback()->OnDecodeError();
return rv;
}
bool HasVideo() MOZ_OVERRIDE
@ -147,22 +126,7 @@ public:
int64_t aCurrentTime) MOZ_OVERRIDE;
nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE;
already_AddRefed<SubBufferDecoder> CreateSubDecoder(const nsACString& aType,
MediaSourceDecoder* aParentDecoder,
MediaTaskQueue* aTaskQueue);
void Shutdown() MOZ_OVERRIDE {
MediaDecoderReader::Shutdown();
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
mDecoders[i]->GetReader()->Shutdown();
}
}
virtual void BreakCycles() MOZ_OVERRIDE {
MediaDecoderReader::BreakCycles();
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
mDecoders[i]->GetReader()->BreakCycles();
}
}
MediaSourceDecoder* aParentDecoder);
void InitializePendingDecoders();
@ -172,12 +136,7 @@ public:
}
private:
// These are read and written on the decode task queue threads.
int64_t mTimeThreshold;
bool mDropVideoBeforeThreshold;
bool MaybeSwitchVideoReaders() {
bool MaybeSwitchVideoReaders(int64_t aTimeThreshold) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
MOZ_ASSERT(mActiveVideoDecoder != -1);
@ -187,7 +146,7 @@ private:
if (!mDecoders[i]->GetReader()->GetMediaInfo().HasVideo()) {
continue;
}
if (mTimeThreshold >= mDecoders[i]->GetMediaStartTime()) {
if (aTimeThreshold >= mDecoders[i]->GetMediaStartTime()) {
GetVideoReader()->SetIdle();
mActiveVideoDecoder = i;
@ -237,7 +196,7 @@ public:
if (!mReader) {
return nullptr;
}
return static_cast<MediaSourceReader*>(mReader.get())->CreateSubDecoder(aType, aParentDecoder, mDecodeTaskQueue);
return static_cast<MediaSourceReader*>(mReader.get())->CreateSubDecoder(aType, aParentDecoder);
}
nsresult EnqueueDecoderInitialization() {
@ -407,9 +366,7 @@ MediaSourceReader::InitializePendingDecoders()
}
already_AddRefed<SubBufferDecoder>
MediaSourceReader::CreateSubDecoder(const nsACString& aType,
MediaSourceDecoder* aParentDecoder,
MediaTaskQueue* aTaskQueue)
MediaSourceReader::CreateSubDecoder(const nsACString& aType, MediaSourceDecoder* aParentDecoder)
{
// XXX: Why/when is mDecoder null here, since it should be equal to aParentDecoder?!
nsRefPtr<SubBufferDecoder> decoder =
@ -418,13 +375,6 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType,
if (!reader) {
return nullptr;
}
// Set a callback on the subreader that forwards calls to this reader.
// This reader will then forward them onto the state machine via this
// reader's callback.
RefPtr<MediaDataDecodedListener<MediaSourceReader>> callback =
new MediaDataDecodedListener<MediaSourceReader>(this, aTaskQueue);
reader->SetCallback(callback);
reader->SetTaskQueue(aTaskQueue);
reader->Init(nullptr);
ReentrantMonitorAutoEnter mon(aParentDecoder->GetReentrantMonitor());
MSE_DEBUG("Registered subdecoder %p subreader %p", decoder.get(), reader.get());
@ -474,7 +424,7 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
while (!mMediaSource->ActiveSourceBuffers()->AllContainsTime (aTime / USECS_PER_S)
&& !IsShutdown()) {
mMediaSource->WaitForData();
MaybeSwitchVideoReaders();
MaybeSwitchVideoReaders(aTime);
}
if (IsShutdown()) {

Просмотреть файл

@ -78,7 +78,6 @@ EXPORTS += [
'Latency.h',
'MediaCache.h',
'MediaData.h',
'MediaDataDecodedListener.h',
'MediaDecoder.h',
'MediaDecoderOwner.h',
'MediaDecoderReader.h',

Просмотреть файл

@ -59,6 +59,9 @@ MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
MediaOmxReader::~MediaOmxReader()
{
ReleaseMediaResources();
ReleaseDecoder();
mOmxDecoder.clear();
}
nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
@ -66,15 +69,6 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
return NS_OK;
}
void MediaOmxReader::Shutdown()
{
ReleaseMediaResources();
if (mOmxDecoder.get()) {
mOmxDecoder->ReleaseDecoder();
}
mOmxDecoder.clear();
}
bool MediaOmxReader::IsWaitingMediaResources()
{
if (!mOmxDecoder.get()) {
@ -105,6 +99,13 @@ void MediaOmxReader::ReleaseMediaResources()
}
}
void MediaOmxReader::ReleaseDecoder()
{
if (mOmxDecoder.get()) {
mOmxDecoder->ReleaseDecoder();
}
}
nsresult MediaOmxReader::InitOmxDecoder()
{
if (!mOmxDecoder.get()) {
@ -374,6 +375,7 @@ nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndT
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
EnsureActive();
ResetDecode();
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
if (container && container->GetImageContainer()) {
container->GetImageContainer()->ClearAllImagesExceptFront();

Просмотреть файл

@ -80,14 +80,14 @@ public:
virtual bool IsDormantNeeded();
virtual void ReleaseMediaResources();
virtual void ReleaseDecoder() MOZ_OVERRIDE;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual void SetIdle() MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
void SetAudioChannel(dom::AudioChannel aAudioChannel) {
mAudioChannel = aAudioChannel;
}

Просмотреть файл

@ -35,6 +35,11 @@ MediaPluginReader::MediaPluginReader(AbstractMediaDecoder *aDecoder,
{
}
MediaPluginReader::~MediaPluginReader()
{
ResetDecode();
}
nsresult MediaPluginReader::Init(MediaDecoderReader* aCloneDonor)
{
return NS_OK;
@ -99,22 +104,18 @@ nsresult MediaPluginReader::ReadMetadata(MediaInfo* aInfo,
return NS_OK;
}
void MediaPluginReader::Shutdown()
{
ResetDecode();
if (mPlugin) {
GetMediaPluginHost()->DestroyDecoder(mPlugin);
mPlugin = nullptr;
}
}
// Resets all state related to decoding, emptying all buffers etc.
nsresult MediaPluginReader::ResetDecode()
{
if (mLastVideoFrame) {
mLastVideoFrame = nullptr;
}
return MediaDecoderReader::ResetDecode();
if (mPlugin) {
GetMediaPluginHost()->DestroyDecoder(mPlugin);
mPlugin = nullptr;
}
return NS_OK;
}
bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip,
@ -320,6 +321,9 @@ nsresult MediaPluginReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aE
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
mVideoQueue.Reset();
mAudioQueue.Reset();
if (mHasAudio && mHasVideo) {
// The decoder seeks/demuxes audio and video streams separately. So if
// we seek both audio and video to aTarget, the audio stream can typically

Просмотреть файл

@ -43,6 +43,7 @@ class MediaPluginReader : public MediaDecoderReader
public:
MediaPluginReader(AbstractMediaDecoder* aDecoder,
const nsACString& aContentType);
~MediaPluginReader();
virtual nsresult Init(MediaDecoderReader* aCloneDonor);
virtual nsresult ResetDecode();
@ -65,8 +66,6 @@ public:
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual void Shutdown() MOZ_OVERRIDE;
class ImageBufferCallback : public MPAPI::BufferCallback {
typedef mozilla::layers::Image Image;

Просмотреть файл

@ -389,7 +389,7 @@ var gUnseekableTests = [
{ name:"bogus.duh", type:"bogus/duh"}
];
// Unfortunately big-buck-bunny-unseekable.mp4 is doesn't play on Windows 7, so
// only include it in the unseekable tests if we're on later versions of Windows.
// only include it in the unseekable tests if we're on later versions of Windows.
// This test actually only passes on win8 at the moment.
if (navigator.userAgent.indexOf("Windows") != -1 && IsWindows8OrLater()) {
gUnseekableTests = gUnseekableTests.concat([
@ -677,14 +677,6 @@ function MediaTestManager() {
is(this.numTestsRunning, this.tokens.length, "[started " + token + "] Length of array should match number of running tests");
}
this.watchdog = null;
this.watchdogFn = function() {
if (this.tokens.length > 0) {
info("Watchdog remaining tests= " + this.tokens);
}
}
// Registers that the test corresponding to 'token' has finished. Call when
// you've finished your test. If all tests are complete this will finish the
// run, otherwise it may start up the next run. It's ok to call multiple times
@ -695,18 +687,10 @@ function MediaTestManager() {
// Remove the element from the list of running tests.
this.tokens.splice(i, 1);
}
if (this.watchdog) {
clearTimeout(this.watchdog);
this.watchdog = null;
}
info("[finished " + token + "] remaining= " + this.tokens);
this.numTestsRunning--;
is(this.numTestsRunning, this.tokens.length, "[finished " + token + "] Length of array should match number of running tests");
if (this.tokens.length < PARALLEL_TESTS) {
this.nextTest();
this.watchdog = setTimeout(this.watchdogFn.bind(this), 10000);
}
}

Просмотреть файл

@ -14,14 +14,11 @@
var manager = new MediaTestManager;
function startTest(e) {
var v = e.target;
info(v._name + " loadedmetadata");
e.target.play();
}
function playbackEnded(e) {
var v = e.target;
info(v._name + " ended");
if (v._finished)
return;
ok(v.currentTime >= v.duration - 0.1 && v.currentTime <= v.duration + 0.1,
@ -35,7 +32,6 @@ function playbackEnded(e) {
function seekEnded(e) {
var v = e.target;
info(v._name + " seeked");
if (v._finished)
return;
ok(v.currentTime == 0, "Checking currentTime after seek: " +
@ -46,11 +42,6 @@ function seekEnded(e) {
manager.finished(v.token);
}
function seeking(e) {
var v = e.target;
info(v._name + " seeking");
}
function initTest(test, token) {
var type = getMajorMimeType(test.type);
var v = document.createElement(type);
@ -71,7 +62,6 @@ function initTest(test, token) {
v.addEventListener("loadedmetadata", startTest, false);
v.addEventListener("ended", playbackEnded, false);
v.addEventListener("seeked", seekEnded, false);
v.addEventListener("seeking", seeking, false);
document.body.appendChild(v);
}

Просмотреть файл

@ -20,22 +20,17 @@ SimpleTest.expectAssertions(0, 2);
var manager = new MediaTestManager;
function start(e) {
var v = e.target;
info("[" + v._name + "] start");
e.target.currentTime = e.target.duration / 4;
}
function startSeeking(e) {
var v = e.target;
info("[" + v._name + "] seeking");
e.target._seeked = true;
}
function canPlayThrough(e) {
var v = e.target;
info("[" + v._name + "] canPlayThrough");
if (v._seeked && !v._finished) {
ok(true, "[" + v._name + "] got canplaythrough after seek");
ok(true, "Got canplaythrough after seek for " + v._name);
v._finished = true;
v.parentNode.removeChild(v);
v.src = "";
@ -43,16 +38,6 @@ function canPlayThrough(e) {
}
}
function seeked(e) {
var v = e.target;
info("[" + v._name + "] seeked");
}
function error(e) {
var v = e.target;
info("[" + v._name + "] error");
}
function startTest(test, token) {
// TODO: Bug 568402, there's a bug in the WAV backend where we sometimes
// don't send canplaythrough events after seeking. Once that is fixed,
@ -73,8 +58,6 @@ function startTest(test, token) {
v.addEventListener("loadedmetadata", start, false);
v.addEventListener("canplaythrough", canPlayThrough, false);
v.addEventListener("seeking", startSeeking, false);
v.addEventListener("seeked", seeked, false);
v.addEventListener("error", error, false);
document.body.appendChild(v);
}

Просмотреть файл

@ -61,10 +61,10 @@ function createTestArray() {
function startTest(test, token) {
var v = document.createElement('video');
v.token = token += "-seek" + test.number + ".js";
manager.started(v.token);
manager.started(token);
v.src = test.name;
v.preload = "metadata";
v.token = token;
document.body.appendChild(v);
var name = test.name + " seek test " + test.number;
var localIs = function(name) { return function(a, b, msg) {
@ -76,7 +76,7 @@ function startTest(test, token) {
var localFinish = function(v, manager) { return function() {
v.onerror = null;
removeNodeAndSource(v);
dump("SEEK-TEST: Finished " + name + " token: " + v.token + "\n");
dump("SEEK-TEST: Finished " + name + "\n");
manager.finished(v.token);
}}(v, manager);
dump("SEEK-TEST: Started " + name + "\n");

Просмотреть файл

@ -252,25 +252,12 @@ MediaDecodeTask::Decode()
return;
}
MediaQueue<AudioData> audioQueue;
nsRefPtr<AudioDecodeRendezvous> barrier(new AudioDecodeRendezvous());
mDecoderReader->SetCallback(barrier);
while (1) {
mDecoderReader->RequestAudioData();
nsAutoPtr<AudioData> audio;
if (NS_FAILED(barrier->Await(audio))) {
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
return;
}
if (!audio) {
// End of stream.
break;
}
audioQueue.Push(audio.forget());
while (mDecoderReader->DecodeAudioData()) {
// consume all of the buffer
continue;
}
mDecoderReader->Shutdown();
mDecoderReader->BreakCycles();
MediaQueue<AudioData>& audioQueue = mDecoderReader->AudioQueue();
uint32_t frameCount = audioQueue.FrameCount();
uint32_t channelCount = mediaInfo.mAudio.mChannels;
uint32_t sampleRate = mediaInfo.mAudio.mRate;

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsThreadUtils.h"
#include "nsReadableUtils.h"
#include "nsNetUtil.h"
#include "nsIObserverService.h"
// NSPR_LOG_MODULES=LoadManager:5
PRLogModuleInfo *gLoadManagerLog = nullptr;
@ -30,10 +31,15 @@ PRLogModuleInfo *gLoadManagerLog = nullptr;
namespace mozilla {
LoadManager::LoadManager(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold)
/* static */ StaticRefPtr<LoadManagerSingleton> LoadManagerSingleton::sSingleton;
NS_IMPL_ISUPPORTS(LoadManagerSingleton, nsIObserver)
LoadManagerSingleton::LoadManagerSingleton(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold)
: mLoadSum(0.0f),
mLoadSumMeasurements(0),
mOveruseActive(false),
@ -41,7 +47,8 @@ LoadManager::LoadManager(int aLoadMeasurementInterval,
mAveragingMeasurements(aAveragingMeasurements),
mHighLoadThreshold(aHighLoadThreshold),
mLowLoadThreshold(aLowLoadThreshold),
mCurrentState(webrtc::kLoadNormal)
mCurrentState(webrtc::kLoadNormal),
mLock("LoadManager")
{
#if defined(PR_LOGGING)
if (!gLoadManagerLog)
@ -56,15 +63,44 @@ LoadManager::LoadManager(int aLoadMeasurementInterval,
mLoadMonitor->SetLoadChangeCallback(this);
}
LoadManager::~LoadManager()
LoadManagerSingleton::~LoadManagerSingleton()
{
LOG(("LoadManager: shutting down LoadMonitor"));
mLoadMonitor->Shutdown();
MOZ_ASSERT(!mLoadMonitor, "why wasn't the LoadMonitor shut down in xpcom-shutdown?");
if (mLoadMonitor) {
mLoadMonitor->Shutdown();
}
}
nsresult
LoadManagerSingleton::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!strcmp(aTopic, "xpcom-shutdown")) {
obs->RemoveObserver(this, "xpcom-shutdown");
{
MutexAutoLock lock(mLock);
mObservers.Clear();
}
if (mLoadMonitor) {
mLoadMonitor->Shutdown();
mLoadMonitor = nullptr;
}
LOG(("Releasing LoadManager singleton and thread"));
// Note: won't be released immediately as the Observer has a ref to us
sSingleton = nullptr;
}
return NS_OK;
}
void
LoadManager::LoadChanged(float aSystemLoad, float aProcesLoad)
LoadManagerSingleton::LoadChanged(float aSystemLoad, float aProcesLoad)
{
MutexAutoLock lock(mLock);
// Update total load, and total amount of measured seconds.
mLoadSum += aSystemLoad;
mLoadSumMeasurements++;
@ -94,9 +130,10 @@ LoadManager::LoadChanged(float aSystemLoad, float aProcesLoad)
}
void
LoadManager::OveruseDetected()
LoadManagerSingleton::OveruseDetected()
{
LOG(("LoadManager - Overuse Detected"));
MutexAutoLock lock(mLock);
mOveruseActive = true;
if (mCurrentState != webrtc::kLoadStressed) {
mCurrentState = webrtc::kLoadStressed;
@ -105,15 +142,17 @@ LoadManager::OveruseDetected()
}
void
LoadManager::NormalUsage()
LoadManagerSingleton::NormalUsage()
{
LOG(("LoadManager - Overuse finished"));
MutexAutoLock lock(mLock);
mOveruseActive = false;
}
void
LoadManager::LoadHasChanged()
LoadManagerSingleton::LoadHasChanged()
{
mLock.AssertCurrentThreadOwns();
LOG(("LoadManager - Signaling LoadHasChanged to %d listeners", mObservers.Length()));
for (size_t i = 0; i < mObservers.Length(); i++) {
mObservers.ElementAt(i)->onLoadStateChanged(mCurrentState);
@ -121,18 +160,36 @@ LoadManager::LoadHasChanged()
}
void
LoadManager::AddObserver(webrtc::CPULoadStateObserver * aObserver)
LoadManagerSingleton::AddObserver(webrtc::CPULoadStateObserver * aObserver)
{
LOG(("LoadManager - Adding Observer"));
MutexAutoLock lock(mLock);
mObservers.AppendElement(aObserver);
if (mObservers.Length() == 1) {
if (!mLoadMonitor) {
mLoadMonitor = new LoadMonitor(mLoadMeasurementInterval);
mLoadMonitor->Init(mLoadMonitor);
mLoadMonitor->SetLoadChangeCallback(this);
}
}
}
void
LoadManager::RemoveObserver(webrtc::CPULoadStateObserver * aObserver)
LoadManagerSingleton::RemoveObserver(webrtc::CPULoadStateObserver * aObserver)
{
LOG(("LoadManager - Removing Observer"));
MutexAutoLock lock(mLock);
if (!mObservers.RemoveElement(aObserver)) {
LOG(("LOadManager - Element to remove not found"));
LOG(("LoadManager - Element to remove not found"));
}
if (mObservers.Length() == 0) {
if (mLoadMonitor) {
// Dance to avoid deadlock on mLock!
nsRefPtr<LoadMonitor> loadMonitor = mLoadMonitor.forget();
MutexAutoUnlock unlock(mLock);
loadMonitor->Shutdown();
}
}
}

Просмотреть файл

@ -7,25 +7,30 @@
#define _LOADMANAGER_H_
#include "LoadMonitor.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Services.h"
#include "nsTArray.h"
#include "nsIObserver.h"
#include "webrtc/common_types.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "mozilla/TimeStamp.h"
#include "nsTArray.h"
extern PRLogModuleInfo *gLoadManagerLog;
namespace mozilla {
class LoadManager : public LoadNotificationCallback,
public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver
class LoadManagerSingleton : public LoadNotificationCallback,
public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver,
public nsIObserver
{
public:
LoadManager(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold);
~LoadManager();
static LoadManagerSingleton* Get();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
// LoadNotificationCallback interface
virtual void LoadChanged(float aSystemLoad, float aProcessLoad) MOZ_OVERRIDE;
@ -39,22 +44,62 @@ public:
virtual void RemoveObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE;
private:
LoadManagerSingleton(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold);
~LoadManagerSingleton();
void LoadHasChanged();
nsRefPtr<LoadMonitor> mLoadMonitor;
float mLoadSum;
int mLoadSumMeasurements;
// This protexts access to the mObservers list, the current state, pretty much all
// the other members (below)
Mutex mLock;
nsTArray<webrtc::CPULoadStateObserver*> mObservers;
webrtc::CPULoadState mCurrentState;
// Set when overuse was signaled to us, and hasn't been un-signaled yet.
bool mOveruseActive;
float mLoadSum;
int mLoadSumMeasurements;
// Load measurement settings
int mLoadMeasurementInterval;
int mAveragingMeasurements;
float mHighLoadThreshold;
float mLowLoadThreshold;
webrtc::CPULoadState mCurrentState;
static StaticRefPtr<LoadManagerSingleton> sSingleton;
};
nsTArray<webrtc::CPULoadStateObserver*> mObservers;
class LoadManager MOZ_FINAL : public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver
{
public:
LoadManager(LoadManagerSingleton* aManager)
: mManager(aManager)
{}
~LoadManager() {}
void AddObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE
{
mManager->AddObserver(aObserver);
}
void RemoveObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE
{
mManager->RemoveObserver(aObserver);
}
void OveruseDetected() MOZ_OVERRIDE
{
mManager->OveruseDetected();
}
void NormalUsage() MOZ_OVERRIDE
{
mManager->NormalUsage();
}
private:
LoadManagerSingleton* mManager;
};
} //namespace

Просмотреть файл

@ -6,33 +6,44 @@
#include "LoadManager.h"
#include "LoadManagerFactory.h"
#include "MainThreadUtils.h"
#include "nsIObserverService.h"
#include "mozilla/Preferences.h"
namespace mozilla {
LoadManager* LoadManagerBuild(void)
// Assume stored in an nsAutoPtr<>
LoadManager *
LoadManagerBuild(void)
{
MOZ_ASSERT(NS_IsMainThread());
int loadMeasurementInterval =
mozilla::Preferences::GetInt("media.navigator.load_adapt.measure_interval", 1000);
int averagingSeconds =
mozilla::Preferences::GetInt("media.navigator.load_adapt.avg_seconds", 3);
float highLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.high_load", 0.90);
float lowLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.low_load", 0.40);
return new LoadManager(loadMeasurementInterval,
averagingSeconds,
highLoadThreshold,
lowLoadThreshold);
return new LoadManager(LoadManagerSingleton::Get());
}
void LoadManagerDestroy(mozilla::LoadManager* aLoadManager)
{
delete aLoadManager;
/* static */ LoadManagerSingleton*
LoadManagerSingleton::Get() {
if (!sSingleton) {
MOZ_ASSERT(NS_IsMainThread());
int loadMeasurementInterval =
mozilla::Preferences::GetInt("media.navigator.load_adapt.measure_interval", 1000);
int averagingSeconds =
mozilla::Preferences::GetInt("media.navigator.load_adapt.avg_seconds", 3);
float highLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.high_load", 0.90);
float lowLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.low_load", 0.40);
sSingleton = new LoadManagerSingleton(loadMeasurementInterval,
averagingSeconds,
highLoadThreshold,
lowLoadThreshold);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
}
}
return sSingleton;
}
}; // namespace

Просмотреть файл

@ -3616,7 +3616,11 @@ nsGlobalWindow::GetPerformance(ErrorResult& aError)
{
FORWARD_TO_INNER_OR_THROW(GetPerformance, (aError), aError, nullptr);
return nsPIDOMWindow::GetPerformance();
nsPerformance* p = nsPIDOMWindow::GetPerformance();
if (!p) {
aError.Throw(NS_ERROR_FAILURE);
}
return p;
}
NS_IMETHODIMP

Просмотреть файл

@ -216,17 +216,17 @@ tv = {
"6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a55" +
"3d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c4831" +
"16ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0c" +
"f539e9cfcdd3de653729ead5d1024100cc8853d1d54da630fac004f471f281c7" +
"b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be" +
"2419b2af72bfe9a030e860b0288b5d77024100d32737e7267ffe1341b2d5c0d1" +
"50a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c" +
"21acf1c11c520c2f26a471dcad212eac7ca39d02410095297b0f95a2fa67d007" +
"07d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866e" +
"fef13c459e1a631386b7e354c899f5f112ca85d7158302400e12bf1718e9cef5" +
"599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305f" +
"becbd2d76819967d4671acc6431e4037968db37878e695c102407fbf3360826f" +
"c125dceac9bf8d38b6cad8ccc8b4f867bfea02dcbf5df008258ee9902ea07e28" +
"7770df660328c81e906184b6aa2239868775204d098fc846c669"
"f539e9cfcdd3de653729ead5d1024100d32737e7267ffe1341b2d5c0d150a81b" +
"586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1" +
"c11c520c2f26a471dcad212eac7ca39d024100cc8853d1d54da630fac004f471" +
"f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0d" +
"d852be2419b2af72bfe9a030e860b0288b5d7702400e12bf1718e9cef5599ba1" +
"c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2" +
"d76819967d4671acc6431e4037968db37878e695c102410095297b0f95a2fa67" +
"d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda" +
"866efef13c459e1a631386b7e354c899f5f112ca85d7158302404f456c502493" +
"bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbe" +
"fd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1"
),
spki: util.hex2abv(
"30819f300d06092a864886f70d010101050003818d0030818902818100a8b3b2" +

Просмотреть файл

@ -7,6 +7,7 @@
#include "builtin/Eval.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Range.h"
#include "jscntxt.h"
#include "jsonparser.h"
@ -20,6 +21,7 @@ using namespace js;
using mozilla::AddToHash;
using mozilla::HashString;
using mozilla::Range;
// We should be able to assert this for *any* fp->scopeChain().
static void
@ -173,9 +175,10 @@ TryEvalJSON(JSContext *cx, JSScript *callerScript,
if (cp == end) {
bool isArray = (chars[0] == '[');
JSONParser<jschar> parser(cx, isArray ? chars : chars + 1U,
isArray ? length : length - 2,
JSONParserBase::NoError);
auto jsonChars = isArray
? Range<const jschar>(chars.get(), length)
: Range<const jschar>(chars.get() + 1U, length - 2);
JSONParser<jschar> parser(cx, jsonChars, JSONParserBase::NoError);
RootedValue tmp(cx);
if (!parser.parse(&tmp))
return EvalJSON_Failure;

Просмотреть файл

@ -0,0 +1,34 @@
function testBasic() {
// Latin1
var s = toLatin1('[1, 2, "foo", "bar\\r\\n", {"xyz": 3}, [1, 2, 3]]');
assertEq(JSON.stringify(JSON.parse(s)), '[1,2,"foo","bar\\r\\n",{"xyz":3},[1,2,3]]');
// TwoByte
s = '[1, 2, "foo\u1200", "bar\\r\\n", {"xyz": 3}, [1, 2, 3]]';
assertEq(JSON.stringify(JSON.parse(s)), '[1,2,"foo\u1200","bar\\r\\n",{"xyz":3},[1,2,3]]');
}
testBasic();
function testErrorPos() {
// Make sure the error location is calculated correctly.
// Latin1
var s = toLatin1('[1, \n2,');
try {
JSON.parse(s);
assertEq(0, 1);
} catch(e) {
assertEq(e instanceof SyntaxError, true);
assertEq(e.toString().contains("line 2 column 3"), true);
}
s = '[1, "\u1300",\n2,';
try {
JSON.parse(s);
assertEq(0, 1);
} catch(e) {
assertEq(e instanceof SyntaxError, true);
assertEq(e.toString().contains("line 2 column 3"), true);
}
}
testErrorPos();

Просмотреть файл

@ -5684,7 +5684,7 @@ JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandle
CHECK_REQUEST(cx);
RootedValue reviver(cx, NullValue());
return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp);
return ParseJSONWithReviver(cx, mozilla::Range<const jschar>(chars, len), reviver, vp);
}
JS_PUBLIC_API(bool)
@ -5692,7 +5692,7 @@ JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, Handle
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp);
return ParseJSONWithReviver(cx, mozilla::Range<const jschar>(chars, len), reviver, vp);
}
/************************************************************************/

Просмотреть файл

@ -352,9 +352,10 @@ AtomizeAndtake(ExclusiveContext *cx, jschar *tbchars, size_t length, InternBehav
}
/* |tbchars| must not point into an inline or short string. */
template <typename CharT>
MOZ_ALWAYS_INLINE
static JSAtom *
AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, InternBehavior ib)
AtomizeAndCopyChars(ExclusiveContext *cx, const CharT *tbchars, size_t length, InternBehavior ib)
{
if (JSAtom *s = cx->staticStrings().lookup(tbchars, length))
return s;
@ -396,6 +397,12 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length,
return atom;
}
template JSAtom *
AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, InternBehavior ib);
template JSAtom *
AtomizeAndCopyChars(ExclusiveContext *cx, const Latin1Char *tbchars, size_t length, InternBehavior ib);
JSAtom *
js::AtomizeString(ExclusiveContext *cx, JSString *str,
js::InternBehavior ib /* = js::DoNotInternAtom */)
@ -458,8 +465,9 @@ js::Atomize(ExclusiveContext *cx, const char *bytes, size_t length, InternBehavi
return AtomizeAndtake(cx, tbcharsZ, length, ib);
}
template <typename CharT>
JSAtom *
js::AtomizeChars(ExclusiveContext *cx, const jschar *chars, size_t length, InternBehavior ib)
js::AtomizeChars(ExclusiveContext *cx, const CharT *chars, size_t length, InternBehavior ib)
{
CHECK_REQUEST(cx);
@ -469,6 +477,12 @@ js::AtomizeChars(ExclusiveContext *cx, const jschar *chars, size_t length, Inter
return AtomizeAndCopyChars(cx, chars, length, ib);
}
template JSAtom *
js::AtomizeChars(ExclusiveContext *cx, const Latin1Char *chars, size_t length, InternBehavior ib);
template JSAtom *
js::AtomizeChars(ExclusiveContext *cx, const jschar *chars, size_t length, InternBehavior ib);
bool
js::IndexToIdSlow(ExclusiveContext *cx, uint32_t index, MutableHandleId idp)
{

Просмотреть файл

@ -13,6 +13,7 @@
#include "gc/Barrier.h"
#include "gc/Rooting.h"
#include "js/GCAPI.h"
#include "vm/CommonPropertyNames.h"
class JSAtom;
@ -85,14 +86,24 @@ struct AtomHasher
{
struct Lookup
{
const jschar *chars;
size_t length;
const JSAtom *atom; /* Optional. */
union {
const JS::Latin1Char *latin1Chars;
const jschar *twoByteChars;
};
bool isLatin1;
size_t length;
const JSAtom *atom; /* Optional. */
JS::AutoCheckCannotGC nogc;
HashNumber hash;
Lookup(const jschar *chars, size_t length)
: chars(chars), length(length), atom(nullptr)
: twoByteChars(chars), isLatin1(false), length(length), atom(nullptr)
{
hash = mozilla::HashString(chars, length);
}
Lookup(const JS::Latin1Char *chars, size_t length)
: latin1Chars(chars), isLatin1(true), length(length), atom(nullptr)
{
hash = mozilla::HashString(chars, length);
}
@ -187,8 +198,9 @@ extern JSAtom *
Atomize(ExclusiveContext *cx, const char *bytes, size_t length,
js::InternBehavior ib = js::DoNotInternAtom);
template <typename CharT>
extern JSAtom *
AtomizeChars(ExclusiveContext *cx, const jschar *chars, size_t length,
AtomizeChars(ExclusiveContext *cx, const CharT *chars, size_t length,
js::InternBehavior ib = js::DoNotInternAtom);
extern JSAtom *

Просмотреть файл

@ -137,9 +137,15 @@ IdToString(JSContext *cx, jsid id)
inline
AtomHasher::Lookup::Lookup(const JSAtom *atom)
: chars(atom->chars()), length(atom->length()), atom(atom)
: isLatin1(atom->hasLatin1Chars()), length(atom->length()), atom(atom)
{
hash = mozilla::HashString(chars, length);
if (isLatin1) {
latin1Chars = atom->latin1Chars(nogc);
hash = mozilla::HashString(latin1Chars, length);
} else {
twoByteChars = atom->twoByteChars(nogc);
hash = mozilla::HashString(twoByteChars, length);
}
}
inline bool
@ -150,7 +156,18 @@ AtomHasher::match(const AtomStateEntry &entry, const Lookup &lookup)
return lookup.atom == key;
if (key->length() != lookup.length)
return false;
return mozilla::PodEqual(key->chars(), lookup.chars, lookup.length);
if (key->hasLatin1Chars()) {
const Latin1Char *keyChars = key->latin1Chars(lookup.nogc);
if (lookup.isLatin1)
return mozilla::PodEqual(keyChars, lookup.latin1Chars, lookup.length);
return EqualCharsLatin1TwoByte(keyChars, lookup.twoByteChars, lookup.length);
}
const jschar *keyChars = key->twoByteChars(lookup.nogc);
if (lookup.isLatin1)
return EqualCharsLatin1TwoByte(lookup.latin1Chars, keyChars, lookup.length);
return mozilla::PodEqual(keyChars, lookup.twoByteChars, lookup.length);
}
inline Handle<PropertyName*>

Просмотреть файл

@ -45,6 +45,7 @@ using mozilla::MinNumberValue;
using mozilla::NegativeInfinity;
using mozilla::PodCopy;
using mozilla::PositiveInfinity;
using mozilla::Range;
using mozilla::RangedPtr;
using JS::AutoCheckCannotGC;
@ -175,14 +176,15 @@ ComputeAccurateBinaryBaseInteger(const CharT *start, const CharT *end, int base)
return value;
}
template <typename CharT>
double
js::ParseDecimalNumber(const JS::TwoByteChars chars)
js::ParseDecimalNumber(const Range<const CharT> chars)
{
MOZ_ASSERT(chars.length() > 0);
uint64_t dec = 0;
RangedPtr<jschar> s = chars.start(), end = chars.end();
RangedPtr<const CharT> s = chars.start(), end = chars.end();
do {
jschar c = *s;
CharT c = *s;
MOZ_ASSERT('0' <= c && c <= '9');
uint8_t digit = c - '0';
uint64_t next = dec * 10 + digit;
@ -193,6 +195,12 @@ js::ParseDecimalNumber(const JS::TwoByteChars chars)
return static_cast<double>(dec);
}
template double
js::ParseDecimalNumber(const Range<const Latin1Char> chars);
template double
js::ParseDecimalNumber(const Range<const jschar> chars);
template <typename CharT>
bool
js::GetPrefixInteger(ThreadSafeContext *cx, const CharT *start, const CharT *end, int base,

Просмотреть файл

@ -8,6 +8,7 @@
#define jsnum_h
#include "mozilla/FloatingPoint.h"
#include "mozilla/Range.h"
#include "NamespaceImports.h"
@ -117,8 +118,9 @@ const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53;
* the double type -- that is, the number will be smaller than
* DOUBLE_INTEGRAL_PRECISION_LIMIT
*/
template <typename CharT>
extern double
ParseDecimalNumber(const JS::TwoByteChars chars);
ParseDecimalNumber(const mozilla::Range<const CharT> chars);
/*
* Compute the positive integer of the given base described immediately at the

Просмотреть файл

@ -772,12 +772,13 @@ Revive(JSContext *cx, HandleValue reviver, MutableHandleValue vp)
return Walk(cx, obj, id, reviver, vp);
}
template <typename CharT>
bool
js::ParseJSONWithReviver(JSContext *cx, ConstTwoByteChars chars, size_t length,
js::ParseJSONWithReviver(JSContext *cx, mozilla::Range<const CharT> chars,
HandleValue reviver, MutableHandleValue vp)
{
/* 15.12.2 steps 2-3. */
JSONParser<jschar> parser(cx, chars, length);
JSONParser<CharT> parser(cx, chars);
if (!parser.parse(vp))
return false;
@ -787,6 +788,14 @@ js::ParseJSONWithReviver(JSContext *cx, ConstTwoByteChars chars, size_t length,
return true;
}
template bool
js::ParseJSONWithReviver(JSContext *cx, mozilla::Range<const Latin1Char> chars,
HandleValue reviver, MutableHandleValue vp);
template bool
js::ParseJSONWithReviver(JSContext *cx, mozilla::Range<const jschar> chars,
HandleValue reviver, MutableHandleValue vp);
#if JS_HAS_TOSOURCE
static bool
json_toSource(JSContext *cx, unsigned argc, Value *vp)
@ -810,17 +819,22 @@ json_parse(JSContext *cx, unsigned argc, Value *vp)
if (!str)
return false;
Rooted<JSFlatString*> flat(cx, str->ensureFlat(cx));
JSFlatString *flat = str->ensureFlat(cx);
if (!flat)
return false;
JS::Anchor<JSString *> anchor(flat);
AutoStableStringChars flatChars(cx, flat);
if (!flatChars.init())
return false;
RootedValue reviver(cx, args.get(1));
/* Steps 2-5. */
return ParseJSONWithReviver(cx, ConstTwoByteChars(flat->chars(), flat->length()),
flat->length(), reviver, args.rval());
return flatChars.isLatin1()
? ParseJSONWithReviver(cx, flatChars.latin1Range(), reviver, args.rval())
: ParseJSONWithReviver(cx, flatChars.twoByteRange(), reviver, args.rval());
}
/* ES5 15.12.3. */

Просмотреть файл

@ -7,6 +7,8 @@
#ifndef json_h
#define json_h
#include "mozilla/Range.h"
#include "NamespaceImports.h"
#include "js/RootingAPI.h"
@ -24,8 +26,9 @@ js_Stringify(JSContext *cx, js::MutableHandleValue vp, JSObject *replacer,
namespace js {
template <typename CharT>
extern bool
ParseJSONWithReviver(JSContext *cx, JS::ConstTwoByteChars chars, size_t length,
ParseJSONWithReviver(JSContext *cx, mozilla::Range<const CharT> chars,
HandleValue reviver, MutableHandleValue vp);
} // namespace js

Просмотреть файл

@ -6,6 +6,7 @@
#include "jsonparser.h"
#include "mozilla/Range.h"
#include "mozilla/RangedPtr.h"
#include <ctype.h>
@ -21,6 +22,7 @@
using namespace js;
using mozilla::Range;
using mozilla::RangedPtr;
JSONParserBase::~JSONParserBase()
@ -126,7 +128,7 @@ JSONParser<CharT>::readString()
* Optimization: if the source contains no escaped characters, create the
* string directly from the source text.
*/
RangedPtr<const jschar> start = current;
CharPtr start = current;
for (; current < end; current++) {
if (*current == '"') {
size_t length = current - start;
@ -259,7 +261,7 @@ JSONParser<CharT>::readNumber()
return token(Error);
}
const RangedPtr<const jschar> digitStart = current;
const CharPtr digitStart = current;
/* 0|[1-9][0-9]+ */
if (!JS7_ISDEC(*current)) {
@ -275,7 +277,7 @@ JSONParser<CharT>::readNumber()
/* Fast path: no fractional or exponent part. */
if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
TwoByteChars chars(digitStart.get(), current - digitStart);
Range<const CharT> chars(digitStart.get(), current - digitStart);
if (chars.length() < strlen("9007199254740992")) {
// If the decimal number is shorter than the length of 2**53, (the
// largest number a double can represent with integral precision),
@ -286,7 +288,7 @@ JSONParser<CharT>::readNumber()
}
double d;
const jschar *dummy;
const CharT *dummy;
if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
return token(OOM);
JS_ASSERT(current == dummy);
@ -332,7 +334,7 @@ JSONParser<CharT>::readNumber()
}
double d;
const jschar *finish;
const CharT *finish;
if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d))
return token(OOM);
JS_ASSERT(current == finish);
@ -452,8 +454,9 @@ JSONParser<CharT>::advanceAfterObjectOpen()
return token(Error);
}
template <typename CharT>
static inline void
AssertPastValue(const RangedPtr<const jschar> current)
AssertPastValue(const RangedPtr<const CharT> current)
{
/*
* We're past an arbitrary JSON value, so the previous character is
@ -827,4 +830,5 @@ JSONParser<CharT>::parse(MutableHandleValue vp)
return true;
}
template class js::JSONParser<Latin1Char>;
template class js::JSONParser<jschar>;

Просмотреть файл

@ -8,6 +8,7 @@
#define jsonparser_h
#include "mozilla/Attributes.h"
#include "mozilla/Range.h"
#include "jspubtd.h"
@ -191,12 +192,12 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase
/* Public API */
/* Create a parser for the provided JSON data. */
JSONParser(JSContext *cx, CharPtr data, size_t length,
JSONParser(JSContext *cx, mozilla::Range<const CharT> data,
ErrorHandling errorHandling = RaiseError)
: JSONParserBase(cx, errorHandling),
current(data),
begin(data),
end((data + length).get(), data.get(), length)
current(data.start()),
begin(current),
end(data.end())
{
JS_ASSERT(current <= end);
}

Просмотреть файл

@ -22,6 +22,7 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
#include "mozilla/TypeTraits.h"
#include <ctype.h>
@ -71,6 +72,7 @@ using mozilla::IsNegativeZero;
using mozilla::IsSame;
using mozilla::PodCopy;
using mozilla::PodEqual;
using mozilla::Range;
using mozilla::SafeCast;
using JS::AutoCheckCannotGC;
@ -1702,16 +1704,6 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static bool
EqualCharsLatin1TwoByte(const Latin1Char *s1, const jschar *s2, size_t len)
{
for (const Latin1Char *s1end = s1 + len; s1 < s1end; s1++, s2++) {
if (jschar(*s1) != *s2)
return false;
}
return true;
}
static bool
HasSubstringAt(JSLinearString *text, JSLinearString *pat, size_t start)
{
@ -4279,51 +4271,90 @@ js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start, size_t len
return JSDependentString::new_(cx, base, start, length);
}
template <AllowGC allowGC>
JSFlatString *
js_NewStringCopyN(ExclusiveContext *cx, const jschar *s, size_t n)
{
if (JSFatInlineString::twoByteLengthFits(n))
return NewFatInlineString<allowGC>(cx, TwoByteChars(s, n));
template <typename CharT>
static void
CopyCharsMaybeInflate(jschar *dest, const CharT *src, size_t len);
jschar *news = cx->pod_malloc<jschar>(n + 1);
template <>
void
CopyCharsMaybeInflate(jschar *dest, const jschar *src, size_t len)
{
PodCopy(dest, src, len);
}
template <>
void
CopyCharsMaybeInflate(jschar *dest, const Latin1Char *src, size_t len)
{
CopyAndInflateChars(dest, src, len);
}
template <AllowGC allowGC, typename CharT>
JSFlatString *
js_NewStringCopyN(ThreadSafeContext *cx, const CharT *s, size_t n)
{
if (EnableLatin1Strings) {
if (JSFatInlineString::lengthFits<CharT>(n))
return NewFatInlineString<allowGC>(cx, Range<const CharT>(s, n));
ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
if (!news)
return nullptr;
PodCopy(news.get(), s, n);
news[n] = 0;
JSFlatString *str = js_NewString<allowGC>(cx, news.get(), n);
if (!str)
return nullptr;
news.forget();
return str;
}
if (JSFatInlineString::twoByteLengthFits(n))
return NewFatInlineString<allowGC>(cx, Range<const CharT>(s, n));
ScopedJSFreePtr<jschar> news(cx->pod_malloc<jschar>(n + 1));
if (!news)
return nullptr;
js_strncpy(news, s, n);
CopyCharsMaybeInflate(news.get(), s, n);
news[n] = 0;
JSFlatString *str = js_NewString<allowGC>(cx, news, n);
JSFlatString *str = js_NewString<allowGC>(cx, news.get(), n);
if (!str)
js_free(news);
return str;
}
template JSFlatString *
js_NewStringCopyN<CanGC>(ExclusiveContext *cx, const jschar *s, size_t n);
template JSFlatString *
js_NewStringCopyN<NoGC>(ExclusiveContext *cx, const jschar *s, size_t n);
template <AllowGC allowGC>
JSFlatString *
js_NewStringCopyN(ThreadSafeContext *cx, const char *s, size_t n)
{
if (JSFatInlineString::twoByteLengthFits(n))
return NewFatInlineString<allowGC>(cx, JS::Latin1Chars(s, n));
jschar *chars = InflateString(cx, s, &n);
if (!chars)
return nullptr;
JSFlatString *str = js_NewString<allowGC>(cx, chars, n);
if (!str)
js_free(chars);
news.forget();
return str;
}
template JSFlatString *
js_NewStringCopyN<CanGC>(ThreadSafeContext *cx, const char *s, size_t n);
js_NewStringCopyN<CanGC>(ThreadSafeContext *cx, const jschar *s, size_t n);
template JSFlatString *
js_NewStringCopyN<NoGC>(ThreadSafeContext *cx, const char *s, size_t n);
js_NewStringCopyN<NoGC>(ThreadSafeContext *cx, const jschar *s, size_t n);
template JSFlatString *
js_NewStringCopyN<CanGC>(ThreadSafeContext *cx, const Latin1Char *s, size_t n);
template JSFlatString *
js_NewStringCopyN<NoGC>(ThreadSafeContext *cx, const Latin1Char *s, size_t n);
template <>
JSFlatString *
js_NewStringCopyN<CanGC>(ThreadSafeContext *cx, const char *s, size_t n)
{
return js_NewStringCopyN<CanGC>(cx, reinterpret_cast<const Latin1Char *>(s), n);
}
template <>
JSFlatString *
js_NewStringCopyN<NoGC>(ThreadSafeContext *cx, const char *s, size_t n)
{
return js_NewStringCopyN<NoGC>(cx, reinterpret_cast<const Latin1Char *>(s), n);
}
template <AllowGC allowGC>
JSFlatString *
@ -4331,7 +4362,7 @@ js_NewStringCopyZ(ExclusiveContext *cx, const jschar *s)
{
size_t n = js_strlen(s);
if (JSFatInlineString::twoByteLengthFits(n))
return NewFatInlineString<allowGC>(cx, TwoByteChars(s, n));
return NewFatInlineString<allowGC>(cx, Range<const jschar>(s, n));
size_t m = (n + 1) * sizeof(jschar);
jschar *news = (jschar *) cx->malloc_(m);

Просмотреть файл

@ -101,13 +101,9 @@ extern JSLinearString *
js_NewDependentString(JSContext *cx, JSString *base, size_t start, size_t length);
/* Copy a counted string and GC-allocate a descriptor for it. */
template <js::AllowGC allowGC>
template <js::AllowGC allowGC, typename CharT>
extern JSFlatString *
js_NewStringCopyN(js::ExclusiveContext *cx, const jschar *s, size_t n);
template <js::AllowGC allowGC>
extern JSFlatString *
js_NewStringCopyN(js::ThreadSafeContext *cx, const char *s, size_t n);
js_NewStringCopyN(js::ThreadSafeContext *cx, const CharT *s, size_t n);
/* Copy a C string and GC-allocate a descriptor for it. */
template <js::AllowGC allowGC>
@ -237,6 +233,16 @@ js_strdup(js::ThreadSafeContext *cx, const jschar *s);
namespace js {
inline bool
EqualCharsLatin1TwoByte(const Latin1Char *s1, const jschar *s2, size_t len)
{
for (const Latin1Char *s1end = s1 + len; s1 < s1end; s1++, s2++) {
if (jschar(*s1) != *s2)
return false;
}
return true;
}
/*
* Inflate bytes in ASCII encoding to jschars. Return null on error, otherwise
* return the jschar that was malloc'ed. length is updated to the length of the

Просмотреть файл

@ -10,6 +10,7 @@
#include "vm/String.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
#include "jscntxt.h"
@ -42,7 +43,7 @@ AllocateFatInlineString(ThreadSafeContext *cx, size_t len, CharT **chars)
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSInlineString *
NewFatInlineString(ThreadSafeContext *cx, JS::Latin1Chars chars)
NewFatInlineString(ThreadSafeContext *cx, mozilla::Range<const Latin1Char> chars)
{
size_t len = chars.length();
@ -70,7 +71,7 @@ NewFatInlineString(ThreadSafeContext *cx, JS::Latin1Chars chars)
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSInlineString *
NewFatInlineString(ExclusiveContext *cx, JS::TwoByteChars chars)
NewFatInlineString(ThreadSafeContext *cx, mozilla::Range<const jschar> chars)
{
/*
* Don't bother trying to find a static atom; measurement shows that not

Просмотреть файл

@ -744,6 +744,57 @@ StaticStrings::isStatic(JSAtom *atom)
}
}
AutoStableStringChars::~AutoStableStringChars()
{
if (ownsChars_) {
MOZ_ASSERT(state_ == Latin1 || state_ == TwoByte);
if (state_ == Latin1)
js_free(const_cast<Latin1Char*>(latin1Chars_));
else
js_free(const_cast<jschar*>(twoByteChars_));
}
}
bool
AutoStableStringChars::init()
{
MOZ_ASSERT(state_ == Uninitialized);
if (s_->hasLatin1Chars()) {
state_ = Latin1;
latin1Chars_ = s_->rawLatin1Chars();
} else {
state_ = TwoByte;
twoByteChars_ = s_->rawTwoByteChars();
}
return true;
}
bool
AutoStableStringChars::initTwoByte(JSContext *cx)
{
MOZ_ASSERT(state_ == Uninitialized);
if (s_->hasTwoByteChars()) {
state_ = TwoByte;
twoByteChars_ = s_->rawTwoByteChars();
return true;
}
jschar *chars = cx->pod_malloc<jschar>(s_->length() + 1);
if (!chars)
return false;
CopyAndInflateChars(chars, s_->rawLatin1Chars(), s_->length());
chars[s_->length()] = 0;
state_ = TwoByte;
ownsChars_ = true;
twoByteChars_ = chars;
return true;
}
#ifdef DEBUG
void
JSAtom::dump()

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
#include "jsapi.h"
#include "jsfriendapi.h"
@ -30,6 +31,7 @@ class JSRope;
namespace js {
class AutoStableStringChars;
class StaticStrings;
class PropertyName;
@ -584,6 +586,7 @@ JS_STATIC_ASSERT(sizeof(JSRope) == sizeof(JSString));
class JSLinearString : public JSString
{
friend class JSString;
friend class js::AutoStableStringChars;
/* Vacuous and therefore unimplemented. */
JSLinearString *ensureLinear(JSContext *cx) MOZ_DELETE;
@ -601,6 +604,9 @@ class JSLinearString : public JSString
return (void *)d.s.u2.nonInlineCharsTwoByte;
}
MOZ_ALWAYS_INLINE const JS::Latin1Char *rawLatin1Chars() const;
MOZ_ALWAYS_INLINE const jschar *rawTwoByteChars() const;
public:
MOZ_ALWAYS_INLINE
const jschar *nonInlineChars() const {
@ -635,10 +641,14 @@ class JSLinearString : public JSString
const CharT *chars(const JS::AutoCheckCannotGC &nogc) const;
MOZ_ALWAYS_INLINE
const JS::Latin1Char *latin1Chars(const JS::AutoCheckCannotGC &nogc) const;
const JS::Latin1Char *latin1Chars(const JS::AutoCheckCannotGC &nogc) const {
return rawLatin1Chars();
}
MOZ_ALWAYS_INLINE
const jschar *twoByteChars(const JS::AutoCheckCannotGC &nogc) const;
const jschar *twoByteChars(const JS::AutoCheckCannotGC &nogc) const {
return rawTwoByteChars();
}
JS::TwoByteChars range() const {
JS_ASSERT(JSString::isLinear());
@ -1042,6 +1052,56 @@ class ScopedThreadSafeStringInspector
}
};
/*
* This class provides safe access to a string's chars across a GC. Once
* we allocate strings and chars in the nursery (bug 903519), this class
* will have to make a copy of the string's chars if they are allocated
* in the nursery, so it's best to avoid using this class unless you really
* need it. It's usually more efficient to use the latin1Chars/twoByteChars
* JSString methods and often the code can be rewritten so that only indexes
* instead of char pointers are used in parts of the code that can GC.
*/
class MOZ_STACK_CLASS AutoStableStringChars
{
/* Ensure the string is kept alive while we're using its chars. */
Rooted<JSLinearString*> s_;
union {
const jschar *twoByteChars_;
const JS::Latin1Char *latin1Chars_;
};
enum State { Uninitialized, Latin1, TwoByte };
State state_;
bool ownsChars_;
public:
AutoStableStringChars(JSContext *cx, JSLinearString *s)
: s_(cx, s), state_(Uninitialized), ownsChars_(false)
{};
~AutoStableStringChars();
bool init();
/* Like init(), but Latin1 chars are inflated to TwoByte. */
bool initTwoByte(JSContext *cx);
bool isLatin1() const { return state_ == Latin1; }
bool isTwoByte() const { return state_ == TwoByte; }
mozilla::Range<const Latin1Char> latin1Range() const {
MOZ_ASSERT(state_ == Latin1);
return mozilla::Range<const Latin1Char>(latin1Chars_, s_->length());
}
mozilla::Range<const jschar> twoByteRange() const {
MOZ_ASSERT(state_ == TwoByte);
return mozilla::Range<const jschar>(twoByteChars_, s_->length());
}
private:
AutoStableStringChars(const AutoStableStringChars &other) MOZ_DELETE;
void operator=(const AutoStableStringChars &other) MOZ_DELETE;
};
class StaticStrings
{
private:
@ -1321,14 +1381,14 @@ template<>
MOZ_ALWAYS_INLINE const jschar *
JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
{
return twoByteChars(nogc);
return rawTwoByteChars();
}
template<>
MOZ_ALWAYS_INLINE const JS::Latin1Char *
JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
{
return latin1Chars(nogc);
return rawLatin1Chars();
}
template<>
@ -1382,19 +1442,19 @@ JSLinearString::chars() const
}
MOZ_ALWAYS_INLINE const JS::Latin1Char *
JSLinearString::latin1Chars(const JS::AutoCheckCannotGC &nogc) const
JSLinearString::rawLatin1Chars() const
{
JS_ASSERT(JSString::isLinear());
JS_ASSERT(hasLatin1Chars());
return isInline() ? asInline().latin1Chars(nogc) : nonInlineLatin1Chars(nogc);
return isInline() ? d.inlineStorageLatin1 : d.s.u2.nonInlineCharsLatin1;
}
MOZ_ALWAYS_INLINE const jschar *
JSLinearString::twoByteChars(const JS::AutoCheckCannotGC &nogc) const
JSLinearString::rawTwoByteChars() const
{
JS_ASSERT(JSString::isLinear());
JS_ASSERT(hasTwoByteChars());
return isInline() ? asInline().twoByteChars(nogc) : nonInlineTwoByteChars(nogc);
return isInline() ? d.inlineStorageTwoByte : d.s.u2.nonInlineCharsTwoByte;
}
inline js::PropertyName *

Просмотреть файл

@ -6,12 +6,16 @@
#include "vm/StringBuffer.h"
#include "mozilla/Range.h"
#include "jsobjinlines.h"
#include "vm/String-inl.h"
using namespace js;
using mozilla::Range;
template <typename CharT, class Buffer>
static CharT *
ExtractWellSized(ExclusiveContext *cx, Buffer &cb)
@ -96,10 +100,10 @@ StringBuffer::finishString()
if (isLatin1()) {
if (JSFatInlineString::latin1LengthFits(len))
return NewFatInlineString<CanGC>(cx, Latin1Chars(latin1Chars().begin(), len));
return NewFatInlineString<CanGC>(cx, Range<const Latin1Char>(latin1Chars().begin(), len));
} else {
if (JSFatInlineString::twoByteLengthFits(len))
return NewFatInlineString<CanGC>(cx, TwoByteChars(twoByteChars().begin(), len));
return NewFatInlineString<CanGC>(cx, Range<const jschar>(twoByteChars().begin(), len));
}
return isLatin1()

Просмотреть файл

@ -416,8 +416,7 @@ WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
codecConfig->mFreq,
codecConfig->mPacSize,
codecConfig->mChannels,
codecConfig->mRate,
codecConfig->mLoadManager);
codecConfig->mRate);
mEngineTransmitting = true;
return kMediaConduitNoError;
@ -910,8 +909,7 @@ WebrtcAudioConduit::CopyCodecToDB(const AudioCodecConfig* codecInfo)
codecInfo->mFreq,
codecInfo->mPacSize,
codecInfo->mChannels,
codecInfo->mRate,
codecInfo->mLoadManager);
codecInfo->mRate);
mRecvCodecList.push_back(cdcConfig);
return true;
}

Просмотреть файл

@ -11,8 +11,6 @@
namespace mozilla {
class LoadManager;
/**
* Minimalistic Audio Codec Config Params
*/
@ -28,22 +26,19 @@ struct AudioCodecConfig
int mPacSize;
int mChannels;
int mRate;
LoadManager* mLoadManager;
/* Default constructor is not provided since as a consumer, we
* can't decide the default configuration for the codec
*/
explicit AudioCodecConfig(int type, std::string name,
int freq,int pacSize,
int channels, int rate,
LoadManager* load_manager = nullptr)
int channels, int rate)
: mType(type),
mName(name),
mFreq(freq),
mPacSize(pacSize),
mChannels(channels),
mRate(rate),
mLoadManager(load_manager)
mRate(rate)
{
}
@ -65,7 +60,6 @@ struct VideoCodecConfig
uint32_t mRtcpFbTypes;
unsigned int mMaxFrameSize;
unsigned int mMaxFrameRate;
LoadManager* mLoadManager;
uint8_t mProfile;
uint8_t mConstraints;
uint8_t mLevel;
@ -75,7 +69,6 @@ struct VideoCodecConfig
VideoCodecConfig(int type,
std::string name,
int rtcpFbTypes,
LoadManager* load_manager = nullptr,
uint8_t profile = 0x42,
uint8_t constraints = 0xC0,
uint8_t level = 30,
@ -85,7 +78,6 @@ struct VideoCodecConfig
mRtcpFbTypes(rtcpFbTypes),
mMaxFrameSize(0),
mMaxFrameRate(0),
mLoadManager(load_manager),
mProfile(profile),
mConstraints(constraints),
mLevel(level),
@ -95,14 +87,12 @@ struct VideoCodecConfig
std::string name,
int rtcpFbTypes,
unsigned int max_fs,
unsigned int max_fr,
LoadManager* load_manager = nullptr) :
unsigned int max_fr) :
mType(type),
mName(name),
mRtcpFbTypes(rtcpFbTypes),
mMaxFrameSize(max_fs),
mMaxFrameRate(max_fr),
mLoadManager(load_manager) {}
mMaxFrameRate(max_fr) {}
bool RtcpFbIsSet(sdp_rtcp_fb_nack_type_e type) const
{

Просмотреть файл

@ -275,6 +275,11 @@ MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
if (temp >= 0) {
mMaxBitrate = temp;
}
bool use_loadmanager = false;
NS_WARN_IF(NS_FAILED(branch->GetBoolPref("media.navigator.load_adapt", &use_loadmanager)));
if (use_loadmanager) {
mLoadManager = LoadManagerBuild();
}
}
}
#endif
@ -552,9 +557,9 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
mEngineTransmitting = false;
}
if (codecConfig->mLoadManager) {
mPtrViEBase->RegisterCpuOveruseObserver(mChannel, codecConfig->mLoadManager);
mPtrViEBase->SetLoadManager(codecConfig->mLoadManager);
if (mLoadManager) {
mPtrViEBase->RegisterCpuOveruseObserver(mChannel, mLoadManager);
mPtrViEBase->SetLoadManager(mLoadManager);
}
if (mExternalSendCodec &&

Просмотреть файл

@ -11,6 +11,7 @@
#include "MediaConduitInterface.h"
#include "MediaEngineWrapper.h"
#include "CodecStatistics.h"
#include "LoadManagerFactory.h"
// conflicts with #include of scoped_ptr.h
#undef FF
@ -358,6 +359,8 @@ private:
// statistics object for video codec;
nsAutoPtr<VideoCodecStatistics> mVideoCodecStat;
nsAutoPtr<LoadManager> mLoadManager;
};
} // end namespace

Просмотреть файл

@ -1692,8 +1692,7 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
payloads[i].audio.frequency,
payloads[i].audio.packet_size,
payloads[i].audio.channels,
payloads[i].audio.bitrate,
pc.impl()->load_manager());
payloads[i].audio.bitrate);
configs.push_back(config_raw);
}
@ -1750,8 +1749,7 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
config_raw = new mozilla::VideoCodecConfig(
payloads[i].remote_rtp_pt,
ccsdpCodecName(payloads[i].codec_type),
payloads[i].video.rtcp_fb_types,
pc.impl()->load_manager());
payloads[i].video.rtcp_fb_types);
if (vcmEnsureExternalCodec(conduit, config_raw, false)) {
continue;
}
@ -2350,8 +2348,7 @@ static int vcmTxCreateAudioConduit(int level,
payload->audio.frequency,
payload->audio.packet_size,
payload->audio.channels,
payload->audio.bitrate,
pc.impl()->load_manager());
payload->audio.bitrate);
// Take possession of this pointer
mozilla::ScopedDeletePtr<mozilla::AudioCodecConfig> config(config_raw);
@ -2398,8 +2395,7 @@ static int vcmTxCreateVideoConduit(int level,
ccsdpCodecName(payload->codec_type),
payload->video.rtcp_fb_types,
payload->video.max_fs,
payload->video.max_fr,
pc.impl()->load_manager());
payload->video.max_fr);
// Take possession of this pointer
mozilla::ScopedDeletePtr<mozilla::VideoCodecConfig> config(config_raw);

Просмотреть файл

@ -489,7 +489,6 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
, mWindow(nullptr)
, mIdentity(nullptr)
, mSTSThread(nullptr)
, mLoadManager(nullptr)
, mMedia(nullptr)
, mNumAudioStreams(0)
, mNumVideoStreams(0)
@ -538,10 +537,6 @@ PeerConnectionImpl::~PeerConnectionImpl()
shutdown(calledFromObject);
}
}
if (mLoadManager) {
mozilla::LoadManagerDestroy(mLoadManager);
mLoadManager = nullptr;
}
#endif
// Since this and Initialize() occur on MainThread, they can't both be
@ -877,12 +872,6 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
return res;
}
#ifdef MOZILLA_INTERNAL_API
if (mozilla::Preferences::GetBool("media.navigator.load_adapt", false)) {
mLoadManager = mozilla::LoadManagerBuild();
}
#endif
return NS_OK;
}

Просмотреть файл

@ -27,7 +27,6 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
#include "StreamBuffer.h"
#include "LoadManagerFactory.h"
#ifdef MOZILLA_INTERNAL_API
#include "mozilla/TimeStamp.h"
@ -254,10 +253,6 @@ public:
return mMedia;
}
mozilla::LoadManager* load_manager() {
return mLoadManager;
}
// Handle system to allow weak references to be passed through C code
virtual const std::string& GetHandle();
@ -694,9 +689,6 @@ private:
// The target to run stuff on
nsCOMPtr<nsIEventTarget> mSTSThread;
// CPU Load adaptation stuff
mozilla::LoadManager* mLoadManager;
#ifdef MOZILLA_INTERNAL_API
// DataConnection that's used to get all the DataChannels
nsRefPtr<mozilla::DataChannelConnection> mDataConnection;

Просмотреть файл

@ -812,7 +812,7 @@ class TransportConduitTest : public ::testing::Test
ASSERT_NE(mVideoSession, (void*)nullptr);
// Configure send codecs on the conduit.
mozilla::VideoCodecConfig cinst1(120, "VP8", 0, max_fs, 0);
mozilla::VideoCodecConfig cinst1(120, "VP8", 0, max_fs);
err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
ASSERT_EQ(mozilla::kMediaConduitNoError, err);

Просмотреть файл

@ -313,6 +313,13 @@ HashString(const char* str, size_t length)
return detail::HashKnownLength(str, length);
}
MOZ_WARN_UNUSED_RESULT
inline uint32_t
HashString(const unsigned char* str, size_t length)
{
return detail::HashKnownLength(str, length);
}
MOZ_WARN_UNUSED_RESULT
inline uint32_t
HashString(const uint16_t* str)

Просмотреть файл

@ -38,7 +38,7 @@
# endif
#endif
#ifdef MOZ_HAVE_IS_LITERAL
#if defined(MOZ_HAVE_IS_LITERAL) && defined(MOZ_HAVE_CXX11_CONSTEXPR)
#include <type_traits>
template<typename T>
void

Просмотреть файл

@ -28,6 +28,7 @@
#include "nsISSLSocketControl.h"
#include "nsISSLStatus.h"
#include "nsISSLStatusProvider.h"
#include "nsISupportsPriority.h"
#include "prprf.h"
#include "prnetdb.h"
#include "sslt.h"
@ -2888,7 +2889,7 @@ Http2Session::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
nsRefPtr<SpdyConnectTransaction> connectTrans =
new SpdyConnectTransaction(ci, aCallbacks,
trans->Caps(), trans, this);
AddStream(connectTrans, trans->Priority(),
AddStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL,
false, nullptr);
Http2Stream *tunnel = mStreamTransactionHash.Get(connectTrans);
MOZ_ASSERT(tunnel);

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsHttp.h"
#include "nsHttpHandler.h"
#include "nsILoadGroup.h"
#include "nsISupportsPriority.h"
#include "prprf.h"
#include "SpdyPush3.h"
#include "SpdySession3.h"
@ -2528,7 +2529,7 @@ SpdySession3::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
nsRefPtr<SpdyConnectTransaction> connectTrans =
new SpdyConnectTransaction(ci, aCallbacks,
trans->Caps(), trans, this);
AddStream(connectTrans, trans->Priority(),
AddStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL,
false, nullptr);
SpdyStream3 *tunnel = mStreamTransactionHash.Get(connectTrans);
MOZ_ASSERT(tunnel);

Просмотреть файл

@ -19,6 +19,7 @@
#include "nsHttpHandler.h"
#include "nsHttpConnection.h"
#include "nsILoadGroup.h"
#include "nsISupportsPriority.h"
#include "prprf.h"
#include "prnetdb.h"
#include "SpdyPush31.h"
@ -2660,7 +2661,7 @@ SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
nsRefPtr<SpdyConnectTransaction> connectTrans =
new SpdyConnectTransaction(ci, aCallbacks,
trans->Caps(), trans, this);
AddStream(connectTrans, trans->Priority(),
AddStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL,
false, nullptr);
SpdyStream31 *tunnel = mStreamTransactionHash.Get(connectTrans);
MOZ_ASSERT(tunnel);