| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| /* |
| * File: muxpdu.c |
| * Comment: Mux level 1 specific routines |
| */ |
| #include "level1.h" |
| #include "h223.h" |
| |
| Level1PduParcom::Level1PduParcom(bool df): |
| iDf(df) |
| { |
| iLogger = PVLogger::GetLoggerObject("3g324m.h223.Level1"); |
| iCurrentInt32 = 0; |
| iCurrentOp = ELookForStartFlag; |
| iSkipBytes = 0; |
| iPduPos = NULL; |
| uint8 HecCrc[18] = |
| { |
| 0x00, 0x05, 0x07, 0x02, 0x03, 0x06, 0x04, 0x01, |
| 0x06, 0x03, 0x01, 0x04, 0x05, 0x00, 0x02, 0x07 |
| }; |
| |
| oscl_memcpy(iHecCrc, HecCrc, 18); |
| } |
| |
| void |
| Level1PduParcom::Construct(uint16 max_outstanding_pdus) |
| { |
| iHdrFragmentAlloc.SetLeaveOnAllocFailure(false); |
| iHdrFragmentAlloc.size(max_outstanding_pdus, (uint16)H223GetMaxStuffingSz(H223_LEVEL1)); |
| } |
| |
| void Level1PduParcom::GetHdrFragment(OsclRefCounterMemFrag& frag) |
| { |
| frag = iHdrFragmentAlloc.get(); |
| } |
| |
| unsigned |
| Level1PduParcom::GetStuffing(uint8* pPdu, uint32 buf_size, uint8 mux_code) |
| { |
| OSCL_UNUSED_ARG(mux_code); |
| OSCL_UNUSED_ARG(buf_size); |
| int32 stuffing_size = iDf ? 4 : 2; |
| int32 size_left = buf_size; |
| while (size_left >= stuffing_size) |
| { |
| *(pPdu) = 0xe1; |
| *(pPdu + 1) = 0x4d; |
| pPdu += 2; |
| size_left -= 2; |
| if (iDf) |
| { |
| *(pPdu) = 0xe1; |
| *(pPdu + 1) = 0x4d; |
| pPdu += 2; |
| size_left -= 2; |
| } |
| } |
| return (buf_size -size_left); |
| } |
| |
| PVMFStatus Level1PduParcom::CompletePdu(OsclSharedPtr<PVMFMediaDataImpl>& pdu, int8 MuxTblNum, uint8 pm) |
| { |
| iClosingNext = 0; |
| OSCL_UNUSED_ARG(pm); |
| OsclRefCounterMemFrag frag; |
| pdu->getMediaFragment(0, frag); |
| pdu->setMediaFragFilledLen(0, GetHeaderSz()); |
| |
| // header |
| uint8* pPdu = (uint8*)frag.getMemFrag().ptr; |
| |
| *pPdu = 0xe1; |
| *(pPdu + 1) = 0x4d; |
| if (iDf) |
| { |
| *(pPdu + 2) = 0xe1; |
| *(pPdu + 3) = 0x4d; |
| *(pPdu + 4) = (uint8)(iHecCrc[MuxTblNum] << 5 | MuxTblNum << 1); |
| } |
| else |
| { |
| *(pPdu + 2) = (uint8)(iHecCrc[MuxTblNum] << 5 | MuxTblNum << 1); |
| } |
| |
| // trailer |
| if (pm) |
| { |
| OsclRefCounterMemFrag frag = iHdrFragmentAlloc.get(); |
| if (frag.getMemFragPtr() == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "Level1PduParcom::CompletePdu Failed to allocate frag")); |
| return PVMFErrNoMemory; |
| } |
| |
| frag.getMemFrag().len = GetHeaderSz(); |
| pPdu = (uint8*)frag.getMemFragPtr(); |
| *pPdu = 0xe1; |
| *(pPdu + 1) = 0x4d; |
| if (iDf) /* L1 Double Flag */ |
| { |
| *(pPdu + 2) = 0xe1; |
| *(pPdu + 3) = 0x4d; |
| *(pPdu + 4) = (uint8)(iHecCrc[MuxTblNum] << 5 | MuxTblNum << 1 | 1); |
| } |
| else |
| { |
| *(pPdu + 2) = (uint8)(iHecCrc[MuxTblNum] << 5 | MuxTblNum << 1 | 1); |
| } |
| pdu->appendMediaFragment(frag); |
| } |
| return PVMFSuccess; |
| } |
| |
| inline void Level1PduParcom::IndicatePdu() |
| { |
| int pdu_size = iPduPos - iPdu; |
| uint8* pdu = iPdu; |
| |
| if (pdu_size >= 1) |
| { |
| if (iHecCrc[((*pdu)>>1)&0xf] != (*pdu) >> 5) |
| { |
| iObserver->MuxPduErrIndicate(EHeaderErr); |
| #ifdef PVANALYZER |
| nCrcError++; |
| PVAnalyzer(ANALYZER_MUXHDR, "Mux Header Error #=%d, %%=%f", nCrcError, (double)nCrcError / (double)nPdu); |
| #endif |
| } |
| else |
| { |
| int fClosing = 0; |
| int muxCode = -1; |
| if ((*pdu) & 1) |
| fClosing = 1; |
| muxCode = ((*pdu) >> 1) & 0xf; |
| pdu++; |
| pdu_size--; |
| iObserver->MuxPduIndicate(pdu, (uint16)pdu_size, fClosing, muxCode); |
| } |
| } |
| iPduPos = NULL; |
| } |
| |
| uint32 Level1PduParcom::Parse(uint8* bsbuf, uint32 bsbsz) |
| { |
| const int FLAG = (iDf) ? 0xE14DE14D : 0xE14D; |
| const int FLAG_SZ = (iDf) ? 4 : 2; |
| const int FLAG_MASK = (iDf) ? 0xFFFFFFFF : 0xFFFF; |
| #ifdef PVANALYZER |
| static unsigned int nPdu = 0; |
| static unsigned int nCrcError = 0; |
| nPdu++; |
| #endif |
| |
| for (unsigned num = 0; num < bsbsz; num++) |
| { |
| iCurrentInt32 <<= 8; |
| iCurrentInt32 |= bsbuf[num]; |
| switch (iCurrentOp) |
| { |
| case ELookForStartFlag: |
| if ((iCurrentInt32 & FLAG_MASK) == FLAG) |
| { |
| iCurrentOp = ESkipFlags; |
| iPduPos = iPdu; |
| } |
| break; |
| case ESkipFlags: |
| iSkipBytes++; |
| if (iSkipBytes == FLAG_SZ) |
| { |
| if ((iCurrentInt32 & FLAG_MASK) != FLAG) |
| { |
| if (!iPduPos) |
| iPduPos = iPdu; |
| // Check if iPduPos+FLAG_SZ-1 overflows |
| int copy_from = iCurrentInt32; |
| for (uint8* write_pos = iPduPos + FLAG_SZ - 1; write_pos >= iPduPos; write_pos--) |
| { |
| *write_pos = (uint8)copy_from; |
| copy_from >>= 8; |
| } |
| iPduPos += FLAG_SZ; |
| iCurrentOp = ELookForEndFlag; |
| } |
| iSkipBytes = 0; |
| } |
| break; |
| case ELookForEndFlag: |
| if ((iCurrentInt32 & FLAG_MASK) == FLAG) |
| { |
| iPduPos -= (FLAG_SZ - 1); |
| // found end flag |
| IndicatePdu(); |
| iCurrentOp = ESkipFlags; |
| } |
| else |
| { |
| *iPduPos++ = bsbuf[num]; |
| // check for pdu size |
| if ((iPduPos - iPdu) == H223_MAX_MUX_PDU_SIZE) |
| { |
| iObserver->MuxPduErrIndicate(ESizeErr); |
| iPduPos = NULL; |
| iCurrentOp = ELookForStartFlag; |
| } |
| } |
| break; |
| } |
| } |
| return 1; |
| } |