799967501@qq.com

添加实时直播接口(目前步步高用)

@@ -5,6 +5,7 @@ var cookieParser = require('cookie-parser'); @@ -5,6 +5,7 @@ var cookieParser = require('cookie-parser');
5 var logger = require('morgan'); 5 var logger = require('morgan');
6 6
7 var indexRouter = require('./routes/index'); 7 var indexRouter = require('./routes/index');
  8 +var bbgRecordingRouter = require('./routes/bbgRecording');
8 9
9 var app = express(); 10 var app = express();
10 11
@@ -18,7 +19,18 @@ app.use(express.urlencoded({ extended: false })); @@ -18,7 +19,18 @@ app.use(express.urlencoded({ extended: false }));
18 app.use(cookieParser()); 19 app.use(cookieParser());
19 app.use(express.static(path.join(__dirname, 'public'))); 20 app.use(express.static(path.join(__dirname, 'public')));
20 21
  22 +app.all("*",function(req,res,next){
  23 + //设置允许跨域的域名,*代表允许任意域名跨域
  24 + res.header("Access-Control-Allow-Origin","*");
  25 + //允许的header类型
  26 + res.header("Access-Control-Allow-Headers","content-type");
  27 + //跨域允许的请求方式
  28 + res.header("Access-Control-Allow-Methods","POST,OPTIONS");
  29 + next();
  30 +});
  31 +
21 app.use('/', indexRouter); 32 app.use('/', indexRouter);
  33 +app.use('/mp4record',bbgRecordingRouter)
22 34
23 // catch 404 and forward to error handler 35 // catch 404 and forward to error handler
24 app.use(function(req, res, next) { 36 app.use(function(req, res, next) {
@@ -28,12 +40,13 @@ app.use(function(req, res, next) { @@ -28,12 +40,13 @@ app.use(function(req, res, next) {
28 // error handler 40 // error handler
29 app.use(function(err, req, res, next) { 41 app.use(function(err, req, res, next) {
30 // set locals, only providing error in development 42 // set locals, only providing error in development
31 - res.locals.message = err.message;  
32 - res.locals.error = req.app.get('env') === 'development' ? err : {}; 43 + // res.locals.message = err.message;
  44 + // res.locals.error = req.app.get('env') === 'development' ? err : {};
33 45
34 // render the error page 46 // render the error page
35 - res.status(err.status || 500);  
36 - res.render('error'); 47 + // res.status(err.status || 500);
  48 + // res.render('error');
  49 + res.send({ code: err.status || 500 });
37 }); 50 });
38 51
39 module.exports = app; 52 module.exports = app;
  1 +{
  2 + "PROJECTWINCATALOG": "F:/project/web_capture_release/win-x64",
  3 + "PROJECTCATALOG": "/Users/zhangaichen/Desktop/学点云/webScreen",
  4 + "BACKMEDIACONFIG": {
  5 + "url": "https://pclive.xuedianyun.com/pcBase/pclive2/dev/index.html",
  6 + "recordMp4": true,
  7 + "classId": "",
  8 + "userId": 0,
  9 + "userName": "",
  10 + "userRole": "invisible",
  11 + "portalIP": "saas.xuedianyun.com",
  12 + "portalPort": 80,
  13 + "channels": 0,
  14 + "playRecord": 1,
  15 + "d": 21600000,
  16 + "s": 3000,
  17 + "fa": 15,
  18 + "k": 0,
  19 + "w": 1280,
  20 + "h": 720
  21 + }
  22 +}
  1 +var express = require('express');
  2 +var router = express.Router();
  3 +const { exec } = require('child_process');
  4 +const fs = require("fs");
  5 +const axios = require('axios');
  6 +
  7 +const method = require("../config/method")
  8 +
  9 +const { dayTimeYMD } = method
  10 +
  11 +
  12 +let classids = []
  13 +
  14 +/**
  15 + *
  16 + * @param {*} id 课堂id
  17 + */
  18 +class MediaCreat {
  19 + constructor() {
  20 + }
  21 +
  22 + wrieLog(text) {
  23 + // 写入log
  24 + let logFile = `./log/${dayTimeYMD().ymd}.txt`
  25 + fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
  26 + }
  27 +
  28 + recordingCreat(id,siteId,classUrl,duration,width,height,frameRate,bitrate) {
  29 + this.wrieLog(" 课堂录制开始:------>" + id)
  30 + let fileConfig = this.getConfigFileJson()
  31 + if (!fileConfig) return false
  32 + const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
  33 + let mediaDir = PROJECTCATALOG + "/media/"
  34 + let classDir = PROJECTCATALOG + "/media/" + siteId
  35 + let ymdDir = null
  36 + let timeDir = dayTimeYMD().ymd
  37 + ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + timeDir
  38 +
  39 + if (!fs.existsSync(mediaDir)) {
  40 + fs.mkdirSync(mediaDir);
  41 + }
  42 + if (!fs.existsSync(classDir)) {
  43 + fs.mkdirSync(classDir);
  44 + }
  45 + if (!fs.existsSync(ymdDir)) {
  46 + fs.mkdirSync(ymdDir);
  47 + }
  48 + // let files = fs.readdirSync(ymdDir);
  49 + // let interValGetFile = setInterval(()=>{
  50 + // this.wrieLog("files:" + files)
  51 + // if (files.indexOf(id + ".mp4") != -1) {
  52 + // this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
  53 + // return
  54 + // }
  55 +
  56 + // if(!classUrl){
  57 + // classUrl = `${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}"`
  58 + // }
  59 + // if(!duration){
  60 + // duration = BACKMEDIACONFIG.d
  61 + // }
  62 + let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${classUrl}" -d=${duration} -s=${BACKMEDIACONFIG.s} -k=${BACKMEDIACONFIG.k} -w=${width} -h=${height} -fa=${frameRate} -vb=${bitrate}`
  63 + this.wrieLog("全地址"+url)
  64 + exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
  65 + if (err != null) {
  66 + this.wrieLog(" 错误" + id + ":" + err)
  67 + this.wrieLog(" 错误 stdout" + id + ":" + stdout)
  68 + this.wrieLog(" 错误 stderr" + id + ":" + stderr)
  69 + // 删除已存元素
  70 + classids.splice(classids.findIndex(item => item === id),1)
  71 + return
  72 + }
  73 + // let files = fs.readdirSync(ymdDir);
  74 + // if (files.indexOf(id + ".mp4") != -1) {
  75 + // 删除已存元素
  76 + classids.splice(classids.findIndex(item => item === id),1)
  77 + this.sendMediaInfo(siteId,id,timeDir)
  78 + // }
  79 + })
  80 + }
  81 + // 上报地址
  82 + async sendMediaInfo(siteId,id,timeDir){
  83 + // https://testmp4.obs.cn-north-4.myhuaweicloud.com/oss/media/eebbktest/20210326/1657547103.mp4
  84 + let MediaUrl = `https://testmp4.obs.cn-north-4.myhuaweicloud.com/oss/media/${siteId}/${timeDir}/${id}.mp4`
  85 + let urlSizeId = {
  86 + "eebbktest": "gdbbkwxyace",
  87 + "gdbbk":"gdbbkwx",
  88 + "gdbbkdev":"gdbbkwxtest"
  89 + }
  90 + let requestUrl = `https://${urlSizeId[siteId]}.xuedianyun.com/bbgserver/app/course/updateRecordUrl`
  91 + let result = await axios.post(
  92 + requestUrl,
  93 + {meetingNumber:id,url:MediaUrl},
  94 + {headers: {'orgId':siteId }}
  95 + )
  96 + if(result.data){
  97 + this.wrieLog("更新视频地址结果:"+JSON.stringify(result.data))
  98 + }
  99 + }
  100 +
  101 + getConfigFileJson() {
  102 + const buffer = fs.readFileSync(process.cwd() + "/config/realTimeConfig.json")
  103 + return String(buffer)
  104 + }
  105 +}
  106 +
  107 +/**
  108 + * {
  109 + * "classId":[{ classId: '389675110', siteId: 'kuaikuenglish' }]
  110 + * }
  111 + */
  112 +router.post('/recording/:id', function (req, res, next) {
  113 + new MediaCreat().wrieLog("录制启动:------>")
  114 + let fileConfig = new MediaCreat().getConfigFileJson()
  115 + if (!fileConfig) return false
  116 + /**
  117 + * classId:课堂号
  118 + * siteId:机构编码
  119 + * url:课堂地址
  120 + * duration:录制时长
  121 + * width height 录制视频宽高
  122 + * frameRate 帧率
  123 + * bitrate 码率
  124 + */
  125 + let { classId,siteId,url:classUrl,duration,width,height,frameRate,bitrate } = req.body
  126 +
  127 + if (classId && siteId && classUrl && duration && width && height && frameRate && bitrate) {
  128 + if(!Number.isInteger(classId) || !Number.isInteger(duration) || !Number.isInteger(width) || !Number.isInteger(height) || !Number.isInteger(frameRate) || !Number.isInteger(bitrate)){
  129 + res.send({ code: "3", message: "参数类型错误" });
  130 + return
  131 + }
  132 + let maxTime = 10*60*60*1000
  133 + if(duration < 0 || duration > maxTime){
  134 + res.send({ code: "4", message: "参数范围错误" });
  135 + return
  136 + }
  137 + // 避免多次重复课堂号请求
  138 + if(!classids.includes(classId)){
  139 + // 没有正在录制的该课堂
  140 + classids.push(classId)
  141 + bitrate = bitrate * 1024 // 转换 * 1024
  142 + new MediaCreat().recordingCreat(classId, siteId,classUrl,duration,width,height,frameRate,bitrate)
  143 + res.send({ code: "0" });
  144 + }else{
  145 + res.send({ code: "2", message: "重复请求课堂号" });
  146 + }
  147 + } else {
  148 + res.send({ code: "1", message: "缺少参数" });
  149 + }
  150 +
  151 +})
  152 +
  153 +
  154 +module.exports = router;