AAMRAssembler.cpp revision 4aae77cbe1bf4369910314a55c2bc2349af10d3c
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//#define LOG_NDEBUG 0 18#define LOG_TAG "AAMRAssembler" 19#include <utils/Log.h> 20 21#include "AAMRAssembler.h" 22 23#include "ARTPSource.h" 24 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/foundation/hexdump.h> 29#include <media/stagefright/Utils.h> 30 31namespace android { 32 33static bool GetAttribute(const char *s, const char *key, AString *value) { 34 value->clear(); 35 36 size_t keyLen = strlen(key); 37 38 for (;;) { 39 const char *colonPos = strchr(s, ';'); 40 41 size_t len = 42 (colonPos == NULL) ? strlen(s) : colonPos - s; 43 44 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { 45 value->setTo(&s[keyLen + 1], len - keyLen - 1); 46 return true; 47 } 48 if (len == keyLen && !strncmp(s, key, keyLen)) { 49 value->setTo("1"); 50 return true; 51 } 52 53 if (colonPos == NULL) { 54 return false; 55 } 56 57 s = colonPos + 1; 58 } 59} 60 61AAMRAssembler::AAMRAssembler( 62 const sp<AMessage> ¬ify, bool isWide, const AString ¶ms) 63 : mIsWide(isWide), 64 mNotifyMsg(notify), 65 mNextExpectedSeqNoValid(false), 66 mNextExpectedSeqNo(0) { 67 AString value; 68 CHECK(GetAttribute(params.c_str(), "octet-align", &value) && value == "1"); 69 CHECK(!GetAttribute(params.c_str(), "crc", &value) || value == "0"); 70 CHECK(!GetAttribute(params.c_str(), "interleaving", &value)); 71} 72 73AAMRAssembler::~AAMRAssembler() { 74} 75 76ARTPAssembler::AssemblyStatus AAMRAssembler::assembleMore( 77 const sp<ARTPSource> &source) { 78 return addPacket(source); 79} 80 81static size_t getFrameSize(bool isWide, unsigned FT) { 82 static const size_t kFrameSizeNB[9] = { 83 95, 103, 118, 134, 148, 159, 204, 244, 39 84 }; 85 static const size_t kFrameSizeWB[10] = { 86 132, 177, 253, 285, 317, 365, 397, 461, 477, 40 87 }; 88 89 if (FT == 15) { 90 return 1; 91 } 92 93 size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; 94 95 // Round up bits to bytes and add 1 for the header byte. 96 frameSize = (frameSize + 7) / 8 + 1; 97 98 return frameSize; 99} 100 101ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( 102 const sp<ARTPSource> &source) { 103 List<sp<ABuffer> > *queue = source->queue(); 104 105 if (queue->empty()) { 106 return NOT_ENOUGH_DATA; 107 } 108 109 if (mNextExpectedSeqNoValid) { 110 List<sp<ABuffer> >::iterator it = queue->begin(); 111 while (it != queue->end()) { 112 if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { 113 break; 114 } 115 116 it = queue->erase(it); 117 } 118 119 if (queue->empty()) { 120 return NOT_ENOUGH_DATA; 121 } 122 } 123 124 sp<ABuffer> buffer = *queue->begin(); 125 126 if (!mNextExpectedSeqNoValid) { 127 mNextExpectedSeqNoValid = true; 128 mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); 129 } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { 130 ALOGV("Not the sequence number I expected"); 131 132 return WRONG_SEQUENCE_NUMBER; 133 } 134 135 // hexdump(buffer->data(), buffer->size()); 136 137 if (buffer->size() < 1) { 138 queue->erase(queue->begin()); 139 ++mNextExpectedSeqNo; 140 141 ALOGV("AMR packet too short."); 142 143 return MALFORMED_PACKET; 144 } 145 146 unsigned payloadHeader = buffer->data()[0]; 147 unsigned CMR = payloadHeader >> 4; 148 CHECK_EQ(payloadHeader & 0x0f, 0u); // RR 149 150 Vector<uint8_t> tableOfContents; 151 152 size_t offset = 1; 153 size_t totalSize = 0; 154 for (;;) { 155 if (offset >= buffer->size()) { 156 queue->erase(queue->begin()); 157 ++mNextExpectedSeqNo; 158 159 ALOGV("Unable to parse TOC."); 160 161 return MALFORMED_PACKET; 162 } 163 164 uint8_t toc = buffer->data()[offset++]; 165 166 unsigned FT = (toc >> 3) & 0x0f; 167 if ((toc & 3) != 0 168 || (mIsWide && FT > 9 && FT != 15) 169 || (!mIsWide && FT > 8 && FT != 15)) { 170 queue->erase(queue->begin()); 171 ++mNextExpectedSeqNo; 172 173 ALOGV("Illegal TOC entry."); 174 175 return MALFORMED_PACKET; 176 } 177 178 totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f); 179 180 tableOfContents.push(toc); 181 182 if (0 == (toc & 0x80)) { 183 break; 184 } 185 } 186 187 sp<ABuffer> accessUnit = new ABuffer(totalSize); 188 CopyTimes(accessUnit, buffer); 189 190 size_t dstOffset = 0; 191 for (size_t i = 0; i < tableOfContents.size(); ++i) { 192 uint8_t toc = tableOfContents[i]; 193 194 size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f); 195 196 if (offset + frameSize - 1 > buffer->size()) { 197 queue->erase(queue->begin()); 198 ++mNextExpectedSeqNo; 199 200 ALOGV("AMR packet too short."); 201 202 return MALFORMED_PACKET; 203 } 204 205 accessUnit->data()[dstOffset++] = toc; 206 memcpy(accessUnit->data() + dstOffset, 207 buffer->data() + offset, frameSize - 1); 208 209 offset += frameSize - 1; 210 dstOffset += frameSize - 1; 211 } 212 213 sp<AMessage> msg = mNotifyMsg->dup(); 214 msg->setObject("access-unit", accessUnit); 215 msg->post(); 216 217 queue->erase(queue->begin()); 218 ++mNextExpectedSeqNo; 219 220 return OK; 221} 222 223void AAMRAssembler::packetLost() { 224 CHECK(mNextExpectedSeqNoValid); 225 ++mNextExpectedSeqNo; 226} 227 228void AAMRAssembler::onByeReceived() { 229 sp<AMessage> msg = mNotifyMsg->dup(); 230 msg->setInt32("eos", true); 231 msg->post(); 232} 233 234} // namespace android 235