1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

use server to build initial stream url's

This commit is contained in:
Luke Pulverenti 2015-03-26 12:58:02 -04:00
parent c64474f046
commit 1fc390dc50
3 changed files with 375 additions and 295 deletions

View file

@ -428,14 +428,12 @@
if (!$(this).hasClass('selectedMediaPopupOption')) {
var maxWidth = parseInt(this.getAttribute('data-maxwidth'));
var bitrate = parseInt(this.getAttribute('data-bitrate'));
AppSettings.maxStreamingBitrate(bitrate);
self.changeStream(self.getCurrentTicks(), {
MaxWidth: maxWidth,
Bitrate: bitrate
});
}
@ -796,7 +794,12 @@
var currentSrc = self.getCurrentSrc(self.currentMediaElement).toLowerCase();
var isStatic = currentSrc.indexOf('static=true') != -1;
var options = getVideoQualityOptions(self.currentMediaSource.MediaStreams);
var videoStream = self.currentMediaSource.MediaStreams.filter(function (stream) {
return stream.Type == "Video";
})[0];
var videoWidth = videoStream ? videoStream.Width : null;
var options = self.getVideoQualityOptions(videoWidth);
if (isStatic) {
options[0].name = "Direct";
@ -819,7 +822,7 @@
cssClass += ' selectedMediaPopupOption';
}
var optionHtml = '<li><a data-maxwidth="' + option.maxWidth + '" data-bitrate="' + option.bitrate + '" class="' + cssClass + '" href="#">';
var optionHtml = '<li><a data-bitrate="' + option.bitrate + '" class="' + cssClass + '" href="#">';
optionHtml += '<p style="margin:0;">';
@ -845,85 +848,6 @@
return html;
}
function getVideoQualityOptions(mediaStreams) {
var videoStream = mediaStreams.filter(function (stream) {
return stream.Type == "Video";
})[0];
var bitrateSetting = AppSettings.maxStreamingBitrate();
var maxAllowedWidth = self.getMaxPlayableWidth();
var options = [];
// We have media info
if (videoStream && videoStream.Width) {
maxAllowedWidth = videoStream.Width;
}
// Some 1080- videos are reported as 1912?
if (maxAllowedWidth >= 1900) {
options.push({ name: '1080p - 30Mbps', maxWidth: 1920, bitrate: 30000000 });
options.push({ name: '1080p - 25Mbps', maxWidth: 1920, bitrate: 25000000 });
options.push({ name: '1080p - 20Mbps', maxWidth: 1920, bitrate: 20000000 });
options.push({ name: '1080p - 15Mbps', maxWidth: 1920, bitrate: 15000000 });
options.push({ name: '1080p - 10Mbps', maxWidth: 1920, bitrate: 10000000 });
options.push({ name: '1080p - 8Mbps', maxWidth: 1920, bitrate: 8000000 });
options.push({ name: '1080p - 6Mbps', maxWidth: 1920, bitrate: 6000000 });
options.push({ name: '1080p - 5Mbps', maxWidth: 1920, bitrate: 5000000 });
}
else if (maxAllowedWidth >= 1260) {
options.push({ name: '720p - 10Mbps', maxWidth: 1280, bitrate: 10000000 });
options.push({ name: '720p - 8Mbps', maxWidth: 1280, bitrate: 8000000 });
options.push({ name: '720p - 6Mbps', maxWidth: 1280, bitrate: 6000000 });
options.push({ name: '720p - 5Mbps', maxWidth: 1280, bitrate: 5000000 });
}
else if (maxAllowedWidth >= 460) {
options.push({ name: '480p - 4Mbps', maxWidth: 720, bitrate: 4000000 });
options.push({ name: '480p - 3Mbps', maxWidth: 720, bitrate: 3000000 });
options.push({ name: '480p - 2.5Mbps', maxWidth: 720, bitrate: 2500000 });
options.push({ name: '480p - 2Mbps', maxWidth: 720, bitrate: 2000000 });
options.push({ name: '480p - 1.5Mbps', maxWidth: 720, bitrate: 1500000 });
}
if (maxAllowedWidth >= 1260) {
options.push({ name: '720p - 4Mbps', maxWidth: 1280, bitrate: 4000000 });
options.push({ name: '720p - 3Mbps', maxWidth: 1280, bitrate: 3000000 });
options.push({ name: '720p - 2Mbps', maxWidth: 1280, bitrate: 2000000 });
// The extra 1 is because they're keyed off the bitrate value
options.push({ name: '720p - 1Mbps', maxWidth: 1280, bitrate: 1000001 });
}
options.push({ name: '480p - 1.0Mbps', maxWidth: 720, bitrate: 1000000 });
options.push({ name: '480p - 720kbps', maxWidth: 720, bitrate: 720000 });
options.push({ name: '480p - 420kbps', maxWidth: 720, bitrate: 420000 });
options.push({ name: '360p', maxWidth: 640, bitrate: 400000 });
options.push({ name: '240p', maxWidth: 426, bitrate: 320000 });
var i, length, option;
var selectedIndex = -1;
for (i = 0, length = options.length; i < length; i++) {
option = options[i];
if (selectedIndex == -1 && option.bitrate <= bitrateSetting) {
selectedIndex = i;
}
}
if (selectedIndex == -1) {
selectedIndex = options.length - 1;
}
options[selectedIndex].selected = true;
return options;
}
function bindEventsForPlayback() {
var hideElementsOnIdle = !$.browser.mobile;
@ -1007,100 +931,70 @@
}
};
self.playVideo = function (playbackInfo, item, mediaSource, startPosition) {
self.playVideo = function (deviceProfile, playbackInfo, item, mediaSource, startPosition) {
var videoUrl;
var contentType;
var mediaStreams = mediaSource.MediaStreams || [];
var subtitleStreams = mediaStreams.filter(function (s) {
return s.Type == 'Subtitle';
});
if (mediaSource.enableDirectPlay) {
videoUrl = mediaSource.Path;
self.startTimeTicksOffset = 0;
contentType = 'video/' + mediaSource.Container;
} else {
var selectedSubtitleStream = subtitleStreams.filter(function (s) {
return s.Index == mediaSource.DefaultSubtitleStreamIndex;
})[0];
var baseParams = {
var transcodingParams = {
audioChannels: 2,
StartTimeTicks: startPosition,
AudioStreamIndex: mediaSource.DefaultAudioStreamIndex,
deviceId: ApiClient.deviceId(),
Static: false,
mediaSourceId: mediaSource.Id,
api_key: ApiClient.accessToken(),
StreamId: playbackInfo.StreamId
StreamId: playbackInfo.StreamId,
ClientTime: new Date().getTime()
};
if (selectedSubtitleStream && (!self.supportsSubtitleStreamExternally(selectedSubtitleStream) || !self.supportsTextTracks())) {
baseParams.SubtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex;
transcodingParams.SubtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex;
}
var mp4Quality = getVideoQualityOptions(mediaStreams).filter(function (opt) {
return opt.selected;
})[0];
mp4Quality = $.extend(mp4Quality, self.getFinalVideoParams(mediaSource, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4'));
var webmQuality = getVideoQualityOptions(mediaStreams).filter(function (opt) {
return opt.selected;
})[0];
webmQuality = $.extend(webmQuality, self.getFinalVideoParams(mediaSource, webmQuality.maxWidth, webmQuality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.webm'));
var m3U8Quality = getVideoQualityOptions(mediaStreams).filter(function (opt) {
return opt.selected;
})[0];
m3U8Quality = $.extend(m3U8Quality, self.getFinalVideoParams(mediaSource, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4'));
var isStatic = mp4Quality.isStatic;
self.startTimeTicksOffset = isStatic ? 0 : startPosition || 0;
self.startTimeTicksOffset = mediaSource.SupportsDirectStream ? 0 : startPosition || 0;
var startPositionInSeekParam = startPosition ? (startPosition / 10000000) : 0;
var seekParam = startPositionInSeekParam ? '#t=' + startPositionInSeekParam : '';
var mp4VideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.mp4', $.extend({}, baseParams, {
Static: isStatic,
maxWidth: mp4Quality.maxWidth,
videoBitrate: mp4Quality.videoBitrate,
audioBitrate: mp4Quality.audioBitrate,
VideoCodec: mp4Quality.videoCodec,
AudioCodec: mp4Quality.audioCodec,
profile: 'high',
//EnableAutoStreamCopy: false,
level: '41'
}));
if (mediaSource.SupportsDirectStream) {
if (isStatic && mediaSource.Protocol == 'Http' && !mediaSource.RequiredHttpHeaders.length) {
mp4VideoUrl = mediaSource.Path;
}
videoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.' + mediaSource.Container, {
Static: true,
mediaSourceId: mediaSource.Id,
api_key: ApiClient.accessToken()
});
videoUrl += seekParam;
contentType = 'video/' + mediaSource.Container;
if (isStatic) {
mp4VideoUrl += seekParam;
} else {
mp4VideoUrl += "&StreamId=" + new Date().getTime();
videoUrl = ApiClient.getUrl(mediaSource.TranscodingUrl);
if (mediaSource.TranscodingSubProtocol == 'hls') {
videoUrl += seekParam;
contentType = 'application/x-mpegURL';
}
else {
var webmVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.webm', $.extend({}, baseParams, {
VideoCodec: 'vpx',
AudioCodec: 'Vorbis',
maxWidth: webmQuality.maxWidth,
videoBitrate: webmQuality.videoBitrate,
audioBitrate: webmQuality.audioBitrate,
EnableAutoStreamCopy: false,
StreamId: new Date().getTime()
}));
var hlsVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/master.m3u8', $.extend({}, baseParams, {
maxWidth: m3U8Quality.maxWidth,
videoBitrate: m3U8Quality.videoBitrate,
audioBitrate: m3U8Quality.audioBitrate,
VideoCodec: m3U8Quality.videoCodec,
AudioCodec: m3U8Quality.audioCodec,
profile: 'high',
level: '41',
StartTimeTicks: 0,
StreamId: new Date().getTime()
})) + seekParam;
contentType = 'video/' + mediaSource.TranscodingContainer;
}
}
}
//======================================================================================>
@ -1118,27 +1012,7 @@
html += '<video class="itemVideo" id="itemVideo" preload="metadata" autoplay>';
}
if (!isStatic) {
// HLS must be at the top for safari
html += '<source type="application/x-mpegURL" src="' + hlsVideoUrl + '" />';
}
var mp4BeforeWebm = self.getVideoTranscodingExtension() != '.webm';
if (mp4BeforeWebm) {
html += '<source type="video/mp4" src="' + mp4VideoUrl + '" />';
}
// Have to put webm ahead of mp4 because it will play in fast forward in chrome
// And firefox doesn't like fragmented mp4
if (!isStatic) {
html += '<source type="video/webm" src="' + webmVideoUrl + '" />';
}
if (!mp4BeforeWebm) {
html += '<source type="video/mp4" src="' + mp4VideoUrl + '" />';
}
html += '<source type="' + contentType + '" src="' + videoUrl + '" />';
if (self.supportsTextTracks()) {
var textStreams = subtitleStreams.filter(function (s) {

View file

@ -37,6 +37,245 @@
return targets;
};
var supportsAac = document.createElement('audio').canPlayType('audio/aac').replace(/no/, '');
self.getVideoQualityOptions = function (videoWidth) {
var bitrateSetting = AppSettings.maxStreamingBitrate();
var maxAllowedWidth = videoWidth || 4096;
var options = [];
// Some 1080- videos are reported as 1912?
if (maxAllowedWidth >= 1900) {
options.push({ name: '1080p - 30Mbps', maxWidth: 1920, bitrate: 30000000 });
options.push({ name: '1080p - 25Mbps', maxWidth: 1920, bitrate: 25000000 });
options.push({ name: '1080p - 20Mbps', maxWidth: 1920, bitrate: 20000000 });
options.push({ name: '1080p - 15Mbps', maxWidth: 1920, bitrate: 15000000 });
options.push({ name: '1080p - 10Mbps', maxWidth: 1920, bitrate: 10000000 });
options.push({ name: '1080p - 8Mbps', maxWidth: 1920, bitrate: 8000000 });
options.push({ name: '1080p - 6Mbps', maxWidth: 1920, bitrate: 6000000 });
options.push({ name: '1080p - 5Mbps', maxWidth: 1920, bitrate: 5000000 });
} else if (maxAllowedWidth >= 1260) {
options.push({ name: '720p - 10Mbps', maxWidth: 1280, bitrate: 10000000 });
options.push({ name: '720p - 8Mbps', maxWidth: 1280, bitrate: 8000000 });
options.push({ name: '720p - 6Mbps', maxWidth: 1280, bitrate: 6000000 });
options.push({ name: '720p - 5Mbps', maxWidth: 1280, bitrate: 5000000 });
} else if (maxAllowedWidth >= 460) {
options.push({ name: '480p - 4Mbps', maxWidth: 720, bitrate: 4000000 });
options.push({ name: '480p - 3Mbps', maxWidth: 720, bitrate: 3000000 });
options.push({ name: '480p - 2.5Mbps', maxWidth: 720, bitrate: 2500000 });
options.push({ name: '480p - 2Mbps', maxWidth: 720, bitrate: 2000000 });
options.push({ name: '480p - 1.5Mbps', maxWidth: 720, bitrate: 1500000 });
}
if (maxAllowedWidth >= 1260) {
options.push({ name: '720p - 4Mbps', maxWidth: 1280, bitrate: 4000000 });
options.push({ name: '720p - 3Mbps', maxWidth: 1280, bitrate: 3000000 });
options.push({ name: '720p - 2Mbps', maxWidth: 1280, bitrate: 2000000 });
// The extra 1 is because they're keyed off the bitrate value
options.push({ name: '720p - 1Mbps', maxWidth: 1280, bitrate: 1000001 });
}
options.push({ name: '480p - 1.0Mbps', maxWidth: 720, bitrate: 1000000 });
options.push({ name: '480p - 720kbps', maxWidth: 720, bitrate: 720000 });
options.push({ name: '480p - 420kbps', maxWidth: 720, bitrate: 420000 });
options.push({ name: '360p', maxWidth: 640, bitrate: 400000 });
options.push({ name: '240p', maxWidth: 426, bitrate: 320000 });
var i, length, option;
var selectedIndex = -1;
for (i = 0, length = options.length; i < length; i++) {
option = options[i];
if (selectedIndex == -1 && option.bitrate <= bitrateSetting) {
selectedIndex = i;
}
}
if (selectedIndex == -1) {
selectedIndex = options.length - 1;
}
options[selectedIndex].selected = true;
return options;
};
self.getDeviceProfile = function () {
var qualityOption = self.getVideoQualityOptions().filter(function (q) {
return q.selected;
})[0];
var bitrateSetting = AppSettings.maxStreamingBitrate();
var profile = {};
profile.MaxStreamingBitrate = bitrateSetting;
profile.MaxStaticBitrate = 40000000;
profile.MusicStreamingTranscodingBitrate = 128000;
profile.DirectPlayProfiles = [];
profile.DirectPlayProfiles.push({
Container: 'mp4',
Type: 'Video',
VideoCodec: 'h264',
AudioCodec: 'aac,mp3'
});
if ($.browser.chrome) {
profile.DirectPlayProfiles.push({
Container: 'mkv,m4v',
Type: 'Video',
VideoCodec: 'h264',
AudioCodec: 'aac,mp3'
});
profile.DirectPlayProfiles.push({
Container: 'flv',
Type: 'Video'
});
}
profile.DirectPlayProfiles.push({
Container: 'mp3',
Type: 'Audio'
});
if (supportsAac) {
profile.DirectPlayProfiles.push({
Container: 'aac',
Type: 'Audio'
});
}
profile.TranscodingProfiles = [];
profile.TranscodingProfiles.push({
Container: 'mp3',
Type: 'Audio',
AudioCodec: 'mp3',
Context: 'Streaming',
Protocol: 'http'
});
if (self.canPlayHls()) {
profile.TranscodingProfiles.push({
Container: 'ts',
Type: 'Video',
AudioCodec: 'aac',
VideoCodec: 'h264',
Context: 'Streaming',
Protocol: 'hls'
});
}
if (self.canPlayWebm()) {
profile.TranscodingProfiles.push({
Container: 'webm',
Type: 'Video',
AudioCodec: 'vorbis',
VideoCodec: 'vpx',
Context: 'Streaming',
Protocol: 'http'
});
}
profile.TranscodingProfiles.push({
Container: 'mp4',
Type: 'Video',
AudioCodec: 'aac',
VideoCodec: 'h264',
Context: 'Streaming',
Protocol: 'http'
});
profile.ContainerProfiles = [];
var audioConditions = [];
if ($.browser.msie) {
audioConditions.push({
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '2'
});
}
profile.CodecProfiles = [];
profile.CodecProfiles.push({
Type: 'Audio',
Conditions: audioConditions
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Conditions: audioConditions
});
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: [
{
Condition: 'Equals',
Property: 'IsCabac',
Value: 'true'
},
{
Condition: 'NotEquals',
Property: 'IsAnamorphic',
Value: 'true'
},
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: 'high|main|baseline|constrained baseline'
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: '41'
},
{
Condition: 'LessThanEqual',
Property: 'Width',
Value: qualityOption.maxWidth
}]
});
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'vpx',
Conditions: [
{
Condition: 'NotEquals',
Property: 'IsAnamorphic',
Value: 'true'
},
{
Condition: 'LessThanEqual',
Property: 'Width',
Value: qualityOption.maxWidth
}]
});
// Subtitle profiles
// External vtt or burn in
profile.SubtitleProfiles = [];
if (self.supportsTextTracks()) {
profile.SubtitleProfiles.push({
Format: 'vtt',
Method: 'External'
});
}
return profile;
};
self.updateCanClientSeek = function (elem) {
var duration = elem.duration;
@ -89,17 +328,27 @@
return currentSrc.substring(currentSrc.lastIndexOf('.'));
};
self.getVideoTranscodingExtension = function (currentSrc) {
if (currentSrc) {
return self.getCurrentMediaExtension(currentSrc);
}
self.canPlayHls = function () {
var media = testableVideoElement;
// safari
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
return true;
}
return false;
};
self.getVideoTranscodingExtension = function (currentSrc) {
if (currentSrc) {
return self.getCurrentMediaExtension(currentSrc);
}
// safari
if (self.canPlayHls()) {
return '.m3u8';
}
@ -151,7 +400,6 @@
currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', (params.SubtitleStreamIndex == -1 ? '' : params.SubtitleStreamIndex));
}
var maxWidth = params.MaxWidth || getParameterByName('MaxWidth', currentSrc);
var audioStreamIndex = params.AudioStreamIndex == null ? getParameterByName('AudioStreamIndex', currentSrc) : params.AudioStreamIndex;
if (typeof (audioStreamIndex) == 'string') {
audioStreamIndex = parseInt(audioStreamIndex);
@ -161,9 +409,8 @@
var audioBitrate = parseInt(getParameterByName('AudioBitrate', currentSrc) || '0');
var bitrate = params.Bitrate || (videoBitrate + audioBitrate);
var finalParams = self.getFinalVideoParams(self.currentMediaSource, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
var finalParams = self.getFinalVideoParams(self.currentMediaSource, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
currentSrc = replaceQueryString(currentSrc, 'MaxWidth', finalParams.maxWidth);
currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate);
currentSrc = replaceQueryString(currentSrc, 'VideoCodec', finalParams.videoCodec);
@ -274,7 +521,7 @@
return supportsTextTracks;
};
self.getVideoDirectPlayMethod = function (mediaSource, videoStream, audioStream, subtitleStream, maxWidth, bitrate) {
self.getVideoDirectPlayMethod = function (mediaSource, videoStream, audioStream, subtitleStream, bitrate) {
if (!mediaSource) {
throw new Error('Null mediaSource');
@ -322,11 +569,6 @@
return null;
}
if (videoStream.Width > maxWidth) {
console.log('Transcoding because resolution is too high');
return null;
}
if (videoStream && videoStream.IsAnamorphic) {
console.log('Transcoding because video is anamorphic');
return null;
@ -372,7 +614,7 @@
return null;
};
self.getFinalVideoParams = function (mediaSource, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension) {
self.getFinalVideoParams = function (mediaSource, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension) {
var mediaStreams = mediaSource.MediaStreams;
@ -388,7 +630,7 @@
return stream.Index === subtitleStreamIndex && stream.Type == 'Subtitle';
})[0];
var directPlayMethod = self.getVideoDirectPlayMethod(mediaSource, videoStream, audioStream, subtitleStream, maxWidth, bitrate);
var directPlayMethod = self.getVideoDirectPlayMethod(mediaSource, videoStream, audioStream, subtitleStream, bitrate);
var audioBitrate = bitrate >= 700000 ? 192000 : 64000;
@ -396,7 +638,6 @@
var params = {
isStatic: directPlayMethod != null,
maxWidth: maxWidth,
audioCodec: transcodingExtension == '.webm' ? 'vorbis' : 'aac',
videoCodec: transcodingExtension == '.webm' ? 'vpx' : 'h264',
audioBitrate: audioBitrate,
@ -504,11 +745,6 @@
};
self.getMaxPlayableWidth = function () {
return Math.max(screen.height, screen.width);
};
self.playWithIntros = function (items, options, user) {
var firstItem = items[0];
@ -534,38 +770,18 @@
function getOptimalMediaSource(mediaType, versions) {
var optimalVersion;
var bitrateSetting = AppSettings.maxStreamingBitrate();
var optimalVersion = versions.filter(function (v) {
if (mediaType == 'Video') {
v.enableDirectPlay = v.SupportsDirectPlay && v.Protocol == 'Http' && !v.RequiredHttpHeaders.length;
var maxAllowedWidth = self.getMaxPlayableWidth();
return v.enableDirectPlay;
})[0];
if (!optimalVersion) {
optimalVersion = versions.filter(function (v) {
var videoStream = v.MediaStreams.filter(function (s) {
return s.Type == 'Video';
})[0];
var audioStream = v.MediaStreams.filter(function (s) {
return s.Type == 'Audio';
})[0];
var directPlayMethod = self.getVideoDirectPlayMethod(v, videoStream, audioStream, null, maxAllowedWidth, bitrateSetting);
if (directPlayMethod == 'DirectPlay') {
return true;
}
return v.SupportsDirectStream && directPlayMethod == 'DirectStream';
})[0];
} else {
optimalVersion = versions.filter(function (v) {
return v.SupportsDirectStream && canPlayAudioMediaSourceDirect(v);
return v.SupportsDirectStream;
})[0];
}
@ -595,11 +811,22 @@
}
var mediaSource;
var deviceProfile = self.getDeviceProfile();
ApiClient.getJSON(ApiClient.getUrl('Items/' + item.Id + '/PlaybackInfo', {
ApiClient.ajax({
url: ApiClient.getUrl('Items/' + item.Id + '/PlaybackInfo', {
userId: Dashboard.getCurrentUserId()
})).done(function (result) {
}),
type: 'POST',
data: JSON.stringify({
DeviceProfile: deviceProfile
}),
contentType: "application/json",
dataType: "json"
}).done(function (result) {
if (validatePlaybackInfoResult(result)) {
@ -612,7 +839,7 @@
if (item.MediaType === "Video") {
self.currentMediaElement = self.playVideo(result, item, self.currentMediaSource, startPosition);
self.currentMediaElement = self.playVideo(deviceProfile, result, item, self.currentMediaSource, startPosition);
self.currentDurationTicks = self.currentMediaSource.RunTimeTicks;
self.updateNowPlayingInfo(item);
@ -1380,63 +1607,36 @@
return $('.mediaPlayerAudio');
}
function canPlayAudioMediaSourceDirect(mediaSource) {
var sourceContainer = (mediaSource.Container || '').toLowerCase();
if (sourceContainer == 'mp3' ||
(sourceContainer == 'aac' && supportsAac)) {
for (var i = 0, length = mediaSource.MediaStreams.length; i < length; i++) {
var stream = mediaSource.MediaStreams[i];
if (stream.Type == "Audio") {
// Stream statically when possible
if (stream.BitRate <= 320000) {
return true;
}
break;
}
}
}
return false;
}
var supportsAac = document.createElement('audio').canPlayType('audio/aac').replace(/no/, '');
function playAudio(playbackInfo, item, mediaSource, startPositionTicks) {
var audioUrl;
if (mediaSource.enableDirectPlay) {
audioUrl = mediaSource.Path;
self.startTimeTicksOffset = 0;
} else {
var isDirectStream = mediaSource.SupportsDirectStream;
startPositionTicks = startPositionTicks || 0;
var baseParams = {
audioChannels: 2,
audioBitrate: 128000,
StartTimeTicks: startPositionTicks,
if (isDirectStream) {
var outputContainer = (mediaSource.Container || '').toLowerCase();
var seekParam = startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : '';
audioUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.' + outputContainer, {
mediaSourceId: mediaSource.Id,
deviceId: ApiClient.deviceId(),
api_key: ApiClient.accessToken(),
StreamId: playbackInfo.StreamId
};
var sourceContainer = (mediaSource.Container || '').toLowerCase();
var isStatic = canPlayAudioMediaSourceDirect(mediaSource);
var outputContainer = isStatic ? sourceContainer : 'mp3';
var audioUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.' + outputContainer, $.extend({}, baseParams, {
audioCodec: outputContainer
}));
if (isStatic) {
var seekParam = startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : '';
api_key: ApiClient.accessToken()
});
audioUrl += "&static=true" + seekParam;
} else {
audioUrl += "&ClientTime=" + new Date().getTime();
audioUrl = ApiClient.getUrl(mediaSource.TranscodingUrl);
}
self.startTimeTicksOffset = isStatic ? 0 : startPositionTicks;
self.startTimeTicksOffset = isDirectStream ? 0 : startPositionTicks;
}
var initialVolume = self.getSavedVolume();

View file

@ -306,7 +306,13 @@
throw new Error("Url name cannot be empty");
}
var url = serverAddress + "/" + name;
var url = serverAddress;
if (name.charAt(0) != '/') {
url += '/';
}
url += name;
if (params) {
url += "?" + AjaxApi.param(params);