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
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.
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
));
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
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!!!
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