import { range } from "lodash" ; import { bufferReader , bufferWriter } from "../../../../common/src" ; import { RtcpHeader } from "../header" ; export class GenericNack { static count = 1 ; readonly count = GenericNack . count ; header ! : RtcpHeader ; senderSsrc ! : number ; mediaSourceSsrc ! : number ; lost : number [ ] = [ ] ; constructor ( props = { } ) { Object . assign ( this , props ) ; if ( ! this . header ) { this . header = new RtcpHeader ( { type : 205 , count : this . count , version : 2 , } ) ; } } static deSerialize ( data , header ) { const [ senderSsrc , mediaSourceSsrc ] = bufferReader ( data , [ 4 , 4 ] ) ; const lost = range ( 8 , data . length , 4 ) . map ( ( pos ) => { const lost = [ ] ; const [ pid , blp ] = bufferReader ( data . slice ( pos ) , [ 2 , 2 ] ) ; lost . push ( pid ) ; range ( 0 , 16 ) . forEach ( ( d ) => { if ( ( blp >> d ) & 1 ) { lost . push ( pid + d + 1 ) ; } } ) ; return lost ; } ) . flatMap ( ( v ) => v ) ; return new GenericNack ( { header , senderSsrc , mediaSourceSsrc , lost , } ) ; } serialize ( ) { const ssrcs = bufferWriter ( [ 4 , 4 ] , [ this . senderSsrc , this . mediaSourceSsrc ] ) ; const fics = [ ] ; if ( this . lost . length > 0 ) { let pid = this . lost [ 0 ] , blp = 0 ; this . lost . slice ( 1 ) . forEach ( ( p ) => { const d = p - pid - 1 ; if ( d < 16 ) { blp |= 1 << d ; } else { fics . push ( bufferWriter ( [ 2 , 2 ] , [ pid , blp ] ) ) ; pid = p ; blp = 0 ; } } ) ; fics . push ( bufferWriter ( [ 2 , 2 ] , [ pid , blp ] ) ) ; } const buf = Buffer . concat ( [ ssrcs , Buffer . concat ( fics ) ] ) ; this . header . length = buf . length / 4 ; return Buffer . concat ( [ this . header . serialize ( ) , buf ] ) ; } }