From f5d1d86b2df5f605644c46b2f3cfed4e44f2208e Mon Sep 17 00:00:00 2001 From: jojohoch <joachim.hoch@iqb.hu-berlin.de> Date: Wed, 10 Nov 2021 14:37:35 +0100 Subject: [PATCH] [player] Use service to prevent simultaneous media playback --- .../element-components/audio.component.ts | 3 +++ .../control-bar/control-bar.component.html | 10 ++++----- .../control-bar/control-bar.component.ts | 3 ++- ...edia-player-element-component.directive.ts | 8 +++++++ .../element-container.component.ts | 21 +++++++++++++++++++ .../src/app/services/media-player.service.ts | 17 +++++++++++++++ 6 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 projects/player/src/app/services/media-player.service.ts diff --git a/projects/common/element-components/audio.component.ts b/projects/common/element-components/audio.component.ts index 582bdfa8e..314eea51c 100644 --- a/projects/common/element-components/audio.component.ts +++ b/projects/common/element-components/audio.component.ts @@ -8,11 +8,14 @@ import { MediaPlayerElementComponent } from '../media-player-element-component.d <div [style.width.%]="100" [style.height.%]="100"> <audio #player + (playing)="mediaPlay.emit(this.elementModel.id)" + (pause)="mediaPause.emit(this.elementModel.id)" [style.width.%]="100" [src]="elementModel.src | safeResourceUrl"> </audio> <app-control-bar [player]="player" [elementModel]="elementModel" + [active]="active" (playbackTimeChanged)="playbackTimeChanged.emit($event)"> </app-control-bar> </div> diff --git a/projects/common/element-components/control-bar/control-bar.component.html b/projects/common/element-components/control-bar/control-bar.component.html index 3867441e3..0a475b307 100644 --- a/projects/common/element-components/control-bar/control-bar.component.html +++ b/projects/common/element-components/control-bar/control-bar.component.html @@ -4,9 +4,9 @@ <button *ngIf="!playing || !elementModel.pauseControl" mat-button class="control-button" - [class.enabled-control]="!disabled" + [class.enabled-control]="!disabled && active" [class.active-control]="playing" - [disabled]="disabled" + [disabled]="disabled || !active" (click)="play($event)"> <mat-icon>play_arrow</mat-icon> </button> @@ -15,9 +15,9 @@ <button *ngIf="playing" mat-button class="control-button" - [class.enabled-control]="!disabled" + [class.enabled-control]="!disabled && active" [class.active-control]="pausing" - [disabled]="disabled" + [disabled]="disabled || !active" (click)="pause($event)"> <mat-icon>pause</mat-icon> </button> @@ -33,7 +33,7 @@ step="1" [max]="player.duration" [value]="player.currentTime" - [disabled]="disabled || !elementModel.interactiveProgressbar" + [disabled]="disabled || !elementModel.interactiveProgressbar || !active" (input)="onTimeChange($event)"> </mat-slider> </ng-container> diff --git a/projects/common/element-components/control-bar/control-bar.component.ts b/projects/common/element-components/control-bar/control-bar.component.ts index 2c684cee7..4c81b1fce 100644 --- a/projects/common/element-components/control-bar/control-bar.component.ts +++ b/projects/common/element-components/control-bar/control-bar.component.ts @@ -14,6 +14,7 @@ import { ValueChangeElement } from '../../models/uI-element'; export class ControlBarComponent implements OnInit, AfterContentInit, OnDestroy { @Input() player!: HTMLVideoElement | HTMLAudioElement; @Input() elementModel!: AudioElement | VideoElement; + @Input() active!: boolean; @Output() playbackTimeChanged = new EventEmitter<ValueChangeElement>(); duration!: number; currentTime!: number; @@ -141,7 +142,7 @@ export class ControlBarComponent implements OnInit, AfterContentInit, OnDestroy private _play(): void { this.player.play().then(() => {}, // eslint-disable-next-line no-console - () => console.error('error')); + () => console.error('player: cannot play this media file')); } private sendPlaybackTimeChanged() { diff --git a/projects/common/media-player-element-component.directive.ts b/projects/common/media-player-element-component.directive.ts index fd1875481..9b29d9d1c 100644 --- a/projects/common/media-player-element-component.directive.ts +++ b/projects/common/media-player-element-component.directive.ts @@ -5,4 +5,12 @@ import { ElementComponent } from './element-component.directive'; @Directive() export abstract class MediaPlayerElementComponent extends ElementComponent { @Output() playbackTimeChanged = new EventEmitter<ValueChangeElement>(); + @Output() mediaPlay = new EventEmitter<string>(); + @Output() mediaPause = new EventEmitter<string>(); + + active: boolean = true; + + setActualPlayingMediaId(id: string | null): void { + this.active = !id || id === this.elementModel.id; + } } diff --git a/projects/player/src/app/components/element-container/element-container.component.ts b/projects/player/src/app/components/element-container/element-container.component.ts index c95a4fcb6..2e8e186e6 100644 --- a/projects/player/src/app/components/element-container/element-container.component.ts +++ b/projects/player/src/app/components/element-container/element-container.component.ts @@ -28,6 +28,8 @@ import { VideoElement } from '../../../../../common/models/video-element'; import { AudioElement } from '../../../../../common/models/audio-element'; import { ImageElement } from '../../../../../common/models/image-element'; import { VeronaPostService } from '../../services/verona-post.service'; +import { MediaPlayerElementComponent } from '../../../../../common/media-player-element-component.directive'; +import { MediaPlayerService } from '../../services/media-player.service'; @Component({ selector: 'app-element-container', @@ -54,6 +56,7 @@ export class ElementContainerComponent implements OnInit { private unitStateService: UnitStateService, private formBuilder: FormBuilder, private veronaPostService: VeronaPostService, + private mediaPlayerService: MediaPlayerService, private markingService: MarkingService) { } @@ -98,6 +101,22 @@ export class ElementContainerComponent implements OnInit { }); } + if (elementComponent.mediaPause) { + elementComponent.mediaPause + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe(() => { + this.mediaPlayerService.broadCastPlayChanges(null); + }); + } + + if (elementComponent.mediaPlay) { + elementComponent.mediaPlay + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe((playId: string) => { + this.mediaPlayerService.broadCastPlayChanges(playId); + }); + } + if (elementComponent.applySelection) { elementComponent.applySelection .pipe(takeUntil(this.ngUnsubscribe)) @@ -181,6 +200,8 @@ export class ElementContainerComponent implements OnInit { formGroup: elementForm }); }); + } else if (elementComponent instanceof MediaPlayerElementComponent) { + this.mediaPlayerService.registerMediaElement(elementComponent); } } diff --git a/projects/player/src/app/services/media-player.service.ts b/projects/player/src/app/services/media-player.service.ts new file mode 100644 index 000000000..ff0df1433 --- /dev/null +++ b/projects/player/src/app/services/media-player.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { MediaPlayerElementComponent } from '../../../../common/media-player-element-component.directive'; + +@Injectable({ + providedIn: 'root' +}) +export class MediaPlayerService { + mediaElements: MediaPlayerElementComponent[] = []; + + registerMediaElement(mediaElement: MediaPlayerElementComponent): void { + this.mediaElements.push(mediaElement); + } + + broadCastPlayChanges(actualId: string | null): void { + this.mediaElements.forEach(mediaElement => mediaElement.setActualPlayingMediaId(actualId)); + } +} -- GitLab