(chunk: EncodedAudioChunk)
| 222 | } |
| 223 | |
| 224 | private async decodeInternal(chunk: EncodedAudioChunk) { |
| 225 | const currentConfigId = this.currentConfigId; |
| 226 | |
| 227 | using lock = this.mutex.lock(); |
| 228 | await lock.ready; // Unconditional await here to queue a microtask |
| 229 | |
| 230 | if (this.currentConfigId !== currentConfigId) { |
| 231 | return; |
| 232 | } |
| 233 | |
| 234 | // Spec: Decrement [[decodeQueueSize]] and run the Schedule Dequeue Event algorithm. |
| 235 | this.decrementQueue(); |
| 236 | |
| 237 | assert(this.codecContext); |
| 238 | |
| 239 | const data = Buffer.from({ length: chunk.byteLength }); |
| 240 | chunk.copyTo(data); |
| 241 | |
| 242 | this.packet.isKeyframe = chunk.type === 'key'; |
| 243 | this.packet.data = data; |
| 244 | this.packet.timeBase = { num: 1, den: 1e6 }; |
| 245 | this.packet.pts = BigInt(chunk.timestamp); |
| 246 | this.packet.dts = AV_NOPTS_VALUE; |
| 247 | this.packet.duration = BigInt(chunk.duration ?? 0); |
| 248 | |
| 249 | const ret = await this.codecContext.sendPacket(this.packet); |
| 250 | |
| 251 | if (ret < 0) { |
| 252 | // Spec: If decoding results in an error, queue a task to run the Close AudioDecoder algorithm |
| 253 | // with EncodingError |
| 254 | throw new DOMException('Failed to send packet', 'EncodingError'); |
| 255 | } |
| 256 | |
| 257 | while (true) { |
| 258 | const receiveRet = await this.codecContext.receiveFrame(this.frame); |
| 259 | if (receiveRet < 0) { |
| 260 | break; |
| 261 | } |
| 262 | |
| 263 | this.outputData(currentConfigId); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /** |
| 268 | * Flushes all pending decode operations and waits for completion. |
no test coverage detected