UNPKG

@sendbird/uikit-react-native

Version:

Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.

277 lines (276 loc) 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _reactNative = require("react-native"); var _uikitUtils = require("@sendbird/uikit-utils"); var _VoiceMessageConfig = _interopRequireDefault(require("../libs/VoiceMessageConfig")); var _expoBackwardUtils = _interopRequireDefault(require("../utils/expoBackwardUtils")); var _expoPermissionGranted = _interopRequireDefault(require("../utils/expoPermissionGranted")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } class BaseAudioRecorderAdapter { constructor() { _defineProperty(this, "uri", undefined); _defineProperty(this, "state", 'idle'); _defineProperty(this, "options", { minDuration: _VoiceMessageConfig.default.DEFAULT.RECORDER.MIN_DURATION, maxDuration: _VoiceMessageConfig.default.DEFAULT.RECORDER.MAX_DURATION, extension: _VoiceMessageConfig.default.DEFAULT.RECORDER.EXTENSION }); _defineProperty(this, "_audioSettings", { sampleRate: _VoiceMessageConfig.default.DEFAULT.RECORDER.SAMPLE_RATE, bitRate: _VoiceMessageConfig.default.DEFAULT.RECORDER.BIT_RATE, numberOfChannels: _VoiceMessageConfig.default.DEFAULT.RECORDER.CHANNELS // encoding: mpeg4_aac }); _defineProperty(this, "_recordingSubscribers", new Set()); _defineProperty(this, "_stateSubscribers", new Set()); // NOTE: In Android, even when startRecorder() is awaited, if stop() is executed immediately afterward, an error occurs _defineProperty(this, "_recordStartedAt", 0); _defineProperty(this, "_getRecorderStopSafeBuffer", () => { const minWaitingTime = 500; const elapsedTime = Date.now() - this._recordStartedAt; if (elapsedTime > minWaitingTime) return 0;else return minWaitingTime - elapsedTime; }); _defineProperty(this, "setState", state => { this.state = state; this._stateSubscribers.forEach(callback => { callback(state); }); }); _defineProperty(this, "addRecordingListener", callback => { this._recordingSubscribers.add(callback); return () => { this._recordingSubscribers.delete(callback); }; }); _defineProperty(this, "addStateListener", callback => { this._stateSubscribers.add(callback); return () => { this._stateSubscribers.delete(callback); }; }); _defineProperty(this, "convertRecordPath", uri => { return uri; }); } } class LegacyExpoAVRecorderAdapter extends BaseAudioRecorderAdapter { constructor(avModule) { super(); _defineProperty(this, "avModule", void 0); _defineProperty(this, "_recorder", void 0); _defineProperty(this, "_audioOptions", void 0); _defineProperty(this, "prepare", async () => { this.setState('preparing'); if (_reactNative.Platform.OS === 'ios') { await this.avModule.Audio.setAudioModeAsync({ allowsRecordingIOS: true, playsInSilentModeIOS: true }); } if (this._recorder._isDoneRecording) { this._recorder = new this.avModule.Audio.Recording(); } this._recorder.setProgressUpdateInterval(100); this._recorder.setOnRecordingStatusUpdate(status => { const completed = status.durationMillis >= this.options.maxDuration; if (completed) this.stop(); if (status.isRecording) { this._recordingSubscribers.forEach(callback => { callback({ currentTime: status.durationMillis, completed: completed }); }); } }); await this._recorder.prepareToRecordAsync(this._audioOptions); }); _defineProperty(this, "requestPermission", async () => { const status = await this.avModule.Audio.getPermissionsAsync(); if ((0, _expoPermissionGranted.default)([status])) { return true; } else { const status = await this.avModule.Audio.requestPermissionsAsync(); return (0, _expoPermissionGranted.default)([status]); } }); _defineProperty(this, "record", async () => { if ((0, _uikitUtils.matchesOneOf)(this.state, ['idle', 'completed'])) { try { await this.prepare(); await this._recorder.startAsync(); if (_reactNative.Platform.OS === 'android') { this._recordStartedAt = Date.now(); } const uri = this._recorder.getURI(); if (uri) this.uri = uri; this.setState('recording'); } catch (e) { this.setState('idle'); throw e; } } }); _defineProperty(this, "stop", async () => { if ((0, _uikitUtils.matchesOneOf)(this.state, ['recording'])) { if (_reactNative.Platform.OS === 'android') { const buffer = this._getRecorderStopSafeBuffer(); if (buffer > 0) await (0, _uikitUtils.sleep)(buffer); } await this._recorder.stopAndUnloadAsync(); if (_reactNative.Platform.OS === 'ios') { await this.avModule.Audio.setAudioModeAsync({ allowsRecordingIOS: false, playsInSilentModeIOS: false }); } this.setState('completed'); } }); _defineProperty(this, "reset", async () => { await this.stop(); this.uri = undefined; this._recordingSubscribers.clear(); this._recorder = new this.avModule.Audio.Recording(); this.setState('idle'); }); this.avModule = avModule; this._recorder = new avModule.Audio.Recording(); this._audioOptions = { android: { ...this._audioSettings, extension: `.${this.options.extension}`, audioEncoder: avModule.Audio.AndroidAudioEncoder.AAC, outputFormat: avModule.Audio.AndroidOutputFormat.MPEG_4 }, ios: { ...this._audioSettings, extension: `.${this.options.extension}`, outputFormat: avModule.Audio.IOSOutputFormat.MPEG4AAC, audioQuality: avModule.Audio.IOSAudioQuality.HIGH }, web: {} }; } } class ExpoAudioRecorderAdapter extends BaseAudioRecorderAdapter { constructor(audioModule) { super(); _defineProperty(this, "audioModule", void 0); _defineProperty(this, "recorder", null); _defineProperty(this, "recordingUpdateInterval", null); _defineProperty(this, "setListener", () => { if (!this.recorder) return; this.recordingUpdateInterval = setInterval(() => { if (this.recorder && this.recorder.isRecording) { const currentTime = this.recorder.currentTime * 1000; const completed = currentTime >= this.options.maxDuration; if (completed) { this.stop().catch(error => { _uikitUtils.Logger.warn('[RecorderService.Expo] Failed to stop in update interval', error); }); } this._recordingSubscribers.forEach(callback => { callback({ currentTime, completed }); }); } }, 100); }); _defineProperty(this, "removeListener", () => { if (this.recordingUpdateInterval) { clearInterval(this.recordingUpdateInterval); this.recordingUpdateInterval = null; } }); _defineProperty(this, "prepare", async () => { this.setState('preparing'); if (_reactNative.Platform.OS === 'ios') { await this.audioModule.setAudioModeAsync({ allowsRecording: true, playsInSilentMode: true }); } const recordingOptions = { ...this._audioSettings, extension: `.${this.options.extension}` }; this.recorder = new this.audioModule.AudioModule.AudioRecorder(recordingOptions); await this.recorder.prepareToRecordAsync(); }); _defineProperty(this, "requestPermission", async () => { const status = await this.audioModule.getRecordingPermissionsAsync(); if ((0, _expoPermissionGranted.default)([status])) { return true; } else { const status = await this.audioModule.requestRecordingPermissionsAsync(); return (0, _expoPermissionGranted.default)([status]); } }); _defineProperty(this, "record", async () => { if ((0, _uikitUtils.matchesOneOf)(this.state, ['idle', 'completed'])) { try { var _this$recorder, _this$recorder2; await this.prepare(); this.setListener(); (_this$recorder = this.recorder) === null || _this$recorder === void 0 || _this$recorder.record(); if (_reactNative.Platform.OS === 'android') { this._recordStartedAt = Date.now(); } const uri = (_this$recorder2 = this.recorder) === null || _this$recorder2 === void 0 ? void 0 : _this$recorder2.uri; if (uri) this.uri = uri; this.setState('recording'); } catch (e) { this.setState('idle'); this.removeListener(); throw e; } } }); _defineProperty(this, "stop", async () => { if ((0, _uikitUtils.matchesOneOf)(this.state, ['recording'])) { var _this$recorder3; if (_reactNative.Platform.OS === 'android') { const buffer = this._getRecorderStopSafeBuffer(); if (buffer > 0) await (0, _uikitUtils.sleep)(buffer); } await ((_this$recorder3 = this.recorder) === null || _this$recorder3 === void 0 ? void 0 : _this$recorder3.stop()); this.removeListener(); if (_reactNative.Platform.OS === 'ios') { await this.audioModule.setAudioModeAsync({ allowsRecording: false, playsInSilentMode: false }); } this.setState('completed'); } }); _defineProperty(this, "reset", async () => { await this.stop(); this.recorder = null; this.uri = undefined; this._recordingSubscribers.clear(); this._stateSubscribers.clear(); this.setState('idle'); }); this.audioModule = audioModule; } } const createExpoRecorderService = ({ avModule }) => { if (_expoBackwardUtils.default.expoAV.isLegacyAVModule(avModule)) { _uikitUtils.Logger.warn('[RecorderService.Expo] expo-av is deprecated and will be removed in Expo 54. Please migrate to expo-audio.'); } return _expoBackwardUtils.default.expoAV.isAudioModule(avModule) ? new ExpoAudioRecorderAdapter(avModule) : new LegacyExpoAVRecorderAdapter(avModule); }; var _default = exports.default = createExpoRecorderService; //# sourceMappingURL=createRecorderService.expo.js.map