| export class MediaSourceAppender { |
| private readonly mediaSource = new MediaSource(); |
| private readonly audioChunks: ArrayBuffer[] = []; |
|
|
| private sourceBuffer?: SourceBuffer; |
|
|
| constructor(type: string) { |
| this.mediaSource.addEventListener('sourceopen', async () => { |
| this.sourceBuffer = this.mediaSource.addSourceBuffer(type); |
|
|
| this.sourceBuffer.addEventListener('updateend', () => { |
| this.tryAppendNextChunk(); |
| }); |
| }); |
| } |
|
|
| private tryAppendNextChunk() { |
| if (this.sourceBuffer != null && !this.sourceBuffer.updating && this.audioChunks.length > 0) { |
| this.sourceBuffer.appendBuffer(this.audioChunks.shift()!); |
| } |
| } |
|
|
| public addBase64Data(base64Data: string) { |
| this.addData(Uint8Array.from(atob(base64Data), (char) => char.charCodeAt(0)).buffer); |
| } |
|
|
| public addData(data: ArrayBuffer) { |
| this.audioChunks.push(data); |
| this.tryAppendNextChunk(); |
| } |
|
|
| public close() { |
| if (this.mediaSource.readyState === 'open') { |
| this.mediaSource.endOfStream(); |
| } |
| } |
|
|
| public get mediaSourceUrl() { |
| return URL.createObjectURL(this.mediaSource); |
| } |
| } |
|
|