[A] basic recordrtc integration
This commit is contained in:
parent
403277c6df
commit
34c03f7402
8 changed files with 133 additions and 46 deletions
5
package-lock.json
generated
5
package-lock.json
generated
|
|
@ -12425,6 +12425,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"recordrtc": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/recordrtc/-/recordrtc-5.6.1.tgz",
|
||||
"integrity": "sha512-UU7Fd9IIuz60TPq4GgL1qtgo2mzEZWzPxEraNe32eo4/ndjKmuj715HB7W1k63G09teM1dXJYubPEmLkQ/lq5Q=="
|
||||
},
|
||||
"redis": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"@ng-bootstrap/ng-bootstrap": "7.0.0",
|
||||
"bootstrap": "4.5.2",
|
||||
"core-js": "3.6.4",
|
||||
"recordrtc": "^5.6.1",
|
||||
"rxjs": "6.5.4",
|
||||
"tslib": "1.13.0",
|
||||
"zone.js": "0.10.2"
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
</nav>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ah-recorder></ah-recorder>
|
||||
</div>
|
||||
<div *ngFor="let user of users" class="col p-3">
|
||||
<div class="text-center" (click)="playStory(user)">
|
||||
<div
|
||||
class="storyImage"
|
||||
style="background-image: url({{user.image}})"
|
||||
[ngClass]="{'hasStory': user.story_link && user.submit_time}"
|
||||
></div>
|
||||
<div class="storyImage" style="background-image: url({{user.image}})"
|
||||
[ngClass]="{'hasStory': user.story_link && user.submit_time}"></div>
|
||||
<p class="mt-2 mb-0"><strong>{{user.name}}</strong></p>
|
||||
<p><small>{{user.submit_time | date :'dd.MM. HH:mm' }}</small></p>
|
||||
</div>
|
||||
|
|
@ -21,60 +21,29 @@
|
|||
<div class="modal-body d-flex flex-column">
|
||||
<div class="btn-group mb-2" role="group" aria-label="Basic example">
|
||||
<button type="button" class="btn btn-secondary" (click)="prevUser(modal)">
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 17L10 12L18 7V17Z" fill="currentColor" />
|
||||
<path d="M6 7H9V17H6V7Z" fill="currentColor" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
(click)="modal.dismiss('Cross click')"
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<button type="button" class="btn btn-secondary" (click)="modal.dismiss('Cross click')">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.2253 4.81108C5.83477 4.42056 5.20161 4.42056 4.81108 4.81108C4.42056 5.20161 4.42056 5.83477 4.81108 6.2253L10.5858 12L4.81114 17.7747C4.42062 18.1652 4.42062 18.7984 4.81114 19.1889C5.20167 19.5794 5.83483 19.5794 6.22535 19.1889L12 13.4142L17.7747 19.1889C18.1652 19.5794 18.7984 19.5794 19.1889 19.1889C19.5794 18.7984 19.5794 18.1652 19.1889 17.7747L13.4142 12L19.189 6.2253C19.5795 5.83477 19.5795 5.20161 19.189 4.81108C18.7985 4.42056 18.1653 4.42056 17.7748 4.81108L12 10.5858L6.2253 4.81108Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" (click)="nextUser(modal)">
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 17L14 12L6 7V17Z" fill="currentColor" />
|
||||
<path d="M18 7H15V12V17H18V7Z" fill="currentColor" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-center m-0">
|
||||
<strong
|
||||
>{{selectedUser.name}} -
|
||||
<small
|
||||
>{{selectedUser.submit_time | date :'dd.MM. HH:mm' }}</small
|
||||
></strong
|
||||
>
|
||||
<strong>{{selectedUser.name}} -
|
||||
<small>{{selectedUser.submit_time | date :'dd.MM. HH:mm' }}</small></strong>
|
||||
</p>
|
||||
<video
|
||||
[src]="selectedUser.story_link"
|
||||
(ended)="nextUser(modal)"
|
||||
autoplay
|
||||
></video>
|
||||
<video [src]="selectedUser.story_link" (ended)="nextUser(modal)" autoplay></video>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
|
@ -3,9 +3,10 @@ import { NgModule } from "@angular/core";
|
|||
|
||||
import { AppComponent } from "./app.component";
|
||||
import { NgbModalModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { RecorderComponent } from './recorder/recorder.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
declarations: [AppComponent, RecorderComponent],
|
||||
imports: [BrowserModule, NgbModalModule],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
|
|
|
|||
29
src/app/recorder/recorder.component.html
Normal file
29
src/app/recorder/recorder.component.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<button class="btn btn-primary" (click)="openModal()">Record</button>
|
||||
|
||||
|
||||
<ng-template #content let-modal>
|
||||
<div class="modal-body d-flex flex-column">
|
||||
<div>
|
||||
<span class="float-right" (click)="modal.dismiss('Cross click')">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.2253 4.81108C5.83477 4.42056 5.20161 4.42056 4.81108 4.81108C4.42056 5.20161 4.42056 5.83477 4.81108 6.2253L10.5858 12L4.81114 17.7747C4.42062 18.1652 4.42062 18.7984 4.81114 19.1889C5.20167 19.5794 5.83483 19.5794 6.22535 19.1889L12 13.4142L17.7747 19.1889C18.1652 19.5794 18.7984 19.5794 19.1889 19.1889C19.5794 18.7984 19.5794 18.1652 19.1889 17.7747L13.4142 12L19.189 6.2253C19.5795 5.83477 19.5795 5.20161 19.189 4.81108C18.7985 4.42056 18.1653 4.42056 17.7748 4.81108L12 10.5858L6.2253 4.81108Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<video *ngIf="stream" [id]="id" [srcObject]="stream" autoplay muted volume="0"></video>
|
||||
<button *ngIf="!isRecording" class="btn btn-success" (click)="startRecording()">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
|
||||
fill="currentColor" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM20 12C20 16.4183 16.4183 20 12 20C7.58172 20 4 16.4183 4 12C4 7.58172 7.58172 4 12 4C16.4183 4 20 7.58172 20 12Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
Record
|
||||
</button>
|
||||
<button *ngIf="isRecording" class="btn btn-danger" (click)="stopRecording()">Stop</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
0
src/app/recorder/recorder.component.scss
Normal file
0
src/app/recorder/recorder.component.scss
Normal file
25
src/app/recorder/recorder.component.spec.ts
Normal file
25
src/app/recorder/recorder.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecorderComponent } from './recorder.component';
|
||||
|
||||
describe('RecorderComponent', () => {
|
||||
let component: RecorderComponent;
|
||||
let fixture: ComponentFixture<RecorderComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ RecorderComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecorderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
57
src/app/recorder/recorder.component.ts
Normal file
57
src/app/recorder/recorder.component.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap";
|
||||
import * as rrtc from 'recordrtc';
|
||||
|
||||
@Component({
|
||||
selector: 'ah-recorder',
|
||||
templateUrl: './recorder.component.html',
|
||||
styleUrls: ['./recorder.component.scss']
|
||||
})
|
||||
export class RecorderComponent implements OnInit {
|
||||
@ViewChild("content") content;
|
||||
@ViewChild("activeStory") video;
|
||||
stream: MediaStream;
|
||||
recorder: rrtc.RecordRTCPromisesHandler;
|
||||
modal: NgbModalRef;
|
||||
isRecording: boolean = false;
|
||||
id: string = 'thisisalocalvideo'+Math.round(Math.random()*10000);
|
||||
|
||||
constructor(
|
||||
private modalService: NgbModal,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
async openModal() {
|
||||
this.modal = this.modalService.open(this.content, {
|
||||
centered: true
|
||||
});
|
||||
this.stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: true,
|
||||
audio: true
|
||||
});
|
||||
setTimeout(() => {
|
||||
const video:any = document.getElementById(this.id);
|
||||
video.volume = 0;
|
||||
video.muted = true;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
startRecording() {
|
||||
this.isRecording = true;
|
||||
this.recorder = new rrtc.RecordRTCPromisesHandler(this.stream, {
|
||||
type: 'video',
|
||||
});
|
||||
this.recorder.startRecording();
|
||||
}
|
||||
|
||||
async stopRecording() {
|
||||
this.isRecording = false;
|
||||
await this.recorder.stopRecording();
|
||||
let blob = await this.recorder.getBlob();
|
||||
// TODO upload instead
|
||||
rrtc.invokeSaveAsDialog(blob, 'Recorded-Video.webm');
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue