AAMRAssembler.cpp revision 6e4c5c499999c04c2477b987f9e64f3ff2bf1a06
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> &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) {
126        LOGV("Not the sequence number I expected");
127
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
137        LOGV("AMR packet too short.");
138
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
155            LOGV("Unable to parse TOC.");
156
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
169            LOGV("Illegal TOC entry.");
170
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
183    sp<ABuffer> accessUnit = new ABuffer(totalSize);
184    CopyTimes(accessUnit, buffer);
185
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
196            LOGV("AMR packet too short.");
197
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
231