365 lines
8.4 KiB
JavaScript
365 lines
8.4 KiB
JavaScript
|
|
// utils/record.js
|
|||
|
|
|
|||
|
|
// ¼<><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
class ScreenRecorder {
|
|||
|
|
constructor() {
|
|||
|
|
this.recordModule = null
|
|||
|
|
this.eventModule = null
|
|||
|
|
this.isRecording = false
|
|||
|
|
this.recordTime = 0
|
|||
|
|
this.recordTimer = null
|
|||
|
|
this.eventListeners = new Map()
|
|||
|
|
|
|||
|
|
this.init()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ʼ<EFBFBD><CABC>
|
|||
|
|
init() {
|
|||
|
|
try {
|
|||
|
|
// <20><>ȡԭ<C8A1><D4AD>ģ<EFBFBD><C4A3>
|
|||
|
|
this.recordModule = uni.requireNativePlugin('Record-Module')
|
|||
|
|
this.eventModule = uni.requireNativePlugin('RecordEvent-Module')
|
|||
|
|
|
|||
|
|
console.log('¼<><C2BC>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>ɹ<EFBFBD>')
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('¼<><C2BC>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ʧ<EFBFBD><CAA7>:', error)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ʼ¼<CABC><C2BC>
|
|||
|
|
start(options = {}) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.recordModule) {
|
|||
|
|
reject(new Error('¼<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (this.isRecording) {
|
|||
|
|
reject(new Error('<27>Ѿ<EFBFBD><D1BE><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const defaultOptions = {
|
|||
|
|
width: 720, // <20><><EFBFBD><EFBFBD>
|
|||
|
|
height: 1280, // <20>߶<EFBFBD>
|
|||
|
|
bitRate: 4000000, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 4Mbps
|
|||
|
|
fileName: null, // <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
|
|||
|
|
recordAudio: true // <20>Ƿ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>Ƶ
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const recordOptions = { ...defaultOptions, ...options }
|
|||
|
|
|
|||
|
|
console.log('<27><>ʼ¼<CABC><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', recordOptions)
|
|||
|
|
|
|||
|
|
this.recordModule.startRecording(recordOptions, (result) => {
|
|||
|
|
console.log('<27><>ʼ¼<CABC><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', result)
|
|||
|
|
|
|||
|
|
if (result.code === 0 && result.success) {
|
|||
|
|
this.isRecording = true
|
|||
|
|
this.startTimer()
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD>¼<EFBFBD>
|
|||
|
|
this.emit('start', { options: recordOptions })
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
message: '<27><>ʼ¼<CABC><C2BC><EFBFBD>ɹ<EFBFBD>',
|
|||
|
|
data: result
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(result.message || '<27><>ʼ¼<CABC><C2BC>ʧ<EFBFBD><CAA7>'))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ֹͣ¼<D6B9><C2BC>
|
|||
|
|
stop() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.recordModule) {
|
|||
|
|
reject(new Error('¼<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!this.isRecording) {
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
message: '<27><>ǰû<C7B0><C3BB><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>'
|
|||
|
|
})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('ֹͣ¼<D6B9><C2BC>')
|
|||
|
|
|
|||
|
|
this.recordModule.stopRecording((result) => {
|
|||
|
|
console.log('ֹͣ¼<D6B9><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', result)
|
|||
|
|
|
|||
|
|
this.isRecording = false
|
|||
|
|
this.stopTimer()
|
|||
|
|
|
|||
|
|
if (result.code === 0 && result.success) {
|
|||
|
|
// <20><><EFBFBD><EFBFBD>ֹͣ<CDA3>¼<EFBFBD>
|
|||
|
|
this.emit('stop', {})
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
message: 'ֹͣ¼<D6B9><C2BC><EFBFBD>ɹ<EFBFBD>',
|
|||
|
|
data: result
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(result.message || 'ֹͣ¼<D6B9><C2BC>ʧ<EFBFBD><CAA7>'))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ȡ¼<C8A1><C2BC>״̬
|
|||
|
|
getStatus() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.recordModule) {
|
|||
|
|
reject(new Error('¼<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.recordModule.getRecordingStatus((result) => {
|
|||
|
|
this.isRecording = result.isRecording
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
isRecording: result.isRecording,
|
|||
|
|
duration: result.duration,
|
|||
|
|
filePath: result.filePath,
|
|||
|
|
...result
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ȡ¼<C8A1><C2BC><EFBFBD>ļ<EFBFBD><C4BC>б<EFBFBD>
|
|||
|
|
getFileList() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.recordModule) {
|
|||
|
|
reject(new Error('¼<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.recordModule.getRecordFiles((result) => {
|
|||
|
|
if (result.code === 0) {
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
files: result.files,
|
|||
|
|
count: result.count
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(result.message || '<27><>ȡ<EFBFBD>ļ<EFBFBD><C4BC>б<EFBFBD>ʧ<EFBFBD><CAA7>'))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ɾ<><C9BE>¼<EFBFBD><C2BC><EFBFBD>ļ<EFBFBD>
|
|||
|
|
deleteFile(filePath) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.recordModule) {
|
|||
|
|
reject(new Error('¼<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.recordModule.deleteRecordFile(filePath, (result) => {
|
|||
|
|
if (result.code === 0 && result.success) {
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
message: 'ɾ<><C9BE><EFBFBD>ɹ<EFBFBD>'
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(result.message || 'ɾ<><C9BE>ʧ<EFBFBD><CAA7>'))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>Ȩ<EFBFBD><C8A8>
|
|||
|
|
checkPermission() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.recordModule) {
|
|||
|
|
reject(new Error('¼<><C2BC>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.recordModule.checkPermission((result) => {
|
|||
|
|
resolve({
|
|||
|
|
hasPermission: result.hasPermission,
|
|||
|
|
message: result.message,
|
|||
|
|
...result
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ʼ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
startListen() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.eventModule) {
|
|||
|
|
reject(new Error('<27>¼<EFBFBD>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.eventModule.startListen((result) => {
|
|||
|
|
if (result.code === 0 && result.success) {
|
|||
|
|
// <20><><EFBFBD><EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD>¼<EFBFBD>
|
|||
|
|
uni.$on('recordEvent', this.handleRecordEvent.bind(this))
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
message: '<27><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>'
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(result.message || '<27><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>'))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ֹͣ<CDA3>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
stopListen() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!this.eventModule) {
|
|||
|
|
reject(new Error('<27>¼<EFBFBD>ģ<EFBFBD><C4A3>δ<EFBFBD><CEB4>ʼ<EFBFBD><CABC>'))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.eventModule.stopListen((result) => {
|
|||
|
|
if (result.code === 0 && result.success) {
|
|||
|
|
// <20>Ƴ<EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
uni.$off('recordEvent', this.handleRecordEvent.bind(this))
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
success: true,
|
|||
|
|
message: 'ֹͣ<CDA3><D6B9><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>'
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(result.message || 'ֹͣ<CDA3><D6B9><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>'))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>¼<EFBFBD>
|
|||
|
|
handleRecordEvent(event) {
|
|||
|
|
console.log('<27>յ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD>¼<EFBFBD>:', event)
|
|||
|
|
|
|||
|
|
const { type, data } = event
|
|||
|
|
|
|||
|
|
switch (type) {
|
|||
|
|
case 'onRecordEvent':
|
|||
|
|
this.handleNativeEvent(data)
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD>¼<EFBFBD>
|
|||
|
|
handleNativeEvent(data) {
|
|||
|
|
const { event, filePath } = data
|
|||
|
|
|
|||
|
|
switch (event) {
|
|||
|
|
case 'start':
|
|||
|
|
console.log('¼<><C2BC><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>:', filePath)
|
|||
|
|
this.emit('started', { filePath })
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
case 'stop':
|
|||
|
|
console.log('¼<><C2BC>ֹͣ<CDA3><D6B9><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>:', filePath)
|
|||
|
|
this.emit('stopped', { filePath })
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ʼ<EFBFBD><CABC>ʱ<EFBFBD><CAB1>
|
|||
|
|
startTimer() {
|
|||
|
|
this.recordTime = 0
|
|||
|
|
this.recordTimer = setInterval(() => {
|
|||
|
|
this.recordTime++
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>¼<EFBFBD>
|
|||
|
|
this.emit('timeupdate', {
|
|||
|
|
currentTime: this.recordTime
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
}, 1000)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ֹͣ<CDA3><D6B9>ʱ<EFBFBD><CAB1>
|
|||
|
|
stopTimer() {
|
|||
|
|
if (this.recordTimer) {
|
|||
|
|
clearInterval(this.recordTimer)
|
|||
|
|
this.recordTimer = null
|
|||
|
|
this.recordTime = 0
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>ʽ<EFBFBD><CABD>ʱ<EFBFBD><CAB1>
|
|||
|
|
formatTime(seconds) {
|
|||
|
|
const hours = Math.floor(seconds / 3600)
|
|||
|
|
const minutes = Math.floor((seconds % 3600) / 60)
|
|||
|
|
const secs = seconds % 60
|
|||
|
|
|
|||
|
|
if (hours > 0) {
|
|||
|
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
|||
|
|
} else {
|
|||
|
|
return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
on(event, callback) {
|
|||
|
|
if (!this.eventListeners.has(event)) {
|
|||
|
|
this.eventListeners.set(event, [])
|
|||
|
|
}
|
|||
|
|
this.eventListeners.get(event).push(callback)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ȡ<><C8A1><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
off(event, callback) {
|
|||
|
|
if (this.eventListeners.has(event)) {
|
|||
|
|
const listeners = this.eventListeners.get(event)
|
|||
|
|
const index = listeners.indexOf(callback)
|
|||
|
|
if (index > -1) {
|
|||
|
|
listeners.splice(index, 1)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
|||
|
|
emit(event, data) {
|
|||
|
|
if (this.eventListeners.has(event)) {
|
|||
|
|
this.eventListeners.get(event).forEach(callback => {
|
|||
|
|
try {
|
|||
|
|
callback(data)
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`ִ<EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD> ${event} <20>Ļص<C4BB>ʧ<EFBFBD><CAA7>:`, error)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD>
|
|||
|
|
destroy() {
|
|||
|
|
this.stop()
|
|||
|
|
this.stopListen()
|
|||
|
|
this.eventListeners.clear()
|
|||
|
|
|
|||
|
|
this.recordModule = null
|
|||
|
|
this.eventModule = null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
let recorderInstance = null
|
|||
|
|
|
|||
|
|
export function getScreenRecorder() {
|
|||
|
|
if (!recorderInstance) {
|
|||
|
|
recorderInstance = new ScreenRecorder()
|
|||
|
|
}
|
|||
|
|
return recorderInstance
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default getScreenRecorder
|