mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
feat(editor): audio block (#10947)
AudioMedia entity for loading & controlling a single audio media AudioMediaManagerService: Global audio state synchronization across tabs AudioAttachmentService + AudioAttachmentBlock for manipulating AttachmentBlock in affine - e.g., filling transcription (using mock endpoint for now) Added AudioBlock + AudioPlayer for rendering audio block in affine (new transcription block whose renderer is provided in affine) fix AF-2292 fix AF-2337
This commit is contained in:
@@ -2,6 +2,7 @@ export * from './app-config-storage';
|
||||
export * from './atom';
|
||||
export * from './framework';
|
||||
export * from './livedata';
|
||||
export * from './media';
|
||||
export * from './orm';
|
||||
export * from './storage';
|
||||
export * from './sync';
|
||||
|
||||
1
packages/common/infra/src/media/index.ts
Normal file
1
packages/common/infra/src/media/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './types';
|
||||
72
packages/common/infra/src/media/types.ts
Normal file
72
packages/common/infra/src/media/types.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Attachment block audio media.
|
||||
* blockId/docId/workspaceId are used to identify the source of the media
|
||||
* to control the exclusivity playback state of audio across the whole application.
|
||||
*/
|
||||
export interface AttachmentBlockAudioMedia {
|
||||
blobId: string; // aka sourceId
|
||||
blockId: string;
|
||||
docId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface AudioMediaDescriptor {
|
||||
key: AudioMediaKey;
|
||||
tabId: string | null;
|
||||
name: string;
|
||||
size: number;
|
||||
blobId: string; // aka sourceId
|
||||
}
|
||||
|
||||
// workspaceId/docId/blockId/blobId
|
||||
export type AudioMediaKey = `${string}/${string}/${string}/${string}`;
|
||||
|
||||
export const attachmentBlockAudioMediaKey = (
|
||||
media: AttachmentBlockAudioMedia
|
||||
): AudioMediaKey => {
|
||||
return `${media.workspaceId}/${media.docId}/${media.blockId}/${media.blobId}`;
|
||||
};
|
||||
|
||||
export const parseAudioMediaKey = (
|
||||
key: AudioMediaKey
|
||||
): AttachmentBlockAudioMedia => {
|
||||
const [workspaceId, docId, blockId, blobId] = key.split('/');
|
||||
return {
|
||||
workspaceId,
|
||||
docId,
|
||||
blockId,
|
||||
blobId,
|
||||
};
|
||||
};
|
||||
|
||||
type State = 'idle' | 'playing' | 'paused' | 'stopped';
|
||||
|
||||
export interface MediaStats {
|
||||
key: AudioMediaKey;
|
||||
tabId: string | null;
|
||||
duration: number;
|
||||
name: string;
|
||||
size: number;
|
||||
waveform: number[]; // for drawing waveform, maxmium of 1000 samples
|
||||
}
|
||||
|
||||
export interface PlaybackState {
|
||||
key: AudioMediaKey;
|
||||
tabId: string | null;
|
||||
state: State;
|
||||
/**
|
||||
* Whenever the user seek the media, the startSeekOffset will be updated
|
||||
*/
|
||||
seekOffset: number;
|
||||
/**
|
||||
* Whenever the media state is updated.
|
||||
* the updateTime will be updated. It is in milliseconds (unix timestamp).
|
||||
* The current playback position (0-based, in seconds) is calculated by `seekOffset + (Date.now() - updateTime) / 1000 * rate`
|
||||
*/
|
||||
updateTime: number;
|
||||
/**
|
||||
* the playback rate
|
||||
* Not implemented yet. Always 1.0.
|
||||
*/
|
||||
// rate: number;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Unreachable } from '@affine/env/constant';
|
||||
|
||||
export interface RcRef<T> {
|
||||
export interface RcRef<T> extends Disposable {
|
||||
obj: T;
|
||||
release: () => void;
|
||||
}
|
||||
@@ -21,17 +21,19 @@ export class ObjectPool<Key, T> {
|
||||
if (exist) {
|
||||
exist.rc++;
|
||||
let released = false;
|
||||
const release = () => {
|
||||
// avoid double release
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
released = true;
|
||||
exist.rc--;
|
||||
this.requestGc();
|
||||
};
|
||||
return {
|
||||
obj: exist.obj,
|
||||
release: () => {
|
||||
// avoid double release
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
released = true;
|
||||
exist.rc--;
|
||||
this.requestGc();
|
||||
},
|
||||
release,
|
||||
[Symbol.dispose]: release,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user