feat(native): async recorder (#14700)

#### PR Dependency Tree


* **PR #14700** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Durable, resumable import queue with explicit import lifecycle and
updated popup/tray status behavior.
* Async native recording APIs and ability to abort recordings; audio
quality metrics (degraded, overflow count).
  * Added "Importing..." translation.

* **Bug Fixes**
* More reliable single-claim import processing, retries and cleanup to
avoid duplicate imports.
  * Improved stop/abort teardown stability and safer shutdown behavior.

* **Tests**
* New/updated tests covering coordinator, import queue, native async
flows and teardown scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-03-23 22:38:52 +08:00
committed by GitHub
parent b0251c93cb
commit 9b56a05159
26 changed files with 3560 additions and 1277 deletions
@@ -17,8 +17,8 @@ import {
appGroups$,
checkCanRecordMeeting,
checkRecordingAvailable,
getCurrentRecordingStatus,
MeetingsSettingsState,
recordingStatus$,
startRecording,
stopRecording,
updateApplicationsPing$,
@@ -158,9 +158,14 @@ class TrayState implements Disposable {
appGroup => appGroup.isRunning
);
const recordingStatus = recordingStatus$.value;
const recordingStatus = getCurrentRecordingStatus();
if (!recordingStatus || recordingStatus.status !== 'recording') {
if (
!recordingStatus ||
(recordingStatus.status !== 'starting' &&
recordingStatus.status !== 'recording' &&
recordingStatus.status !== 'finalizing')
) {
const appMenuItems = runningAppGroups.map(appGroup => ({
label: appGroup.name,
icon: appGroup.icon || undefined,
@@ -197,8 +202,8 @@ class TrayState implements Disposable {
...appMenuItems
);
} else {
const recordingLabel = recordingStatus.appGroup?.name
? `Recording (${recordingStatus.appGroup?.name})`
const recordingLabel = recordingStatus.appName
? `Recording (${recordingStatus.appName})`
: 'Recording';
// recording is active
@@ -210,11 +215,14 @@ class TrayState implements Disposable {
},
{
label: 'Stop',
disabled: recordingStatus.status !== 'recording',
click: () => {
logger.info('User action: Stop Recording');
stopRecording(recordingStatus.id).catch(err => {
logger.error('Failed to stop recording:', err);
});
if (recordingStatus.status === 'recording') {
stopRecording(recordingStatus.id).catch(err => {
logger.error('Failed to stop recording:', err);
});
}
},
}
);