diff --git a/src/app/html-video-player/html-video-player.component.html b/src/app/html-video-player/html-video-player.component.html
new file mode 100644
index 000000000..2c9a82ce5
--- /dev/null
+++ b/src/app/html-video-player/html-video-player.component.html
@@ -0,0 +1,7 @@
+
diff --git a/src/app/html-video-player/html-video-player.component.scss b/src/app/html-video-player/html-video-player.component.scss
new file mode 100644
index 000000000..7891abef6
--- /dev/null
+++ b/src/app/html-video-player/html-video-player.component.scss
@@ -0,0 +1,4 @@
+#video-player {
+ width: 100%;
+ height: calc(100vh - 100px);
+}
\ No newline at end of file
diff --git a/src/app/html-video-player/html-video-player.component.spec.ts b/src/app/html-video-player/html-video-player.component.spec.ts
new file mode 100644
index 000000000..ad6da5de6
--- /dev/null
+++ b/src/app/html-video-player/html-video-player.component.spec.ts
@@ -0,0 +1,45 @@
+/* eslint-disable @typescript-eslint/unbound-method */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { SimpleChange } from '@angular/core';
+
+import { HtmlVideoPlayerComponent } from './html-video-player.component';
+
+describe('HtmlVideoPlayerComponent', () => {
+ let component: HtmlVideoPlayerComponent;
+ let fixture: ComponentFixture;
+ const TEST_CHANNEL = {
+ id: '1234',
+ url: 'http://test',
+ name: 'Test channel',
+ group: {
+ title: 'News group',
+ },
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [HtmlVideoPlayerComponent],
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HtmlVideoPlayerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should call play channel function after input changes', () => {
+ spyOn(component, 'playChannel');
+ component.ngOnChanges({
+ channel: new SimpleChange(null, TEST_CHANNEL, true),
+ });
+ fixture.detectChanges();
+
+ expect(component.playChannel).toBeCalledTimes(1);
+ expect(component.playChannel).toBeCalledWith(TEST_CHANNEL);
+ });
+});
diff --git a/src/app/html-video-player/html-video-player.component.ts b/src/app/html-video-player/html-video-player.component.ts
new file mode 100644
index 000000000..aea783cde
--- /dev/null
+++ b/src/app/html-video-player/html-video-player.component.ts
@@ -0,0 +1,61 @@
+import {
+ Component,
+ ElementRef,
+ Input,
+ OnChanges,
+ SimpleChanges,
+ ViewChild,
+} from '@angular/core';
+import { Channel } from 'app/state';
+import * as Hls from 'hls.js';
+
+@Component({
+ selector: 'app-html-video-player',
+ templateUrl: './html-video-player.component.html',
+ styleUrls: ['./html-video-player.component.scss'],
+})
+export class HtmlVideoPlayerComponent implements OnChanges {
+ /** Channel to play */
+ @Input() channel: Channel;
+
+ /** Video player DOM element */
+ @ViewChild('videoPlayer', { static: false })
+ videoPlayer: ElementRef;
+
+ /** HLS object */
+ hls = new Hls();
+
+ /**
+ * Listen for component input changes
+ * @param changes component changes
+ */
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.channel && changes.channel.currentValue) {
+ this.playChannel(changes.channel.currentValue);
+ }
+ }
+
+ /**
+ * Starts to play the given channel
+ * @param channel given channel object
+ */
+ playChannel(channel: Channel): void {
+ if (Hls.isSupported()) {
+ console.log('... switching channel to ', channel.name, channel.url);
+ this.hls.loadSource(channel.url);
+ this.hls.attachMedia(this.videoPlayer.nativeElement);
+ } else if (
+ this.videoPlayer.nativeElement.canPlayType(
+ 'application/vnd.apple.mpegurl'
+ )
+ ) {
+ this.videoPlayer.nativeElement.src = channel.url;
+ this.videoPlayer.nativeElement.addEventListener(
+ 'loadedmetadata',
+ () => {
+ this.videoPlayer.nativeElement.play();
+ }
+ );
+ }
+ }
+}