diff --git a/.nx/cache/18.3.4-nx.win32-x64-msvc.node b/.nx/cache/18.3.4-nx.win32-x64-msvc.node
new file mode 100644
index 0000000..4981b20
Binary files /dev/null and b/.nx/cache/18.3.4-nx.win32-x64-msvc.node differ
diff --git a/angular.json b/angular.json
index e59acb9..5104365 100644
--- a/angular.json
+++ b/angular.json
@@ -43,6 +43,13 @@
},
"configurations": {
"production": {
+ "optimization": false,
+ "sourceMap": true,
+ "namedChunks": false,
+ "aot": false,
+ "extractLicenses": false,
+ "vendorChunk": false,
+ "buildOptimizer": false,
"budgets": [
{
"type": "initial",
diff --git a/src/app/components/controls/custom-table/custom-table.component.html b/src/app/components/controls/custom-table/custom-table.component.html
index 2f5040a..06f7564 100644
--- a/src/app/components/controls/custom-table/custom-table.component.html
+++ b/src/app/components/controls/custom-table/custom-table.component.html
@@ -17,7 +17,7 @@
class="this-table"
>
@@ -37,16 +37,16 @@
- {{ element[item] }}
+ {{ element[getKeyBy(item)] }}
|
-
+
val === value)?.[0] : value;
+ }
selectedRowIndex: number = -1; // -1 is selected nothings
@Output() rowClick: EventEmitter = new EventEmitter();
diff --git a/src/app/components/controls/flexible-chart/flexible-chart.component.html b/src/app/components/controls/flexible-chart/flexible-chart.component.html
index bca392e..ac0b411 100644
--- a/src/app/components/controls/flexible-chart/flexible-chart.component.html
+++ b/src/app/components/controls/flexible-chart/flexible-chart.component.html
@@ -1,10 +1,12 @@
-
-
diff --git a/src/app/components/controls/flexible-chart/flexible-chart.component.ts b/src/app/components/controls/flexible-chart/flexible-chart.component.ts
index be9eb4d..9d093da 100644
--- a/src/app/components/controls/flexible-chart/flexible-chart.component.ts
+++ b/src/app/components/controls/flexible-chart/flexible-chart.component.ts
@@ -25,13 +25,16 @@ export interface ChartData {
})
export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy {
exampleData: ChartData[] = [];
+ @Input() globalMinMax: boolean = false
mousePosition: any = {
inside: false,
mousedown: false,
x: 0,
y: 0
};
+ @Input() fullToolTip = false;
@Input() isRange = true;
+ @Input() startXAxisNumber = 0;
@Input() options: any = {
axisX: false,
axisY: false
@@ -89,7 +92,7 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
// const { layerX = 0, layerY = 0 }:any = {};
const { offsetWidth, offsetHeight, offsetLeft, offsetTop } = this.canvas.nativeElement;
const dX = layerX - offsetLeft;
- const dY = layerX - offsetTop;
+ const dY = layerX - offsetTop;
switch (event.type) {
case 'mousemove':
@@ -152,10 +155,10 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
const index = Math.ceil((this.mousePosition.x) / stepX);
return index;
}
- tooltip(ctx: any, text: string) {
+ tooltip(ctx: any, text: string, index = 0) {
const padding = 4;
ctx.font = `14px monospace`;
- const textElement = ctx.measureText(text);
+ const textElement = ctx.measureText(text.split('\n')[0]);
const w = textElement.width;
const x = Math.max(0, Math.min(
ctx.canvas.clientWidth - w - padding * 2,
@@ -165,10 +168,13 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
ctx.fillStyle = 'black';
- this.drawText(ctx, text, {
- x, y,
- bgColor: 'rgba(255, 255, 255, 0.8)',
- color: 'black'
+ text.split('\n').forEach((line, k) => {
+
+ this.drawText(ctx, line, {
+ x, y: y + k * 20,
+ bgColor: 'rgba(255, 255, 255, 0.8)',
+ color: 'black'
+ })
})
}
@@ -206,18 +212,38 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
ctx.lineWidth = 1;
}
draw(ctx: any) {
+
+ let minData = Number.MAX_VALUE, maxData = Number.MIN_VALUE;
+ if (this.globalMinMax) {
+ this.exampleData.forEach(({ data }: any) => {
+ minData = Math.min(...data, minData, 0);
+ maxData = Math.max(...data, maxData);
+ });
+ }
this.exampleData.forEach(({ data, color, typeOfChart }: any) => {
- this.drawChart(ctx, data, color, typeOfChart);
+ this.drawChart(ctx, data, color, typeOfChart, [minData, maxData]);
})
if (this.isRange) {
this.drawRange(ctx);
if (this.mousePosition.inside) {
this.drawTarget(ctx);
- this.tooltip(ctx, JSON.stringify(
- !this.mousePosition.mousedown ?
- this.getIndexOfData() :
- this.сalcRangeByData()));
+ if (this.fullToolTip) {
+
+ const idx = this.getIndexOfData() - 1;
+ console.log({ exampleData: this.exampleData });
+ this.tooltip(ctx,
+
+ this.exampleData.map(i => i.data[idx] ? `${i.name}: ${i.data[idx]}` : '').filter(i => !!i).join('\n')
+
+ )
+ } else {
+
+ this.tooltip(ctx, JSON.stringify(
+ !this.mousePosition.mousedown ?
+ this.getIndexOfData() :
+ this.сalcRangeByData()));
+ }
}
}
@@ -282,7 +308,7 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
ctx.moveTo(x, y - 5);
ctx.lineTo(x, y + 3);
ctx.stroke();
- this.drawText(ctx, `${(data.length * (i + 1) / L).toFixed(0)}`, {
+ this.drawText(ctx, `${(this.startXAxisNumber + data.length * (i + 1) / L).toFixed(0)}`, {
x: x - 10,
y: y,
bgColor: 'rgba(255, 255, 255, 0)',
@@ -307,11 +333,21 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
ctx.stroke();
}
}
- drawChart(ctx: any, data: any[], color = 'rgba(0,255,255,0.5)', type: TypeOfChart = this.typeOfChart) {
+ drawChart(ctx: any, data: any[], color = 'rgba(0,255,255,0.5)', type: TypeOfChart = this.typeOfChart, [min, max]: any) {
data = Functions.cloneObject(data);
const pudding = { x: 10, y: this.options.axisX ? 40 : 0 }; // px
- const minY = Math.min(...data, 0);
- const maxY = Math.max(...data);
+ let minY;
+ let maxY;
+ if (this.globalMinMax) {
+ minY = min;
+ maxY = max;
+
+ } else {
+
+ minY = Math.min(...data, 0);
+ maxY = Math.max(...data);
+ }
+
let stepX = ((ctx.canvas.offsetWidth - pudding.x * 2) / (data.length));
const stepY = ((ctx.canvas.offsetHeight - pudding.y * 2) / maxY);
@@ -380,7 +416,7 @@ export class FlexibleChartComponent implements OnInit, AfterViewInit, OnDestroy
const c = this.canvas.nativeElement;
c.width = `${c.offsetWidth}`;
- c.height = `${c.offsetHeight}`;
+ c.height = `${c.offsetHeight - 5}`;
if (c.getContext) {
var ctx = c.getContext('2d');
diff --git a/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.html b/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.html
new file mode 100644
index 0000000..adc1b6c
--- /dev/null
+++ b/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.html
@@ -0,0 +1,161 @@
+
+
+
+
+
+ CurrentTime:
+ {{ rec.player?.getCurrentTime() || 0 | number : "1.3-3" }}s
+
+
Duration: {{ rec.player?.getDuration() || 0 }}
+
PlaybackRate: {{ rec.player?.getPlaybackRate() || 0 }}
+
+
+
+
Audio file is empty (size : 0b)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Line
+ Bar
+ Area
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.scss b/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.scss
new file mode 100644
index 0000000..489506b
--- /dev/null
+++ b/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.scss
@@ -0,0 +1,18 @@
+.player-card-data {
+ display: flex;
+ & > div {
+ padding: 0.5rem;
+ }
+}
+.top-container {
+ display: flex;
+ margin-bottom: 3rem;
+ flex-direction: column;
+ // position: sticky;
+ top: 0;
+ z-index: 1;
+}
+
+.labels ::ng-deep .mdc-checkbox {
+ display: none !important;
+}
diff --git a/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.ts b/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.ts
new file mode 100644
index 0000000..e791cee
--- /dev/null
+++ b/src/app/components/controls/tap/tap-rtp-streams/stream-detail/stream-detail.component.ts
@@ -0,0 +1,349 @@
+import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { WebSharkDataService } from '@app/services/web-shark-data.service';
+import { hash } from '@app/helper/functions';
+import WaveSurfer from 'wavesurfer.js';
+import TimelinePlugin from 'wavesurfer.js/dist/plugins/timeline';
+import { TypeOfChart } from '@app/components/controls/flexible-chart/flexible-chart.component';
+
+declare const transcode: Function;
+const DATA_TYPE = 'application/octet-stream';
+
+@Component({
+ selector: 'stream-detail',
+ templateUrl: './stream-detail.component.html',
+ styleUrls: ['./stream-detail.component.scss']
+})
+export class StreamDetailComponent implements OnInit {
+
+ // constructor() { }
+
+ // ngOnInit() {
+ // }
+ onClose() {
+ console.log('StreamDetailComponent::onClose');
+ this.close.emit({})
+ }
+
+ lastRange: any;
+ _data: any;
+ columns: any;
+ streams: any[] = [];
+ selectedStreams: any;
+ selectedColumns: any;
+
+ players: any[] = [];
+ optionsAudioContainer = {
+ // waveColor: '#D2EDD4',
+ normalize: true,
+ progressColor: 'green',
+ responsive: true,
+ minPxPerSec: 100,
+
+ }
+ @Input() rec: any;
+
+ @Input() set data(val: any) {
+ this._data = val;
+ this.streams = val.streams || [];
+ const [stream] = this.streams || [];
+ this.columns = Object.keys(stream || []);
+ }
+ @Output() close: EventEmitter = new EventEmitter();
+ get data(): any {
+ return this._data;
+ }
+ typeOfChartRadio:TypeOfChart = 'bar'
+ isReady = false;
+ progressMessage = ['Initialization'];
+ chartData: any[] = [];
+ rangeChartData: any[] = [];
+ audioStreamsBlobURL: any[] = [];
+ columnDictionary: any = {
+ bw: 'IP BW (kbps)',
+ d: 'Delta',
+ f: 'Packet (Time)',
+ j: 'Jitter',
+ mark: 'Marker',
+ o: 'o',
+ s: 'Status',
+ sk: 'Skew (ms)',
+ sn: 'Sequence',
+ t: 't',
+ };
+
+ chartFilter = Object.entries(this.columnDictionary).map(([key, val]: any) => ({
+ title: val,
+ index: key,
+ color: '#' + hash(key, 3),
+ value: true
+ }))
+ columnsDictionary: any = Object.values(this.columnDictionary);
+ constructor(
+ private webSharkDataService: WebSharkDataService,
+ private cdr: ChangeDetectorRef
+ ) { }
+ get titleId() {
+ const [tap] = this.rec.rowData.taps;
+ // console.log(
+ // tap
+ // )
+ const [sip, sport, dip, dport, ssrc] = (tap.tap || '').split(/[_]+/g);
+ return `${ssrc} - ${sip}:${sport} -> ${dip}:${dport}`
+ }
+ get captureFile() {
+ return this.webSharkDataService.getCapture();
+ }
+ async getFileArrayOfUint8Array(filename: string) {
+ const href = encodeURIComponent('/' + filename);
+ const url = `/webshark/json?method=download&capture=${href}&token=self`;
+ const { body } = await fetch(url);
+ const reader = body?.getReader();
+ if (!reader) {
+ console.error(new Error('Could not get file'));
+ return new Blob([], { type: DATA_TYPE });
+ }
+ let isDone = false;
+ const collectArrayData = [];
+
+ while (!isDone) {
+ const { value, done } = await reader.read();
+ if (value) {
+ collectArrayData.push(value);
+ }
+ isDone = done;
+ }
+
+ // console.log({ collectArrayData });
+ return new Blob(collectArrayData, { type: DATA_TYPE });
+
+ }
+ // blobSaveAsFile(blobUrl: string, filename: string) {
+ // var link = document.createElement("a"); // Or maybe get it from the current document
+ // link.href = blobUrl;
+ // link.download = filename;
+ // link.innerHTML = "Click here to download the file";
+ // document.body.appendChild(link);
+ // }
+ /**
+ * parse PCAP to rtp-strems binnary data
+ * FFMPEG
+ */
+ async ffmpegDecoder() {
+ this.progressMessage.push(`Reading data from ${this.captureFile} file`);
+ this.cdr.detectChanges();
+ const blobData: Blob = await this.getFileArrayOfUint8Array(this.captureFile);
+ // console.log(this.captureFile, { blobData });
+ // const blobUrl = await transcode(blobData);
+ // console.log(blobUrl)
+
+ this.progressMessage.push('Separate PCAP to frames');
+ this.cdr.detectChanges();
+
+ const index = await this.webSharkDataService.getFrames(0);
+ let offset = 24;
+ const arrOffset = index.map((i: any, k: number, arr: any[]) => {
+ if (k > 0) {
+ offset += +arr[k - 1].c[5];
+ }
+ offset += 16;
+ return [offset, ...i.c, blobData.slice(offset, offset + +i.c[5], DATA_TYPE)];
+ })
+ // console.log(arrOffset);
+ this.progressMessage.push('Collect payload binary to streams')
+ this.cdr.detectChanges();
+ // rtp-streams
+ const { taps: [{ streams: rtpStreams }] } = await this.webSharkDataService.getTapJson('rtp-streams');
+ // console.log(rtpStreams);
+
+ const arr = rtpStreams.map((streamData: any) => {
+ return {
+ ssrc: streamData.ssrc,
+ data: streamData,
+ blob: new Blob(arrOffset
+ .filter((frame: any) => frame[7].toUpperCase().includes(`SSRC=${streamData.ssrc.toUpperCase()}`))
+ .map((i: any) => (i[8] as Blob).slice(54)), { type: DATA_TYPE })
+ };
+ })
+ // console.log({ arr })
+ const codecDictionary: any = {
+ 'g711a': 'alaw',
+ 'g711u': 'mulaw',
+ 'g722': 'g722',
+ };
+ const out: any[] = [];
+ for (let item of arr) {
+ // console.log('<>>>>', item.data);
+
+ const codec = codecDictionary[(item.data.payload + '').toLowerCase()] || 'g722';
+ // console.log('<>>>>', {codec});
+
+ // const i = arr[0];
+ this.progressMessage.push(`FFmpeg:: converting ${item.ssrc} stream to audio (mp3)`);
+ this.cdr.detectChanges();
+ const blobUrl = await transcode(item.blob, codec, `audio-${item.ssrc}.mp3`);
+ // console.log(blobUrl)
+
+ out.push({ ssrc: item.ssrc, blobUrl });
+ // this.blobSaveAsFile(blobUrl, `audio-${item.ssrc}.mp3`);
+ }
+
+ return out;
+ }
+ getPlayer(rec: any) {
+ /**
+ * rec: { id, mp3, player }
+ */
+ if (!rec.player) {
+ try {
+ // rec.mp3 = 'http://localhost:8003/assets/we__will_rock_you.mp3'
+ const player = WaveSurfer.create({
+ ...this.optionsAudioContainer,
+ container: '#' + (rec.id || 'audio-player'),
+ plugins: [TimelinePlugin.create({
+ /** The duration of the timeline in seconds, defaults to wavesurfer's duration */
+ // duration: 1,
+ /** Interval between ticks in seconds */
+ timeInterval: 0.1,
+ /** Interval between numeric labels in seconds */
+ primaryLabelInterval: 1,
+ /** Interval between secondary numeric labels in seconds */
+ // secondaryLabelInterval: 8,
+ })]
+
+ });
+ if (rec.mp3) {
+ // this.webSharkDataService.getBLOB(rec.mp3).subscribe((data: any) => {
+ // const data = {}
+ // console.log({ data })
+ // if (!data || data.size === 0) {
+ // rec.noData = true;
+ // this.cdr.detectChanges();
+ // } else {
+ player.load(rec.mp3);
+ player.on('ready', () => {
+ player.zoom(1);
+ player.on('audioprocess', (event: any) => {
+ /**
+ * needs to sync the playback with table stream data
+ */
+ // console.log(event);
+ this.cdr.detectChanges();
+ });
+ this.cdr.detectChanges();
+ });
+ // }
+ // });
+ } else {
+ rec.noData = true;
+ this.cdr.detectChanges();
+ }
+ rec.player = player;
+
+
+ } catch (err) {
+ console.log(err, rec);
+ }
+ }
+ return rec;
+
+ }
+ async ngOnInit() {
+
+ this.audioStreamsBlobURL = await this.ffmpegDecoder();
+ this.progressMessage.push('done.');
+ this.cdr.detectChanges();
+ requestAnimationFrame(() => {
+
+ this.isReady = true;
+ this.setRecActive();
+ this.cdr.detectChanges();
+ })
+
+ }
+
+ setRecActive() {
+
+ console.log('setRecActive()', this.rec);
+ // this.players.forEach(p => p.isActive = p.id === id);
+ let playerElement = this.rec;
+ const [tap]: any = playerElement.rowData?.taps || [];
+ this.selectedStreams = tap?.items || [];
+ const [item] = this.selectedStreams;
+ this.selectedColumns = ["bw", "d", "f", "j", "mark", "o", "s", "sk", "sn", "t"]; // Object.keys(item);
+ this.chartData = this.getChartData();
+ this.onRange([0, 0]);
+ this.cdr.detectChanges();
+ }
+ playItemClick(event: any) {
+ console.log({ event });
+ }
+ onZoomAudio(event: any, player: any) {
+ // console.log(event.wheelDelta);
+ if (!player._myZoom) {
+ player._myZoom = 1;
+ }
+ player._myZoom += event.wheelDelta / 12
+ player._myZoom = Math.max(1, player._myZoom);
+ player.zoom(player._myZoom);
+ this.cdr.detectChanges();
+
+ }
+ onRange([a, b]: any) {
+ const start = Math.min(a, b);
+ const end = Math.max(a, b);
+
+ console.log({ start, end });
+ this.lastRange = { start, end };
+ this.rangeChartData = [];
+
+ this.chartData.forEach(item => {
+ const out = Object.assign({}, item);
+ if (start >= 0 && end >= 0 && start != end) {
+ out.data = out.data.slice(start, end);
+ } else {
+ out.data = out.data;
+ }
+ this.rangeChartData.push(out)
+
+ })
+ }
+ getChartData() {
+ /**
+ * format have to be like this:
+ * [
+ { data: [1, 3, 2, 4, 5, 4, 3, 2] },
+ { data: [2, 4, 5, 4, 3, 2], typeOfChart: 'area', color: 'red' },
+ . . .
+ { data: [5, 4, 3, 2, 1, 4] }
+ ]
+ */
+ // this.columnDictionary
+ const outData: any[] = [];
+ this.selectedColumns.forEach((column: string) => {
+ if (this.chartFilter.find(i => i.index == column)?.value) {
+
+ const d = {
+ color: '#' + hash(column, 3),
+ name: this.columnDictionary[column],
+ data: this.selectedStreams.map((stream: any) => stream[column])
+ };
+ outData.push(d)
+ }
+ })
+ console.log({ selectedStreams: this.selectedStreams });
+ return outData;
+
+ }
+ onFilterChart() {
+ console.log({ f: 'onFilterChart', d: this.chartFilter })
+ this.chartData = this.getChartData();
+ if (this.lastRange) {
+ const { start, end } = this.lastRange;
+ this.onRange([start, end]);
+ } else {
+ this.onRange([]);
+ }
+ this.cdr.detectChanges();
+ }
+
+}
diff --git a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.html b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.html
index ba96da5..d9000df 100644
--- a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.html
+++ b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.html
@@ -1,16 +1,38 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
{{ col }}:
+ {{ item[col] }}
+
+
+
+
+
+
+
+
+
-
{{ item }}
diff --git a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.scss b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.scss
index cb21db5..a5f87df 100644
--- a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.scss
+++ b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.scss
@@ -1,16 +1,46 @@
-@use 'sass:map';
-@use '@angular/material' as mat;
+@use "sass:map";
+@use "@angular/material" as mat;
@import "/src/theme.scss";
$primary: map.get($my-theme, primary);
-
+$bgColor: rgba(black, 0.12);
:host {
+ .table-row-wrapper {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-end;
+ // justify-content: space-between;
+ margin: 5px;
+ /* border: 2px solid red; */
+ border-radius: 0.5rem;
+ box-shadow: 1px 1px 8px -3px #000;
+ &:hover {
+ background-color: $bgColor;
+ cursor: pointer;
+ }
+ .table-row {
+ width: 200px;
+ min-width: 200px;
+ padding: 0.5rem;
+ background: rgba(0, 0, 0, 0.05);
+ margin: 4px;
+ border-radius: 4px;
+ // border: 1px solid #999;
+ > h3 {
+ display: inline-block;
+ font-weight: 500;
+ line-height: initial;
+ letter-spacing: inherit;
+ margin: 0;
+ }
+ }
+ }
.is-data-wrapper {
width: 100%;
display: block;
}
.player-card-data {
display: flex;
- &>div{
+ & > div {
padding: 0.5rem;
}
}
@@ -50,7 +80,7 @@ $primary: map.get($my-theme, primary);
opacity: 0;
transition: opacity 0.3s;
z-index: 10;
- >* {
+ > * {
margin: 0.3rem;
}
}
diff --git a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.ts b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.ts
index 101465d..ec656ad 100644
--- a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.ts
+++ b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.component.ts
@@ -51,6 +51,9 @@ export class TapRtpStreamsComponent implements OnInit {
get captureFile() {
return this.webSharkDataService.getCapture();
}
+ getKeys(obj: any) {
+ return Object.keys(obj).filter(i => i !== '__selected');
+ }
async getFileArrayOfUint8Array(filename: string) {
const href = encodeURIComponent('/' + filename);
const url = `/webshark/json?method=download&capture=${href}&token=self`;
@@ -75,13 +78,13 @@ export class TapRtpStreamsComponent implements OnInit {
return new Blob(collectArrayData, { type: DATA_TYPE });
}
- blobSaveAsFile(blobUrl: string, filename: string) {
- var link = document.createElement("a"); // Or maybe get it from the current document
- link.href = blobUrl;
- link.download = filename;
- link.innerHTML = "Click here to download the file";
- document.body.appendChild(link);
- }
+ // blobSaveAsFile(blobUrl: string, filename: string) {
+ // var link = document.createElement("a"); // Or maybe get it from the current document
+ // link.href = blobUrl;
+ // link.download = filename;
+ // link.innerHTML = "Click here to download the file";
+ // document.body.appendChild(link);
+ // }
/**
* parse PCAP to rtp-strems binnary data
* FFMPEG
@@ -142,7 +145,7 @@ export class TapRtpStreamsComponent implements OnInit {
// console.log(blobUrl)
out.push({ ssrc: item.ssrc, blobUrl });
- this.blobSaveAsFile(blobUrl, `audio-${item.ssrc}.mp3`);
+ // this.blobSaveAsFile(blobUrl, `audio-${item.ssrc}.mp3`);
}
return out;
@@ -153,7 +156,6 @@ export class TapRtpStreamsComponent implements OnInit {
*/
if (!rec.player) {
try {
- // rec.mp3 = 'http://localhost:8003/assets/we__will_rock_you.mp3'
const player = WaveSurfer.create({
...this.optionsAudioContainer,
container: '#' + (rec.id || 'audio-player'),
@@ -217,8 +219,15 @@ export class TapRtpStreamsComponent implements OnInit {
})
}
+ onClosePlayer(idx: any) {
+ // console.log({idx})
+ this.players = this.players.filter((i, k) => k !== idx);
+ this.cdr.detectChanges();
+ }
async rowClick({ row }: any) {
- // console.log({ row });
+ // this.streams
+ console.log(this.streams, { row });
+
const id = `player-${hash(JSON.stringify(row))}`;
let playerElement = this.players.find(p => p.id === id);
if (!playerElement) {
@@ -233,10 +242,7 @@ export class TapRtpStreamsComponent implements OnInit {
rowData,
};
-
-
-
- setTimeout(() => {
+ requestAnimationFrame(() => {
playerElement = this.getPlayer(playerElement);
this.cdr.detectChanges();
});
diff --git a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.module.ts b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.module.ts
index 696632b..3120e49 100644
--- a/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.module.ts
+++ b/src/app/components/controls/tap/tap-rtp-streams/tap-rtp-streams.module.ts
@@ -8,9 +8,18 @@ import { TapRtpStreamsComponent } from './tap-rtp-streams.component';
import { CustomTableModule } from '../../custom-table/custom-table.module';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { NoDataModule } from '../../no-data/no-data.module';
+import { StreamDetailComponent } from './stream-detail/stream-detail.component';
+import { ModalResizableModule } from '../../modal-resizable/modal-resizable.module';
+import { MatTabsModule } from '@angular/material/tabs';
+import { FlexibleChartModule } from '../../flexible-chart/flexible-chart.module';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import {MatRadioModule} from '@angular/material/radio';
@NgModule({
imports: [
+ FormsModule,
+ ReactiveFormsModule,
CommonModule,
CustomTableModule,
AngularSplitModule,
@@ -18,9 +27,18 @@ import { NoDataModule } from '../../no-data/no-data.module';
MatIconModule,
MatButtonModule,
ScrollingModule,
- NoDataModule
+ NoDataModule,
+ ModalResizableModule,
+ MatTabsModule,
+ FlexibleChartModule,
+ MatCheckboxModule,
+ MatRadioModule
+ ],
+ declarations: [
+ // ModalResizableComponent,
+ StreamDetailComponent,
+ TapRtpStreamsComponent
],
- declarations: [TapRtpStreamsComponent],
exports: [TapRtpStreamsComponent]
})
export class TapRtpStreamsModule { }
diff --git a/src/app/components/controls/webshark/webshark.component.html b/src/app/components/controls/webshark/webshark.component.html
index 7787a9a..723381d 100644
--- a/src/app/components/controls/webshark/webshark.component.html
+++ b/src/app/components/controls/webshark/webshark.component.html
@@ -1,6 +1,9 @@
0) && !(detailsTable.length > 0)">
-
+
@@ -22,7 +25,8 @@ Files
font-size: 40px;
width: 40px;
height: 40px;
- ">notenote
{{ note.name }}
@@ -38,60 +42,69 @@
Files
*ngIf="!(!(dataTree.length > 0) && !(detailsTable.length > 0))"
[noDataIf]="!(dataTree.length > 0) && !(detailsTable.length > 0)"
>
-
-
-
-
-
-
-
-
- 0"
- [data]="dataTree"
- style="flex: 1; overflow: auto"
- (clickRow)="onSelected($event)"
- [isFilter]="true"
- [selectedHexArray]="selectedHexArray"
- (filter)="setFilter($event)"
- >
-
- No Data
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ 0"
+ [data]="dataTree"
+ style="flex: 1; overflow: auto"
+ (clickRow)="onSelected($event)"
+ [isFilter]="true"
+ [selectedHexArray]="selectedHexArray"
+ (filter)="setFilter($event)"
+ >
+
+ No Data
+
+
+
+
+
+
+
+
+