Chromecast m3u8 error - javascript

I have an Android sender that casts a M3U8 file like this:
metaData = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
metaData.putString(MediaMetadata.KEY_TITLE, "Test");
MediaInfo mediaInfo = new MediaInfo.Builder(m3u8URL)
.setContentType("application/x-mpegURL")
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setMetadata(metaData)
.build();
try {
player.load(client, mediaInfo, true)
}
Here is my onLoad function (for MediaManager) in my Custom Receiver:
var self = this;
var title = sampleplayer.getValue_(event.data, ['media', 'metadata', 'title']
);
var titleElement = self.element_.querySelector('.media-title');
sampleplayer.setInnerText_(titleElement, title);
var subtitle = sampleplayer.getValue_(event.data, ['media', 'metadata',
'subtitle']);
var subtitleElement = self.element_.querySelector('.media-subtitle');
sampleplayer.setInnerText_(subtitleElement, subtitle);
var artwork = sampleplayer.getValue_(event.data, ['media', 'metadata',
'images', 0, 'url']);
var artworkElement = self.element_.querySelector('.media-artwork');
sampleplayer.setBackgroundImage_(artworkElement, artwork);
var autoplay = sampleplayer.getValue_(event.data, ['autoplay']);
var contentId = sampleplayer.getValue_(event.data, ['media', 'contentId']);
var contentType = sampleplayer.getValue_(event.data, ['media', 'contentType']
);
self.setContentType_(contentType);
self.setState_(sampleplayer.State.LOADING, false);
if (self.mediaPlayer != null)
{
self.mediaPlayer.unload();
}
if (event.data['media'] && event.data['media']['contentId'])
{
self.mediaHost = new cast.player.api.Host(
{
'mediaElement': self.mediaElement_,
'url': contentId
}
);
self.mediaHost.onError = function (errCode)
{
if(self.mediaPlayer != null)
{
self.mediaPlayer.unload();
}
}
var initialTimeIndexSeconds = event.data['media']['currentTime'] || 0;
self.protocol = null;
self.parser = document.createElement('a');
self.parser.href = contentId;
self.ext = self.parser.pathname.split('.').pop();
if (self.ext === 'm3u8') {
self.protocol = cast.player.api.CreateHlsStreamingProtocol(self.mediaHost);
} else if (self.ext === 'mpd') {
self.protocol = cast.player.api.CreateDashStreamingProtocol(self.mediaHost);
} else if (self.ext === 'ism/') {
self.protocol = cast.player.api.CreateSmoothStreamingProtocol(self.mediaHost);
}
console.log('### Media Protocol Identified as ' + self.ext);
if (self.protocol === null) {
self.mediaManager_['onLoadOrig'](event); // Call on the original callback
} else {
self.mediaPlayer = new cast.player.api.Player(self.mediaHost);
self.mediaPlayer.load(self.protocol, initialTimeIndexSeconds);
}
}
self.mediaElement_.autoplay = autoplay || true;
I am not sure what is causing this. This is only happening to M3U8 files. I tested in mp4 and it seems to work. When I debug on Chrome, I tracked that it goes to playing state then the buffering state and gives this error in media_player.js 81. So I am not sure where this is coming from.
Uncaught InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable.
Any ideas as to whats causing this?

Related

Why does this barcode detection cause Chrome or the whole Android OS to crash?

I built a barcode scanning system using Chrome's built-in BarcodeDetector. I based the work on Paul Kinlan's QR code scanner which works fine on my phone, but when I run my own code on my phone, it often causes Chrome or the whole System UI to freeze. Sometimes it gets so bad that I need to restart the phone by holding down the power button.
I have tried debugging in the Chrome developer console, but when the phone freezes, so does the developer console.
When I comment out the actual QR code detection, I can leave the page open in Chrome for 10 minutes and it just keeps running. With QR code detection running, the phone will freeze anywhere from immediately to 3 minutes later.
I put the support files (js and HTML) in a Gist - I don't think they are the issue because everything works when the barcode scanning is commented out.
My first attempt:
// Inspired by/based on on https://github.com/PaulKinlan/qrcode/blob/production/app/scripts/main.mjs
import WebCamManager from './scan/WebCamManager.js';
(function () {
'use strict';
var QRCodeCamera = function (element) {
var root = document.getElementById(element);
var cameraRoot = root.querySelector('.CameraRealtime');
var cameraManager = new WebCamManager(cameraRoot);
var cameraVideo = root.querySelector('.Camera-video');
// Offscreen canvas is supposed to help with processing speed
var cameraCanvas = new OffscreenCanvas(1,1);
var context = cameraCanvas.getContext('2d');
const detector = new BarcodeDetector({
formats: ['qr_code'],
});
cameraManager.onframeready = async function (frameData) {
cameraCanvas.width = cameraVideo.videoWidth;
cameraCanvas.height = cameraVideo.videoHeight;
context.drawImage(frameData, 0, 0, cameraVideo.videoWidth, cameraVideo.videoHeight);
if (self.onframe) {
// Comment out the line below to stop processing QR codes
await self.onframe(cameraCanvas);
}
};
var processingFrame = false;
self.onframe = async function (cameraCanvas) {
// There is a frame in the camera, what should we do with it?
if (processingFrame == false) {
processingFrame = true;
let result = await detector.detect(cameraCanvas);
processingFrame = false;
if (result === undefined || result === null || result.length === 0) {
return
};
if ('vibrate' in navigator) {
navigator.vibrate([200]);
}
cameraManager.stop();
var currentURL = new URL(window.location.href);
var newURL;
if (result[0].rawValue
&& (newURL = new URL(result[0].rawValue))
&& newURL.hostname == currentURL.hostname
&& newURL.pathname.startsWith('/pickup/qr/')
) {
window.location.href = newURL;
} else {
alert('Unsupported QR Code: ' + result[0].rawValue);
}
cameraManager.start();
}
};
};
window.addEventListener('load', function () {
var camera = new QRCodeCamera('camera');
});
})();
I also tried splitting the QR detection to a worker (worker code in Gist), but I have the same issue:
const worker = new Worker('/js/scan-worker.js');
worker.addEventListener('message', async (e) => {
if (Array.isArray(e.data)) {
var result = e.data;
if (result === undefined || result === null || result.length === 0) {
processingFrame = false;
return
};
if ('vibrate' in navigator) {
navigator.vibrate([200]);
}
var currentURL = new URL(window.location.href);
var newURL;
if (result[0].rawValue
&& (newURL = new URL(result[0].rawValue))
&& newURL.hostname == currentURL.hostname
&& newURL.pathname.startsWith('/pickup/qr/')
) {
worker.terminate();
window.location.href = newURL;
} else {
alert('Unsupported QR Code: ' + result[0].rawValue);
}
} else {
var newError = document.createElement('div');
newError.classList.add('alert', 'alert-danger');
newError.innerHTML = e.data;
errorContainer.prepend(newError);
worker.terminate();
}
processingFrame = false;
});
cameraManager.onframeready = async function (frameData) {
if (processingFrame == false) {
cameraCanvas.width = cameraVideo.videoWidth;
cameraCanvas.height = cameraVideo.videoHeight;
context.drawImage(frameData, 0, 0, cameraVideo.videoWidth, cameraVideo.videoHeight);
if (self.onframe) {
await self.onframe(cameraCanvas, context);
}
}
};
self.onframe = async function (cameraCanvas, context) {
// There is a frame in the camera, what should we do with it?
if (processingFrame == false) {
processingFrame = true;
worker.postMessage(context.getImageData(0, 0, cameraCanvas.width, cameraCanvas.height));
}
};
Not sure if this would make a difference - all the JS code is run through Laravel Mix.

Download file after secure link has been returned

I hope this is simple. This is a react app where the user can click a button to download a file. When the button is clicked I make a server call to get a secure S3 bucket URL. I'm returning the URL and using window.open() to open the file. This works.
Instead of opening the file I would like to just download it. How do I do this?
handleDownloadResumeFile(event) {
event.preventDefault();
const url = event.target.value;
Meteor.call('getResumeUrl', url, function(error, result) {
if (error) {
console.log(error);
}
if (result && result.url) {
window.open(result.url);
}
});
}
Use saveAs(url, fileName') function from this, it works for me
https://github.com/eligrey/FileSaver.js
/* FileSaver.js
* A saveAs() FileSaver implementation.
* 1.3.8
* 2018-03-22 14:03:47
*
* By Eli Grey, https://eligrey.com
* License: MIT
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
*/
/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
/*! #source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */
var saveAs = saveAs || (function(view) {
"use strict";
// IE <10 is explicitly unsupported
if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
return;
}
var
doc = view.document
// only get URL when necessary in case Blob.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
, can_use_save_link = "download" in save_link
, click = function(node) {
var event = new MouseEvent("click");
node.dispatchEvent(event);
}
, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
, setImmediate = view.setImmediate || view.setTimeout
, throw_outside = function(ex) {
setImmediate(function() {
throw ex;
}, 0);
}
, force_saveable_type = "application/octet-stream"
// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
, arbitrary_revoke_timeout = 1000 * 40 // in ms
, revoke = function(file) {
var revoker = function() {
if (typeof file === "string") { // file is an object URL
get_URL().revokeObjectURL(file);
} else { // file is a File
file.remove();
}
};
setTimeout(revoker, arbitrary_revoke_timeout);
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types[i]];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}
}
}
}
, auto_bom = function(blob) {
// prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
}
return blob;
}
, FileSaver = function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}
// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, force = type === force_saveable_type
, object_url
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
// Safari doesn't allow downloading of blob urls
var reader = new FileReader();
reader.onloadend = function() {
var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
var popup = view.open(url, '_blank');
if(!popup) view.location.href = url;
url=undefined; // release reference before dispatching
filesaver.readyState = filesaver.DONE;
dispatch_all();
};
reader.readAsDataURL(blob);
filesaver.readyState = filesaver.INIT;
return;
}
// don't create more object URLs than needed
if (!object_url) {
object_url = get_URL().createObjectURL(blob);
}
if (force) {
view.location.href = object_url;
} else {
var opened = view.open(object_url, "_blank");
if (!opened) {
// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
view.location.href = object_url;
}
}
filesaver.readyState = filesaver.DONE;
dispatch_all();
revoke(object_url);
}
;
filesaver.readyState = filesaver.INIT;
if (can_use_save_link) {
object_url = get_URL().createObjectURL(blob);
setImmediate(function() {
save_link.href = object_url;
save_link.download = name;
click(save_link);
dispatch_all();
revoke(object_url);
filesaver.readyState = filesaver.DONE;
}, 0);
return;
}
fs_error();
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name, no_auto_bom) {
return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
}
;
// IE 10+ (native saveAs)
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
return function(blob, name, no_auto_bom) {
name = name || blob.name || "download";
if (!no_auto_bom) {
blob = auto_bom(blob);
}
return navigator.msSaveOrOpenBlob(blob, name);
};
}
// todo: detect chrome extensions & packaged apps
//save_link.target = "_blank";
FS_proto.abort = function(){};
FS_proto.readyState = FS_proto.INIT = 0;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;
FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror =
FS_proto.onwriteend =
null;
return saveAs;
}(
typeof self !== "undefined" && self
|| typeof window !== "undefined" && window
|| this
));

WebRTC file transfer and syntax querySelector

i never use WebRTC. so do not have any understand how their syntax look like.
i got a couple of syntax which i think it is not jquery. so anyone mind to tell me is it specific to webRTC related code.
document.querySelector('#stop-recording').onclick = function() {
this.disabled = true;
mediaRecorder.stop();
mediaRecorder.stream.stop();
document.querySelector('#pause-recording').disabled = true;
document.querySelector('#start-recording').disabled = false;
};
what is querySelector ?
i got the code from this url https://github.com/streamproc/MediaStreamRecorder/blob/master/demos/video-recorder.html
looking for bit info. thanks
You can refer following code:
var audio_context;
var recorder;
$(function () {
try {
//Audio Recording
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
window.URL = window.URL || window.webkitURL;
var recorderObject;
var VM_IDForAudio = "";
var audio_context = new AudioContext;
var localMediaStreamForAudio;
var audioStream;
//Audio-Video Recording (Firefox)
var videoFile = !!navigator.mozGetUserMedia ? 'video.gif' : 'video.webm';
var inner = document.querySelector('.inner');
var videoElement = document.getElementById('webcamVideo');
var VM_IDForAudioVideo = "";
var localMediaStreamForAudioVideo;
//Disable Live Webcam Button
$("#btnShowWebcam").prop("disabled", true);
} catch (e) {
//alert('No web audio support in this browser!');
console.log("No web audio support in this browser!");
}
//Audio Recording
$("[id$='btnAudioRecord']").click(function () {
//VM_IDForAudio = $("[id$='hdVMID']").val();
VM_IDForAudio = $("[id$='hdPRN']").val() + "_" + $("[id$='hdVMID']").val() + "_" +
patientDet.visitType + "_" + replateDateString(patientDet.visitDate);
$this = $(this);
$recorder = $this.parent();
if ($("[id$='btnAudioRecord']").val() == "Record Audio") {
if (VM_IDForAudio != "") {
$this.attr("value", "Stop Record");
navigator.getUserMedia({ audio: true }, function (stream) {
if (window.IsChrome) stream = new window.MediaStream(stream.getAudioTracks());
audioStream = stream;
recorder = window.RecordRTC(stream, {
type: 'audio'
});
recorder.startRecording();
}, function () { });
}
else {
//Select Patient
}
} else {
$this.attr("value", "Record Audio");
if (recorder)
recorder.stopRecording(function (url) {
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
base64data = reader.result;
PageMethods.SaveAudioRecording(base64data, VM_IDForAudio);
audioStream.stop();
}
});
}
});
//Audio-Video Recording
$("[id$='btnAudioVideoRecord']").click(function () {
//VM_IDForAudioVideo = $("[id$='hdVMID']").val();
VM_IDForAudioVideo = $("[id$='hdPRN']").val() + "_" + $("[id$='hdVMID']").val() + "_" +
patientDet.visitType + "_" + replateDateString(patientDet.visitDate);
$this = $(this);
if ($("[id$='btnAudioVideoRecord']").val() == "Record Aud/Vid") {
if (VM_IDForAudioVideo != "") {
$this.attr("value", "Stop Record");
captureUserMedia(function (stream) {
window.audioVideoRecorder = window.RecordRTC(stream, {
type: 'video', // don't forget this; otherwise you'll get video/webm instead of audio/ogg
canvas: {
width: 320,
height: 240
}
});
localMediaStreamForAudioVideo = stream;
$("#btnShowWebcam").prop("disabled", false);
window.audioVideoRecorder.startRecording();
});
}
else {
//Select Patient
}
} else {
$this.attr("value", "Record Aud/Vid");
$("#btnShowWebcam").prop("disabled", true);
window.audioVideoRecorder.stopRecording(function (url) {
convertStreams(audioVideoRecorder.getBlob(), videoFile, VM_IDForAudioVideo);
});
localMediaStreamForAudioVideo.stop();
}
});
and use RecordRTC javascript library.
for more go through this: http://recordrtc.org/RecordRTC.html,
for live demo: https://www.webrtc-experiment.com/RecordRTC/AudioVideo-on-Firefox.html
you should check webtorrent github repository, there is a detailed description about webRTC and how it is implemented. also check out the webtorrent official website

How to decode only part of the mp3 for use with WebAudio API?

In my web application, I have a requirement to play part of mp3 file. This is a local web app, so I don't care about downloads etc, everything is stored locally.
My use case is as follows:
determine file to play
determine start and stop of the sound
load the file [I use BufferLoader]
play
Quite simple.
Right now I just grab the mp3 file, decode it in memory for use with WebAudio API, and play it.
Unfortunately, because the mp3 files can get quite long [30minutes of audio for example] the decoded file in memory can take up to 900MB. That's a bit too much to handle.
Is there any option, where I could decode only part of the file? How could I detect where to start and how far to go?
I cannot anticipate the bitrate, it can be constant, but I would expect variable as well.
Here's an example of what I did:
http://tinyurl.com/z9vjy34
The code [I've tried to make it as compact as possible]:
var MediaPlayerAudioContext = window.AudioContext || window.webkitAudioContext;
var MediaPlayer = function () {
this.mediaPlayerAudioContext = new MediaPlayerAudioContext();
this.currentTextItem = 0;
this.playing = false;
this.active = false;
this.currentPage = null;
this.currentAudioTrack = 0;
};
MediaPlayer.prototype.setPageNumber = function (page_number) {
this.pageTotalNumber = page_number
};
MediaPlayer.prototype.generateAudioTracks = function () {
var audioTracks = [];
var currentBegin;
var currentEnd;
var currentPath;
audioTracks[0] = {
begin: 4.300,
end: 10.000,
path: "example.mp3"
};
this.currentPageAudioTracks = audioTracks;
};
MediaPlayer.prototype.show = function () {
this.mediaPlayerAudioContext = new MediaPlayerAudioContext();
};
MediaPlayer.prototype.hide = function () {
if (this.playing) {
this.stop();
}
this.mediaPlayerAudioContext = null;
this.active = false;
};
MediaPlayer.prototype.play = function () {
this.stopped = false;
console.trace();
this.playMediaPlayer();
};
MediaPlayer.prototype.playbackStarted = function() {
this.playing = true;
};
MediaPlayer.prototype.playMediaPlayer = function () {
var instance = this;
var audioTrack = this.currentPageAudioTracks[this.currentAudioTrack];
var newBufferPath = audioTrack.path;
if (this.mediaPlayerBufferPath && this.mediaPlayerBufferPath === newBufferPath) {
this.currentBufferSource = this.mediaPlayerAudioContext.createBufferSource();
this.currentBufferSource.buffer = this.mediaPlayerBuffer;
this.currentBufferSource.connect(this.mediaPlayerAudioContext.destination);
this.currentBufferSource.onended = function () {
instance.currentBufferSource.disconnect(0);
instance.audioTrackFinishedPlaying()
};
this.playing = true;
this.currentBufferSource.start(0, audioTrack.begin, audioTrack.end - audioTrack.begin);
this.currentAudioStartTimeInAudioContext = this.mediaPlayerAudioContext.currentTime;
this.currentAudioStartTimeOffset = audioTrack.begin;
this.currentTrackStartTime = this.mediaPlayerAudioContext.currentTime - (this.currentTrackResumeOffset || 0);
this.currentTrackResumeOffset = null;
}
else {
function finishedLoading(bufferList) {
instance.mediaPlayerBuffer = bufferList[0];
instance.playMediaPlayer();
}
if (this.currentBufferSource){
this.currentBufferSource.disconnect(0);
this.currentBufferSource.stop(0);
this.currentBufferSource = null;
}
this.mediaPlayerBuffer = null;
this.mediaPlayerBufferPath = newBufferPath;
this.bufferLoader = new BufferLoader(this.mediaPlayerAudioContext, [this.mediaPlayerBufferPath], finishedLoading);
this.bufferLoader.load();
}
};
MediaPlayer.prototype.stop = function () {
this.stopped = true;
if (this.currentBufferSource) {
this.currentBufferSource.onended = null;
this.currentBufferSource.disconnect(0);
this.currentBufferSource.stop(0);
this.currentBufferSource = null;
}
this.bufferLoader = null;
this.mediaPlayerBuffer = null;
this.mediaPlayerBufferPath = null;
this.currentTrackStartTime = null;
this.currentTrackResumeOffset = null;
this.currentAudioTrack = 0;
if (this.currentTextTimeout) {
clearTimeout(this.currentTextTimeout);
this.textHighlightFinished();
this.currentTextTimeout = null;
this.currentTextItem = null;
}
this.playing = false;
};
MediaPlayer.prototype.getNumberOfPages = function () {
return this.pageTotalNumber;
};
MediaPlayer.prototype.playbackFinished = function () {
this.currentAudioTrack = 0;
this.playing = false;
};
MediaPlayer.prototype.audioTrackFinishedPlaying = function () {
this.currentAudioTrack++;
if (this.currentAudioTrack >= this.currentPageAudioTracks.length) {
this.playbackFinished();
} else {
this.playMediaPlayer();
}
};
//
//
// Buffered Loader
//
// Class used to get the sound files
//
function BufferLoader(context, urlList, callback) {
this.context = context;
this.urlList = urlList;
this.onload = callback;
this.bufferList = [];
this.loadCount = 0;
}
// this allows us to handle media files with embedded artwork/id3 tags
function syncStream(node) { // should be done by api itself. and hopefully will.
var buf8 = new Uint8Array(node.buf);
buf8.indexOf = Array.prototype.indexOf;
var i = node.sync, b = buf8;
while (1) {
node.retry++;
i = b.indexOf(0xFF, i);
if (i == -1 || (b[i + 1] & 0xE0 == 0xE0 )) break;
i++;
}
if (i != -1) {
var tmp = node.buf.slice(i); //carefull there it returns copy
delete(node.buf);
node.buf = null;
node.buf = tmp;
node.sync = i;
return true;
}
return false;
}
BufferLoader.prototype.loadBuffer = function (url, index) {
// Load buffer asynchronously
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
var loader = this;
function decode(sound) {
loader.context.decodeAudioData(
sound.buf,
function (buffer) {
if (!buffer) {
alert('error decoding file data');
return
}
loader.bufferList[index] = buffer;
if (++loader.loadCount == loader.urlList.length)
loader.onload(loader.bufferList);
},
function (error) {
if (syncStream(sound)) {
decode(sound);
} else {
console.error('decodeAudioData error', error);
}
}
);
}
request.onload = function () {
// Asynchronously decode the audio file data in request.response
var sound = {};
sound.buf = request.response;
sound.sync = 0;
sound.retry = 0;
decode(sound);
};
request.onerror = function () {
alert('BufferLoader: XHR error');
};
request.send();
};
BufferLoader.prototype.load = function () {
for (var i = 0; i < this.urlList.length; ++i)
this.loadBuffer(this.urlList[i], i);
};
There is no way of streaming with decodeAudioData(), you need to use MediaElement with createMediaStreamSource and run your stuff then. decodeAudioData() cannot stream on a part.#zre00ne And mp3 will be decoded big!!! Verybig!!!

In regards to stopping a nsIRequest before completion and determining when a nsIRequest is complete (firefox extension)

Thanks to everyone in advance!
I am using a xul:browser and attaching a nsIWebProgressListener to it. I am trying to accomplish two things:
1. Determine when a request is complete (when a document is completely load with all css/js/imgs).
2. Stop a request from completing, specifically URLs with files that issue the download prompt.
In regards to my first issue, because the aStateFlags argument is set with (STATE_IS_* | STATE_STOP) in nsIWebProgressListener.onStateChange() and is called multiple times it is impossible to determine when a request is 100% complete and there are no more state changes. How is this accomplished?
What I am trying to accomplish specifically with the second issue that I am having is terminating a request when a certain "content-type" header value is found. For instance if a "application/pdf" content type is found, if the request is terminated then the download prompt (which from my understanding is not part of the nsIDownloadManager) is never displayed - this is the exact behavior I am trying to accomplish.
Here is the nsIWebProgressListener code I am currently working with:
//setup progress listener
var progressListener = {
stateIsRequest:false,
methodCalled:"",
WebProgress:"",
Request:"",
Flag:"",
Status:"",
Location:"",
CurSelfProgress:"",
MaxSelfProgress:"",
CurTotalProgress:"",
MaxTotalProgress:"",
Message:"",
State:"",
QueryInterface : function(aIID) {
if(aIID.equals(Components.interfaces.nsIWebProgressListener) || aIID.equals(Components.interfaces.nsISupportsWeakReference) || aIID.equals(Components.interfaces.nsISupports)){
return this;
}
else{
throw Components.results.NS_NOINTERFACE;
}
},
onStateChange : function(aWebProgress, aRequest, aFlag, aStatus) {
this.methodCalled = "onStateChange";
this.WebProgress = aWebProgress;
this.Request = aRequest;
this.Flag = aFlag;
this.Status = aStatus;
this.Location = "";
this.CurSelfProgress = "";
this.MaxSelfProgress = "";
this.CurTotalProgress = "";
this.MaxTotalProgress = "";
this.Message = "";
this.State = "";
this.CaptureHeaders(aRequest);
},
onLocationChange : function(aWebProgress, aRequest, aLocation) {
this.methodCalled = "onLocationChange";
this.WebProgress = aWebProgress;
this.Request = aRequest;
this.Flag = "";
this.Status = "";
this.Location = aLocation;
this.CurSelfProgress = "";
this.MaxSelfProgress = "";
this.CurTotalProgress = "";
this.MaxTotalProgress = "";
this.Message = "";
this.State = "";
this.CaptureHeaders(aRequest);
},
onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress){
this.methodCalled = "onProgressChange";
this.WebProgress = aWebProgress;
this.Request = aRequest;
this.Flag = "";
this.Status = "";
this.Location = "";
this.CurSelfProgress = aCurSelfProgress;
this.MaxSelfProgress = aMaxSelfProgress;
this.CurTotalProgress = aCurTotalProgress;
this.MaxTotalProgress = aMaxTotalProgress;
this.Message = "";
this.State = "";
this.CaptureHeaders(aRequest);
},
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage){
this.methodCalled = "onStatusChange";
this.WebProgress = aWebProgress;
this.Request = aRequest;
this.Flag = "";
this.Status = aStatus;
this.Location = "";
this.CurSelfProgress = "";
this.MaxSelfProgress = "";
this.CurTotalProgress = "";
this.MaxTotalProgress = "";
this.Message = aMessage;
this.State = "";
this.CaptureHeaders(aRequest);
},
onSecurityChange : function(aWebProgress, aRequest, aState){
this.methodCalled = "onSecurityChange";
this.WebProgress = aWebProgress;
this.Request = aRequest;
this.Flag = "";
this.Status = "";
this.Location = "";
this.CurSelfProgress = "";
this.MaxSelfProgress = "";
this.CurTotalProgress = "";
this.MaxTotalProgress = "";
this.Message = "";
this.State = aState;
this.CaptureHeaders(aRequest);
},
onLinkIconAvailable : function(a){},
CaptureHeaders : function(ThisRequest){
try{
//specify response headers to get
var ResponseHeaders = new Array();
ResponseHeaders.push("status");
ResponseHeaders.push("data");
ResponseHeaders.push("server");
ResponseHeaders.push("content-language");
ResponseHeaders.push("content-encoding");
ResponseHeaders.push("content-length");
ResponseHeaders.push("expires");
ResponseHeaders.push("cache-control");
ResponseHeaders.push("keep-alive");
ResponseHeaders.push("status");
ResponseHeaders.push("connection");
ResponseHeaders.push("content-type");
ResponseHeaders.push("set-cookie");
//specify request headers to get
var RequestHeaders = new Array();
RequestHeaders.push("host");
RequestHeaders.push("user-agent");
RequestHeaders.push("accept");
RequestHeaders.push("accept-language");
RequestHeaders.push("accept-encoding");
RequestHeaders.push("accept-charset");
RequestHeaders.push("keep-alive");
RequestHeaders.push("connection");
RequestHeaders.push("cookie");
RequestHeaders.push("cache-control");
//get browser
var CurrentBrowser = document.getElementById("current_browser");
//var CurrentURL = CurrentBrowser.current_url;
//var CurrentURL = ThisRequest.nsIHttpChannel.originalURI.spec;
if(ThisRequest.nsIHttpChannel != undefined){
var CurrentURL = ThisRequest.nsIHttpChannel.originalURI.spec;
//is this the first time headers were created for this browser?
if(CurrentBrowser.headers instanceof Object){
//have we collected headers for this url before
if(CurrentBrowser.headers[CurrentURL] instanceof Object){
//do nothing
}
else{
CurrentBrowser.headers[CurrentURL] = new Object();
CurrentBrowser.headers[CurrentURL].request = new Object();
CurrentBrowser.headers[CurrentURL].response = new Object()
}
}
else{
CurrentBrowser.headers = new Object();
CurrentBrowser.headers[CurrentURL] = new Object();
CurrentBrowser.headers[CurrentURL].request = new Object();
CurrentBrowser.headers[CurrentURL].response = new Object()
}
//load up headers
//add response headers
for(i = 0; i < ResponseHeaders.length; i++){
try{
if(ResponseHeaders[i] == "status"){
CurrentBrowser.headers[CurrentURL].response[ResponseHeaders[i]] = ThisRequest.nsIHttpChannel.responseStatus;
}
else{
CurrentBrowser.headers[CurrentURL].response[ResponseHeaders[i]] = ThisRequest.nsIHttpChannel.getResponseHeader(ResponseHeaders[i]);
}
}
catch(e){}
}
//add request headers
for(i = 0; i < RequestHeaders.length; i++){
try{
CurrentBrowser.headers[CurrentURL].request[RequestHeaders[i]] = ThisRequest.nsIHttpChannel.getRequestHeader(RequestHeaders[i]);
}
catch(e){}
}
//end load up headers
/*
Completed flag - STATE_IS_REQUEST:65552
Completed flag - STATE_IS_DOCUMENT:131088
Completed flag - STATE_IS_NETWORK:262160
Completed flag - STATE_IS_WINDOW:524304
//CurrentBrowser.webNavigation.nsIWebNavigation.stop(1);
//CurrentBrowser.webNavigation.nsIWebNavigation.stop(2);
//CurrentBrowser.webNavigation.nsIWebNavigation.stop(3);
//CurrentBrowser.stop();
//ThisRequest.cancel(2152398850);
//ThisRequest.cancel(Components.results.NS_OK);
//ThisRequest.suspend();
*/
//setup nonload rules
if(CurrentBrowser.headers[CurrentURL].response["content-type"] == "application/zip"){
MyExtension.WriteToDebug("Cancelled Request: "+ CurrentURL);
//try multiple ways to terminate the request
if(ThisRequest.nsIHttpChannel.loadGroup.activeCount > 0){
ThisRequest.nsIHttpChannel.loadGroup.removeRequest(ThisRequest, ThisRequest, Components.results.NS_BINDING_ABORTED);
}
CurrentBrowser.webNavigation.nsIWebNavigation.stop(1);
CurrentBrowser.webNavigation.nsIWebNavigation.stop(2);
CurrentBrowser.webNavigation.nsIWebNavigation.stop(3);
CurrentBrowser.stop();
ThisRequest.cancel(Components.results.NS_OK);
//end try multiple ways to terminate the request
//after request is terminated execute onNONload
CurrentBrowser.OnNonLoad(CurrentURL);
}
//setup nonload rules
else if(CurrentBrowser.headers[CurrentURL].response["content-type"] == "application/pdf"){
MyExtension.WriteToDebug("Cancelled Request: "+ CurrentURL);
//try multiple ways to terminate the request
if(ThisRequest.nsIHttpChannel.loadGroup.activeCount > 0){
ThisRequest.nsIHttpChannel.loadGroup.removeRequest(ThisRequest, ThisRequest, Components.results.NS_BINDING_ABORTED);
}
CurrentBrowser.webNavigation.nsIWebNavigation.stop(1);
CurrentBrowser.webNavigation.nsIWebNavigation.stop(2);
CurrentBrowser.webNavigation.nsIWebNavigation.stop(3);
CurrentBrowser.stop();
ThisRequest.cancel(Components.results.NS_OK);
//end try multiple ways to terminate the request
//after request is terminated execute onNONload
CurrentBrowser.OnNonLoad(CurrentURL);
}
//determine if finished loading
else if(this.Flag == 65552 || this.Flag == 131088 || this.Flag == 262160 || this.Flag == 524304){
MyExtension.WriteToDebug("Request Completed!");
MyExtension.WriteToDebug("pending:"+ ThisRequest.isPending() +"<br/>name:"+ ThisRequest.name +"<br/>URL:"+ CurrentURL +"<br/>content-type:"+ CurrentBrowser.headers[CurrentURL].response["content-type"]+"<br/>status:"+ CurrentBrowser.headers[CurrentURL].response["status"]);
if(this.Flag == (Components.interfaces.nsIWebProgressListener.STATE_IS_REQUEST | Components.interfaces.nsIWebProgressListener.STATE_STOP)){
MyExtension.WriteToDebug("Completed flag - STATE_IS_REQUEST:"+ (Components.interfaces.nsIWebProgressListener.STATE_IS_REQUEST | Components.interfaces.nsIWebProgressListener.STATE_STOP));
}
if(this.Flag == (Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT | Components.interfaces.nsIWebProgressListener.STATE_STOP)){
MyExtension.WriteToDebug("Completed flag - STATE_IS_DOCUMENT:"+ (Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT | Components.interfaces.nsIWebProgressListener.STATE_STOP));
}
if(this.Flag == (Components.interfaces.nsIWebProgressListener.STATE_IS_NETWORK | Components.interfaces.nsIWebProgressListener.STATE_STOP)){
MyExtension.WriteToDebug("Completed flag - STATE_IS_NETWORK:"+ (Components.interfaces.nsIWebProgressListener.STATE_IS_NETWORK | Components.interfaces.nsIWebProgressListener.STATE_STOP));
}
if(this.Flag == (Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW | Components.interfaces.nsIWebProgressListener.STATE_STOP)){
MyExtension.WriteToDebug("Completed flag - STATE_IS_WINDOW:"+ (Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW | Components.interfaces.nsIWebProgressListener.STATE_STOP));
}
//MyExtension.WriteToDebug("methodCalled:"+ this.methodCalled);
//MyExtension.WriteToDebug("WebProgress:"+ this.WebProgress);
//MyExtension.WriteToDebug("Request:"+ this.Request);
MyExtension.WriteToDebug("Flag:"+ this.Flag);
//MyExtension.WriteToDebug("Status:"+ this.Status);
//MyExtension.WriteToDebug("Location:"+ this.Location);
//MyExtension.WriteToDebug("CurSelfProgress:"+ this.CurSelfProgress);
//MyExtension.WriteToDebug("MaxSelfProgress:"+ this.MaxSelfProgress);
//MyExtension.WriteToDebug("CurTotalProgress:"+ this.CurTotalProgress);
//MyExtension.WriteToDebug("MaxTotalProgress:"+ this.MaxTotalProgress);
//MyExtension.WriteToDebug("Message:"+ this.Message);
//MyExtension.WriteToDebug("State:"+ this.State);
MyExtension.WriteToDebug("Load group count:"+ ThisRequest.nsIHttpChannel.loadGroup.activeCount);
MyExtension.WriteToDebug("WebProgress.isLoadingDocument:"+ this.WebProgress.isLoadingDocument);
MyExtension.WriteToDebug("WebProgress.DOMWindow:"+ this.WebProgress.DOMWindow);
//execute non load
//CurrentBrowser.OnNonLoad(CurrentURL);
}
}
}
catch(e){
MyExtension.WriteToDebug("Error Name:"+ e.name +" Message:"+ e.message);
}
}
};
//add progress listener
ThisBrowser.addProgressListener(progressListener);
//end setup progress listener
https://developer.mozilla.org/en/nsIWebProgressListener
I'm in a rather lazy mood at the moment, so I can't say that I've done much research...
Question 1:
Why not just hook into the contentDocument for the load event. If contentDocument isn't exposed early, then use the following code to see if it's available then:
Listener.prototype.onStateChange = function(webProgress, request, stateFlags, status) {
if(stateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP && stateFlags & Components.interfaces.nsIWebProgressListener.STATE_IS_NETWORK) {
// Should be ready now.... please?
}
};
Question 2:
I'm not sure what you're trying to do with this and how it relates to the xul:browser, but a really comprehensive way to do this is to hook into nsIObserverService for http-on-modify-request and cancel the request there.
For anyone with this question in the future ...
This is a decent example to start: https://developer.mozilla.org/en-US/docs/Code_snippets/Progress_Listeners#Example
An IMHO cleaner example that takes care of adding/removing ProgressListeners as tabs open and close (prevents memory leaks) is available here: http://mdn.beonex.com/en/XUL_School/Intercepting_Page_Loads
Only by using STATE_IS_DOCUMENT and STATE_STOP will you get a one result per URI request: for the final page loaded.
You will need to get aLocation if you want to test for a URL you need to cancel aLocation.spec and aRequest so that you can issue aRequest.cancel(NS_BINDING_ABORTED). You can just goof with the page to be loaded by ussuing aWebProgress.DOMWindow adding some XUL, and reloading.
HTH,
Eric

Categories

Resources