mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-29 08:09:52 +08: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:
@@ -0,0 +1 @@
|
||||
export * from './types';
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user