Bật tính năng truyền cho ứng dụng web

1. Tổng quan

Biểu trưng Google Cast

Lớp học lập trình này sẽ hướng dẫn bạn cách sửa đổi một ứng dụng video hiện có trên web để truyền nội dung trên một thiết bị có hỗ trợ Google Cast.

Google Cast là gì?

Google Cast cho phép người dùng truyền nội dung từ thiết bị di động lên TV. Sau đó, người dùng có thể dùng thiết bị di động làm điều khiển từ xa để phát nội dung nghe nhìn trên TV.

Google Cast SDK giúp bạn mở rộng ứng dụng để điều khiển TV hoặc hệ thống âm thanh. Cast SDK cho phép bạn thêm các thành phần giao diện người dùng cần thiết dựa trên Danh sách kiểm tra thiết kế của Google Cast.

Danh sách kiểm tra thiết kế Google Cast được cung cấp để giúp trải nghiệm người dùng Cast trở nên đơn giản và dễ đoán trên tất cả các nền tảng được hỗ trợ.

Chúng ta sẽ xây dựng những gì?

Khi hoàn tất lớp học lập trình này, bạn sẽ có một ứng dụng video trên web dành cho Chrome có thể truyền video đến một thiết bị truyền.

Kiến thức bạn sẽ học được

  • Cách thêm Google Cast SDK vào một ứng dụng video mẫu.
  • Cách thêm nút Truyền để chọn một thiết bị truyền.
  • Cách kết nối với thiết bị truyền và chạy trình nhận nội dung nghe nhìn.
  • Cách truyền video.
  • Cách tích hợp Cast Connect

Bạn cần có

  • Trình duyệt Google Chrome mới nhất.
  • Dịch vụ lưu trữ HTTPS, chẳng hạn như Lưu trữ Firebase hoặc ngrok.
  • Một thiết bị Google Cast, chẳng hạn như Chromecast hoặc Android TV được thiết lập để có quyền truy cập vào Internet.
  • TV hoặc màn hình có cổng đầu vào HDMI.
  • Bạn cần có Chromecast có Google TV để kiểm thử việc tích hợp Cast Connect, nhưng không bắt buộc đối với phần còn lại của Lớp học lập trình. Nếu không có, bạn có thể bỏ qua bước Thêm tính năng hỗ trợ Cast Connect ở gần cuối hướng dẫn này.

Trải nghiệm

  • Bạn cần có kiến thức về phát triển web.
  • Bạn cũng cần có kiến thức về cách xem TV :)

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc Đọc và hoàn thành bài tập

Bạn đánh giá thế nào về trải nghiệm xây dựng ứng dụng web?

Người mới bắt đầu Trung cấp Thành thạo

Bạn đánh giá thế nào về trải nghiệm xem truyền hình?

Người mới bắt đầu Trung cấp Thành thạo

2. Nhận mã mẫu

Bạn có thể tải tất cả mã mẫu xuống máy tính...

và giải nén tệp zip đã tải xuống.

3. Chạy ứng dụng mẫu

Biểu trưng Google Chrome

Trước tiên, hãy xem ứng dụng mẫu hoàn chỉnh trông như thế nào. Ứng dụng này là một trình phát video cơ bản. Người dùng có thể chọn một video trong danh sách rồi phát video đó trên thiết bị hoặc truyền video đó đến một thiết bị truyền Google Cast.

Để có thể sử dụng, bạn cần lưu trữ thành phần đã hoàn tất.

Nếu không có máy chủ để sử dụng, bạn có thể dùng Lưu trữ Firebase hoặc ngrok.

Chạy máy chủ

Sau khi thiết lập dịch vụ bạn chọn, hãy chuyển đến app-done rồi khởi động máy chủ.

Trong trình duyệt, hãy truy cập vào URL https cho mẫu mà bạn lưu trữ.

  1. Bạn sẽ thấy ứng dụng video xuất hiện.
  2. Nhấp vào nút Truyền rồi chọn thiết bị truyền của bạn.
  3. Chọn một video rồi nhấp vào nút phát.
  4. Video sẽ bắt đầu phát trên thiết bị Google Cast.

Hình ảnh video đang phát trên một thiết bị truyền

Nhấp vào nút tạm dừng trong phần tử video để tạm dừng video trên thiết bị nhận. Nhấp vào nút phát trong phần tử video để tiếp tục phát lại video.

Nhấp vào nút Truyền để dừng truyền đến thiết bị truyền.

Trước khi tiếp tục, hãy dừng máy chủ.

4. Chuẩn bị dự án khởi đầu

Hình ảnh video đang phát trên một thiết bị truyền

Bạn cần thêm tính năng hỗ trợ Google Cast vào ứng dụng khởi động mà bạn đã tải xuống. Sau đây là một số thuật ngữ về Google Cast mà chúng ta sẽ sử dụng trong lớp học lập trình này:

  • ứng dụng người gửi chạy trên thiết bị di động hoặc máy tính xách tay,
  • ứng dụng receiver chạy trên thiết bị truyền Google Cast.

Giờ đây, bạn đã sẵn sàng xây dựng dựa trên dự án khởi đầu bằng trình chỉnh sửa văn bản mà bạn yêu thích:

  1. Chọn thư mục biểu tượng thư mụcapp-start trong tệp tải mã mẫu xuống.
  2. Chạy ứng dụng bằng máy chủ của bạn và khám phá giao diện người dùng.

Xin lưu ý rằng khi tham gia lớp học lập trình này, bạn sẽ cần lưu trữ lại mẫu trên máy chủ của mình, tuỳ thuộc vào dịch vụ.

Thiết kế ứng dụng

Ứng dụng tìm nạp danh sách video từ một máy chủ web từ xa và cung cấp danh sách để người dùng duyệt xem. Người dùng có thể chọn một video để xem thông tin chi tiết hoặc phát video đó trên thiết bị di động.

Ứng dụng này bao gồm một khung hiển thị chính, được xác định trong index.html và bộ điều khiển chính, CastVideos.js.

index.html

Tệp HTML này khai báo hầu hết giao diện người dùng cho ứng dụng web.

Có một số phần của khung hiển thị, chúng ta có div#main_video chứa phần tử video. Liên quan đến thẻ div video, chúng ta có div#media_control, thẻ này xác định tất cả các nút điều khiển cho phần tử video. Bên dưới đó là media_info, nơi hiển thị thông tin chi tiết về video đang được xem. Cuối cùng, div carousel sẽ hiển thị danh sách video trong một div.

Tệp index.html cũng khởi động Cast SDK và yêu cầu hàm CastVideos tải.

Hầu hết nội dung sẽ điền sẵn vào các phần tử này đều được xác định, chèn và kiểm soát trong CastVideos.js. Vậy hãy cùng xem xét vấn đề này.

CastVideos.js

Tập lệnh này quản lý tất cả logic cho ứng dụng web Cast Videos. Danh sách video và siêu dữ liệu liên kết được xác định trong CastVideos.js nằm trong một đối tượng có tên là mediaJSON.

Có một số phần chính cùng nhau chịu trách nhiệm quản lý và phát video cả cục bộ và từ xa. Nhìn chung, đây là một ứng dụng web khá đơn giản.

CastPlayer là lớp chính quản lý toàn bộ ứng dụng, thiết lập trình phát, chọn nội dung nghe nhìn và liên kết các sự kiện với PlayerHandler để phát nội dung nghe nhìn. CastPlayer.prototype.initializeCastPlayer là phương thức thiết lập tất cả chức năng Truyền. CastPlayer.prototype.switchPlayer chuyển đổi trạng thái giữa trình phát cục bộ và trình phát từ xa. CastPlayer.prototype.setupLocalPlayerCastPlayer.prototype.setupRemotePlayer khởi động người chơi cục bộ và từ xa.

PlayerHandler là lớp chịu trách nhiệm quản lý hoạt động phát nội dung nghe nhìn. Có một số phương thức khác chịu trách nhiệm về thông tin chi tiết của việc quản lý nội dung nghe nhìn và hoạt động phát.

Câu hỏi thường gặp

5. Thêm nút Truyền

Hình ảnh về một ứng dụng hỗ trợ Cast

Ứng dụng có hỗ trợ Cast sẽ hiển thị nút Truyền trong phần tử video. Khi nhấp vào nút Truyền, người dùng sẽ thấy danh sách các thiết bị truyền mà họ có thể chọn. Nếu người dùng đang phát nội dung cục bộ trên thiết bị gửi, thì việc chọn một thiết bị truyền sẽ bắt đầu hoặc tiếp tục phát trên thiết bị truyền đó. Bất cứ lúc nào trong phiên truyền, người dùng có thể nhấp vào nút Truyền và dừng truyền ứng dụng của bạn đến thiết bị truyền. Người dùng phải có thể kết nối hoặc ngắt kết nối với thiết bị truyền trong khi ở bất kỳ màn hình nào của ứng dụng, như mô tả trong Danh sách kiểm tra thiết kế Google Cast.

Cấu hình

Dự án khởi đầu yêu cầu các phần phụ thuộc và chế độ thiết lập giống như bạn đã thực hiện cho ứng dụng mẫu hoàn chỉnh, nhưng lần này hãy lưu trữ nội dung của app-start.

Trong trình duyệt, hãy truy cập vào URL https cho mẫu mà bạn đã lưu trữ.

Xin lưu ý rằng khi thực hiện các thay đổi, bạn sẽ cần lưu trữ lại mẫu trên máy chủ của mình, tuỳ thuộc vào dịch vụ.

Khởi chạy

Khung Cast có một đối tượng singleton chung là CastContext, đối tượng này điều phối tất cả các hoạt động của khung. Đối tượng này phải được khởi chạy sớm trong vòng đời của ứng dụng, thường được gọi từ một lệnh gọi lại được chỉ định cho window['__onGCastApiAvailable']. Lệnh gọi này được gọi sau khi Cast SDK đã được tải và có thể sử dụng. Trong trường hợp này, CastContext được gọi trong CastPlayer.prototype.initializeCastPlayer, được gọi từ lệnh gọi lại nêu trên.

Bạn phải cung cấp một đối tượng JSON options khi khởi chạy CastContext. Lớp này chứa các lựa chọn ảnh hưởng đến hành vi của khung. Quan trọng nhất trong số này là mã ứng dụng nhận. Mã này được dùng để lọc danh sách các thiết bị Cast có sẵn để chỉ hiện những thiết bị có thể chạy ứng dụng đã chỉ định và để chạy ứng dụng nhận khi một phiên Cast bắt đầu.

Khi phát triển ứng dụng của riêng mình có hỗ trợ Cast, bạn phải đăng ký làm nhà phát triển Cast rồi lấy mã ứng dụng cho ứng dụng của mình. Trong lớp học lập trình này, chúng ta sẽ sử dụng một mã ứng dụng mẫu.

Thêm mã sau vào index.html ở cuối phần body:

<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

Thêm mã sau vào index.html để khởi chạy ứng dụng CastVideos, cũng như để khởi chạy CastContext:

<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    castPlayer.initializeCastPlayer();
  }
};
</script>

Giờ đây, chúng ta cần thêm một phương thức mới vào CastVideos.js, tương ứng với phương thức mà chúng ta vừa gọi trong index.html. Hãy thêm một phương thức mới có tên là initializeCastPlayer, phương thức này sẽ đặt các lựa chọn trên CastContext và khởi động RemotePlayerRemotePlayerControllers mới:

/**
 * This method sets up the CastContext, and a few other members
 * that are necessary to play and control videos on a Cast
 * device.
 */
CastPlayer.prototype.initializeCastPlayer = function() {

    var options = {};

    // Set the receiver application ID to your own (created in
    // the Google Cast Developer Console), or optionally
    // use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    options.receiverApplicationId = 'C0868879';

    // Auto join policy can be one of the following three:
    // ORIGIN_SCOPED - Auto connect from same appId and page origin
    // TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
    // PAGE_SCOPED - No auto connect
    options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;

    cast.framework.CastContext.getInstance().setOptions(options);

    this.remotePlayer = new cast.framework.RemotePlayer();
    this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
        this.switchPlayer.bind(this)
    );
};

Cuối cùng, chúng ta cần tạo các biến cho RemotePlayerRemotePlayerController:

var CastPlayer = function() {
  //...
  /* Cast player variables */
  /** @type {cast.framework.RemotePlayer} */
  this.remotePlayer = null;
  /** @type {cast.framework.RemotePlayerController} */
  this.remotePlayerController = null;
  //...
};

Nút truyền

Giờ đây, sau khi CastContext được khởi chạy, chúng ta cần thêm nút Truyền để cho phép người dùng chọn một thiết bị truyền. Cast SDK cung cấp một thành phần nút truyền có tên là google-cast-launcher với mã nhận dạng là "castbutton". Bạn có thể thêm thành phần này vào phần tử video của ứng dụng bằng cách chỉ cần thêm một button vào phần media_control.

Phần tử nút sẽ có dạng như sau:

<google-cast-launcher id="castbutton"></google-cast-launcher>

Thêm mã sau vào index.html trong phần media_control:

<div id="media_control">
  <div id="play"></div>
  <div id="pause"></div>
  <div id="progress_bg"></div>
  <div id="progress"></div>
  <div id="progress_indicator"></div>
  <div id="fullscreen_expand"></div>
  <div id="fullscreen_collapse"></div>
  <google-cast-launcher id="castbutton"></google-cast-launcher>
  <div id="audio_bg"></div>
  <div id="audio_bg_track"></div>
  <div id="audio_indicator"></div>
  <div id="audio_bg_level"></div>
  <div id="audio_on"></div>
  <div id="audio_off"></div>
  <div id="duration">00:00:00</div>
</div>

Bây giờ, hãy làm mới trang trong trình duyệt Chrome. Bạn sẽ thấy nút Truyền trong phần tử video và khi bạn nhấp vào nút này, danh sách các thiết bị truyền trên mạng cục bộ sẽ xuất hiện. Trình duyệt Chrome tự động quản lý việc phát hiện thiết bị. Chọn thiết bị truyền và ứng dụng nhận mẫu sẽ tải trên thiết bị truyền.

Chúng tôi chưa thiết lập bất kỳ tính năng hỗ trợ nào cho việc phát nội dung nghe nhìn, vì vậy, bạn chưa thể phát video trên thiết bị truyền. Nhấp vào nút Truyền để dừng truyền.

6. Truyền nội dung video

Hình ảnh về ứng dụng hỗ trợ Cast có trình đơn chọn thiết bị truyền

Chúng ta sẽ mở rộng ứng dụng mẫu để phát video từ xa trên thiết bị truyền. Để làm được điều đó, chúng ta cần theo dõi nhiều sự kiện do khung Cast tạo ra.

Truyền nội dung nghe nhìn

Nhìn chung, nếu bạn muốn phát nội dung nghe nhìn trên một thiết bị truyền, thì cần phải thực hiện những việc sau:

  1. Tạo một đối tượng MediaInfo JSON từ Cast SDK mô hình hoá một mục nội dung nghe nhìn.
  2. Người dùng kết nối với thiết bị truyền để khởi chạy ứng dụng nhận.
  3. Tải đối tượng MediaInfo vào bộ nhận và phát nội dung.
  4. Theo dõi trạng thái của nội dung nghe nhìn.
  5. Gửi lệnh phát đến bộ nhận dựa trên hoạt động tương tác của người dùng.

Bước 1 là ánh xạ một đối tượng sang một đối tượng khác; MediaInfo là thứ mà Cast SDK hiểu được và mediaJSON là quá trình đóng gói của ứng dụng cho một mục nội dung nghe nhìn; chúng ta có thể dễ dàng ánh xạ một mediaJSON sang một MediaInfo. Chúng ta đã thực hiện Bước 2 trong phần trước. Bạn có thể dễ dàng thực hiện bước 3 bằng Cast SDK.

Ứng dụng mẫu CastPlayer đã phân biệt giữa chế độ phát cục bộ và chế độ phát từ xa trong phương thức switchPlayer:

if (cast && cast.framework) {
  if (this.remotePlayer.isConnected) {
    //...

Trong lớp học lập trình này, bạn không cần phải hiểu chính xác cách hoạt động của tất cả logic trong trình phát mẫu. Tuy nhiên, bạn cần hiểu rằng trình phát nội dung nghe nhìn của ứng dụng sẽ phải được sửa đổi để nhận biết cả chế độ phát cục bộ và từ xa.

Hiện tại, trình phát cục bộ luôn ở trạng thái phát cục bộ vì trình phát này chưa biết gì về trạng thái Truyền. Chúng ta cần cập nhật giao diện người dùng dựa trên các quá trình chuyển đổi trạng thái diễn ra trong khung Cast. Ví dụ: nếu bắt đầu truyền, chúng ta cần dừng phát cục bộ và tắt một số nút điều khiển. Tương tự, nếu dừng truyền khi đang ở trong trình điều khiển khung hiển thị này, chúng ta cần chuyển sang chế độ phát cục bộ. Để xử lý việc đó, chúng ta cần theo dõi nhiều sự kiện do khung Cast tạo ra.

Quản lý phiên truyền

Đối với khung truyền, một phiên truyền kết hợp các bước kết nối với thiết bị, khởi chạy (hoặc tham gia một phiên hiện có), kết nối với một ứng dụng nhận và khởi tạo kênh điều khiển nội dung nghe nhìn nếu thích hợp. Kênh điều khiển nội dung nghe nhìn là cách khung Cast gửi và nhận các thông báo liên quan đến hoạt động phát nội dung nghe nhìn từ bộ nhận.

Phiên truyền sẽ tự động bắt đầu khi người dùng chọn một thiết bị trong nút Truyền và tự động dừng khi người dùng ngắt kết nối. Khung Cast cũng tự động xử lý việc kết nối lại với một phiên nhận do sự cố về mạng.

Các phiên truyền được quản lý bằng CastSession. Bạn có thể truy cập vào CastSession thông qua cast.framework.CastContext.getInstance().getCurrentSession(). Bạn có thể dùng các lệnh gọi lại EventListener để theo dõi các sự kiện của phiên, chẳng hạn như tạo, tạm ngưng, tiếp tục và kết thúc.

Trong ứng dụng hiện tại, tất cả hoạt động quản lý phiên và trạng thái đều được xử lý cho chúng ta trong phương thức setupRemotePlayer. Hãy bắt đầu định cấu hình trong ứng dụng của bạn bằng cách thêm mã sau vào CastVideos.js:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

Chúng ta vẫn cần liên kết tất cả các sự kiện từ lệnh gọi lại và xử lý tất cả các sự kiện đến. Đây là một việc khá đơn giản, vì vậy, hãy thực hiện ngay:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    // Add event listeners for player changes which may occur outside sender app
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
        function() {
            if (this.remotePlayer.isPaused) {
                this.playerHandler.pause();
            } else {
                this.playerHandler.play();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
        function() {
            if (this.remotePlayer.isMuted) {
                this.playerHandler.mute();
            } else {
                this.playerHandler.unMute();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
        function() {
            var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
            var p = document.getElementById('audio_bg_level');
            p.style.height = newVolume + 'px';
            p.style.marginTop = -newVolume + 'px';
        }.bind(this)
    );

    // This object will implement PlayerHandler callbacks with
    // remotePlayerController, and makes necessary UI updates specific
    // to remote playback
    var playerTarget = {};

    playerTarget.play = function () {
        if (this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }

        var vi = document.getElementById('video_image');
        vi.style.display = 'block';
        var localPlayer = document.getElementById('video_element');
        localPlayer.style.display = 'none';
    }.bind(this);

    playerTarget.pause = function () {
        if (!this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }
    }.bind(this);

    playerTarget.stop = function () {
         this.remotePlayerController.stop();
    }.bind(this);

    playerTarget.getCurrentMediaTime = function() {
        return this.remotePlayer.currentTime;
    }.bind(this);

    playerTarget.getMediaDuration = function() {
        return this.remotePlayer.duration;
    }.bind(this);

    playerTarget.updateDisplayMessage = function () {
        document.getElementById('playerstate').style.display = 'block';
        document.getElementById('playerstatebg').style.display = 'block';
        document.getElementById('video_image_overlay').style.display = 'block';
        document.getElementById('playerstate').innerHTML =
            this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
            this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
    }.bind(this);

    playerTarget.setVolume = function (volumeSliderPosition) {
        // Add resistance to avoid loud volume
        var currentVolume = this.remotePlayer.volumeLevel;
        var p = document.getElementById('audio_bg_level');
        if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
            var vScale =  this.currentVolume * FULL_VOLUME_HEIGHT;
            if (volumeSliderPosition > vScale) {
                volumeSliderPosition = vScale + (pos - vScale) / 2;
            }
            p.style.height = volumeSliderPosition + 'px';
            p.style.marginTop = -volumeSliderPosition + 'px';
            currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
        } else {
            currentVolume = 1;
        }
        this.remotePlayer.volumeLevel = currentVolume;
        this.remotePlayerController.setVolumeLevel();
    }.bind(this);

    playerTarget.mute = function () {
        if (!this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.unMute = function () {
        if (this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.isMuted = function() {
        return this.remotePlayer.isMuted;
    }.bind(this);

    playerTarget.seekTo = function (time) {
        this.remotePlayer.currentTime = time;
        this.remotePlayerController.seek();
    }.bind(this);

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

Đang tải nội dung nghe nhìn

Trong Cast SDK, RemotePlayerRemotePlayerController cung cấp một tập hợp các API thuận tiện để quản lý việc phát nội dung nghe nhìn từ xa trên bộ nhận. Đối với CastSession hỗ trợ phát nội dung nghe nhìn, các thực thể của RemotePlayerRemotePlayerController sẽ được SDK tự động tạo. Bạn có thể truy cập vào các đối tượng này bằng cách tạo các thực thể của cast.framework.RemotePlayercast.framework.RemotePlayerController tương ứng, như đã trình bày trước đó trong lớp học lập trình.

Tiếp theo, chúng ta cần tải video hiện được chọn trên thiết bị nhận bằng cách tạo một đối tượng MediaInfo để SDK xử lý và truyền vào yêu cầu. Thêm mã sau vào setupRemotePlayer để thực hiện việc này:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    //...

    playerTarget.load = function (mediaIndex) {
        console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
        var mediaInfo = new chrome.cast.media.MediaInfo(
            this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');

        mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
        mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
        mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
        mediaInfo.metadata.images = [
            {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];

        var request = new chrome.cast.media.LoadRequest(mediaInfo);
        castSession.loadMedia(request).then(
            this.playerHandler.loaded.bind(this.playerHandler),
            function (errorCode) {
                this.playerState = PLAYER_STATE.ERROR;
                console.log('Remote media load error: ' +
                    CastPlayer.getErrorMessage(errorCode));
            }.bind(this));
    }.bind(this);

    //...
};

Bây giờ, hãy thêm một phương thức để chuyển đổi giữa chế độ phát cục bộ và chế độ phát từ xa:

/**
 * This is a method for switching between the local and remote
 * players. If the local player is selected, setupLocalPlayer()
 * is run. If there is a cast device connected we run
 * setupRemotePlayer().
 */
CastPlayer.prototype.switchPlayer = function() {
    this.stopProgressTimer();
    this.resetVolumeSlider();
    this.playerHandler.stop();
    this.playerState = PLAYER_STATE.IDLE;
    if (cast && cast.framework) {
        if (this.remotePlayer.isConnected) {
            this.setupRemotePlayer();
            return;
        }
    }
    this.setupLocalPlayer();
};

Cuối cùng, hãy thêm một phương thức để xử lý mọi thông báo lỗi Cast:

/**
 * Makes human-readable message from chrome.cast.Error
 * @param {chrome.cast.Error} error
 * @return {string} error message
 */
CastPlayer.getErrorMessage = function(error) {
  switch (error.code) {
    case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
      return 'The API is not initialized.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CANCEL:
      return 'The operation was canceled by the user' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CHANNEL_ERROR:
      return 'A channel to the receiver is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.EXTENSION_MISSING:
      return 'The Cast extension is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.INVALID_PARAMETER:
      return 'The parameters to the operation were not valid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
      return 'No receiver was compatible with the session request.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.SESSION_ERROR:
      return 'A session could not be created, or a session was invalid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.TIMEOUT:
      return 'The operation timed out.' +
        (error.description ? ' :' + error.description : '');
  }
};

Bây giờ, hãy chạy ứng dụng, kết nối với thiết bị truyền và bắt đầu phát video. Bạn sẽ thấy video phát trên thiết bị nhận.

7. Thêm tính năng hỗ trợ Cast Connect

Thư viện Cast Connect cho phép các ứng dụng gửi hiện có giao tiếp với các ứng dụng Android TV thông qua giao thức Cast. Cast Connect được xây dựng dựa trên cơ sở hạ tầng Cast, trong đó ứng dụng cho Android TV của bạn đóng vai trò là một bộ nhận.

Phần phụ thuộc

  • Trình duyệt Chrome phiên bản M87 trở lên

Thiết lập để Android Receiver tương thích

Để chạy ứng dụng Android TV (còn gọi là Trình nhận Android), chúng ta cần đặt cờ androidReceiverCompatible thành true trong đối tượng CastOptions.

Thêm mã sau vào CastVideos.js trong hàm initializeCastPlayer:

var options = {};
...
options.androidReceiverCompatible = true;

cast.framework.CastContext.getInstance().setOptions(options);

Đặt thông tin đăng nhập để khởi chạy

Về phía người gửi, bạn có thể chỉ định CredentialsData để biểu thị người đang tham gia phiên. credentials là một chuỗi do người dùng xác định, miễn là ứng dụng ATV của bạn có thể hiểu được chuỗi đó. CredentialsData chỉ được truyền đến ứng dụng cho Android TV của bạn trong thời gian khởi chạy hoặc tham gia. Nếu bạn đặt lại mật khẩu trong khi đang kết nối, mật khẩu đó sẽ không được chuyển đến ứng dụng Android TV.

Để đặt Launch Credentials (Thông tin đăng nhập khi khởi chạy), bạn cần xác định CredentialsData bất cứ lúc nào sau khi đặt các tuỳ chọn khởi chạy.

Thêm mã sau vào lớp CastVideos.js trong hàm initializeCastPlayer:

cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...

Đặt thông tin đăng nhập cho yêu cầu tải

Trong trường hợp ứng dụng Web Receiver và ứng dụng cho Android TV của bạn xử lý credentials theo cách khác nhau, bạn có thể cần xác định thông tin đăng nhập riêng cho từng ứng dụng. Để xử lý việc này, hãy thêm mã sau vào CastVideos.js trong playerTarget.load trong hàm setupRemotePlayer:

...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

Tuỳ thuộc vào ứng dụng nhận mà thiết bị gửi đang truyền đến, giờ đây, SDK sẽ tự động xử lý thông tin đăng nhập cần dùng cho phiên hiện tại.

Kiểm thử Cast Connect

Các bước cài đặt APK Android TV trên Chromecast có Google TV:

  1. Tìm địa chỉ IP của thiết bị Android TV. Thông thường, bạn có thể xem thông tin này trong phần Cài đặt > Mạng và Internet > (Tên mạng mà thiết bị của bạn đang kết nối). Ở bên phải, thông tin chi tiết và địa chỉ IP của thiết bị trên mạng sẽ xuất hiện.
  2. Sử dụng địa chỉ IP của thiết bị để kết nối với thiết bị đó qua ADB bằng thiết bị đầu cuối:
$ adb connect <device_ip_address>:5555
  1. Trong cửa sổ thiết bị đầu cuối, hãy chuyển đến thư mục cấp cao nhất cho các mẫu của lớp học lập trình mà bạn đã tải xuống khi bắt đầu lớp học lập trình này. Ví dụ:
$ cd Desktop/chrome_codelab_src
  1. Cài đặt tệp .apk trong thư mục này vào Android TV bằng cách chạy:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Giờ đây, bạn sẽ thấy một ứng dụng có tên là Truyền video trong trình đơn Ứng dụng của bạn trên thiết bị Android TV.
  2. Chạy mã nguồn người gửi web đã cập nhật và thiết lập một phiên truyền với thiết bị Android TV bằng biểu tượng truyền hoặc chọn Cast.. trong trình đơn thả xuống của trình duyệt Chrome. Thao tác này sẽ khởi chạy ứng dụng cho Android TV trên Bộ thu Android và cho phép bạn điều khiển quá trình phát bằng điều khiển từ xa của Android TV.

8. Xin chúc mừng

Giờ đây, bạn đã biết cách bật tính năng truyền cho một ứng dụng video bằng cách sử dụng các tiện ích Cast SDK trên một ứng dụng web Chrome.

Để biết thêm thông tin chi tiết, hãy xem hướng dẫn dành cho nhà phát triển Web Sender.