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> &notify, bool isWide, const AString &params)
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