mirror of https://github.com/OpenVidu/openvidu.git
ov-components: add recordingStreamBaseUrl directive and integrate with config service for dynamic stream URL construction
parent
6137bdbbbc
commit
90fd0ef44e
|
@ -36,6 +36,7 @@ import {
|
|||
MinimalDirective,
|
||||
ParticipantNameDirective,
|
||||
PrejoinDirective,
|
||||
RecordingStreamBaseUrlDirective,
|
||||
TokenDirective,
|
||||
TokenErrorDirective,
|
||||
VideoEnabledDirective
|
||||
|
@ -56,6 +57,7 @@ import {
|
|||
PrejoinDisplayParticipantName,
|
||||
VideoEnabledDirective,
|
||||
AudioEnabledDirective,
|
||||
RecordingStreamBaseUrlDirective,
|
||||
ToolbarCameraButtonDirective,
|
||||
ToolbarMicrophoneButtonDirective,
|
||||
ToolbarScreenshareButtonDirective,
|
||||
|
@ -100,6 +102,7 @@ import {
|
|||
PrejoinDisplayParticipantName,
|
||||
VideoEnabledDirective,
|
||||
AudioEnabledDirective,
|
||||
RecordingStreamBaseUrlDirective,
|
||||
ToolbarCameraButtonDirective,
|
||||
ToolbarMicrophoneButtonDirective,
|
||||
ToolbarScreenshareButtonDirective,
|
||||
|
|
|
@ -725,3 +725,69 @@ export class AudioEnabledDirective implements OnDestroy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **recordingStreamBaseUrl** directive sets the base URL for retrieving recording streams.
|
||||
* The complete request URL is dynamically constructed by concatenating the supplied URL, the
|
||||
* internally managed recordingId, and the `/stream` segment.
|
||||
*
|
||||
* The final URL format will be:
|
||||
*
|
||||
* {recordingStreamBaseUrl}/{recordingId}/stream
|
||||
*
|
||||
* Default: `"/{recordingId}/stream"`
|
||||
*
|
||||
* It is essential that the resulting route is declared and configured on your backend, as it is
|
||||
* used for serving and accessing the recording streams.
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [recordingStreamBaseUrl]="'https://myserver.com/api/recordings'">
|
||||
* </ov-videoconference>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[recordingStreamBaseUrl]'
|
||||
})
|
||||
export class RecordingStreamBaseUrlDirective implements AfterViewInit, OnDestroy {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set recordingStreamBaseUrl(url: string) {
|
||||
this.update(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
constructor(
|
||||
private elementRef: ElementRef,
|
||||
private libService: OpenViduComponentsConfigService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
ngAfterViewInit(): void {
|
||||
this.update(this.recordingStreamBaseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
clear() {
|
||||
this.update('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
update(value: string) {
|
||||
if (value) this.libService.setRecordingStreamBaseUrl(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ export class OpenViduComponentsConfigService {
|
|||
private audioEnabled = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
audioEnabled$: Observable<boolean>;
|
||||
|
||||
private recordingStreamBaseUrl = <BehaviorSubject<string>>new BehaviorSubject('');
|
||||
recordingStreamBaseUrl$: Observable<string>;
|
||||
|
||||
//Toolbar settings
|
||||
private cameraButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
cameraButton$: Observable<boolean>;
|
||||
|
@ -121,6 +124,7 @@ export class OpenViduComponentsConfigService {
|
|||
this.prejoinDisplayParticipantName$ = this.prejoinDisplayParticipantName.asObservable();
|
||||
this.videoEnabled$ = this.videoEnabled.asObservable();
|
||||
this.audioEnabled$ = this.audioEnabled.asObservable();
|
||||
this.recordingStreamBaseUrl$ = this.recordingStreamBaseUrl.asObservable();
|
||||
//Toolbar observables
|
||||
this.cameraButton$ = this.cameraButton.asObservable();
|
||||
this.microphoneButton$ = this.microphoneButton.asObservable();
|
||||
|
@ -214,6 +218,17 @@ export class OpenViduComponentsConfigService {
|
|||
return this.audioEnabled.getValue();
|
||||
}
|
||||
|
||||
setRecordingStreamBaseUrl(recordingStreamBaseUrl: string) {
|
||||
this.recordingStreamBaseUrl.next(recordingStreamBaseUrl);
|
||||
}
|
||||
|
||||
getRecordingStreamBaseUrl(): string {
|
||||
let baseUrl = this.recordingStreamBaseUrl.getValue();
|
||||
// Add trailing slash if not present
|
||||
baseUrl += baseUrl.endsWith('/') ? '' : '/';
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
//Toolbar settings
|
||||
|
||||
setCameraButton(cameraButton: boolean) {
|
||||
|
|
|
@ -2,7 +2,9 @@ import { Injectable } from '@angular/core';
|
|||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { RecordingInfo, RecordingStatus, RecordingStatusInfo } from '../../models/recording.model';
|
||||
import { ActionService } from '../action/action.service';
|
||||
import { GlobalConfigService } from '../config/global-config.service';
|
||||
import { LoggerService } from '../logger/logger.service';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { OpenViduComponentsConfigService } from '../config/directive-config.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -13,19 +15,19 @@ export class RecordingService {
|
|||
*/
|
||||
recordingStatusObs: Observable<RecordingStatusInfo>;
|
||||
private recordingTimeInterval: NodeJS.Timeout;
|
||||
private API_RECORDINGS_PREFIX = 'call/api/recordings/';
|
||||
private recordingStatus = <BehaviorSubject<RecordingStatusInfo>>new BehaviorSubject({
|
||||
status: RecordingStatus.STOPPED,
|
||||
recordingList: [] as RecordingInfo[],
|
||||
recordingElapsedTime: new Date(0, 0, 0, 0, 0, 0, 0)
|
||||
});
|
||||
private log: ILogger;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(private actionService: ActionService, private globalService: GlobalConfigService) {
|
||||
constructor(private actionService: ActionService, private libService: OpenViduComponentsConfigService, private loggerService: LoggerService) {
|
||||
this.log = this.loggerService.get('RecordingService');
|
||||
this.recordingStatusObs = this.recordingStatus.asObservable();
|
||||
this.API_RECORDINGS_PREFIX = this.globalService.getBaseHref() + this.API_RECORDINGS_PREFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,9 +148,10 @@ export class RecordingService {
|
|||
*/
|
||||
playRecording(recording: RecordingInfo) {
|
||||
// Only COMPOSED recording is supported. The extension will allways be 'mp4'.
|
||||
console.log('Playing recording', recording);
|
||||
this.log.d('Playing recording', recording);
|
||||
const queryParamForAvoidCache = `?t=${new Date().getTime()}`;
|
||||
const streamRecordingUrl = `${this.API_RECORDINGS_PREFIX}${recording.id}/stream${queryParamForAvoidCache}`;
|
||||
const baseUrl = this.libService.getRecordingStreamBaseUrl();
|
||||
const streamRecordingUrl = `${baseUrl}${recording.id}/stream${queryParamForAvoidCache}`;
|
||||
this.actionService.openRecordingPlayerDialog(streamRecordingUrl);
|
||||
}
|
||||
|
||||
|
@ -161,7 +164,8 @@ export class RecordingService {
|
|||
// Only COMPOSED recording is supported. The extension will allways be 'mp4'.
|
||||
const queryParamForAvoidCache = `?t=${new Date().getTime()}`;
|
||||
const link = document.createElement('a');
|
||||
link.href = `${this.API_RECORDINGS_PREFIX}${recording.id}/stream${queryParamForAvoidCache}`;
|
||||
const baseUrl = this.libService.getRecordingStreamBaseUrl();
|
||||
link.href = `${baseUrl}${recording.id}/stream${queryParamForAvoidCache}`;
|
||||
link.download = recording.filename || 'openvidu-recording.mp4';
|
||||
link.dispatchEvent(
|
||||
new MouseEvent('click', {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[participantName]="'Participant'"
|
||||
[videoEnabled]="true"
|
||||
[audioEnabled]="true"
|
||||
[recordingStreamBaseUrl]="'call/api/recordings'"
|
||||
[toolbarCameraButton]="true"
|
||||
[toolbarMicrophoneButton]="true"
|
||||
[toolbarScreenshareButton]="true"
|
||||
|
|
Loading…
Reference in New Issue