AAMRAssembler.cpp revision 39ddf8e0f18766f7ba1e3246b774aa6ebd93eea8
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "AAMRAssembler.h" 18 19#include "ARTPSource.h" 20 21#include <media/stagefright/foundation/ABuffer.h> 22#include <media/stagefright/foundation/ADebug.h> 23#include <media/stagefright/foundation/AMessage.h> 24#include <media/stagefright/foundation/hexdump.h> 25#include <media/stagefright/Utils.h> 26 27namespace android { 28 29static bool GetAttribute(const char *s, const char *key, AString *value) { 30 value->clear(); 31 32 size_t keyLen = strlen(key); 33 34 for (;;) { 35 const char *colonPos = strchr(s, ';'); 36 37 size_t len = 38 (colonPos == NULL) ? strlen(s) : colonPos - s; 39 40 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { 41 value->setTo(&s[keyLen + 1], len - keyLen - 1); 42 return true; 43 } 44 if (len == keyLen && !strncmp(s, key, keyLen)) { 45 value->setTo("1"); 46 return true; 47 } 48 49 if (colonPos == NULL) { 50 return false; 51 } 52 53 s = colonPos + 1; 54 } 55} 56 57AAMRAssembler::AAMRAssembler( 58 const sp<AMessage> ¬ify, bool isWide, const AString ¶ms) 59 : mIsWide(isWide), 60 mNotifyMsg(notify), 61 mNextExpectedSeqNoValid(false), 62 mNextExpectedSeqNo(0) { 63 AString value; 64 CHECK(GetAttribute(params.c_str(), "octet-align", &value) && value == "1"); 65 CHECK(!GetAttribute(params.c_str(), "crc", &value) || value == "0"); 66 CHECK(!GetAttribute(params.c_str(), "interleaving", &value)); 67} 68 69AAMRAssembler::~AAMRAssembler() { 70} 71 72ARTPAssembler::AssemblyStatus AAMRAssembler::assembleMore( 73 const sp<ARTPSource> &source) { 74 return addPacket(source); 75} 76 77static size_t getFrameSize(bool isWide, unsigned FT) { 78 static const size_t kFrameSizeNB[8] = { 79 95, 103, 118, 134, 148, 159, 204, 244 80 }; 81 static const size_t kFrameSizeWB[9] = { 82 132, 177, 253, 285, 317, 365, 397, 461, 477 83 }; 84 85 size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; 86 87 // Round up bits to bytes and add 1 for the header byte. 88 frameSize = (frameSize + 7) / 8 + 1; 89 90 return frameSize; 91} 92 93ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( 94 const sp<ARTPSource> &source) { 95 List<sp<ABuffer> > *queue = source->queue(); 96 97 if (queue->empty()) { 98 return NOT_ENOUGH_DATA; 99 } 100 101 if (mNextExpectedSeqNoValid) { 102 List<sp<ABuffer> >::iterator it = queue->begin(); 103 while (it != queue->end()) { 104 if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { 105 break; 106 } 107 108 it = queue->erase(it); 109 } 110 111 if (queue->empty()) { 112 return NOT_ENOUGH_DATA; 113 } 114 } 115 116 sp<ABuffer> buffer = *queue->begin(); 117 118 if (!mNextExpectedSeqNoValid) { 119 mNextExpectedSeqNoValid = true; 120 mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); 121 } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { 122#if VERBOSE 123 LOG(VERBOSE) << "Not the sequence number I expected"; 124#endif 125 126 return WRONG_SEQUENCE_NUMBER; 127 } 128 129 // hexdump(buffer->data(), buffer->size()); 130 131 if (buffer->size() < 1) { 132 queue->erase(queue->begin()); 133 ++mNextExpectedSeqNo; 134 135 LOG(VERBOSE) << "AMR packet too short."; 136 137 return MALFORMED_PACKET; 138 } 139 140 unsigned payloadHeader = buffer->data()[0]; 141 unsigned CMR = payloadHeader >> 4; 142 CHECK_EQ(payloadHeader & 0x0f, 0u); // RR 143 144 Vector<uint8_t> tableOfContents; 145 146 size_t offset = 1; 147 size_t totalSize = 0; 148 for (;;) { 149 if (offset >= buffer->size()) { 150 queue->erase(queue->begin()); 151 ++mNextExpectedSeqNo; 152 153 LOG(VERBOSE) << "Unable to parse TOC."; 154 155 return MALFORMED_PACKET; 156 } 157 158 uint8_t toc = buffer->data()[offset++]; 159 160 unsigned FT = (toc >> 3) & 0x0f; 161 if ((toc & 3) != 0 162 || (mIsWide && FT > 8) 163 || (!mIsWide && FT > 7)) { 164 queue->erase(queue->begin()); 165 ++mNextExpectedSeqNo; 166 167 LOG(VERBOSE) << "Illegal TOC entry."; 168 169 return MALFORMED_PACKET; 170 } 171 172 totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f); 173 174 tableOfContents.push(toc); 175 176 if (0 == (toc & 0x80)) { 177 break; 178 } 179 } 180 181 uint64_t ntpTime; 182 CHECK(buffer->meta()->findInt64( 183 "ntp-time", (int64_t *)&ntpTime)); 184 185 sp<ABuffer> accessUnit = new ABuffer(totalSize); 186 accessUnit->meta()->setInt64("ntp-time", ntpTime); 187 188 size_t dstOffset = 0; 189 for (size_t i = 0; i < tableOfContents.size(); ++i) { 190 uint8_t toc = tableOfContents[i]; 191 192 size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f); 193 194 if (offset + frameSize - 1 > buffer->size()) { 195 queue->erase(queue->begin()); 196 ++mNextExpectedSeqNo; 197 198 LOG(VERBOSE) << "AMR packet too short."; 199 200 return MALFORMED_PACKET; 201 } 202 203 accessUnit->data()[dstOffset++] = toc; 204 memcpy(accessUnit->data() + dstOffset, 205 buffer->data() + offset, frameSize - 1); 206 207 offset += frameSize - 1; 208 dstOffset += frameSize - 1; 209 } 210 211 sp<AMessage> msg = mNotifyMsg->dup(); 212 msg->setObject("access-unit", accessUnit); 213 msg->post(); 214 215 queue->erase(queue->begin()); 216 ++mNextExpectedSeqNo; 217 218 return OK; 219} 220 221void AAMRAssembler::packetLost() { 222 CHECK(mNextExpectedSeqNoValid); 223 ++mNextExpectedSeqNo; 224} 225 226void AAMRAssembler::onByeReceived() { 227 sp<AMessage> msg = mNotifyMsg->dup(); 228 msg->setInt32("eos", true); 229 msg->post(); 230} 231 232} // namespace android 233