( videoData: ArrayBuffer, options: NativeVideoExportFinishOptions, )
| 4146 | } |
| 4147 | |
| 4148 | export async function muxExportedVideoAudioBuffer( |
| 4149 | videoData: ArrayBuffer, |
| 4150 | options: NativeVideoExportFinishOptions, |
| 4151 | ) { |
| 4152 | const tempVideoPath = path.join( |
| 4153 | app.getPath("temp"), |
| 4154 | `recordly-export-video-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.mp4`, |
| 4155 | ); |
| 4156 | const metrics: NativeVideoAudioMuxMetrics = {}; |
| 4157 | let succeeded = false; |
| 4158 | let outputPath = tempVideoPath; |
| 4159 | |
| 4160 | try { |
| 4161 | const tempVideoWriteStartedAt = getNowMs(); |
| 4162 | await fs.writeFile(tempVideoPath, Buffer.from(videoData)); |
| 4163 | metrics.tempVideoWriteMs = getNowMs() - tempVideoWriteStartedAt; |
| 4164 | metrics.tempVideoBytes = videoData.byteLength; |
| 4165 | const finalized = await muxNativeVideoExportAudio(tempVideoPath, options); |
| 4166 | Object.assign(metrics, finalized.metrics); |
| 4167 | outputPath = finalized.outputPath; |
| 4168 | // Record byte size via stat instead of reading the whole file into a |
| 4169 | // Buffer — fs.readFile throws ERR_FS_FILE_TOO_LARGE on >2 GiB outputs. |
| 4170 | try { |
| 4171 | const stat = await fs.stat(outputPath); |
| 4172 | metrics.muxedVideoBytes = stat.size; |
| 4173 | } catch { |
| 4174 | // Stat failures are non-fatal; size is purely metric data. |
| 4175 | } |
| 4176 | succeeded = true; |
| 4177 | return { |
| 4178 | outputPath, |
| 4179 | metrics, |
| 4180 | }; |
| 4181 | } finally { |
| 4182 | // Always remove the unmuxed intermediate when the muxer wrote a separate |
| 4183 | // file. Only remove the muxed output on failure — on success the caller |
| 4184 | // owns it and is responsible for moving/deleting it. |
| 4185 | const cleanupTargets: string[] = []; |
| 4186 | if (outputPath !== tempVideoPath) { |
| 4187 | cleanupTargets.push(tempVideoPath); |
| 4188 | } |
| 4189 | if (!succeeded) { |
| 4190 | cleanupTargets.push(outputPath); |
| 4191 | } |
| 4192 | if (cleanupTargets.length > 0) { |
| 4193 | await Promise.allSettled( |
| 4194 | cleanupTargets.map((target) => removeTemporaryExportFile(target)), |
| 4195 | ); |
| 4196 | } |
| 4197 | } |
| 4198 | } |
no test coverage detected