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.

244 lines (243 loc) 10.5 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 _nativePermissionGranted = _interopRequireDefault(require("../utils/nativePermissionGranted")); 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 AudioRecorderPlayerAdapter { constructor(audioRecorderModule) { _defineProperty(this, "module", void 0); _defineProperty(this, "audioOptions", void 0); this.module = new audioRecorderModule.default(); this.audioOptions = _reactNative.Platform.select({ android: { AudioEncodingBitRateAndroid: _VoiceMessageConfig.default.DEFAULT.RECORDER.BIT_RATE, AudioChannelsAndroid: _VoiceMessageConfig.default.DEFAULT.RECORDER.CHANNELS, AudioSamplingRateAndroid: _VoiceMessageConfig.default.DEFAULT.RECORDER.SAMPLE_RATE, AudioEncoderAndroid: audioRecorderModule.AudioEncoderAndroidType.AAC, OutputFormatAndroid: audioRecorderModule.OutputFormatAndroidType.MPEG_4, AudioSourceAndroid: audioRecorderModule.AudioSourceAndroidType.VOICE_RECOGNITION }, ios: { AVEncoderBitRateKeyIOS: _VoiceMessageConfig.default.DEFAULT.RECORDER.BIT_RATE, AVNumberOfChannelsKeyIOS: _VoiceMessageConfig.default.DEFAULT.RECORDER.CHANNELS, AVSampleRateKeyIOS: _VoiceMessageConfig.default.DEFAULT.RECORDER.SAMPLE_RATE, AVFormatIDKeyIOS: audioRecorderModule.AVEncodingOption.mp4, // same with aac AVEncoderAudioQualityKeyIOS: audioRecorderModule.AVEncoderAudioQualityIOSType.high }, default: {} }); } async setSubscriptionDuration(duration) { await this.module.setSubscriptionDuration(duration); } addRecordBackListener(callback) { this.module.addRecordBackListener(callback); } convertRecordPath(uri) { return _reactNative.Platform.OS === 'ios' ? uri.split('/').pop() || uri : uri; } async startRecorder(uri) { await this.module.startRecorder(uri, this.audioOptions); } async stopRecorder() { await this.module.stopRecorder(); } } class NitroSoundOrLegacyV4Adapter { constructor(audioRecorderModule) { _defineProperty(this, "module", void 0); _defineProperty(this, "audioOptions", void 0); this.module = audioRecorderModule.default; this.audioOptions = _reactNative.Platform.select({ android: { AudioEncodingBitRateAndroid: _VoiceMessageConfig.default.DEFAULT.RECORDER.BIT_RATE, AudioChannelsAndroid: _VoiceMessageConfig.default.DEFAULT.RECORDER.CHANNELS, AudioSamplingRateAndroid: _VoiceMessageConfig.default.DEFAULT.RECORDER.SAMPLE_RATE, AudioEncoderAndroid: audioRecorderModule.AudioEncoderAndroidType.AAC, OutputFormatAndroid: audioRecorderModule.OutputFormatAndroidType.MPEG_4, AudioSourceAndroid: audioRecorderModule.AudioSourceAndroidType.VOICE_RECOGNITION }, ios: { AVEncoderBitRateKeyIOS: _VoiceMessageConfig.default.DEFAULT.RECORDER.BIT_RATE, AVNumberOfChannelsKeyIOS: _VoiceMessageConfig.default.DEFAULT.RECORDER.CHANNELS, AVSampleRateKeyIOS: _VoiceMessageConfig.default.DEFAULT.RECORDER.SAMPLE_RATE, AVFormatIDKeyIOS: 'mp4', // same with aac AVEncoderAudioQualityKeyIOS: audioRecorderModule.AVEncoderAudioQualityIOSType.high }, default: {} }); } setSubscriptionDuration(duration) { try { this.module.setSubscriptionDuration(duration); } catch (error) { _uikitUtils.Logger.warn('[RecorderService.Native] Failed to set subscription duration', error); } } addRecordBackListener(callback) { this.module.addRecordBackListener(callback); } convertRecordPath(uri) { return uri; } async startRecorder(uri) { await this.module.startRecorder(uri, this.audioOptions); } async stopRecorder() { await this.module.stopRecorder(); } } class VoiceRecorder { constructor(adapter, permissionModule) { this.adapter = adapter; this.permissionModule = permissionModule; _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, "_recordStartedAt", 0); _defineProperty(this, "_stopping", false); _defineProperty(this, "recordingSubscribers", new Set()); _defineProperty(this, "stateSubscribers", new Set()); _defineProperty(this, "setState", state => { this.state = state; this.stateSubscribers.forEach(callback => { callback(state); }); }); _defineProperty(this, "getRecorderStopSafeBuffer", () => { const minWaitingTime = 500; const elapsedTime = Date.now() - this._recordStartedAt; if (elapsedTime > minWaitingTime) return 0;else return minWaitingTime - elapsedTime; }); _defineProperty(this, "requestPermission", async () => { const permission = _reactNative.Platform.select({ android: [this.permissionModule.PERMISSIONS.ANDROID.RECORD_AUDIO], ios: [this.permissionModule.PERMISSIONS.IOS.MICROPHONE], windows: [this.permissionModule.PERMISSIONS.WINDOWS.MICROPHONE], default: undefined }); if (_reactNative.Platform.OS === 'android' && _reactNative.Platform.Version <= 28) { permission === null || permission === void 0 || permission.push(this.permissionModule.PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); } if (permission) { const status = await this.permissionModule.checkMultiple(permission); if ((0, _nativePermissionGranted.default)(status)) { return true; } else { const status = await this.permissionModule.requestMultiple(permission); return (0, _nativePermissionGranted.default)(status); } } else { return true; } }); _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, "record", async uri => { if ((0, _uikitUtils.matchesOneOf)(this.state, ['idle', 'completed'])) { try { this.setState('preparing'); await this.adapter.startRecorder(uri); if (_reactNative.Platform.OS === 'android') { this._recordStartedAt = Date.now(); } this.uri = uri; this.setState('recording'); } catch (e) { this.setState('idle'); throw e; } } }); _defineProperty(this, "stop", async () => { if ((0, _uikitUtils.matchesOneOf)(this.state, ['recording']) && !this._stopping) { this._stopping = true; try { if (_reactNative.Platform.OS === 'android') { const buffer = this.getRecorderStopSafeBuffer(); if (buffer > 0) await (0, _uikitUtils.sleep)(buffer); } await this.adapter.stopRecorder(); this.setState('completed'); } catch (error) { _uikitUtils.Logger.error('[RecorderService.Native] Failed to stop recorder', error); throw error; } finally { this._stopping = false; } } }); _defineProperty(this, "reset", async () => { await this.stop(); this.uri = undefined; this.recordingSubscribers.clear(); this.setState('idle'); }); _defineProperty(this, "convertRecordPath", uri => { return this.adapter.convertRecordPath(uri); }); this.initialize(); } initialize() { const setDurationResult = this.adapter.setSubscriptionDuration(0.1); if (setDurationResult instanceof Promise) { setDurationResult.catch(error => { _uikitUtils.Logger.warn('[RecorderService.Native] Failed to set subscription duration', error); }); } this.adapter.addRecordBackListener(data => { const completed = data.currentPosition >= this.options.maxDuration; if (completed) { this.stop().catch(error => { _uikitUtils.Logger.warn('[RecorderService.Native] Failed to stop in RecordBackListener', error); }); } if (this.state === 'recording') { this.recordingSubscribers.forEach(callback => { callback({ currentTime: data.currentPosition, completed }); }); } }); } } const createNativeRecorderService = modules => { const adapter = isNitroSoundOrLegacyV4Module(modules.audioRecorderModule) ? new NitroSoundOrLegacyV4Adapter(modules.audioRecorderModule) : new AudioRecorderPlayerAdapter(modules.audioRecorderModule); return new VoiceRecorder(adapter, modules.permissionModule); }; function isNitroSoundOrLegacyV4Module(module) { const isNitroSound = 'createSound' in module && typeof module.createSound === 'function'; const isLegacyV4 = 'default' in module && 'getHybridObject' in module.default && typeof module.default.getHybridObject === 'function'; if (isLegacyV4) { _uikitUtils.Logger.warn('react-native-audio-recorder-player is deprecated. Please use react-native-nitro-sound instead.'); } return isNitroSound || isLegacyV4; } var _default = exports.default = createNativeRecorderService; //# sourceMappingURL=createRecorderService.native.js.map