blob: b1f6e9a3c147d0176ab1a9ebfe8509638eb12898 [file] [log] [blame]
Andreas Huber57648e42010-08-04 10:14:30 -07001/*
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
Andreas Huber6e3fa442010-09-21 13:13:15 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "AAMRAssembler"
19#include <utils/Log.h>
20
Andreas Huber57648e42010-08-04 10:14:30 -070021#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> &notify, bool isWide, const AString &params)
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[8] = {
83 95, 103, 118, 134, 148, 159, 204, 244
84 };
85 static const size_t kFrameSizeWB[9] = {
86 132, 177, 253, 285, 317, 365, 397, 461, 477
87 };
88
89 size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
90
91 // Round up bits to bytes and add 1 for the header byte.
92 frameSize = (frameSize + 7) / 8 + 1;
93
94 return frameSize;
95}
96
97ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket(
98 const sp<ARTPSource> &source) {
99 List<sp<ABuffer> > *queue = source->queue();
100
101 if (queue->empty()) {
102 return NOT_ENOUGH_DATA;
103 }
104
105 if (mNextExpectedSeqNoValid) {
106 List<sp<ABuffer> >::iterator it = queue->begin();
107 while (it != queue->end()) {
108 if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
109 break;
110 }
111
112 it = queue->erase(it);
113 }
114
115 if (queue->empty()) {
116 return NOT_ENOUGH_DATA;
117 }
118 }
119
120 sp<ABuffer> buffer = *queue->begin();
121
122 if (!mNextExpectedSeqNoValid) {
123 mNextExpectedSeqNoValid = true;
124 mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
125 } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700126 LOGV("Not the sequence number I expected");
Andreas Huber57648e42010-08-04 10:14:30 -0700127
128 return WRONG_SEQUENCE_NUMBER;
129 }
130
131 // hexdump(buffer->data(), buffer->size());
132
133 if (buffer->size() < 1) {
134 queue->erase(queue->begin());
135 ++mNextExpectedSeqNo;
136
Andreas Huber6e3fa442010-09-21 13:13:15 -0700137 LOGV("AMR packet too short.");
Andreas Huber57648e42010-08-04 10:14:30 -0700138
139 return MALFORMED_PACKET;
140 }
141
142 unsigned payloadHeader = buffer->data()[0];
143 unsigned CMR = payloadHeader >> 4;
144 CHECK_EQ(payloadHeader & 0x0f, 0u); // RR
145
146 Vector<uint8_t> tableOfContents;
147
148 size_t offset = 1;
149 size_t totalSize = 0;
150 for (;;) {
151 if (offset >= buffer->size()) {
152 queue->erase(queue->begin());
153 ++mNextExpectedSeqNo;
154
Andreas Huber6e3fa442010-09-21 13:13:15 -0700155 LOGV("Unable to parse TOC.");
Andreas Huber57648e42010-08-04 10:14:30 -0700156
157 return MALFORMED_PACKET;
158 }
159
160 uint8_t toc = buffer->data()[offset++];
161
162 unsigned FT = (toc >> 3) & 0x0f;
163 if ((toc & 3) != 0
164 || (mIsWide && FT > 8)
165 || (!mIsWide && FT > 7)) {
166 queue->erase(queue->begin());
167 ++mNextExpectedSeqNo;
168
Andreas Huber6e3fa442010-09-21 13:13:15 -0700169 LOGV("Illegal TOC entry.");
Andreas Huber57648e42010-08-04 10:14:30 -0700170
171 return MALFORMED_PACKET;
172 }
173
174 totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f);
175
176 tableOfContents.push(toc);
177
178 if (0 == (toc & 0x80)) {
179 break;
180 }
181 }
182
Andreas Huber57648e42010-08-04 10:14:30 -0700183 sp<ABuffer> accessUnit = new ABuffer(totalSize);
Andreas Hubereeb97d92010-08-27 13:29:08 -0700184 CopyTimes(accessUnit, buffer);
Andreas Huber57648e42010-08-04 10:14:30 -0700185
186 size_t dstOffset = 0;
187 for (size_t i = 0; i < tableOfContents.size(); ++i) {
188 uint8_t toc = tableOfContents[i];
189
190 size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f);
191
192 if (offset + frameSize - 1 > buffer->size()) {
193 queue->erase(queue->begin());
194 ++mNextExpectedSeqNo;
195
Andreas Huber6e3fa442010-09-21 13:13:15 -0700196 LOGV("AMR packet too short.");
Andreas Huber57648e42010-08-04 10:14:30 -0700197
198 return MALFORMED_PACKET;
199 }
200
201 accessUnit->data()[dstOffset++] = toc;
202 memcpy(accessUnit->data() + dstOffset,
203 buffer->data() + offset, frameSize - 1);
204
205 offset += frameSize - 1;
206 dstOffset += frameSize - 1;
207 }
208
209 sp<AMessage> msg = mNotifyMsg->dup();
210 msg->setObject("access-unit", accessUnit);
211 msg->post();
212
213 queue->erase(queue->begin());
214 ++mNextExpectedSeqNo;
215
216 return OK;
217}
218
219void AAMRAssembler::packetLost() {
220 CHECK(mNextExpectedSeqNoValid);
221 ++mNextExpectedSeqNo;
222}
223
224void AAMRAssembler::onByeReceived() {
225 sp<AMessage> msg = mNotifyMsg->dup();
226 msg->setInt32("eos", true);
227 msg->post();
228}
229
230} // namespace android