Bug 245725 Make downloads display an approximation to the current transfer rate rather than the overall average speed p=son.le0@gmail.com r=biesi sr=me

This commit is contained in:
neil%parkwaycc.co.uk 2006-02-06 00:34:30 +00:00
parent f280152c5c
commit 5417075f05
12 changed files with 121 additions and 51 deletions

View File

@ -180,6 +180,13 @@ nsDownloadListener::GetStartTime(PRInt64 *aStartTime)
return NS_OK;
}
/* readonly attribute double speed; */
NS_IMETHODIMP
nsDownloadListener::GetSpeed(double* aSpeed)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsIMIMEInfo MIMEInfo; */
NS_IMETHODIMP
nsDownloadListener::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)

View File

@ -151,6 +151,13 @@ nsDownloadListener::GetStartTime(PRInt64 *aStartTime)
return NS_OK;
}
/* readonly attribute double speed; */
NS_IMETHODIMP
nsDownloadListener::GetSpeed(double* aSpeed)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsIMIMEInfo MIMEInfo; */
NS_IMETHODIMP
nsDownloadListener::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)

View File

@ -142,6 +142,12 @@ NS_IMETHODIMP CDownload::GetStartTime(PRInt64 *aStartTime)
return NS_OK;
}
/* readonly attribute double speed; */
NS_IMETHODIMP CDownload::GetSpeed(double *aSpeed)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsIMIMEInfo MIMEInfo; */
NS_IMETHODIMP CDownload::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)
{

View File

@ -65,6 +65,7 @@
#include "nsEnumeratorUtils.h"
#include "nsIFileURL.h"
#include "nsEmbedCID.h"
#include "nsInt64.h"
/* Outstanding issues/todo:
* 1. Implement pause/resume.
@ -85,7 +86,8 @@ static PRBool gStoppingDownloads = PR_FALSE;
#define PREF_BDM_FOCUSWHENSTARTING "browser.download.manager.focusWhenStarting"
#define PREF_BDM_CLOSEWHENDONE "browser.download.manager.closeWhenDone"
#define PREF_BDM_FLASHCOUNT "browser.download.manager.flashCount"
#define INTERVAL 500
static const nsInt64 gInterval((PRUint32)(400 * PR_USEC_PER_MSEC));
static nsIRDFResource* gNC_DownloadsRoot = nsnull;
static nsIRDFResource* gNC_File = nsnull;
@ -1806,10 +1808,11 @@ NS_IMPL_ISUPPORTS4(nsDownload, nsIDownload, nsITransfer, nsIWebProgressListener,
nsDownload::nsDownload():mDownloadState(nsIDownloadManager::DOWNLOAD_NOTSTARTED),
mPercentComplete(0),
mCurrBytes(0),
mMaxBytes(0),
mStartTime(0),
mLastUpdate(-500)
mCurrBytes(LL_ZERO),
mMaxBytes(LL_ZERO),
mStartTime(LL_ZERO),
mSpeed(0),
mLastUpdate(PR_Now() - (PRUint32)gInterval)
{
}
@ -1947,6 +1950,7 @@ nsresult
nsDownload::SetStartTime(PRInt64 aStartTime)
{
mStartTime = aStartTime;
mLastUpdate = aStartTime;
return NS_OK;
}
@ -1972,10 +1976,9 @@ nsDownload::OnProgressChange64(nsIWebProgress *aWebProgress,
mRequest = aRequest; // used for pause/resume
// filter notifications since they come in so frequently
PRTime delta;
PRTime now = PR_Now();
LL_SUB(delta, now, mLastUpdate);
if (LL_CMP(delta, <, INTERVAL) && aMaxTotalProgress != -1 && aCurTotalProgress < aMaxTotalProgress)
nsInt64 delta = now - mLastUpdate;
if (delta < gInterval)
return NS_OK;
mLastUpdate = now;
@ -1989,6 +1992,21 @@ nsDownload::OnProgressChange64(nsIWebProgress *aWebProgress,
mDownloadManager->DownloadStarted(path.get());
}
// Calculate the speed using the elapsed delta time and bytes downloaded
// during that time for more accuracy.
double elapsedSecs = double(delta) / PR_USEC_PER_SEC;
if (elapsedSecs > 0) {
nsUint64 curTotalProgress = (PRUint64)aCurTotalProgress;
nsUint64 diffBytes = curTotalProgress - nsUint64(mCurrBytes);
double speed = double(diffBytes) / elapsedSecs;
if (LL_IS_ZERO(mCurrBytes))
mSpeed = speed;
else {
// Calculate 'smoothed average' of 10 readings.
mSpeed = mSpeed * 0.9 + speed * 0.1;
}
}
if (aMaxTotalProgress > 0)
mPercentComplete = (PRInt32)((PRFloat64)aCurTotalProgress * 100 / aMaxTotalProgress + .5);
else
@ -2077,8 +2095,9 @@ nsDownload::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
nsresult aStatus)
{
if (aStateFlags & STATE_START)
mStartTime = PR_Now();
// Record the start time only if it hasn't been set.
if (LL_IS_ZERO(mStartTime) && (aStateFlags & STATE_START))
SetStartTime(PR_Now());
// When we break the ref cycle with mCancelable, we don't want to lose
// access to out member vars!
@ -2096,7 +2115,7 @@ nsDownload::OnStateChange(nsIWebProgress* aWebProgress,
else
mDownloadState = nsIXPInstallManagerUI::INSTALL_FINISHED;
// Set file size at the end of a tranfer (for unknown transfer amounts)
// Set file size at the end of a tranfer (for unknown transfer amounts)
if (mMaxBytes == -1)
mMaxBytes = mCurrBytes;
@ -2286,6 +2305,13 @@ nsDownload::GetTargetFile(nsILocalFile** aTargetFile)
return rv;
}
NS_IMETHODIMP
nsDownload::GetSpeed(double* aSpeed)
{
*aSpeed = mSpeed;
return NS_OK;
}
void
nsDownload::Pause(PRBool aPaused)
{

View File

@ -259,8 +259,9 @@ private:
PRInt32 mPercentComplete;
PRUint64 mCurrBytes;
PRUint64 mMaxBytes;
PRInt64 mStartTime;
PRTime mStartTime;
PRTime mLastUpdate;
double mSpeed;
friend class nsDownloadManager;
};

View File

@ -154,6 +154,11 @@ public:
return mInner->GetTargetFile(aTargetFile);
}
NS_IMETHODIMP GetSpeed(double* aSpeed)
{
return mInner->GetSpeed(aSpeed);
}
NS_IMETHODIMP OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)

View File

@ -59,7 +59,6 @@ function DownloadProgressListener (aDocument, aStringBundle)
DownloadProgressListener.prototype =
{
elapsed: 0,
rateChanges: 0,
rateChangeLimit: 0,
priorRate: 0,
@ -91,14 +90,6 @@ DownloadProgressListener.prototype =
// Update this time.
this.lastUpdate = now;
// Update download rate.
this.elapsed = now - (aDownload.startTime / 1000);
var rate; // aCurTotalProgress/sec
if (this.elapsed)
rate = (aCurTotalProgress * 1024) / this.elapsed;
else
rate = 0;
var aDownloadID = aDownload.targetFile.path;
var download = this.doc.getElementById(aDownloadID);
@ -138,6 +129,7 @@ DownloadProgressListener.prototype =
if (download)
download.setAttribute("status-internal", kbProgress);
var rate = aDownload.speed;
if (rate) {
// rate is bytes/sec
var kRate = rate / 1024; // K bytes/sec;
@ -157,13 +149,13 @@ DownloadProgressListener.prototype =
else
this.rateChanges = 0;
var fraction = kRate % 10;
kRate = parseInt((kRate - fraction) / 10);
var fraction = kRate % 10;
kRate = parseInt((kRate - fraction) / 10);
// Insert 3 is the download rate (in kilobytes/sec).
if (kRate < 100)
kRate += "." + fraction;
status = this._replaceInsert(status, 2, kRate);
// Insert 3 is the download rate (in kilobytes/sec).
if (kRate < 100)
kRate += "." + fraction;
status = this._replaceInsert(status, 2, kRate);
}
else
status = this._replaceInsert(status, 2, "??.?");

View File

@ -45,7 +45,7 @@ interface nsICancelable;
interface nsIWebProgressListener;
interface nsIMIMEInfo;
[scriptable, uuid(a60c9199-2e21-434f-a43b-ab954ea2f6b7)]
[scriptable, uuid(07910093-d70b-4621-9888-b811f42293c3)]
interface nsIDownload : nsITransfer {
/**
@ -95,7 +95,12 @@ interface nsIDownload : nsITransfer {
* The time a transfer was started.
*/
readonly attribute long long startTime;
/**
* The speed of the transfer in bytes/sec.
*/
readonly attribute double speed;
/**
* Optional. If set, it will contain the target's relevant MIME information.
* This includes it's MIME Type, helper app, and whether that helper should be

View File

@ -1602,6 +1602,10 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
{
NS_PRECONDITION(request, "OnStartRequest without request?");
// Set mTimeDownloadStarted here as the download has already started and
// we want to record the start time before showing the filepicker.
mTimeDownloadStarted = PR_Now();
mRequest = request;
nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
@ -1685,8 +1689,6 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
encChannel->SetApplyConversion( applyConversion );
}
mTimeDownloadStarted = PR_Now();
// now that the temp file is set up, find out if we need to invoke a dialog
// asking the user what they want us to do with this content...

View File

@ -66,6 +66,7 @@
#include "nsIAlertsService.h"
#endif
#include "nsEmbedCID.h"
#include "nsInt64.h"
/* Outstanding issues/todo:
* 1. Implement pause/resume.
@ -73,7 +74,8 @@
#define DOWNLOAD_MANAGER_FE_URL "chrome://communicator/content/downloadmanager/downloadmanager.xul"
#define DOWNLOAD_MANAGER_BUNDLE "chrome://communicator/locale/downloadmanager/downloadmanager.properties"
#define INTERVAL 500
static const nsInt64 gInterval((PRUint32)(400 * PR_USEC_PER_MSEC));
static nsIRDFResource* gNC_DownloadsRoot = nsnull;
static nsIRDFResource* gNC_File = nsnull;
@ -900,10 +902,11 @@ nsDownload::nsDownload(nsDownloadManager* aManager,
mCancelable(aCancelable),
mDownloadState(NOTSTARTED),
mPercentComplete(0),
mCurrBytes(0),
mMaxBytes(0),
mStartTime(0),
mLastUpdate(-500)
mCurrBytes(LL_ZERO),
mMaxBytes(LL_ZERO),
mStartTime(LL_ZERO),
mSpeed(0),
mLastUpdate(PR_Now() - (PRUint32)gInterval)
{
}
@ -1027,10 +1030,9 @@ nsDownload::OnProgressChange64(nsIWebProgress *aWebProgress,
mRequest = aRequest; // used for pause/resume
// filter notifications since they come in so frequently
PRTime delta;
PRTime now = PR_Now();
LL_SUB(delta, now, mLastUpdate);
if (LL_CMP(delta, <, INTERVAL) && aMaxTotalProgress != -1 && aCurTotalProgress < aMaxTotalProgress)
nsInt64 delta = now - mLastUpdate;
if (delta < gInterval)
return NS_OK;
mLastUpdate = now;
@ -1044,6 +1046,21 @@ nsDownload::OnProgressChange64(nsIWebProgress *aWebProgress,
mDownloadManager->DownloadStarted(path);
}
// Calculate the speed using the elapsed delta time and bytes downloaded
// during that time for more accuracy.
double elapsedSecs = double(delta) / PR_USEC_PER_SEC;
if (elapsedSecs > 0) {
nsUint64 curTotalProgress = (PRUint64)aCurTotalProgress;
nsUint64 diffBytes = curTotalProgress - nsUint64(mCurrBytes);
double speed = double(diffBytes) / elapsedSecs;
if (LL_IS_ZERO(mCurrBytes))
mSpeed = speed;
else {
// Calculate 'smoothed average' of 10 readings.
mSpeed = mSpeed * 0.9 + speed * 0.1;
}
}
if (aMaxTotalProgress > 0)
mPercentComplete = aCurTotalProgress * 100 / aMaxTotalProgress;
else
@ -1196,8 +1213,9 @@ nsDownload::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
nsresult aStatus)
{
if (aStateFlags & STATE_START)
mStartTime = PR_Now();
// Record the start time only if it hasn't been set.
if (LL_IS_ZERO(mStartTime) && (aStateFlags & STATE_START))
SetStartTime(PR_Now());
// When we break the ref cycle with mPersist, we don't want to lose
// access to out member vars!
@ -1210,7 +1228,7 @@ nsDownload::OnStateChange(nsIWebProgress* aWebProgress,
if (mDownloadState == DOWNLOADING || mDownloadState == NOTSTARTED) {
mDownloadState = FINISHED;
// Set file size at the end of a tranfer (for unknown transfer amounts)
// Set file size at the end of a tranfer (for unknown transfer amounts)
if (mMaxBytes == -1)
mMaxBytes = mCurrBytes;
@ -1409,3 +1427,10 @@ nsDownload::GetTargetFile(nsILocalFile** aTargetFile)
rv = CallQueryInterface(file, aTargetFile);
return rv;
}
NS_IMETHODIMP
nsDownload::GetSpeed(double* aSpeed)
{
*aSpeed = mSpeed;
return NS_OK;
}

View File

@ -159,6 +159,7 @@ public:
}
void SetStartTime(PRInt64 aStartTime) {
mStartTime = aStartTime;
mLastUpdate = aStartTime;
}
private:
nsDownloadManager* mDownloadManager;
@ -179,6 +180,7 @@ private:
PRUint64 mMaxBytes;
PRTime mStartTime;
PRTime mLastUpdate;
double mSpeed;
};
#endif

View File

@ -43,7 +43,6 @@ function nsDownloadProgressListener() {
}
nsDownloadProgressListener.prototype = {
elapsed: 0,
rateChanges: 0,
rateChangeLimit: 0,
priorRate: "",
@ -93,14 +92,6 @@ nsDownloadProgressListener.prototype = {
// Update this time.
this.lastUpdate = now;
// Update download rate.
this.elapsed = now - (aDownload.startTime / 1000);
var rate; // aCurTotalProgress/sec
if ( this.elapsed )
rate = ( aCurTotalProgress * 1000 ) / this.elapsed;
else
rate = 0;
var aDownloadID = aDownload.targetFile.path
var elt = this.doc.getElementById(aDownloadID).firstChild.firstChild;
if (this.doc.getElementById("TimeElapsed").getAttribute("hidden") != "true") {
@ -144,6 +135,7 @@ nsDownloadProgressListener.prototype = {
status = replaceInsert( status, 2, "??" );
var rateMsg = getString( "rateMsg", this.doc );
var rate = aDownload.speed;
if ( rate )
{
// rate is bytes/sec