@hysc/boom-cpp-plugin
Version:
```markdown 使用示例,展示如何在 Electron 主进程中集成和使用该插件,使用 CommonJS 的引用方式:
363 lines (320 loc) • 11.2 kB
JavaScript
const logger = require('electron-log')
const os = require('os')
const fs = require('fs')
const path = require('path')
const arch = os.arch()
const platform = os.platform()
const isWindows = () => platform === 'win32'
const isMac = () => platform === 'darwin'
/*
* @Author: baijiayun.com
* @Date: 2023-08-10 15:01:53
* @Description: 这是cpp 插件的 bridge 层, 单例
*/
class CppPluginBridge {
constructor() {
if (CppPluginBridge.instance) {
return CppPluginBridge.instance
}
this.mainWindow = null
this.instance = null
CppPluginBridge.instance = this
}
bindTargetWindow(mainWindow) {
this.mainWindow = mainWindow
}
/**
*
* @param {string} winArc
* windows 应用架构,只能为 x64 或者 x86 默认是x86
* mac arm传递 arm x86传递 x86 默认 x86
* @returns
*/
init(winArc) {
if (this.instance) {
return this.instance
}
let lib
let dllPath
let fileMidPath = `${platform}-${arch}`
if (isWindows()) {
if (arch === 'x64') {
dllPath = path.resolve(process.resourcesPath, '../node_modules/@hysc/boom-cpp-plugin/cppPlugin', fileMidPath);
process.env.PATH = dllPath + ';' + process.env.PATH;
lib = require(`../cppPlugin/win32-x64/bjy_electron_plugin.node`)
} else {
dllPath = path.resolve(process.resourcesPath, '../node_modules/@hysc/boom-cpp-plugin/cppPlugin', fileMidPath);
process.env.PATH = dllPath + ';' + process.env.PATH;
lib = require(`../cppPlugin/win32-ia32/bjy_electron_plugin.node`)
}
} else if (isMac()) {
dllPath = path.resolve(process.resourcesPath, '../node_modules/@hysc/boom-cpp-plugin/cppPlugin', fileMidPath);
let exists = fs.existsSync(dllPath);
console.log('cpp plugin dllPath:', dllPath, 'exists:', exists)
if ((os.arch() === 'arm64' && exists)) {
lib = require(`../cppPlugin/darwin-arm64/bjy_electron_plugin.node`)
} else {
fileMidPath = 'darwin-x64';
lib = require(`../cppPlugin/darwin-x64/bjy_electron_plugin.node`)
}
dllPath = path.resolve(process.resourcesPath, '../node_modules/@hysc/boom-cpp-plugin/cppPlugin', fileMidPath);
exists = fs.existsSync(dllPath);
if (!exists) {
console.error('cpp plugin not exists, please check the path:', dllPath)
}
}
if (lib) {
this.instance = new lib.BJYCppPlugin()
this.instance.createEngineInstance()
if (isMac()) {
this.setOnLogEventCallback()
}
logger.log('init cpp plugin success, dllPath:', dllPath)
return
} else {
logger.log('init cpp plugin failed', dllPath)
throw new Error('init cpp plugin failed')
}
}
initWithPath(filePath) {
if (this.instance) {
return this.instance
}
let lib
let dllPath
let fileMidPath = `${platform}-${arch}`
if (isWindows()) {
if (arch === 'x64') {
lib = require(`../cppPlugin/win32-x64/bjy_electron_plugin.node`)
} else {
lib = require(`../cppPlugin/win32-ia32/bjy_electron_plugin.node`)
}
} else if (isMac()) {
if ((os.arch() === 'arm64')) {
lib = require(`../cppPlugin/darwin-arm64/bjy_electron_plugin.node`)
} else {
lib = require(`../cppPlugin/darwin-x64/bjy_electron_plugin.node`)
}
}
if (lib) {
this.instance = new lib.BJYCppPlugin()
this.instance.createEngineInstance()
if (isMac()) {
this.setOnLogEventCallback()
}
logger.log('init cpp plugin success, dllPath:', dllPath)
return
} else {
logger.log('init cpp plugin failed', dllPath)
throw new Error('init cpp plugin failed')
}
}
// ======================= event callback ======================= //
/**
* cpp 音频采集事件回调
* @param {*} data
* @param {*} sampleRate
* @param {*} channel
* @param {*} timestamp
*/
audioEventCallback(data, sampleRate, channel, timestamp) {
if (this.mainWindow) {
this.mainWindow.webContents.send('onAudioData', data, sampleRate, channel, timestamp)
} else {
logger.log('mainWindow is null, audioEventCallback', sampleRate)
}
}
/**
* cpp 音频采集错误回调
* @param {*} code
* @param {*} msg
*/
audioCaptureErrorCallback(code, msg) {
logger.log('cpp audio plugin capture audio error', code, msg)
logger.log('stop audio capture')
this.stopCapture()
logger.log('restart audio capture')
const res = this.instance.startAudioCapture(0, false)
logger.log('start audio plugin result', res)
}
/**
* cpp 窗口全屏事件回调
* @param {*} isFullScreen
* @param {*} fullScreenWId
*/
async fullScreenCallBack(isFullScreen, fullScreenWId) {
logger.log('isFullScreen', isFullScreen, 'fullScreenWId', fullScreenWId)
const id = `window:${fullScreenWId}:0`
logger.log('send select source to webContents', id)
this.mainWindow.webContents.send('onFullScreen', { id }, isFullScreen)
}
setOnLogEventCallback() {
if (this.instance) {
this.instance.setEventCallback('onLog', this.cppLogCallback.bind(this))
}
}
cppLogCallback(logs) {
logger.log('cpp plugin logs', logs)
}
/**
* 设置窗口全屏事件回调
*/
setWinPluginEventCallBack() {
if (this.instance) {
console.log('set win plugin event callback')
this.instance.setEventCallback('onWindowFullScreenEvent', this.fullScreenCallBack.bind(this))
}
}
setAudioPluginEventCallback() {
if (this.instance) {
this.instance.setEventCallback('onCapturedRawAudioFrame', this.audioEventCallback.bind(this))
this.instance.setEventCallback('onAudioCaptureError', this.audioCaptureErrorCallback.bind(this))
}
}
// ======================= event callback end ======================= //
bringWindowToTop(wid) {
if (this.instance) {
const isNumber = !Number.isNaN(Number(wid))
if (isNumber) {
logger.log('bring target window to top')
return this.instance.bringWindowToTop(Number(wid))
} else {
logger.log('bring window to top failed, wid is not a number')
}
}
}
/**
* 采集系统声音
* @param {Number} sid sourceId 指定窗口ID,设置为0表示采集当前运行进程本身
* @param {Boolean} onlySourceId 采集模式,true表示只采集指定窗口进程 false表示采集除了本地窗口进程
*/
startAudioCapture(sid, onlySourceId) {
logger.log('startCapture', sid, onlySourceId)
if (this.instance) {
const isNumber = !Number.isNaN(Number(sid))
if (isNumber) {
const res = this.instance.startAudioCapture(Number(sid), onlySourceId)
logger.log('startCapture result', res)
if (res < 0) {
logger.log('startCapture failed')
this.stopCapture()
this.mainWindow.webContents.send('onAudioCaptureError', { failed: true, res })
}
} else {
logger.log('startCapture failed, sid is not a number')
}
}
}
/**
* 检测视频窗口变化
* @param {*} wid
*/
startWindowDetector(wid, sourceName) {
logger.log('startWindowDetector', wid, sourceName)
if (this.instance) {
const isNumber = !Number.isNaN(Number(wid))
if (isNumber) {
const res = this.instance.startWindowDetector(Number(wid))
logger.log('start window capture res', res)
if (res < 0) {
logger.log('start window capture failed')
this.stopWindowDetector()
this.mainWindow.webContents.send('onWindowCaptureError', { failed: true, res })
}
} else {
logger.log('start window capture failed, wid is not a number')
}
}
}
stopWindowDetector() {
if (this.instance) {
this.instance.stopWindowDetector()
}
}
stopCapture() {
if (this.instance) {
this.instance.stopAudioCapture()
}
}
destroy() {
if (this.instance) {
this.stopCapture()
this.stopWindowDetector()
this.releaseAudioDeviceMgr()
this.instance.destroyEngineInstance()
this.instance = null
this.mainWindow = null
}
}
// ================ 音频管理 ==================== //
initAudioDeviceManage() {
this.instance.audioDeviceMgrInitialize()
}
/**
* 设置当前音频设备
*
* @param {String} speakerName 扬声器名称
* @param {String} micName 麦克风名称
*/
setAudioDevice(speakerName, micName) {
return this.instance.setAudioDevice(speakerName, micName)
}
/**
* 设置扬声器音量
* @param {Number} volume
* @returns {Boolean} true 成功 false 失败
*/
setSpeakerVolume(volume) {
return this.instance.setSpeakerVolume(volume)
}
/**
* 获取扬声器音量
* @returns {Number}
*/
getSpeakerVolume() {
return this.instance.getSpeakerVolume()
}
/**
* 设置麦克风音量
* @param {Number} volume
* @returns {Boolean} true 成功 false 失败
*/
setMicVolume(volume) {
return this.instance.setMicVolume(volume)
}
/**
* 获取麦克风音量
* @returns {Number}
*/
getMicVolume() {
return this.instance.getMicVolume()
}
/**
* 扬声器是否静音
* @returns {Boolean} true 静音 false 未静音
*/
isSpeakerMute() {
return this.instance.isSpeakerMute()
}
/**
* 麦克风是否静音
* @returns {Boolean} true 静音 false 未静音
*/
isMicMute() {
return this.instance.isMicMute()
}
enableMicrophoneDevice() {
if (isWindows()) {
return this.instance.enableMicrophoneDevice()
} else {
return true
}
}
releaseAudioDeviceMgr() {
if (isWindows()) {
return this.instance.releaseAudioDeviceMgr()
}
}
// ==================================== //
}
module.exports = CppPluginBridge