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 __unused = buffer->data()[0]; 147 unsigned CMR __unused = payloadHeader >> 4; 148 149 Vector<uint8_t> tableOfContents; 150 151 size_t offset = 1; 152 size_t totalSize = 0; 153 for (;;) { 154 if (offset >= buffer->size()) { 155 queue->erase(queue->begin()); 156 ++mNextExpectedSeqNo; 157 158 ALOGV("Unable to parse TOC."); 159 160 return MALFORMED_PACKET; 161 } 162 163 uint8_t toc = buffer->data()[offset++]; 164 165 unsigned FT = (toc >> 3) & 0x0f; 166 if ((toc & 3) != 0 167 || (mIsWide && FT > 9 && FT != 15) 168 || (!mIsWide && FT > 8 && FT != 15)) { 169 queue->erase(queue->begin()); 170 ++mNextExpectedSeqNo; 171 172 ALOGV("Illegal TOC entry."); 173 174 return MALFORMED_PACKET; 175 } 176 177 totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f); 178 179 tableOfContents.push(toc); 180 181 if (0 == (toc & 0x80)) { 182 break; 183 } 184 } 185 186 sp<ABuffer> accessUnit = new ABuffer(totalSize); 187 CopyTimes(accessUnit, buffer); 188 189 size_t dstOffset = 0; 190 for (size_t i = 0; i < tableOfContents.size(); ++i) { 191 uint8_t toc = tableOfContents[i]; 192 193 size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f); 194 195 if (offset + frameSize - 1 > buffer->size()) { 196 queue->erase(queue->begin()); 197 ++mNextExpectedSeqNo; 198 199 ALOGV("AMR packet too short."); 200 201 return MALFORMED_PACKET; 202 } 203 204 accessUnit->data()[dstOffset++] = toc; 205 memcpy(accessUnit->data() + dstOffset, 206 buffer->data() + offset, frameSize - 1); 207 208 offset += frameSize - 1; 209 dstOffset += frameSize - 1; 210 } 211 212 sp<AMessage> msg = mNotifyMsg->dup(); 213 msg->setBuffer("access-unit", accessUnit); 214 msg->post(); 215 216 queue->erase(queue->begin()); 217 ++mNextExpectedSeqNo; 218 219 return OK; 220} 221 222void AAMRAssembler::packetLost() { 223 CHECK(mNextExpectedSeqNoValid); 224 ++mNextExpectedSeqNo; 225} 226 227void AAMRAssembler::onByeReceived() { 228 sp<AMessage> msg = mNotifyMsg->dup(); 229 msg->setInt32("eos", true); 230 msg->post(); 231} 232 233} // namespace android 234