Play HLS with Exoplayer on Android (#6606)

This commit is contained in:
uvjustin 2020-08-24 17:50:40 +08:00 committed by GitHub
parent 1e477226ea
commit d263b19910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 14 deletions

View File

@ -12,6 +12,8 @@ import {
import { fireEvent } from "../common/dom/fire_event";
import { computeStateName } from "../common/entity/compute_state_name";
import { supportsFeature } from "../common/entity/supports-feature";
import { nextRender } from "../common/util/render-status";
import { getExternalConfig } from "../external_app/external_config";
import {
CAMERA_SUPPORT_STREAM,
computeMJPEGStreamUrl,
@ -37,6 +39,8 @@ class HaCameraStream extends LitElement {
private _hlsPolyfillInstance?: Hls;
private _useExoPlayer = false;
public connectedCallback() {
super.connectedCallback();
this._attached = true;
@ -125,22 +129,33 @@ class HaCameraStream extends LitElement {
return this.shadowRoot!.querySelector("video")!;
}
private async _getUseExoPlayer(): Promise<boolean> {
if (!this.hass!.auth.external) {
return false;
}
const externalConfig = await getExternalConfig(this.hass!.auth.external);
return externalConfig && externalConfig.hasExoPlayer;
}
private async _startHls(): Promise<void> {
// eslint-disable-next-line
const Hls = ((await import(
/* webpackChunkName: "hls.js" */ "hls.js"
)) as any).default as HLSModule;
let hlsSupported = Hls.isSupported();
let hls;
const videoEl = this._videoEl;
this._useExoPlayer = await this._getUseExoPlayer();
if (!this._useExoPlayer) {
hls = ((await import(/* webpackChunkName: "hls.js" */ "hls.js")) as any)
.default as HLSModule;
let hlsSupported = hls.isSupported();
if (!hlsSupported) {
hlsSupported =
videoEl.canPlayType("application/vnd.apple.mpegurl") !== "";
}
if (!hlsSupported) {
hlsSupported =
videoEl.canPlayType("application/vnd.apple.mpegurl") !== "";
}
if (!hlsSupported) {
this._forceMJPEG = this.stateObj!.entity_id;
return;
if (!hlsSupported) {
this._forceMJPEG = this.stateObj!.entity_id;
return;
}
}
try {
@ -149,8 +164,10 @@ class HaCameraStream extends LitElement {
this.stateObj!.entity_id
);
if (Hls.isSupported()) {
this._renderHLSPolyfill(videoEl, Hls, url);
if (this._useExoPlayer) {
this._renderHLSExoPlayer(url);
} else if (hls.isSupported()) {
this._renderHLSPolyfill(videoEl, hls, url);
} else {
this._renderHLSNative(videoEl, url);
}
@ -163,6 +180,29 @@ class HaCameraStream extends LitElement {
}
}
private async _renderHLSExoPlayer(url: string) {
window.addEventListener("resize", this._resizeExoPlayer);
this.updateComplete.then(() => nextRender()).then(this._resizeExoPlayer);
this._videoEl.style.visibility = "hidden";
await this.hass!.auth.external!.sendMessage({
type: "exoplayer/play_hls",
payload: new URL(url, window.location.href).toString(),
});
}
private _resizeExoPlayer = () => {
const rect = this._videoEl.getBoundingClientRect();
this.hass!.auth.external!.fireMessage({
type: "exoplayer/resize",
payload: {
left: rect.left,
top: rect.top,
right: rect.right,
bottom: rect.bottom,
},
});
};
private async _renderHLSNative(videoEl: HTMLVideoElement, url: string) {
videoEl.src = url;
await new Promise((resolve) =>
@ -194,11 +234,15 @@ class HaCameraStream extends LitElement {
fireEvent(this, "iron-resize");
}
private _destroyPolyfill(): void {
private _destroyPolyfill() {
if (this._hlsPolyfillInstance) {
this._hlsPolyfillInstance.destroy();
this._hlsPolyfillInstance = undefined;
}
if (this._useExoPlayer) {
window.removeEventListener("resize", this._resizeExoPlayer);
this.hass!.auth.external!.fireMessage({ type: "exoplayer/stop" });
}
}
static get styles(): CSSResult {

View File

@ -3,6 +3,7 @@ import { ExternalMessaging } from "./external_messaging";
export interface ExternalConfig {
hasSettingsScreen: boolean;
canWriteTag: boolean;
hasExoPlayer: boolean;
}
export const getExternalConfig = (