Skip to content

Commit

Permalink
[CLNP-2908] Typescript error fix for hooks (#1054)
Browse files Browse the repository at this point in the history
Fixes: [CLNP-2908](https://sendbird.atlassian.net/browse/CLNP-2908)


[CLNP-2908]:
https://sendbird.atlassian.net/browse/CLNP-2908?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

---------

Co-authored-by: OnestarLee <100272033+OnestarLee@users.noreply.github.com>
Co-authored-by: bang9 <gusrn1423@naver.com>
  • Loading branch information
3 people committed May 9, 2024
1 parent 19d3fba commit 9979c4c
Show file tree
Hide file tree
Showing 244 changed files with 1,396 additions and 1,370 deletions.
23 changes: 13 additions & 10 deletions src/hooks/VoicePlayer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,23 @@ export const VoicePlayerProvider = ({
}
};

const pause = (groupKey: string | null) => {
if (currentGroupKey === groupKey && currentPlayer !== null) {
logger.info('VoicePlayer: Pause playing(by group key).');
currentPlayer?.pause();
}
if (groupKey === ALL) {
logger.info('VoicePlayer: Pause playing(all).');
currentPlayer?.pause();
const pause = (groupKey?: string) => {
if (currentPlayer) {
if (groupKey === currentGroupKey) {
logger.info('VoicePlayer: Pause playing(by group key).');
currentPlayer.pause();
} else if (groupKey === ALL) {
logger.info('VoicePlayer: Pause playing(all).');
currentPlayer.pause();
}
} else {
logger.warning('VoicePlayer: No currentPlayer to pause.');
}
};

const play = ({
groupKey,
audioFile = null,
audioFile,
audioFileUrl = '',
}: VoicePlayerPlayProps): void => {
if (groupKey !== currentGroupKey) {
Expand All @@ -96,7 +99,7 @@ export const VoicePlayerProvider = ({
// Clear the previous AudioPlayer element
const voicePlayerRoot = document.getElementById(VOICE_PLAYER_ROOT_ID);
const voicePlayerAudioElement = document.getElementById(VOICE_PLAYER_AUDIO_ID);
if (voicePlayerAudioElement) {
if (voicePlayerRoot && voicePlayerAudioElement) {
voicePlayerRoot.removeChild(voicePlayerAudioElement);
}

Expand Down
10 changes: 5 additions & 5 deletions src/hooks/VoicePlayer/useVoicePlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { useVoicePlayerContext } from '.';
import { VOICE_PLAYER_AUDIO_ID } from '../../utils/consts';
import { useVoiceRecorderContext } from '../VoiceRecorder';
Expand All @@ -7,8 +7,8 @@ import { AudioUnitDefaultValue, VoicePlayerStatusType } from './dux/initialState
import { generateGroupKey } from './utils';

export interface UseVoicePlayerProps {
key: string;
channelUrl: string;
key?: string;
channelUrl?: string;
audioFile?: File;
audioFileUrl?: string;
}
Expand All @@ -25,10 +25,10 @@ export interface UseVoicePlayerContext {
export const useVoicePlayer = ({
key = '',
channelUrl = '',
audioFile = null,
audioFile,
audioFileUrl = '',
}: UseVoicePlayerProps): UseVoicePlayerContext => {
const [groupKey] = useState<string>(generateGroupKey(channelUrl, key));
const groupKey = generateGroupKey(channelUrl, key);
const {
play,
pause,
Expand Down
32 changes: 21 additions & 11 deletions src/hooks/VoiceRecorder/WebAudioUtils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Thanks to https://codesandbox.io/s/media-recorder-api-downsampling-16k-mp3-encode-using-lame-js-forked-n1pblw
import { VOICE_RECORDER_AUDIO_SAMPLE_RATE } from '../../utils/consts';
// @ts-ignore
import { WavHeader, Mp3Encoder } from '../../_externals/lamejs/lame.all';

function encodeMp3(arrayBuffer: ArrayBuffer): WavHeader {
function encodeMp3(arrayBuffer: ArrayBuffer) {
const wav = WavHeader.readHeader(new DataView(arrayBuffer));
const dataView = new Int16Array(arrayBuffer, wav.dataOffset, wav.dataLen / 2);
const mp3Encoder = new Mp3Encoder(wav.channels, wav.sampleRate, 128);
Expand All @@ -14,11 +15,13 @@ function encodeMp3(arrayBuffer: ArrayBuffer): WavHeader {
if (wav.channels > 1) {
for (let j = 0; j < samplesLeft.length; j++) {
samplesLeft[j] = dataView[j * 2];
samplesRight[j] = dataView[j * 2 + 1];
if (samplesRight) {
samplesRight[j] = dataView[j * 2 + 1];
}
}
}

const dataBuffer = [];
const dataBuffer: Int8Array[] = [];
let remaining = samplesLeft.length;
for (let i = 0; remaining >= maxSamples; i += maxSamples) {
const left = samplesLeft.subarray(i, i + maxSamples);
Expand All @@ -44,7 +47,7 @@ function downsampleToWav(file: File, callback: (buffer: ArrayBuffer) => void): v
const fileReader = new FileReader();
fileReader.onload = function (ev) {
// Decode audio
audioCtx.decodeAudioData(ev.target.result as ArrayBuffer, (buffer) => {
audioCtx.decodeAudioData(ev.target?.result as ArrayBuffer, (buffer) => {
// this is where you down sample the audio, usually is 44100 samples per second
const usingWebkit = !window.OfflineAudioContext;
const offlineAudioCtx = new OfflineAudioContext(1, 16000 * buffer.duration, 16000);
Expand All @@ -55,8 +58,8 @@ function downsampleToWav(file: File, callback: (buffer: ArrayBuffer) => void): v

const reader = new FileReader();
reader.onload = function () {
const renderCompleteHandler = (evt): void => {
const renderedBuffer = usingWebkit ? evt.renderedBuffer : evt;
const renderCompleteHandler = (evt: OfflineAudioCompletionEvent | AudioBuffer) => {
const renderedBuffer = usingWebkit ? (evt as OfflineAudioCompletionEvent).renderedBuffer : (evt as AudioBuffer);
const buffer = bufferToWav(renderedBuffer, renderedBuffer.length);
if (callback) {
callback(buffer);
Expand All @@ -80,12 +83,12 @@ function downsampleToWav(file: File, callback: (buffer: ArrayBuffer) => void): v
fileReader.readAsArrayBuffer(file);
}

function bufferToWav(abuffer, len) {
function bufferToWav(abuffer: AudioBuffer, len: number) {
const numOfChan = abuffer.numberOfChannels;
const length = len * numOfChan * 2 + 44;
const buffer = new ArrayBuffer(length);
const view = new DataView(buffer);
const channels = [];
const channels: any[] = [];
let i = 0;
let sample;
let offset = 0;
Expand All @@ -105,9 +108,11 @@ function bufferToWav(abuffer, len) {
setUint16(16); // 16-bit (hardcoded in this demo)
setUint32(0x61746164); // "data" - chunk
setUint32(length - pos - 4); // chunk length

// write interleaved data
for (i = 0; i < abuffer.numberOfChannels; i++)
for (i = 0; i < abuffer.numberOfChannels; i++) {
channels.push(abuffer.getChannelData(i));
}

while (pos < length) {
for (i = 0; i < numOfChan; i++) {
Expand All @@ -122,15 +127,20 @@ function bufferToWav(abuffer, len) {

return buffer;

function setUint16(data) {
function setUint16(data: number) {
view.setUint16(pos, data, true);
pos += 2;
}

function setUint32(data) {
function setUint32(data: number) {
view.setUint32(pos, data, true);
pos += 4;
}
}

export interface WebAudioUtils {
downsampleToWav: typeof downsampleToWav;
encodeMp3: typeof encodeMp3;
}

export { downsampleToWav, encodeMp3 };
47 changes: 20 additions & 27 deletions src/hooks/VoiceRecorder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
VOICE_RECORDER_AUDIO_BIT_RATE,
} from '../../utils/consts';
import useSendbirdStateContext from '../useSendbirdStateContext';
import { type WebAudioUtils } from './WebAudioUtils';
import { noop } from '../../utils/utils';

// Input props of VoiceRecorder
export interface VoiceRecorderProps {
Expand All @@ -22,11 +24,11 @@ export interface VoiceRecorderEventHandler {

// Output of VoiceRecorder
export interface VoiceRecorderContext {
start: (eventHandler?: VoiceRecorderEventHandler) => void,
stop: () => void,
start: (eventHandler?: VoiceRecorderEventHandler) => void;
stop: () => void;
isRecordable: boolean;
}
const noop = () => { /* noop */ };

const Context = createContext<VoiceRecorderContext>({
start: noop,
stop: noop,
Expand All @@ -37,13 +39,13 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
const { children } = props;
const { config } = useSendbirdStateContext();
const { logger, groupChannel } = config;
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder>(null);
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
const [isRecordable, setIsRecordable] = useState<boolean>(false);
const [permissionWarning, setPermissionWarning] = useState<boolean>(false);
const { stringSet } = useLocalization();

const isVoiceMessageEnabled = groupChannel.enableVoiceMessage;
const [webAudioUtils, setWebAudioUtils] = useState(null);
const [webAudioUtils, setWebAudioUtils] = useState<WebAudioUtils | null>(null);

const browserSupportMimeType = BROWSER_SUPPORT_MIME_TYPE_LIST.find((mimeType) => MediaRecorder.isTypeSupported(mimeType)) ?? '';
if (isVoiceMessageEnabled && !browserSupportMimeType) {
Expand All @@ -52,13 +54,11 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle

useEffect(() => {
if (isVoiceMessageEnabled && !webAudioUtils) {
import('./WebAudioUtils').then((data) => {
setWebAudioUtils(data);
});
import('./WebAudioUtils').then((module) => setWebAudioUtils(module));
}
}, [isVoiceMessageEnabled, webAudioUtils]);

const start = useCallback((eventHandler: VoiceRecorderEventHandler): void => {
const start = useCallback((eventHandler?: VoiceRecorderEventHandler): void => {
if (isVoiceMessageEnabled && !webAudioUtils) {
logger.error('VoiceRecorder: Recording audio processor is being loaded.');
return;
Expand Down Expand Up @@ -95,7 +95,8 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
mimeType: browserSupportMimeType,
audioBitsPerSecond: VOICE_RECORDER_AUDIO_BIT_RATE,
});
mediaRecorder.ondataavailable = (e) => { // when recording stops
// when recording stops
mediaRecorder.ondataavailable = (e) => {
logger.info('VoiceRecorder: Succeeded getting an available data.', e.data);
const audioFile = new File([e.data], VOICE_MESSAGE_FILE_NAME, {
lastModified: new Date().getTime(),
Expand All @@ -108,10 +109,11 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
lastModified: new Date().getTime(),
type: VOICE_MESSAGE_MIME_TYPE,
});
eventHandler?.onRecordingEnded(convertedAudioFile);
eventHandler?.onRecordingEnded?.(convertedAudioFile);
logger.info('VoiceRecorder: Succeeded converting audio file.', convertedAudioFile);
});
stream?.getAudioTracks?.().forEach?.(track => track?.stop());
const tracks = stream.getAudioTracks();
tracks.forEach((track) => track.stop());
setIsRecordable(false);
};
mediaRecorder.onstart = eventHandler?.onRecordingStarted ?? noop;
Expand All @@ -133,22 +135,13 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
}, [mediaRecorder]);

return (
<Context.Provider value={{
start,
stop,
isRecordable,
}}>
<Context.Provider value={{ start, stop, isRecordable }}>
{children}
{
permissionWarning && (
<Modal
hideFooter
onCancel={() => setPermissionWarning(false)}
>
<>{stringSet.VOICE_RECORDING_PERMISSION_DENIED}</>
</Modal>
)
}
{permissionWarning && (
<Modal hideFooter onClose={() => setPermissionWarning(false)}>
<>{stringSet.VOICE_RECORDING_PERMISSION_DENIED}</>
</Modal>
)}
</Context.Provider>
);
};
Expand Down
23 changes: 12 additions & 11 deletions src/hooks/VoiceRecorder/useVoiceRecorder.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { VoiceRecorderEventHandler, useVoiceRecorderContext } from '.';
import useSendbirdStateContext from '../useSendbirdStateContext';
import { noop } from '../../utils/utils';

// export interface UseVoiceRecorderProps extends VoiceRecorderEventHandler {
// /**
Expand All @@ -22,23 +23,21 @@ export interface UseVoiceRecorderContext {
cancel: () => void;
recordingLimit: number;
recordingTime: number;
recordedFile: File;
recordedFile: File | null;
recordingStatus: VoiceRecorderStatus;
}

const noop = () => { /* noop */ };

export const useVoiceRecorder = ({
onRecordingStarted = noop,
onRecordingEnded = noop,
}: VoiceRecorderEventHandler): UseVoiceRecorderContext => {
const { config } = useSendbirdStateContext();
const { voiceRecord } = config;
const { maxRecordingTime } = voiceRecord;
const maxRecordingTime = voiceRecord.maxRecordingTime;
const voiceRecorder = useVoiceRecorderContext();
const { isRecordable } = voiceRecorder;

const [recordedFile, setRecordedFile] = useState<File>(null);
const [recordedFile, setRecordedFile] = useState<File | null>(null);
const [recordingStatus, setRecordingStatus] = useState<VoiceRecorderStatus>(VoiceRecorderStatus.PREPARING);
useEffect(() => {
if (isRecordable && recordingStatus === VoiceRecorderStatus.PREPARING) {
Expand Down Expand Up @@ -72,11 +71,12 @@ export const useVoiceRecorder = ({

// Timer
const [recordingTime, setRecordingTime] = useState<number>(0);
let timer: ReturnType<typeof setInterval> = null;
const timer = useRef<ReturnType<typeof setInterval> | null>(null);
function startTimer() {
stopTimer();
setRecordingTime(0);
const interval = setInterval(() => {

timer.current = setInterval(() => {
setRecordingTime(prevTime => {
const newTime = prevTime + 100;
if (newTime > maxRecordingTime) {
Expand All @@ -85,11 +85,12 @@ export const useVoiceRecorder = ({
return newTime;
});
}, 100);
timer = interval;
}
function stopTimer() {
clearInterval(timer);
timer = null;
if (timer.current) {
clearInterval(timer.current);
timer.current = null;
}
}
useEffect(() => {
if (recordingTime > maxRecordingTime) {
Expand Down
8 changes: 4 additions & 4 deletions src/hooks/useThrottleCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export function useThrottleCallback<T extends(...args: any[]) => void>(
trailing: false,
},
) {
const timer = useRef(null);
const trailingArgs = useRef(null);
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
const trailingArgs = useRef<any[] | null>(null);

useEffect(() => {
return () => {
Expand Down Expand Up @@ -58,8 +58,8 @@ export function throttle<T extends(...args: any[]) => void>(
trailing: false,
},
) {
let timer = null;
let trailingArgs = null;
let timer: ReturnType<typeof setTimeout> | null = null;
let trailingArgs: null | any[] = null;

return ((...args: any[]) => {
if (timer) {
Expand Down

0 comments on commit 9979c4c

Please sign in to comment.