Tạo ứng dụng bằng Sencha Ext JS

Mục tiêu của tài liệu này là giúp bạn bắt đầu xây dựng Ứng dụng Chrome bằng Sencha Ext JS khung. Để đạt được mục tiêu này, chúng ta sẽ đi sâu vào một ứng dụng đa phương tiện do Sencha phát triển. Nguồn mãTài liệu API đều có trên GitHub.

Ứng dụng này phát hiện các máy chủ đa phương tiện hiện có của người dùng, bao gồm cả các thiết bị đa phương tiện được kết nối với máy tính và giúp quản lý phương tiện truyền thông qua mạng. Người dùng có thể duyệt qua nội dung nghe nhìn, phát qua mạng hoặc lưu ngoại tuyến.

Dưới đây là những việc chính bạn phải làm để tạo ứng dụng trình phát nội dung đa phương tiện bằng Sencha Ext JS:

  • Tạo tệp kê khai, manifest.json.
  • Tạo trang sự kiện, background.js.
  • Logic của ứng dụng Hộp cát.
  • Giao tiếp giữa ứng dụng Chrome và các tệp hộp cát.
  • Khám phá máy chủ nội dung nghe nhìn.
  • Khám phá và phát nội dung nghe nhìn.
  • Lưu nội dung nghe nhìn để xem khi không có mạng.

Tạo tệp kê khai

Tất cả ứng dụng Chrome đều yêu cầu một tệp kê khai chứa thông tin mà Chrome cần để khởi chạy của chúng tôi. Như thể hiện trong tệp kê khai, ứng dụng trình phát nội dung đa phương tiện có trạng thái "offline_enabled"; nội dung nghe nhìn có thể là được lưu cục bộ, truy cập và phát bất kể kết nối.

"Hộp cát" trường này dùng để hộp cát logic chính của ứng dụng trong một nguồn gốc duy nhất. Tất cả đều ở dạng hộp cát nội dung được miễn trừ khỏi Chính sách bảo mật nội dung của ứng dụng Chrome, nhưng không thể truy cập trực tiếp vào API ứng dụng Chrome. Tệp kê khai cũng bao gồm "socket" quyền; ứng dụng trình phát nội dung đa phương tiện sẽ sử dụng socket API để kết nối với một máy chủ đa phương tiện qua mạng.

{
    "name": "Video Player",
    "description": "Features network media discovery and playlist management",
    "version": "1.0.0",
    "manifest_version": 2,
    "offline_enabled": true,
    "app": {
        "background": {
            "scripts": [
                "background.js"
            ]
        }
    },
    ...

    "sandbox": {
        "pages": ["sandbox.html"]
    },
    "permissions": [
        "experimental",
        "http://*/*",
        "unlimitedStorage",
        {
            "socket": [
                "tcp-connect",
                "udp-send-to",
                "udp-bind"
            ]
        }
    ]
}

Tạo trang sự kiện

Tất cả ứng dụng Chrome đều cần có background.js để chạy ứng dụng này. Trang chính của trình phát đa phương tiện, index.html, mở trong một cửa sổ có kích thước được chỉ định:

chrome.app.runtime.onLaunched.addListener(function(launchData) {
    var opt = {
        width: 1000,
        height: 700
    };

    chrome.app.window.create('index.html', opt, function (win) {
        win.launchData = launchData;
    });

});

Logic của ứng dụng Sandbox

Ứng dụng Chrome chạy trong môi trường được kiểm soát và thực thi một Chính sách bảo mật nội dung nghiêm ngặt (CSP). Ứng dụng trình phát nội dung đa phương tiện cần một số đặc quyền cao hơn để kết xuất các thành phần Ext JS. Người nhận tuân thủ CSP và thực thi logic của ứng dụng, trang chính của ứng dụng index.html sẽ tạo một iframe hoạt động như một môi trường hộp cát:

<iframe id="sandbox-frame" sandbox="allow-scripts" src="sandbox.html"></iframe>

Iframe trỏ đến sandbox.html, bao gồm các tệp cần thiết cho phần Ext JS ứng dụng:

<html>
<head>
    <link rel="stylesheet" type="text/css" href="resources/css/app.css" />'
    <script src="sdk/ext-all-dev.js"></script>'
    <script src="lib/ext/data/PostMessage.js"></script>'
    <script src="lib/ChromeProxy.js"></script>'
    <script src="app.js"></script>
</head>
<body></body>
</html>

Tập lệnh app.js thực thi tất cả mã Ext JS và hiển thị chế độ xem trình phát nội dung đa phương tiện. Từ ngày này tập lệnh là hộp cát, không thể truy cập trực tiếp vào API Ứng dụng Chrome. Liên lạc giữa app.js và các tệp không có hộp cát được hoàn tất bằng cách sử dụng HTML5 Post Message API.

Giao tiếp giữa các tệp

Để ứng dụng trình phát nội dung đa phương tiện truy cập vào API ứng dụng Chrome, chẳng hạn như truy vấn mạng cho nội dung nghe nhìn máy chủ, app.js sẽ đăng thông báo lên index.js. Không giống như app.js hộp cát, index.js có thể truy cập trực tiếp vào API Ứng dụng Chrome.

index.js tạo iframe:

var iframe = document.getElementById('sandbox-frame');

iframeWindow = iframe.contentWindow;

Và lắng nghe tin nhắn từ các tệp hộp cát:

window.addEventListener('message', function(e) {
    var data= e.data,
        key = data.key;

    console.log('[index.js] Post Message received with key ' + key);

    switch (key) {
        case 'extension-baseurl':
            extensionBaseUrl(data);
            break;

        case 'upnp-discover':
            upnpDiscover(data);
            break;

        case 'upnp-browse':
            upnpBrowse(data);
            break;

        case 'play-media':
            playMedia(data);
            break;

        case 'download-media':
            downloadMedia(data);
            break;

        case 'cancel-download':
            cancelDownload(data);
            break;

        default:
            console.log('[index.js] unidentified key for Post Message: "' + key + '"');
    }
}, false);

Trong ví dụ sau, app.js gửi tin nhắn đến index.js để yêu cầu khoá "extension-baseurl":

Ext.data.PostMessage.request({
    key: 'extension-baseurl',
    success: function(data) {
        //...
    }
});

index.js nhận yêu cầu, chỉ định kết quả và phản hồi bằng cách gửi lại URL cơ sở:

function extensionBaseUrl(data) {
    data.result = chrome.extension.getURL('/');
    iframeWindow.postMessage(data, '*');
}

Khám phá máy chủ nội dung nghe nhìn

Có rất nhiều việc cần làm để khám phá các máy chủ phương tiện. Nhìn chung, quy trình khám phá là do người dùng thực hiện để tìm kiếm máy chủ nội dung nghe nhìn có sẵn. Bộ điều khiển MediaServer đăng tin nhắn lên index.js; index.js lắng nghe tin nhắn này và khi nhận được, cuộc gọi Upnp.js.

Upnp library sử dụng API ổ cắm của ứng dụng Chrome để kết nối ứng dụng trình phát nội dung nghe nhìn với bất kỳ khám phá máy chủ phương tiện và nhận dữ liệu phương tiện từ máy chủ phương tiện. Upnp.js cũng sử dụng soapclient.js để phân tích cú pháp dữ liệu máy chủ nội dung nghe nhìn. Phần còn lại của phần này mô tả điều này quy trình làm việc một cách chi tiết hơn.

Đăng tin nhắn

Khi người dùng nhấp vào nút Máy chủ nội dung đa phương tiện ở giữa ứng dụng trình phát nội dung đa phương tiện, MediaServers.js gọi discoverServers(). Trước tiên, hàm này kiểm tra xem có yêu cầu khám phá nào chưa xử lý hay không và true, huỷ chúng để có thể khởi tạo yêu cầu mới. Tiếp theo, bộ điều khiển sẽ đăng thông báo lên index.js với một key upnp-Discovery và 2 trình nghe gọi lại:

me.activeDiscoverRequest = Ext.data.PostMessage.request({
    key: 'upnp-discover',
    success: function(data) {
        var items = [];
        delete me.activeDiscoverRequest;

        if (serversGraph.isDestroyed) {
            return;
        }

        mainBtn.isLoading = false;
        mainBtn.removeCls('pop-in');
        mainBtn.setIconCls('ico-server');
        mainBtn.setText('Media Servers');

        //add servers
        Ext.each(data, function(server) {
            var icon,
                urlBase = server.urlBase;

            if (urlBase) {
                if (urlBase.substr(urlBase.length-1, 1) === '/'){
                        urlBase = urlBase.substr(0, urlBase.length-1);
                }
            }

            if (server.icons && server.icons.length) {
                if (server.icons[1]) {
                    icon = server.icons[1].url;
                }
                else {
                    icon = server.icons[0].url;
                }

                icon = urlBase + icon;
            }

            items.push({
                itemId: server.id,
                text: server.friendlyName,
                icon: icon,
                data: server
            });
        });

        ...
    },
    failure: function() {
        delete me.activeDiscoverRequest;

        if (serversGraph.isDestroyed) {
            return;
        }

        mainBtn.isLoading = false;
        mainBtn.removeCls('pop-in');
        mainBtn.setIconCls('ico-error');
        mainBtn.setText('Error...click to retry');
    }
});

Gọi upnpExplore()

index.js đang nghe bài hát "upnp-Explore" tin nhắn từ app.js và trả lời bằng cách gọi upnpDiscover(). Khi phát hiện một máy chủ nội dung nghe nhìn, index.js sẽ trích xuất miền máy chủ nội dung nghe nhìn từ các tham số, lưu máy chủ cục bộ, định dạng dữ liệu máy chủ truyền thông và đẩy dữ liệu vào bộ điều khiển MediaServer.

Phân tích cú pháp dữ liệu máy chủ đa phương tiện

Khi phát hiện thấy một máy chủ nội dung nghe nhìn mới, Upnp.js sẽ truy xuất nội dung mô tả về thiết bị và gửi một Soaprequest để duyệt qua và phân tích cú pháp dữ liệu máy chủ đa phương tiện; soapclient.js phân tích cú pháp các thành phần đa phương tiện theo tên thẻ vào một tài liệu.

Kết nối với máy chủ nội dung nghe nhìn

Upnp.js kết nối với các máy chủ nội dung nghe nhìn đã khám phá và nhận dữ liệu nội dung nghe nhìn bằng cổng cắm Ứng dụng Chrome API:

socket.create("udp", {}, function(info) {
    var socketId = info.socketId;

    //bind locally
    socket.bind(socketId, "0.0.0.0", 0, function(info) {

        //pack upnp message
        var message = String.toBuffer(UPNP_MESSAGE);

        //broadcast to upnp
        socket.sendTo(socketId, message, UPNP_ADDRESS, UPNP_PORT, function(info) {

            // Wait 1 second
            setTimeout(function() {

                //receive
                socket.recvFrom(socketId, function(info) {

                    //unpack message
                    var data        = String.fromBuffer(info.data),
                        servers     = [],
                        locationReg = /^location:/i;

                    //extract location info
                    if (data) {
                        data = data.split("\r\n");

                        data.forEach(function(value) {
                            if (locationReg.test(value)){
                                servers.push(value.replace(locationReg, "").trim());
                            }
                        });
                    }

                    //success
                    callback(servers);
                });

            }, 1000);
        });
    });
});

Khám phá và phát nội dung nghe nhìn

Bộ điều khiển Media Explorer liệt kê tất cả tệp đa phương tiện bên trong thư mục máy chủ đa phương tiện và chịu trách nhiệm cập nhật điều hướng breadcrumb (tập hợp liên kết phân cấp) trong cửa sổ ứng dụng trình phát nội dung đa phương tiện. Khi một người dùng chọn một tệp nội dung nghe nhìn, tay điều khiển sẽ đăng một thông báo cho index.js kèm theo nút "play-media" khoá:

onFileDblClick: function(explorer, record) {
    var serverPanel, node,
        type    = record.get('type'),
        url     = record.get('url'),
        name    = record.get('name'),
        serverId= record.get('serverId');

    if (type === 'audio' || type === 'video') {
        Ext.data.PostMessage.request({
            key     : 'play-media',
            params  : {
                url: url,
                name: name,
                type: type
            }
        });
    }
},

index.js nghe tin nhắn bài đăng này và trả lời bằng cách gọi playMedia():

function playMedia(data) {
    var type        = data.params.type,
        url         = data.params.url,
        playerCt    = document.getElementById('player-ct'),
        audioBody   = document.getElementById('audio-body'),
        videoBody   = document.getElementById('video-body'),
        mediaEl     = playerCt.getElementsByTagName(type)[0],
        mediaBody   = type === 'video' ? videoBody : audioBody,
        isLocal     = false;

    //save data
    filePlaying = {
        url : url,
        type: type,
        name: data.params.name
    };

    //hide body els
    audioBody.style.display = 'none';
    videoBody.style.display = 'none';

    var animEnd = function(e) {

        //show body el
        mediaBody.style.display = '';

        //play media
        mediaEl.play();

        //clear listeners
        playerCt.removeEventListener( 'transitionend', animEnd, false );
        animEnd = null;
    };

    //load media
    mediaEl.src = url;
    mediaEl.load();

    //animate in player
    playerCt.addEventListener( 'transitionend', animEnd, false );
    playerCt.style.transform = "translateY(0)";

    //reply postmessage
    data.result = true;
    sendMessage(data);
}

Lưu nội dung nghe nhìn để xem khi không có mạng

Hầu hết các công việc khó khăn để lưu nội dung nghe nhìn khi không có mạng đều được thực hiện thông qua thư viện filer.js. Bạn có thể đọc thêm thư viện này trong phần Giới thiệu tệpr.js.

Quá trình này bắt đầu khi người dùng chọn một hoặc nhiều tệp và bắt đầu thao tác "Tải ngoại tuyến" hành động. Trình điều khiển Media Explorer sẽ đăng một thông báo cho index.js kèm theo khoá "download-media"; index.js sẽ lắng nghe thông báo này và gọi hàm downloadMedia() để bắt đầu quá trình tải xuống:

function downloadMedia(data) {
        DownloadProcess.run(data.params.files, function() {
            data.result = true;
            sendMessage(data);
        });
    }

Phương thức tiện ích DownloadProcess tạo một yêu cầu xhr để lấy dữ liệu từ máy chủ đa phương tiện và để chờ trạng thái hoàn thành. Thao tác này sẽ bắt đầu lệnh gọi lại khi đang tải để kiểm tra nội dung đã nhận và lưu dữ liệu trên máy bằng cách sử dụng hàm filer.js:

filer.write(
    saveUrl,
    {
        data: Util.arrayBufferToBlob(fileArrayBuf),
        type: contentType
    },
    function(fileEntry, fileWriter) {

        console.log('file saved!');

        //increment downloaded
        me.completedFiles++;

        //if reached the end, finalize the process
        if (me.completedFiles === me.totalFiles) {

            sendMessage({
                key             : 'download-progresss',
                totalFiles      : me.totalFiles,
                completedFiles  : me.completedFiles
            });

            me.completedFiles = me.totalFiles = me.percentage = me.downloadedFiles = 0;
            delete me.percentages;

            //reload local
            loadLocalFiles(callback);
        }
    },
    function(e) {
        console.log(e);
    }
);

Khi quá trình tải xuống hoàn tất, MediaExplorer sẽ cập nhật danh sách tệp nội dung nghe nhìn và nội dung nghe nhìn bảng điều khiển cây trình phát.