Merge branch 'master' of github.com:abdallahsoliman/moonlight-chrome

This commit is contained in:
Abdallah Soliman 2016-07-12 19:36:31 -05:00
commit e269b73bd3
6 changed files with 103 additions and 84 deletions

View File

@ -23,6 +23,11 @@ static int ConvertPPButtonToLiButton(PP_InputEvent_MouseButton ppButton) {
void MoonlightInstance::DidLockMouse(int32_t result) { void MoonlightInstance::DidLockMouse(int32_t result) {
m_MouseLocked = (result == PP_OK); m_MouseLocked = (result == PP_OK);
if (m_MouseLocked) {
// Request an IDR frame to dump the frame queue that may have
// built up from the GL pipeline being stalled.
g_Instance->m_RequestIdrFrame = true;
}
} }
void MoonlightInstance::MouseLockLost() { void MoonlightInstance::MouseLockLost() {

View File

@ -53,6 +53,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
pp::MouseLock(this), pp::MouseLock(this),
m_HasNextPicture(false), m_HasNextPicture(false),
m_IsPainting(false), m_IsPainting(false),
m_RequestIdrFrame(false),
m_OpusDecoder(NULL), m_OpusDecoder(NULL),
m_CallbackFactory(this), m_CallbackFactory(this),
m_MouseLocked(false), m_MouseLocked(false),
@ -122,6 +123,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
void PictureReady(int32_t result, PP_VideoPicture picture); void PictureReady(int32_t result, PP_VideoPicture picture);
void PaintPicture(void); void PaintPicture(void);
void InitializeRenderingSurface(int width, int height); void InitializeRenderingSurface(int width, int height);
void DidChangeFocus(bool got_focus);
static void VidDecSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags); static void VidDecSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags);
static void VidDecCleanup(void); static void VidDecCleanup(void);
@ -159,6 +161,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
bool m_HasNextPicture; bool m_HasNextPicture;
PP_VideoPicture m_CurrentPicture; PP_VideoPicture m_CurrentPicture;
bool m_IsPainting; bool m_IsPainting;
bool m_RequestIdrFrame;
OpusMSDecoder* m_OpusDecoder; OpusMSDecoder* m_OpusDecoder;
pp::Audio m_AudioPlayer; pp::Audio m_AudioPlayer;

View File

@ -3,6 +3,7 @@ var hosts = [];
var pairingCert; var pairingCert;
var myUniqueid; var myUniqueid;
var api; var api;
var relaunchSourceEvent;
// Called by the common.js module. // Called by the common.js module.
function attachListeners() { function attachListeners() {
@ -104,49 +105,44 @@ function pairTo(host, onSuccess, onFailure) {
snackbarLog('ERROR: cert has not been generated yet. Is NaCl initialized?'); snackbarLog('ERROR: cert has not been generated yet. Is NaCl initialized?');
console.log("User wants to pair, and we still have no cert. Problem = very yes."); console.log("User wants to pair, and we still have no cert. Problem = very yes.");
onFailure(); onFailure();
return;
} }
if(!api) { api = new NvHTTP(host, myUniqueid);
api = new NvHTTP(host, myUniqueid); api.refreshServerInfo().then(function (ret) {
} if (api.paired) {
onSuccess();
if(api.paired) { return;
onSuccess();
}
var randomNumber = String("0000" + (Math.random()*10000|0)).slice(-4);
var pairingDialog = document.querySelector('#pairingDialog');
$('#pairingDialogText').html('Please enter the number ' + randomNumber + ' on the GFE dialog on the computer. This dialog will be dismissed once complete');
pairingDialog.showModal();
console.log('sending pairing request to ' + host + ' with random number ' + randomNumber);
api.pair(randomNumber).then(function (paired) {
if (!paired) {
if (api.currentGame != 0) {
$('#pairingDialogText').html('Error: ' + host + ' is in app. Cannot pair until the app is stopped.');
} else {
$('#pairingDialogText').html('Error: failed to pair with ' + host + '. failure reason unknown.');
}
onFailure();
} }
snackbarLog('Pairing successful'); var randomNumber = String("0000" + (Math.random()*10000|0)).slice(-4);
pairingDialog.close(); var pairingDialog = document.querySelector('#pairingDialog');
$('#pairingDialogText').html('Please enter the number ' + randomNumber + ' on the GFE dialog on the computer. This dialog will be dismissed once complete');
pairingDialog.showModal();
console.log('sending pairing request to ' + host + ' with random number ' + randomNumber);
var cell = document.createElement('div'); api.pair(randomNumber).then(function (paired) {
cell.className += 'mdl-cell mdl-cell--3-col'; if (!paired) {
cell.id = 'hostgrid-' + hosts[i]; if (api.currentGame != 0) {
cell.innerHTML = hosts[i]; $('#pairingDialogText').html('Error: ' + host + ' is in app. Cannot pair until the app is stopped.');
$('#host-grid').append(cell); } else {
cell.onclick = hostChosen; $('#pairingDialogText').html('Error: failed to pair with ' + host + '. failure reason unknown.');
}
onFailure();
return;
}
saveHosts(); snackbarLog('Pairing successful');
onSuccess(); pairingDialog.close();
onSuccess();
}, function (failedPairing) { }, function (failedPairing) {
snackbarLog('Failed pairing to: ' + host); snackbarLog('Failed pairing to: ' + host);
console.log('pairing failed, and returned ' + failedPairing); console.log('pairing failed, and returned ' + failedPairing);
onFailure(); onFailure();
});
}, function (failedRefreshInfo) {
snackbarLog('Failed to connect to ' + host + '! Are you sure the host is on?');
console.log('Returned error was: ' + failedRefreshInfo);
}); });
} }
@ -157,24 +153,13 @@ function hostChosen(sourceEvent) {
host = sourceEvent.srcElement.innerText; host = sourceEvent.srcElement.innerText;
} }
api = new NvHTTP(host, myUniqueid);
if(!api || api.address != host) {
api = new NvHTTP(host, myUniqueid);
}
api.refreshServerInfo().then(function (ret) { api.refreshServerInfo().then(function (ret) {
if(!api.paired) { if(!api.paired) {
pairTo(host); pairTo(host, function(){ showApps(); }, function(){});
} else {
showApps();
} }
if(hosts.indexOf(host) < 0) { // we don't have this host in our list. add it, and save it.
var cell = document.createElement('div');
cell.className += 'mdl-cell mdl-cell--3-col';
cell.id = 'hostgrid-' + hosts[i];
cell.innerHTML = hosts[i];
$('#host-grid').append(cell);
cell.onclick = hostChosen;
}
showApps();
}, function (failedRefreshInfo) { }, function (failedRefreshInfo) {
snackbarLog('Failed to connect to ' + host + '! Are you sure the host is on?'); snackbarLog('Failed to connect to ' + host + '! Are you sure the host is on?');
console.log('Returned error was: ' + failedRefreshInfo); console.log('Returned error was: ' + failedRefreshInfo);
@ -192,14 +177,30 @@ function cancelAddHost() {
document.querySelector('#addHostDialog').close(); document.querySelector('#addHostDialog').close();
} }
function addHostToGrid(host) {
if(hosts.indexOf(host) < 0) { // we don't have this host in our list. add it, and save it.
var cell = document.createElement('div');
cell.className += 'mdl-cell mdl-cell--3-col';
cell.id = 'hostgrid-' + host;
cell.innerHTML = host;
$('#host-grid').append(cell);
cell.onclick = hostChosen;
hosts.push(host);
saveHosts();
}
}
function continueAddHost() { function continueAddHost() {
var inputHost = $('#dialogInputHost').val(); var inputHost = $('#dialogInputHost').val();
pairTo(inputHost, pairTo(inputHost,
function() { document.querySelector('#addHostDialog').close() }, function() {
function() {snackbarLog('pairing to ' + inputHost + ' failed!');} addHostToGrid(inputHost);
); document.querySelector('#addHostDialog').close();
},
function() {
snackbarLog('pairing to ' + inputHost + ' failed!');
});
} }
// locally remove the hostname/ip from the saved `hosts` array. // locally remove the hostname/ip from the saved `hosts` array.
@ -224,14 +225,10 @@ function showApps() {
return; return;
} }
// if game grid is populated, empty it
$("#game-grid").empty();
api.getAppList().then(function (appList) { api.getAppList().then(function (appList) {
// if game grid is populated, empty it
if($("#game-grid").children().length > 0) {
$("#game-grid").empty();
}
appList.forEach(function (app) { appList.forEach(function (app) {
api.getBoxArt(app.id).then(function (resolvedPromise) { api.getBoxArt(app.id).then(function (resolvedPromise) {
var imageBlob = new Blob([resolvedPromise], {type: "image/png"}); var imageBlob = new Blob([resolvedPromise], {type: "image/png"});
@ -310,6 +307,10 @@ function startGame(sourceEvent) {
api.refreshServerInfo().then(function (ret) { api.refreshServerInfo().then(function (ret) {
if(api.currentGame != 0 && api.currentGame != appID) { if(api.currentGame != 0 && api.currentGame != appID) {
api.getAppById(api.currentGame).then(function (currentApp) { api.getAppById(api.currentGame).then(function (currentApp) {
// This event gets saved and passed back to this callback
// after the game is quit
relaunchSourceEvent = sourceEvent;
var quitAppDialog = document.querySelector('#quitAppDialog'); var quitAppDialog = document.querySelector('#quitAppDialog');
document.getElementById('quitAppDialogText').innerHTML = document.getElementById('quitAppDialogText').innerHTML =
currentApp.title + ' is already running. Would you like to quit ' + currentApp.title + ' is already running. Would you like to quit ' +
@ -337,7 +338,7 @@ function startGame(sourceEvent) {
$('#loadingMessage').text('Starting ' + appName + '...'); $('#loadingMessage').text('Starting ' + appName + '...');
playGameMode(); playGameMode();
if(api.currentGame == appID) // if user wants to launch the already-running app, then we resume it. if(api.currentGame == appID) { // if user wants to launch the already-running app, then we resume it.
return api.resumeApp(rikey, rikeyid).then(function (ret) { return api.resumeApp(rikey, rikeyid).then(function (ret) {
sendMessage('startRequest', [host, streamWidth, streamHeight, frameRate, sendMessage('startRequest', [host, streamWidth, streamHeight, frameRate,
bitrate.toString(), api.serverMajorVersion.toString(), rikey, rikeyid.toString()]); bitrate.toString(), api.serverMajorVersion.toString(), rikey, rikeyid.toString()]);
@ -346,6 +347,7 @@ function startGame(sourceEvent) {
console.log('Returned error was: ' + failedResumeApp); console.log('Returned error was: ' + failedResumeApp);
return; return;
}); });
}
api.launchApp(appID, api.launchApp(appID,
streamWidth + "x" + streamHeight + "x" + frameRate, streamWidth + "x" + streamHeight + "x" + frameRate,
@ -365,6 +367,7 @@ function startGame(sourceEvent) {
} }
function cancelQuitApp() { function cancelQuitApp() {
relaunchSourceEvent = null;
document.querySelector('#quitAppDialog').close(); document.querySelector('#quitAppDialog').close();
console.log('closing app dialog, and returning'); console.log('closing app dialog, and returning');
} }
@ -372,7 +375,18 @@ function cancelQuitApp() {
function continueQuitApp(sourceEvent) { function continueQuitApp(sourceEvent) {
// I want the sourceEvent's sourceEvent // I want the sourceEvent's sourceEvent
console.log('stopping game, and closing app dialog, and returning'); console.log('stopping game, and closing app dialog, and returning');
stopGame(); stopGame(
function() {
if (relaunchSourceEvent != null) {
// Save and null relaunchSourceEvent just in case startGame()
// wants to set it again.
var event = relaunchSourceEvent;
relaunchSourceEvent = null;
startGame(event);
}
}
);
document.querySelector('#quitAppDialog').close(); document.querySelector('#quitAppDialog').close();
} }
@ -408,7 +422,6 @@ function fullscreenNaclModule() {
} }
function stopGame(callbackFunction) { function stopGame(callbackFunction) {
api.refreshServerInfo().then(function (ret) { api.refreshServerInfo().then(function (ret) {
api.getAppById(api.currentGame).then(function (runningApp) { api.getAppById(api.currentGame).then(function (runningApp) {
if (!runningApp) { if (!runningApp) {
@ -542,12 +555,7 @@ function onWindowLoad(){
var ips = Object.keys(finder.byService_['_nvstream._tcp']); var ips = Object.keys(finder.byService_['_nvstream._tcp']);
for (var ip in ips) { for (var ip in ips) {
if (finder.byService_['_nvstream._tcp'][ip]) { if (finder.byService_['_nvstream._tcp'][ip]) {
var cell = document.createElement('div'); addHostToGrid(ip);
cell.className += 'mdl-cell mdl-cell--3-col';
cell.id = 'hostgrid-' + ip;
cell.innerHTML = ip;
$('#host-grid').append(cell);
cell.onclick = hostChosen;
} }
} }
} }

View File

@ -23,7 +23,7 @@ function handleMessage(msg) {
if(msg.data === 'streamTerminated') { // if it's a recognized event, notify the appropriate function if(msg.data === 'streamTerminated') { // if it's a recognized event, notify the appropriate function
$('#loadingSpinner').css('display', 'none'); // This is a fallback for RTSP handshake failing, which immediately terminates the stream. $('#loadingSpinner').css('display', 'none'); // This is a fallback for RTSP handshake failing, which immediately terminates the stream.
api.refreshServerInfo().then(function (ret) { api.refreshServerInfo().then(function (ret) {
showAppsMode(); showApps();
chrome.app.window.current().restore(); chrome.app.window.current().restore();
}); });
} else if(msg.data === 'Connection Established') { } else if(msg.data === 'Connection Established') {

View File

@ -40,7 +40,6 @@ function NvHTTP(address, clientUid) {
this.clientUid = clientUid; this.clientUid = clientUid;
this._baseUrlHttps = 'https://' + address + ':47984'; this._baseUrlHttps = 'https://' + address + ':47984';
this._baseUrlHttp = 'http://' + address + ':47989'; this._baseUrlHttp = 'http://' + address + ':47989';
this._appListCache = null;
this._memCachedBoxArtArray = {}; this._memCachedBoxArtArray = {};
_self = this; _self = this;
}; };
@ -133,13 +132,6 @@ NvHTTP.prototype = {
}, },
getAppList: function () { getAppList: function () {
if (_self._appListCache) {
console.log('Returning app list from cache');
return new Promise(function (resolve, reject) {
resolve(_self._appListCache);
});
}
return sendMessage('openUrl', [_self._baseUrlHttps + '/applist?' + _self._buildUidStr(), false]).then(function (ret) { return sendMessage('openUrl', [_self._baseUrlHttps + '/applist?' + _self._buildUidStr(), false]).then(function (ret) {
$xml = _self._parseXML(ret); $xml = _self._parseXML(ret);
@ -155,9 +147,6 @@ NvHTTP.prototype = {
}); });
} }
if (appList)
_self._appListCache = appList;
return appList; return appList;
}); });
}, },

View File

@ -62,6 +62,14 @@ static const char k_FragmentShaderExternal[] =
" gl_FragColor = texture2D(s_texture, v_texCoord); \n" " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
"}"; "}";
void MoonlightInstance::DidChangeFocus(bool got_focus) {
// Request an IDR frame to dump the frame queue that may have
// built up from the GL pipeline being stalled.
if (got_focus) {
g_Instance->m_RequestIdrFrame = true;
}
}
void MoonlightInstance::InitializeRenderingSurface(int width, int height) { void MoonlightInstance::InitializeRenderingSurface(int width, int height) {
if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
return; return;
@ -230,6 +238,12 @@ int MoonlightInstance::VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
bool isSps = false; bool isSps = false;
bool isPps = false; bool isPps = false;
bool isIframe = false; bool isIframe = false;
// Request an IDR frame if needed
if (g_Instance->m_RequestIdrFrame) {
g_Instance->m_RequestIdrFrame = false;
return DR_NEED_IDR;
}
// Look at the NALU type // Look at the NALU type
if (decodeUnit->bufferList->length > 5) { if (decodeUnit->bufferList->length > 5) {