[A] basic recordrtc integration

This commit is contained in:
Jan 2020-10-03 01:59:08 +02:00
parent 403277c6df
commit 34c03f7402
8 changed files with 133 additions and 46 deletions

5
package-lock.json generated
View file

@ -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": { "redis": {
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz",

View file

@ -24,6 +24,7 @@
"@ng-bootstrap/ng-bootstrap": "7.0.0", "@ng-bootstrap/ng-bootstrap": "7.0.0",
"bootstrap": "4.5.2", "bootstrap": "4.5.2",
"core-js": "3.6.4", "core-js": "3.6.4",
"recordrtc": "^5.6.1",
"rxjs": "6.5.4", "rxjs": "6.5.4",
"tslib": "1.13.0", "tslib": "1.13.0",
"zone.js": "0.10.2" "zone.js": "0.10.2"

View file

@ -3,13 +3,13 @@
</nav> </nav>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12">
<ah-recorder></ah-recorder>
</div>
<div *ngFor="let user of users" class="col p-3"> <div *ngFor="let user of users" class="col p-3">
<div class="text-center" (click)="playStory(user)"> <div class="text-center" (click)="playStory(user)">
<div <div class="storyImage" style="background-image: url({{user.image}})"
class="storyImage" [ngClass]="{'hasStory': user.story_link && user.submit_time}"></div>
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 class="mt-2 mb-0"><strong>{{user.name}}</strong></p>
<p><small>{{user.submit_time | date :'dd.MM. HH:mm' }}</small></p> <p><small>{{user.submit_time | date :'dd.MM. HH:mm' }}</small></p>
</div> </div>
@ -21,60 +21,29 @@
<div class="modal-body d-flex flex-column"> <div class="modal-body d-flex flex-column">
<div class="btn-group mb-2" role="group" aria-label="Basic example"> <div class="btn-group mb-2" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary" (click)="prevUser(modal)"> <button type="button" class="btn btn-secondary" (click)="prevUser(modal)">
<svg <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/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="M18 17L10 12L18 7V17Z" fill="currentColor" />
<path d="M6 7H9V17H6V7Z" fill="currentColor" /> <path d="M6 7H9V17H6V7Z" fill="currentColor" />
</svg> </svg>
</button> </button>
<button <button type="button" class="btn btn-secondary" (click)="modal.dismiss('Cross click')">
type="button" <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
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 <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" 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> </svg>
</button> </button>
<button type="button" class="btn btn-secondary" (click)="nextUser(modal)"> <button type="button" class="btn btn-secondary" (click)="nextUser(modal)">
<svg <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/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="M6 17L14 12L6 7V17Z" fill="currentColor" />
<path d="M18 7H15V12V17H18V7Z" fill="currentColor" /> <path d="M18 7H15V12V17H18V7Z" fill="currentColor" />
</svg> </svg>
</button> </button>
</div> </div>
<p class="text-center m-0"> <p class="text-center m-0">
<strong <strong>{{selectedUser.name}} -
>{{selectedUser.name}} - <small>{{selectedUser.submit_time | date :'dd.MM. HH:mm' }}</small></strong>
<small
>{{selectedUser.submit_time | date :'dd.MM. HH:mm' }}</small
></strong
>
</p> </p>
<video <video [src]="selectedUser.story_link" (ended)="nextUser(modal)" autoplay></video>
[src]="selectedUser.story_link"
(ended)="nextUser(modal)"
autoplay
></video>
</div> </div>
</ng-template> </ng-template>

View file

@ -3,9 +3,10 @@ import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component"; import { AppComponent } from "./app.component";
import { NgbModalModule } from "@ng-bootstrap/ng-bootstrap"; import { NgbModalModule } from "@ng-bootstrap/ng-bootstrap";
import { RecorderComponent } from './recorder/recorder.component';
@NgModule({ @NgModule({
declarations: [AppComponent], declarations: [AppComponent, RecorderComponent],
imports: [BrowserModule, NgbModalModule], imports: [BrowserModule, NgbModalModule],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View 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>

View file

View 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();
});
});

View 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();
}
}