void AMRAudioRTPSink::doSpecialFrameHandling(unsigned fragmentationOffset, unsigned char* frameStart, unsigned numBytesInFrame, struct timeval framePresentationTime, unsigned numRemainingBytes) { // If this is the 1st frame in the 1st packet, set the RTP 'M' (marker) // bit (because this is considered the start of a talk spurt): if (isFirstPacket() && isFirstFrameInPacket()) { setMarkerBit(); } // If this is the first frame in the packet, set the 1-byte payload // header (using CMR 15) if (isFirstFrameInPacket()) { u_int8_t payloadHeader = 0xF0; setSpecialHeaderBytes(&payloadHeader, 1, 0); } // Set the TOC field for the current frame, based on the "FT" and "Q" // values from our source: AMRAudioSource* amrSource = (AMRAudioSource*)fSource; if (amrSource == NULL) return; // sanity check u_int8_t toc = amrSource->lastFrameHeader(); // Clear the "F" bit, because we're the last frame in this packet: ##### toc &=~ 0x80; setSpecialHeaderBytes(&toc, 1, 1+numFramesUsedSoFar()); // Important: Also call our base class's doSpecialFrameHandling(), // to set the packet's timestamp: MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, frameStart, numBytesInFrame, framePresentationTime, numRemainingBytes); }
void AMRAudioFileSink::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) { AMRAudioSource* source = (AMRAudioSource*)fSource; if (!fHaveWrittenHeader && fPerFrameFileNameBuffer == NULL) { // Output the appropriate AMR header to the start of the file. // This header is defined in RFC 3267, section 5. // (However, we don't do this if we're creating one file per frame.) char headerBuffer[100]; sprintf(headerBuffer, "#!AMR%s%s\n", source->isWideband() ? "-WB" : "", source->numChannels() > 1 ? "_MC1.0" : ""); unsigned headerLength = strlen(headerBuffer); if (source->numChannels() > 1) { // Also add a 32-bit channel description field: headerBuffer[headerLength++] = 0; headerBuffer[headerLength++] = 0; headerBuffer[headerLength++] = 0; headerBuffer[headerLength++] = source->numChannels(); } addData((unsigned char*)headerBuffer, headerLength, presentationTime); } fHaveWrittenHeader = True; // Add the 1-byte header, before writing the file data proper: // (Again, we don't do this if we're creating one file per frame.) if (fPerFrameFileNameBuffer == NULL) { u_int8_t frameHeader = source->lastFrameHeader(); addData(&frameHeader, 1, presentationTime); } // Call the parent class to complete the normal file write with the input data: FileSink::afterGettingFrame1(frameSize, presentationTime); }