Skip to content

Commit

Permalink
Pausing while recording ends current mining command
Browse files Browse the repository at this point in the history
  • Loading branch information
killergerbah committed Aug 4, 2024
1 parent 9c73b5f commit c784e18
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 41 deletions.
68 changes: 39 additions & 29 deletions extension/src/handlers/video/stop-recording-media-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import ImageCapturer from '../../services/image-capturer';
import {
AudioModel,
Command,
ExtensionToVideoCommand,
ImageModel,
Message,
RecordingFinishedMessage,
StopRecordingMediaMessage,
SubtitleModel,
VideoToExtensionCommand,
Expand All @@ -14,6 +12,7 @@ import { SettingsProvider } from '@project/common/settings';
import { mockSurroundingSubtitles } from '@project/common/util';
import { CardPublisher } from '../../services/card-publisher';
import AudioRecorderService from '../../services/audio-recorder-service';
import { AutoRecordingInProgressError } from '../../services/audio-recorder-delegate';

export default class StopRecordingMediaHandler {
private readonly _audioRecorder: AudioRecorderService;
Expand Down Expand Up @@ -77,33 +76,44 @@ export default class StopRecordingMediaHandler {
}

const preferMp3 = await this._settingsProvider.getSingle('preferMp3');
const audioBase64 = await this._audioRecorder.stop(preferMp3, {
tabId: sender.tab!.id!,
src: stopRecordingCommand.src,
});
const audioModel: AudioModel = {
base64: audioBase64,
extension: preferMp3 ? 'mp3' : 'webm',
paddingStart: 0,
paddingEnd: 0,
start: stopRecordingCommand.message.startTimestamp,
end: stopRecordingCommand.message.endTimestamp,
playbackRate: stopRecordingCommand.message.playbackRate,
};
try {
const audioBase64 = await this._audioRecorder.stop(preferMp3, {
tabId: sender.tab!.id!,
src: stopRecordingCommand.src,
});
const audioModel: AudioModel = {
base64: audioBase64,
extension: preferMp3 ? 'mp3' : 'webm',
paddingStart: 0,
paddingEnd: 0,
start: stopRecordingCommand.message.startTimestamp,
end: stopRecordingCommand.message.endTimestamp,
playbackRate: stopRecordingCommand.message.playbackRate,
};

this._cardPublisher.publish(
{
subtitle: subtitle,
surroundingSubtitles: surroundingSubtitles,
image: imageModel,
audio: audioModel,
url: stopRecordingCommand.message.url,
subtitleFileName: stopRecordingCommand.message.subtitleFileName,
mediaTimestamp: stopRecordingCommand.message.startTimestamp,
},
stopRecordingCommand.message.postMineAction,
sender.tab!.id!,
stopRecordingCommand.src
);
this._cardPublisher.publish(
{
subtitle: subtitle,
surroundingSubtitles: surroundingSubtitles,
image: imageModel,
audio: audioModel,
url: stopRecordingCommand.message.url,
subtitleFileName: stopRecordingCommand.message.subtitleFileName,
mediaTimestamp: stopRecordingCommand.message.startTimestamp,
},
stopRecordingCommand.message.postMineAction,
sender.tab!.id!,
stopRecordingCommand.src
);
} catch (e) {
if (!(e instanceof AutoRecordingInProgressError)) {
throw e;
}

// Else a recording scheduled from record-media-handler (or rerecord-media-handler) was in-progress
// and the call to stop() just above force-stopped it.
// We should do nothing else because execution in record-media-handler will continue
// and publish the card etc.
}
}
}
16 changes: 13 additions & 3 deletions extension/src/offscreen-audio-recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
StartRecordingAudioMessage,
OffscreenDocumentToExtensionCommand,
} from '@project/common';
import AudioRecorder from './services/audio-recorder';
import AudioRecorder, { AutoRecordingInProgressError } from './services/audio-recorder';
import { bufferToBase64 } from './services/base64';
import { Mp3Encoder } from '@project/common/audio-clip';

Expand Down Expand Up @@ -81,8 +81,18 @@ window.onload = async () => {
const stopRecordingAudioMessage = request.message as StopRecordingAudioMessage;
audioRecorder
.stop()
.then((audioBase64) => _sendAudioBase64(audioBase64, stopRecordingAudioMessage.preferMp3));
break;
.then((audioBase64) => {
sendResponse(true);
_sendAudioBase64(audioBase64, stopRecordingAudioMessage.preferMp3);
})
.catch((e) => {
if (e instanceof AutoRecordingInProgressError) {
sendResponse(false);
} else {
console.error(e);
}
});
return true;
}
}
};
Expand Down
16 changes: 14 additions & 2 deletions extension/src/services/audio-recorder-delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export interface AudioRecorderDelegate {

export class DrmProtectedStreamError extends Error {}

export class AutoRecordingInProgressError extends Error {}

export class OffscreenAudioRecorder implements AudioRecorderDelegate {
private audioBase64Resolve?: (value: string) => void;

Expand Down Expand Up @@ -131,7 +133,12 @@ export class OffscreenAudioRecorder implements AudioRecorderDelegate {
preferMp3,
},
};
chrome.runtime.sendMessage(command);
const stopped = (await chrome.runtime.sendMessage(command)) as boolean;

if (stopped === false) {
throw new AutoRecordingInProgressError();
}

return await this._audioBase64();
}

Expand Down Expand Up @@ -202,7 +209,12 @@ export class CaptureStreamAudioRecorder implements AudioRecorderDelegate {
},
src,
};
chrome.tabs.sendMessage(tabId, command);
const stopped = (await chrome.tabs.sendMessage(tabId, command)) as boolean;

if (stopped === false) {
throw new AutoRecordingInProgressError();
}

return await this._audioBase64();
}

Expand Down
20 changes: 18 additions & 2 deletions extension/src/services/audio-recorder.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { bufferToBase64 } from './base64';

export class AutoRecordingInProgressError extends Error {}

export default class AudioRecorder {
private recording: boolean;
private recorder: MediaRecorder | null;
private stream: MediaStream | null;
private blobPromise: Promise<Blob> | null;
private timeoutId?: NodeJS.Timeout;
private timeoutResolve?: (base64: string) => void;

constructor() {
this.recording = false;
Expand All @@ -24,7 +28,9 @@ export default class AudioRecorder {

await this.start(stream);
onStartedCallback();
setTimeout(async () => {
this.timeoutResolve = resolve;
this.timeoutId = setTimeout(async () => {
this.timeoutId = undefined;
resolve(await this.stop());
}, time);
} catch (e) {
Expand Down Expand Up @@ -78,6 +84,16 @@ export default class AudioRecorder {
this.stream = null;
const blob = await this.blobPromise;
this.blobPromise = null;
return await bufferToBase64(await blob!.arrayBuffer());
const base64 = await bufferToBase64(await blob!.arrayBuffer());

if (this.timeoutId !== undefined) {
clearTimeout(this.timeoutId);
this.timeoutId = undefined;
this.timeoutResolve?.(base64);
this.timeoutResolve = undefined;
throw new AutoRecordingInProgressError();
}

return base64;
}
}
25 changes: 20 additions & 5 deletions extension/src/services/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import { MobileVideoOverlayController } from '../controllers/mobile-video-overla
import NotificationController from '../controllers/notification-controller';
import SubtitleController, { SubtitleModelWithIndex } from '../controllers/subtitle-controller';
import VideoDataSyncController from '../controllers/video-data-sync-controller';
import AudioRecorder from './audio-recorder';
import AudioRecorder, { AutoRecordingInProgressError } from './audio-recorder';
import { bufferToBase64 } from './base64';
import { isMobile } from './device-detection';
import { OffsetAnchor } from './element-overlay';
Expand Down Expand Up @@ -93,6 +93,7 @@ export default class Binding {
private _syncedTimestamp?: number;

recordingState: RecordingState = RecordingState.notRecording;
recordingPostMineAction?: PostMineAction;
wasPlayingBeforeRecordingMedia?: boolean;
postMinePlayback: PostMinePlayback = PostMinePlayback.remember;
private recordingMediaStartedTimestamp?: number;
Expand Down Expand Up @@ -429,6 +430,10 @@ export default class Binding {
};

chrome.runtime.sendMessage(command);

if (this.recordingMedia && this.recordingPostMineAction !== undefined) {
this._toggleRecordingMedia(this.recordingPostMineAction);
}
};

this.seekedListener = (event) => {
Expand Down Expand Up @@ -761,10 +766,18 @@ export default class Binding {
const stopRecordingAudioMessage = request.message as StopRecordingAudioMessage;
this._audioRecorder
.stop()
.then((audioBase64) =>
this._sendAudioBase64(audioBase64, stopRecordingAudioMessage.preferMp3)
);
break;
.then((audioBase64) => {
sendResponse(true);
this._sendAudioBase64(audioBase64, stopRecordingAudioMessage.preferMp3);
})
.catch((e) => {
if (e instanceof AutoRecordingInProgressError) {
sendResponse(false);
} else {
console.error(e);
}
});
return true;
case 'notification-dialog':
const notificationDialogMessage = request.message as NotificationDialogMessage;
this.notificationController.show(
Expand Down Expand Up @@ -954,6 +967,7 @@ export default class Binding {

if (this.recordMedia) {
this.recordingState = RecordingState.requested;
this.recordingPostMineAction = postMineAction;
this.wasPlayingBeforeRecordingMedia = !this.video.paused;
this.recordingMediaStartedTimestamp = this.video.currentTime * 1000;
this.recordingMediaWithScreenshot = this.takeScreenshot;
Expand Down Expand Up @@ -1034,6 +1048,7 @@ export default class Binding {
this.wasPlayingBeforeRecordingMedia = !this.video.paused;
this.recordingMediaStartedTimestamp = timestamp;
this.recordingMediaWithScreenshot = this.takeScreenshot;
this.recordingPostMineAction = postMineAction;

if (this.video.paused) {
await this.play();
Expand Down

0 comments on commit c784e18

Please sign in to comment.