李勇

MCU返回的消息中增加了当前人员数量的统计

@@ -63,7 +63,7 @@ export default class MessageEntrance extends Emiter { @@ -63,7 +63,7 @@ export default class MessageEntrance extends Emiter {
63 super(); 63 super();
64 this.lastClassActiveTime=0;//最后一次课堂激活的时间戳 64 this.lastClassActiveTime=0;//最后一次课堂激活的时间戳
65 //sdk 信息 65 //sdk 信息
66 - GlobalConfig.sdkVersion = "v2.31.12.20171122"; 66 + GlobalConfig.sdkVersion = "v2.32.1.20171123";
67 loger.warn("sdkVersion:" + GlobalConfig.sdkVersion); 67 loger.warn("sdkVersion:" + GlobalConfig.sdkVersion);
68 console.log("sdkVersion:" + GlobalConfig.sdkVersion); 68 console.log("sdkVersion:" + GlobalConfig.sdkVersion);
69 //设置 69 //设置
@@ -1177,7 +1177,7 @@ export default class MessageEntrance extends Emiter { @@ -1177,7 +1177,7 @@ export default class MessageEntrance extends Emiter {
1177 _mcuJoinMCUClassSuccessHandler(_data) { 1177 _mcuJoinMCUClassSuccessHandler(_data) {
1178 //loger.log('MCU 课堂成功.'); 1178 //loger.log('MCU 课堂成功.');
1179 loger.warn('=====================STEP9======================='); 1179 loger.warn('=====================STEP9=======================');
1180 - //console.log("当前课堂人员列表",GlobalConfig.rosterNumber,GlobalConfig.rosters) 1180 + //console.log("当前课堂人员列表",GlobalConfig.rosterNum,GlobalConfig.rosters)
1181 GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2); 1181 GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2);
1182 GlobalConfig.classJoinSuccess = true; 1182 GlobalConfig.classJoinSuccess = true;
1183 1183
@@ -2742,11 +2742,11 @@ export default class MessageEntrance extends Emiter { @@ -2742,11 +2742,11 @@ export default class MessageEntrance extends Emiter {
2742 let interval=new Date().getTime()-parseInt(this.lastClassActiveTime); 2742 let interval=new Date().getTime()-parseInt(this.lastClassActiveTime);
2743 interval=interval/1000; 2743 interval=interval/1000;
2744 //loger.log("最后一次记录的时间->"+this.lastClassActiveTime,"当前时间:"+new Date().getTime(),"间隔:"+interval+"秒"); 2744 //loger.log("最后一次记录的时间->"+this.lastClassActiveTime,"当前时间:"+new Date().getTime(),"间隔:"+interval+"秒");
2745 - loger.log("文档加入频道成功->isHost=", GlobalConfig.isHost, "当前总人数:", GlobalConfig.rosterNumber, "sassDoclength=", GlobalConfig.docListPrepare.length); 2745 + loger.log("文档加入频道成功->isHost=", GlobalConfig.isHost, "当前总人数:", GlobalConfig.rosterNum, "sassDoclength=", GlobalConfig.docListPrepare.length);
2746 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传 2746 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
2747 if (GlobalConfig.docListPrepare && GlobalConfig.docListPrepare.length > 0) { 2747 if (GlobalConfig.docListPrepare && GlobalConfig.docListPrepare.length > 0) {
2748 //如果当前身份是老师或者当前课堂内只有一个人并且不是H5,有权限同步文档到MCU 2748 //如果当前身份是老师或者当前课堂内只有一个人并且不是H5,有权限同步文档到MCU
2749 - if (GlobalConfig.isHost || (GlobalConfig.rosterNumber <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) { 2749 + if (GlobalConfig.isHost || (GlobalConfig.rosterNum <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) {
2750 for (let i = 0; i < GlobalConfig.docListPrepare.length; i++) { 2750 for (let i = 0; i < GlobalConfig.docListPrepare.length; i++) {
2751 let value = GlobalConfig.docListPrepare[i]; 2751 let value = GlobalConfig.docListPrepare[i];
2752 if (value) { 2752 if (value) {
@@ -2774,7 +2774,7 @@ export default class MessageEntrance extends Emiter { @@ -2774,7 +2774,7 @@ export default class MessageEntrance extends Emiter {
2774 musicShareApeJoinChannelSuccess() { 2774 musicShareApeJoinChannelSuccess() {
2775 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传 2775 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
2776 if (GlobalConfig.musicListPrepare&& GlobalConfig.musicListPrepare.length > 0) { 2776 if (GlobalConfig.musicListPrepare&& GlobalConfig.musicListPrepare.length > 0) {
2777 - if (GlobalConfig.isHost || (GlobalConfig.rosterNumber <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) { 2777 + if (GlobalConfig.isHost || (GlobalConfig.rosterNum <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) {
2778 for (let i = 0; i < GlobalConfig.musicListPrepare.length; i++) { 2778 for (let i = 0; i < GlobalConfig.musicListPrepare.length; i++) {
2779 let value = GlobalConfig.musicListPrepare[i]; 2779 let value = GlobalConfig.musicListPrepare[i];
2780 if (value) { 2780 if (value) {
@@ -2805,7 +2805,7 @@ export default class MessageEntrance extends Emiter { @@ -2805,7 +2805,7 @@ export default class MessageEntrance extends Emiter {
2805 mediaShareApeJoinChannelSuccess() { 2805 mediaShareApeJoinChannelSuccess() {
2806 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传 2806 //如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
2807 if (GlobalConfig.sharedMediaList&& GlobalConfig.sharedMediaList.length > 0) { 2807 if (GlobalConfig.sharedMediaList&& GlobalConfig.sharedMediaList.length > 0) {
2808 - if (GlobalConfig.isHost || (GlobalConfig.rosterNumber <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) { 2808 + if (GlobalConfig.isHost || (GlobalConfig.rosterNum <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) {
2809 for (let i = 0; i < GlobalConfig.sharedMediaList.length; i++) { 2809 for (let i = 0; i < GlobalConfig.sharedMediaList.length; i++) {
2810 let value = GlobalConfig.sharedMediaList[i]; 2810 let value = GlobalConfig.sharedMediaList[i];
2811 if (value) { 2811 if (value) {
@@ -641,7 +641,7 @@ GlobalConfig.serverTime = 0; //服务器当前时间戳 @@ -641,7 +641,7 @@ GlobalConfig.serverTime = 0; //服务器当前时间戳
641 GlobalConfig.serverAndLoacTimeDistanc = 0; //本地时间和服务器时间错的差值; 641 GlobalConfig.serverAndLoacTimeDistanc = 0; //本地时间和服务器时间错的差值;
642 GlobalConfig.logUrl = ""; //日志上报地址; 642 GlobalConfig.logUrl = ""; //日志上报地址;
643 643
644 -GlobalConfig.rosterNumber = 0;//当前总人数 644 +GlobalConfig.rosterNum = 0;//当前总人数
645 GlobalConfig.rosters = {};//当前课堂内的人员数据 645 GlobalConfig.rosters = {};//当前课堂内的人员数据
646 646
647 GlobalConfig.isMobile = false; //是否是移动端 647 GlobalConfig.isMobile = false; //是否是移动端
@@ -81,6 +81,17 @@ export default class Ape extends Emiter { @@ -81,6 +81,17 @@ export default class Ape extends Emiter {
81 // 数据同步处理 81 // 数据同步处理
82 _pduRegAdapterHandler(regBuffer, seekTime) { 82 _pduRegAdapterHandler(regBuffer, seekTime) {
83 let regPdu = pdu['RCAdapterPdu'].decode(regBuffer); 83 let regPdu = pdu['RCAdapterPdu'].decode(regBuffer);
  84 + if(!regPdu){
  85 + console.warn("regPdu 无效");
  86 + return;
  87 + }
  88 + //console.log("regPdu",regPdu);
  89 + let newUserNum=regPdu.userNum||0;
  90 + if(newUserNum!=GlobalConfig.rosterNum){
  91 + GlobalConfig.rosterNum=newUserNum;
  92 + this._emit(MessageTypes.CLASS_UPDATE_ROSTER_NUM,{rosterLen:GlobalConfig.rosterNum});
  93 + }
  94 +
84 let regItems = regPdu.item; 95 let regItems = regPdu.item;
85 let regItemSize = regItems.length; 96 let regItemSize = regItems.length;
86 //console.log("RCAdapterPdu数据同步处理",regPdu); 97 //console.log("RCAdapterPdu数据同步处理",regPdu);
@@ -26,7 +26,6 @@ class ConferApe extends Ape { @@ -26,7 +26,6 @@ class ConferApe extends Ape {
26 this.isSendInsterRoster=false;//这个很重要,每次MCU连接成功之后只发一次 26 this.isSendInsterRoster=false;//这个很重要,每次MCU连接成功之后只发一次
27 this.isLeave=false;//记录自己是否已经离开 27 this.isLeave=false;//记录自己是否已经离开
28 this.rosters = {}; //用户列表 28 this.rosters = {}; //用户列表
29 - this.rosterLen = 0;//当前课堂人数  
30 this.timerCounter = new TimerCounter(); //计时器 29 this.timerCounter = new TimerCounter(); //计时器
31 this.startRecordTimer;//开始录制的计时器 30 this.startRecordTimer;//开始录制的计时器
32 this.recordStatus=false;//记录录制状态 31 this.recordStatus=false;//记录录制状态
@@ -290,13 +289,13 @@ class ConferApe extends Ape { @@ -290,13 +289,13 @@ class ConferApe extends Ape {
290 return; 289 return;
291 } 290 }
292 //如果已经开始录制就不再开启 291 //如果已经开始录制就不再开启
293 - if (GlobalConfig.recordStatus && this.rosterLen > 1) {  
294 - loger.warn('目前已经是录制状态->当前课堂人数:' + this.rosterLen); 292 + if (GlobalConfig.recordStatus && GlobalConfig.rosterNum > 1) {
  293 + loger.warn('目前已经是录制状态->当前课堂人数:' + GlobalConfig.rosterNum);
295 return false; 294 return false;
296 } 295 }
297 //如果是host或者当前课堂只有1个人,并且不是H5 296 //如果是host或者当前课堂只有1个人,并且不是H5
298 if (this.checkHasRecordControl()) { 297 if (this.checkHasRecordControl()) {
299 - loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus, "当前人数:" + this.rosterLen); 298 + loger.warn('开启录制', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus, "当前人数:" +GlobalConfig.rosterNum);
300 //如果录制的文件名不存在,需要创建一个名字 299 //如果录制的文件名不存在,需要创建一个名字
301 let timestampYMD = EngineUtils.creatTimestampYMD(); 300 let timestampYMD = EngineUtils.creatTimestampYMD();
302 if (!GlobalConfig.recordFileName) { 301 if (!GlobalConfig.recordFileName) {
@@ -313,7 +312,7 @@ class ConferApe extends Ape { @@ -313,7 +312,7 @@ class ConferApe extends Ape {
313 checkHasRecordControl() { 312 checkHasRecordControl() {
314 //loger.warn('检测是否有控制录制操作的权限', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen); 313 //loger.warn('检测是否有控制录制操作的权限', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus,"当前人数:"+this.rosterLen);
315 //1.如果自己是老师或者当前课堂只有一个人 314 //1.如果自己是老师或者当前课堂只有一个人
316 - if (GlobalConfig.isHost || (this.rosterLen <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) { 315 + if (GlobalConfig.isHost || (GlobalConfig.rosterNum <= 1&&GlobalConfig.deviceType!=GlobalConfig.deviceH5)) {
317 return true; 316 return true;
318 } 317 }
319 //2.如果自己不是老师,需要判断当前课堂内是否有老师,如果有老师就不做操作 318 //2.如果自己不是老师,需要判断当前课堂内是否有老师,如果有老师就不做操作
@@ -973,8 +972,8 @@ class ConferApe extends Ape { @@ -973,8 +972,8 @@ class ConferApe extends Ape {
973 //loger.log("自己加入课堂的消息->",nodeId,"role-->", nodeData.role, ApeConsts.userTypes[nodeData.role]); 972 //loger.log("自己加入课堂的消息->",nodeId,"role-->", nodeData.role, ApeConsts.userTypes[nodeData.role]);
974 //自己加入的时候,需要做一下判断操作,如果满足以下3个条件就要暂停课堂: 973 //自己加入的时候,需要做一下判断操作,如果满足以下3个条件就要暂停课堂:
975 // 1.当前课堂只有自己;2.自己的身份不是host;3当前的课堂状态为(CLASS_STATUS_STARTED= 1;//直播中) 974 // 1.当前课堂只有自己;2.自己的身份不是host;3当前的课堂状态为(CLASS_STATUS_STARTED= 1;//直播中)
976 - this.rosterLen = Object.keys(this.rosters).length;  
977 - GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数 975 + //this.rosterLen = Object.keys(this.rosters).length;
  976 + //GlobalConfig.rosterNum = this.rosterLen;//记录当前的总人数
978 /* if (this.rosterLen <=1 && !GlobalConfig.isHost && GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) { 977 /* if (this.rosterLen <=1 && !GlobalConfig.isHost && GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
979 loger.warn("当前课堂没有老师->暂停课堂"); 978 loger.warn("当前课堂没有老师->暂停课堂");
980 this.pauseClass({isForce: true}); 979 this.pauseClass({isForce: true});
@@ -1030,9 +1029,10 @@ class ConferApe extends Ape { @@ -1030,9 +1029,10 @@ class ConferApe extends Ape {
1030 return; 1029 return;
1031 } 1030 }
1032 if (!rosterExists) { 1031 if (!rosterExists) {
1033 - this.rosterLen = Object.keys(this.rosters).length;  
1034 - GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数  
1035 - newNodeData.rosterLen = this.rosterLen; 1032 + //this.rosterLen = Object.keys(this.rosters).length;
  1033 + //GlobalConfig.rosterNum = this.rosterLen;//记录当前的总人数
  1034 + //newNodeData.rosterLen = this.rosterLen;
  1035 + newNodeData.rosterLen=GlobalConfig.rosterNum
1036 if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){ 1036 if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){
1037 loger.log("人员加入->", newNodeData); 1037 loger.log("人员加入->", newNodeData);
1038 } 1038 }
@@ -1043,9 +1043,9 @@ class ConferApe extends Ape { @@ -1043,9 +1043,9 @@ class ConferApe extends Ape {
1043 } 1043 }
1044 } else { 1044 } else {
1045 //loger.log("更新人员列表数据,rosterExists已经存在",rosterExists); 1045 //loger.log("更新人员列表数据,rosterExists已经存在",rosterExists);
1046 - this.rosterLen = Object.keys(this.rosters).length;  
1047 - GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数  
1048 - newNodeData.rosterLen = this.rosterLen; 1046 + //this.rosterLen = Object.keys(this.rosters).length;
  1047 + //GlobalConfig.rosterNum = this.rosterLen;//记录当前的总人数
  1048 + newNodeData.rosterLen = GlobalConfig.rosterNum;
1049 if (nodeId != GlobalConfig.nodeId) { 1049 if (nodeId != GlobalConfig.nodeId) {
1050 if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){ 1050 if(GlobalConfig.classType!= ApeConsts.CLASS_TYPE_ZHIBO){
1051 loger.log("人员更新信息->", newNodeData); 1051 loger.log("人员更新信息->", newNodeData);
@@ -1079,13 +1079,13 @@ class ConferApe extends Ape { @@ -1079,13 +1079,13 @@ class ConferApe extends Ape {
1079 //如果推流的人员已经不存在,并且当前课堂内人员大于0; 1079 //如果推流的人员已经不存在,并且当前课堂内人员大于0;
1080 // 如果不判断当前的人数,会出现把正常的视频消息释放的情况; 1080 // 如果不判断当前的人数,会出现把正常的视频消息释放的情况;
1081 // 因为会出现先收到视频消息后收到人员加入和更新的消息 1081 // 因为会出现先收到视频消息后收到人员加入和更新的消息
1082 - if(this.rosters[_param.fromNodeId] == null&&this.rosterLen>0){ 1082 + if(this.rosters[_param.fromNodeId] == null&&GlobalConfig.rosterNum>0){
1083 //H5不做释放处理 1083 //H5不做释放处理
1084 if(GlobalConfig.deviceType==GlobalConfig.deviceH5){ 1084 if(GlobalConfig.deviceType==GlobalConfig.deviceH5){
1085 - loger.warn("H5不做媒体模块的频道释放->当前总人数->"+this.rosterLen, _param); 1085 + loger.warn("H5不做媒体模块的频道释放->当前总人数->"+GlobalConfig.rosterNum, _param);
1086 return ; 1086 return ;
1087 } 1087 }
1088 - loger.warn("媒体模块被占用->占有人已经不存在课堂中->释放->当前总人数->"+this.rosterLen, _param); 1088 + loger.warn("媒体模块被占用->占有人已经不存在课堂中->释放->当前总人数->"+GlobalConfig.rosterNum, _param);
1089 this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": _param.fromNodeId}); 1089 this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": _param.fromNodeId});
1090 } 1090 }
1091 } 1091 }
@@ -1118,12 +1118,12 @@ class ConferApe extends Ape { @@ -1118,12 +1118,12 @@ class ConferApe extends Ape {
1118 } 1118 }
1119 delete this.rosters[nodeId]; 1119 delete this.rosters[nodeId];
1120 GlobalConfig.rosters = this.rosters; 1120 GlobalConfig.rosters = this.rosters;
1121 - this.rosterLen = Object.keys(this.rosters).length;  
1122 - GlobalConfig.rosterNumber = this.rosterLen;//记录当前的总人数 1121 + //this.rosterLen = Object.keys(this.rosters).length;
  1122 + //GlobalConfig.rosterNum = this.rosterLen;//记录当前的总人数
1123 1123
1124 if(!GlobalConfig.isH5) { 1124 if(!GlobalConfig.isH5) {
1125 this.emitRosterChange(); 1125 this.emitRosterChange();
1126 - this._emit(MessageTypes.CLASS_DELETE_ROSTER, {"nodeId": nodeId, "rosterLen": this.rosterLen}); 1126 + this._emit(MessageTypes.CLASS_DELETE_ROSTER, {"nodeId": nodeId, "rosterLen": GlobalConfig.rosterNum});
1127 1127
1128 //当前人员列表中抽一个人来检查离开人员是否占用频道 1128 //当前人员列表中抽一个人来检查离开人员是否占用频道
1129 for (let key in this.rosters) { 1129 for (let key in this.rosters) {
@@ -1131,7 +1131,7 @@ class ConferApe extends Ape { @@ -1131,7 +1131,7 @@ class ConferApe extends Ape {
1131 //判断是否是自己就处理以下操作 1131 //判断是否是自己就处理以下操作
1132 if (randNodeId == GlobalConfig.nodeId) { 1132 if (randNodeId == GlobalConfig.nodeId) {
1133 loger.log("检查离开的人员是否占用channel"); 1133 loger.log("检查离开的人员是否占用channel");
1134 - this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": nodeId, "rosterLen": this.rosterLen}); 1134 + this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": nodeId, "rosterLen": GlobalConfig.rosterNum});
1135 //如果离开的人员是老师,需要暂停当前的课堂 1135 //如果离开的人员是老师,需要暂停当前的课堂
1136 if (user && user.role == ApeConsts.NR_HOST) { 1136 if (user && user.role == ApeConsts.NR_HOST) {
1137 this.pauseClass(); 1137 this.pauseClass();
@@ -1145,9 +1145,9 @@ class ConferApe extends Ape { @@ -1145,9 +1145,9 @@ class ConferApe extends Ape {
1145 1145
1146 //广播当前的人数 1146 //广播当前的人数
1147 emitRosterChange() { 1147 emitRosterChange() {
1148 - if(!GlobalConfig.isH5){  
1149 - this._emit(MessageTypes.CLASS_UPDATE_ROSTER_NUM, Object.keys(this.rosters).length);  
1150 - } 1148 + //if(!GlobalConfig.isH5){
  1149 + this._emit(MessageTypes.CLASS_UPDATE_ROSTER_NUM,{rosterLen:GlobalConfig.rosterNum});
  1150 + //}
1151 } 1151 }
1152 1152
1153 ///////数据的封包和解包///////////////////////////////////////// 1153 ///////数据的封包和解包/////////////////////////////////////////
@@ -1222,8 +1222,7 @@ class ConferApe extends Ape { @@ -1222,8 +1222,7 @@ class ConferApe extends Ape {
1222 1222
1223 stopApe() { 1223 stopApe() {
1224 this.rosters = {}; 1224 this.rosters = {};
1225 - this.rosterLen = 0;  
1226 - GlobalConfig.rosterNumber = this.rosterLen; 1225 + GlobalConfig.rosterNum = 0;
1227 GlobalConfig.rosters = this.rosters; 1226 GlobalConfig.rosters = this.rosters;
1228 this.isLeave=true; 1227 this.isLeave=true;
1229 this.isSendInsterRoster=false; 1228 this.isSendInsterRoster=false;
@@ -684,7 +684,7 @@ class DocApe extends Ape { @@ -684,7 +684,7 @@ class DocApe extends Ape {
684 return; 684 return;
685 } 685 }
686 //如果自己不是老师,并且当前课堂内人数大于1,不能操作 686 //如果自己不是老师,并且当前课堂内人数大于1,不能操作
687 - if (!GlobalConfig.isHost && GlobalConfig.rosterNumber > 1) { 687 + if (!GlobalConfig.isHost && GlobalConfig.rosterNum > 1) {
688 return; 688 return;
689 } 689 }
690 690
@@ -253,6 +253,7 @@ message RCAdapterItemPdu { @@ -253,6 +253,7 @@ message RCAdapterItemPdu {
253 message RCAdapterPdu { 253 message RCAdapterPdu {
254 optional RCPduType_E type = 1 [default = RCPDU_REG_ADAPTER]; 254 optional RCPduType_E type = 1 [default = RCPDU_REG_ADAPTER];
255 repeated RCAdapterItemPdu item = 2; 255 repeated RCAdapterItemPdu item = 2;
  256 + optional uint32 user_num = 3;//rosterLen
256 } 257 }
257 258
258 // table operation pdu 259 // table operation pdu