快速入門:使用「播放至」功能串流投影片放映 (HTML)
[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]
您可以使用「播放至」功能,讓使用者在自己的家用網路上輕易地將音訊、視訊或影像從電腦串流至裝置。這個主題會教您如何在 Windows 市集應用程式中使用「播放至」功能,讓使用者將影像以投影片放映串流處理至目標裝置。
目標: 使用「播放至」將影像以投影片放映串流處理至目標裝置。
先決條件
Microsoft Visual Studio
指示
1. 建立新專案並啟用對 [圖片] 的存取
- 開啟 Visual Studio,然後選取 [檔案] 功能表的 [新增專案]。在 [Javascript] 區段中,選取 [空白的應用程式]。將應用程式命名為 PlayToSlideShow,然後按一下 [確定]。
- 開啟 Package.appxmanifest 檔案,然後選取 [功能]**** 索引標籤。選取 [圖片庫] 功能,讓應用程式可以存取電腦的 [圖片] 資料夾。關閉並儲存資訊清單檔案。
2. 新增 HTML UI
開啟 Default.html 檔案,然後將下列的 HTML 新增到 <body> 區段。UI 包含一個用來顯示影像的 <div>,以及另一個用來顯示狀態訊息的 <div>。UI 還包含一個告知使用者如何使用「播放至」開始串流處理的 <div>,以及一個可讓使用者在串流處理時中斷連線的按鈕。要隱藏或顯示這兩個元素,取決於是否正在串流處理投影片放映。
<div id="slideshowDiv" style="height:600px;display:table-cell;vertical-align:bottom;"></div>
<div id="messageDiv">Slideshow disconnected</div>
<button id="disconnectButton" style="width:600px;height:60px;display: none">
Connected to <img id="iconImage" style="width: 30px;" /> <span id="deviceSpan" />
</button>
<div id="instructionsDiv">Swipe from the right edge of the screen, select "Devices", and select a device to stream the slide show to.</div>
3. 新增初始化程式碼
這個步驟中的程式碼會開始投影片放映,並針對中斷連線按鈕按一下事件建立處理常式。程式碼也包含捷徑函式 id,以方便存取 getElementById 函式。
開啟 js 資料夾。開啟 Default.js 檔案,然後將下列程式碼新增至預設的 onactivated 函式。
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
startSlideShow();
args.setPromise(WinJS.UI.processAll());
}
};
// Disconnect button event handler.
function disconnectButtonClick() {
Windows.Media.PlayTo.PlayToManager.showPlayToUI();
}
// Shortcut function.
function id(tagName) {
return document.getElementById(tagName);
}
4. 新增程式碼以取得影像並以投影片放映的方式顯示
這個範例會使用 [圖片] 的根資料夾中的影像,將影像顯示成投影片放映。首先從 [圖片] 取得影像清單,然後建立 <image> 物件循環播放清單,就可以完成這項工作。
使用「播放至」串流處理影像時,這個投影片放映應用程式的程式碼會利用功能,使用「播放至」緩衝下一個媒體項目。這是選用的方式,不過當我們需要額外時間才能串流下一個媒體項目的時候,卻很實用。透過媒體緩衝的方式,當目前的媒體項目完成後,可以立即串流處理,避免媒體項目之間的延遲。
如果要緩衝下一個媒體項目,我們會將下一個項目的「播放至」來源設定為目前項目的 next 屬性。當目前的項目完成時,我們呼叫目前項目的 playNext 方法,將下一個媒體來源串流處理至目標裝置。
如果投影片放映只在本機播放,程式碼會使用逾時移到清單中的下一個影像。如果投影片放映是串流處理到「播放至」接收器,程式碼還是會使用逾時移到下一個影像,但也會在「播放至」接收器暫停投影片放映時、在逾時到期之前移到下一個影像時或中斷連線時做出回應。使用影像物件的 msPlayToSource 屬性參照之「播放至」來源的 statechanged 事件,就可以完成這項工作。在 statechanged 事件中,程式碼會檢查已傳遞到事件之引數的 currentState 和 previousState 屬性。不同的狀態以及識別引發 statechanged 事件的影像索引編號,都會告訴我們如何回應,如下表所示。
currentState | 要採取的行動 |
---|---|
disconnected | 如果引發事件的影像索引與目前顯示的影像索引相同,「播放至」來源就會在影像顯示時中斷連線。這表示「播放至」接收器不再處於連線狀態,而我們會使用最新的影像索引在本機開始投影片放映。否則,disconnected 的狀態只會指出投影片放映已完成顯示引發事件的影像,而我們可以清除不再需要的影像物件。 |
connected | 如果先前的狀態是 disconnected, 則表示引發事件的影像剛剛才連接到「播放至」接收器。此時我們取得下一個影像,會在顯示目前影像時載入。 如果先前的狀態是 rendering,則表示使用者已暫停「播放至」接收器上的投影片放映,而我們可以清除目前的逾時,直到使用者重新開始放映 為止。 |
rendering | 如果先前的狀態是 connected,則表示「播放至」接收器已經取消暫停投影片放映,而我們可以再次開始放映。 |
在 Default.js 檔案中,將下列程式碼新增到上一個步驟的程式碼後面。
var states = Windows.Media.PlayTo.PlayToConnectionState, // alias for PlayToConnectionState
imageList, // contains the list of images to show
streaming = false, // true when streaming using Play To; otherwise false
cancel = 0, // used to cancel a timeout
timeLapse = 5, // time between images (5 seconds)
imageSize = "600px", // size of current displayed image
thumbnailSize = "200px", // size of "thumbnail" of next image
currentImage = 0; // index of the current image from imageList
// Get the list of images from the Pictures folder and start the slide show.
function startSlideShow() {
Windows.Storage.KnownFolders.picturesLibrary.getFilesAsync().then(
function (resultsLibrary) {
imageList = resultsLibrary;
if (imageList.length > 0) {
var image = queueImage(0, true);
} else {
id("messageDiv").innerHTML = "There are no images in the Pictures library.";
}
});
}
// playNextImage
// Called when a new image is displayed due to a timeout.
// Removes the current image object and queues a new next image.
// Sets the next image index as the new current image, and increases the size
// of the new current image. Then sets the timeout to display the next image.
function playNextImage(num) {
id("slideshowDiv").removeChild(id("image" + num));
queueImage(num + 2, false);
currentImage = num + 1;
id("image" + currentImage).style.width = imageSize;
cancel = setTimeout(function () {
playNextImage(num + 1);
}, timeLapse * 1000);
}
// queueImage
// Called to create an image object for the displayed images.
function queueImage(num, isFirstImage) {
// Create the image element for the specified image index and add to the
// slide show div.
var image = document.createElement("img");
image.style.width = (isFirstImage ? imageSize : thumbnailSize);
image.id = "image" + num;
image.src = URL.createObjectURL(imageList[num % imageList.length], { oneTimeOnly: true });
id("slideshowDiv").appendChild(image);
// If this is the first image of the slide show, queue the next image. Do
// not queue if streaming as images are already queued before
// streaming using Play To.
if (isFirstImage && !streaming) {
queueImage(num + 1, false);
cancel = setTimeout(function () {
playNextImage(num);
}, timeLapse * 1000);
}
// Use the transferred event of the Play To connection for the current image object
// to "move" to the next image in the slide show. The transferred event occurs
// when the PlayToSource.playNext() method is called, or when the Play To
// Receiver selects the next image.
image.msPlayToSource.connection.addEventListener("transferred", function () {
currentImage = num + 1;
id("image" + currentImage).style.width = imageSize;
}, false);
// Use the statechanged event to determine which action to take or to respond
// if the Play To Receiver is disconnected.
image.msPlayToSource.connection.addEventListener("statechanged", function (e) {
switch (e.currentState) {
case states.disconnected:
// If the state is disconnected and the current image index equals the
// num value passed to queueImage, then the image element is not connected
// to the Play To Receiver any more. Restart the slide show.
// Otherwise, the current image has been discarded and the slide show
// has moved to the next image. Clear the current image object and
// remove it from the slide show div.
if (currentImage == num) {
id("messageDiv").innerHTML = "Slideshow disconnected";
// Cancel any existing timeout
if (cancel) {
clearTimeout(cancel);
}
// Clear all image objects from the slide show div
while (id("slideshowDiv").firstChild) {
id("slideshowDiv").removeChild(id("slideshowDiv").firstChild);
}
// Reset the slide show objects and values to their beginning state
streaming = false;
id("disconnectButton").style.display = "none";
id("instructionsDiv").style.display = "block";
disconnectButton.removeEventListener("click", disconnectButtonClick, false);
// Restart the slide show from the current image index
queueImage(currentImage, true);
} else {
image.msPlayToSource.next = null;
image.removeAttribute("src");
if (streaming) {
id("slideshowDiv").removeChild(image);
}
}
break;
case states.connected:
// If the state is connected and the previous state is disconnected,
// then the image element is newly connected. Queue up the next image so
// that it is loaded while the current image is being displayed.
// If the previous state is rendering, then the user has paused the slideshow
// on the Play To Receiver. Clear the current timeout until the user restarts
// the slide show.
if (e.previousState === states.disconnected) {
var imageNext = queueImage(num + 1, false);
image.msPlayToSource.next = imageNext.msPlayToSource;
} else if (e.previousState === states.rendering) {
if (cancel) {
clearTimeout(cancel);
cancel = 0;
}
}
if (currentImage == num) {
id("messageDiv").innerHTML = "Slideshow connected";
}
break;
case states.rendering:
// If the state is rendering and the previous state is
// connected, then the Play To Receiver has restarted
// the slide show.
if (e.previousState === states.connected) {
// Clear any existing timeout.
if (cancel) {
clearTimeout(cancel);
}
// Restart the slide show.
cancel = setTimeout(function () {
image.msPlayToSource.playNext();
}, timeLapse * 1000);
}
if (currentImage == num) {
id("messageDiv").innerHTML = "Slideshow rendering";
}
break;
}
}, false);
return image;
}
5. 新增「播放至」程式碼
這個步驟中的程式碼會實作播放至協定。它會為目前應用程式取得 PlayToManager 的參考,然後和 sourcerequested、sourceselected 事件的事件處理常式建立關聯。
因為影像物件是針對投影片放映中的每個影像所建立和摧毀,所以我們在 sourcerequested 事件中使用永遠不會摧毀的暫時影像物件。這是因為我們不知道逾時是否會在使用者選取「播放至」接收器之前到期。如果發生這種情況,會摧毀目前的影像,並將 Null 參照傳送到「播放至」。所以,我們會將永遠不會摧毀的影像物件參照傳送到「播放至」,並在使用者選取「播放至」接收器時,將影像來源更新為目前顯示的影像。當影像狀態變更為 connected,我們就知道發生了這個狀況。
在 Default.js 檔案中,將下列程式碼新增到上一個步驟的程式碼後面。
// Set up the Play To contract.
// Used to pass an image to Play To that will not be removed/destroyed
// by the slide show logic. For example, if the user opens the Devices
// charm and the sourcerequested event fires, but the image display timeout
// completes before the user selects a target device, then the image that
// was being displayed is removed and destroyed. intialImage is never
// destroyed so Play To will always have a valid source to stream.
var initialImage = null;
var ptm = Windows.Media.PlayTo.PlayToManager.getForCurrentView();
ptm.addEventListener("sourcerequested", function (e) {
initialImage = document.createElement("img");
// Use the statechanged event of the image passed to Play To to determine when
// the image is finally connected to the Play To Receiver.
initialImage.msPlayToSource.connection.addEventListener("statechanged", function (e) {
if (e.currentState === states.connected) {
// Clear any existing timeout.
if (cancel) {
clearTimeout(cancel);
cancel = 0;
}
// Clear the slide show div.
while (id("slideshowDiv").firstChild) {
id("slideshowDiv").removeChild(id("slideshowDiv").firstChild);
}
// Set the slide show objects and values to show that we are streaming.
streaming = true;
id("disconnectButton").style.display = "block";
id("instructionsDiv").style.display = "none";
// Queue and display the next image.
var image = queueImage(currentImage, true);
initialImage.msPlayToSource.next = image.msPlayToSource;
initialImage.msPlayToSource.playNext();
}
}, false);
// Provide Play To with the first image to stream.
e.sourceRequest.setSource(initialImage.msPlayToSource);
}, false);
// Update the once the user has selected a device to stream to.
ptm.addEventListener("sourceselected", function (e) {
disconnectButton.addEventListener("click", disconnectButtonClick, false);
id("messageDiv").innerHTML = "Streaming to " + e.friendlyName + "...";
id("deviceSpan").innerHTML = e.friendlyName + ".<br/>Click here to disconnect.";
id("iconImage").src = URL.createObjectURL(e.icon, { oneTimeOnly: true });
}, false);
6. 建立「播放至」目標 (選用)
如果要執行應用程式,您需要一個目標裝置,讓「播放至」可以串流媒體。如果您沒有已認證的「播放至」接收器,可以使用 Windows Media Player 做為目標裝置。為了使用 Windows Media Player 當作目標裝置,您的電腦必須連線至私人網路。執行 Windows Media Player 的電腦不能是「播放至」來源應用程式所在的電腦。
- 啟動 Windows Media Player。
- 展開 [串流] 功能表,然後啟用 [允許遠端控制我的播放程式...]**** 選項。讓 Windows Media Player 保持開啟;它必須為執行中,才能當作「播放至」目標。
- 開啟 [裝置和印表機] 控制台。按一下 [新增裝置和印表機]。在 [新增裝置和印表機] 精靈中的 [選擇要新增至此電腦的裝置或印表機] 視窗中,找到電腦的 [數位媒體轉譯器]。這是您電腦的 Windows Media Player。選取它,然後按 [下一步]****。精靈完成之後,您會在 [多媒體裝置] 的清單中看到 Windows Media Player 的執行個體。
7. 執行應用程式
- 在 Visual Studio 中,按 F5 (偵錯) 以執行應用程式。您可以選取任何媒體按鈕,即可播放或查看不同媒體櫃中的第一個媒體項目。播放媒體的時候,開啟裝置常用鍵並選取「播放至」目標,即可將媒體串流至目標裝置。
摘要
在這個快速入門中,您已將「播放至」功能新增到應用程式,該應用程式會將影像當作投影片放映在目標裝置上顯示。「播放至」功能可以讓使用者將來自應用程式的內容串流到網路上已認證的「播放至」接收器。
相關主題
範例