157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber/*
257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * Copyright (C) 2010 The Android Open Source Project
357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber *
457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * you may not use this file except in compliance with the License.
657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * You may obtain a copy of the License at
757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber *
857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber *
1057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * Unless required by applicable law or agreed to in writing, software
1157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * See the License for the specific language governing permissions and
1457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber * limitations under the License.
1557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber */
1657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
176e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber//#define LOG_NDEBUG 0
186e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber#define LOG_TAG "AAMRAssembler"
196e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber#include <utils/Log.h>
206e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber
2157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include "AAMRAssembler.h"
2257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
2357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include "ARTPSource.h"
2457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
2557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
2657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include <media/stagefright/foundation/ADebug.h>
2757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include <media/stagefright/foundation/AMessage.h>
2857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include <media/stagefright/foundation/hexdump.h>
2957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber#include <media/stagefright/Utils.h>
3057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
3157648e4eec7dd2593af467877bc7cce4aa654759Andreas Hubernamespace android {
3257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
3357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
3457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    value->clear();
3557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
3657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    size_t keyLen = strlen(key);
3757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
3857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    for (;;) {
3957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        const char *colonPos = strchr(s, ';');
4057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
4157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        size_t len =
4257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
4357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
4457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
4557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
4657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return true;
4757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
4857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (len == keyLen && !strncmp(s, key, keyLen)) {
4957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            value->setTo("1");
5057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return true;
5157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
5257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
5357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (colonPos == NULL) {
5457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return false;
5557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
5657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
5757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        s = colonPos + 1;
5857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
5957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
6057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
6157648e4eec7dd2593af467877bc7cce4aa654759Andreas HuberAAMRAssembler::AAMRAssembler(
6257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        const sp<AMessage> &notify, bool isWide, const AString &params)
6357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    : mIsWide(isWide),
6457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber      mNotifyMsg(notify),
6557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber      mNextExpectedSeqNoValid(false),
6657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber      mNextExpectedSeqNo(0) {
6757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    AString value;
6857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    CHECK(GetAttribute(params.c_str(), "octet-align", &value) && value == "1");
6957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    CHECK(!GetAttribute(params.c_str(), "crc", &value) || value == "0");
7057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    CHECK(!GetAttribute(params.c_str(), "interleaving", &value));
7157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
7257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
7357648e4eec7dd2593af467877bc7cce4aa654759Andreas HuberAAMRAssembler::~AAMRAssembler() {
7457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
7557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
7657648e4eec7dd2593af467877bc7cce4aa654759Andreas HuberARTPAssembler::AssemblyStatus AAMRAssembler::assembleMore(
7757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        const sp<ARTPSource> &source) {
7857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    return addPacket(source);
7957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
8057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
8157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huberstatic size_t getFrameSize(bool isWide, unsigned FT) {
829a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber    static const size_t kFrameSizeNB[9] = {
839a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber        95, 103, 118, 134, 148, 159, 204, 244, 39
8457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    };
859a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber    static const size_t kFrameSizeWB[10] = {
869a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber        132, 177, 253, 285, 317, 365, 397, 461, 477, 40
8757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    };
8857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
899a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber    if (FT == 15) {
909a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber        return 1;
919a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber    }
929a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber
9357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
9457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
9557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    // Round up bits to bytes and add 1 for the header byte.
9657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    frameSize = (frameSize + 7) / 8 + 1;
9757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
9857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    return frameSize;
9957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
10057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
10157648e4eec7dd2593af467877bc7cce4aa654759Andreas HuberARTPAssembler::AssemblyStatus AAMRAssembler::addPacket(
10257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        const sp<ARTPSource> &source) {
10357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    List<sp<ABuffer> > *queue = source->queue();
10457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
10557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    if (queue->empty()) {
10657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        return NOT_ENOUGH_DATA;
10757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
10857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
10957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    if (mNextExpectedSeqNoValid) {
11057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        List<sp<ABuffer> >::iterator it = queue->begin();
11157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        while (it != queue->end()) {
11257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
11357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                break;
11457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            }
11557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
11657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            it = queue->erase(it);
11757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
11857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
11957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (queue->empty()) {
12057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return NOT_ENOUGH_DATA;
12157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
12257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
12357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
12457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    sp<ABuffer> buffer = *queue->begin();
12557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
12657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    if (!mNextExpectedSeqNoValid) {
12757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        mNextExpectedSeqNoValid = true;
12857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
12957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
1306e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber        LOGV("Not the sequence number I expected");
13157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
13257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        return WRONG_SEQUENCE_NUMBER;
13357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
13457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
13557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    // hexdump(buffer->data(), buffer->size());
13657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
13757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    if (buffer->size() < 1) {
13857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        queue->erase(queue->begin());
13957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        ++mNextExpectedSeqNo;
14057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
1416e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber        LOGV("AMR packet too short.");
14257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
14357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        return MALFORMED_PACKET;
14457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
14557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
14657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    unsigned payloadHeader = buffer->data()[0];
14757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    unsigned CMR = payloadHeader >> 4;
14857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    CHECK_EQ(payloadHeader & 0x0f, 0u);  // RR
14957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
15057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    Vector<uint8_t> tableOfContents;
15157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
15257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    size_t offset = 1;
15357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    size_t totalSize = 0;
15457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    for (;;) {
15557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (offset >= buffer->size()) {
15657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            queue->erase(queue->begin());
15757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            ++mNextExpectedSeqNo;
15857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
1596e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber            LOGV("Unable to parse TOC.");
16057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
16157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return MALFORMED_PACKET;
16257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
16357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
16457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        uint8_t toc = buffer->data()[offset++];
16557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
16657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        unsigned FT = (toc >> 3) & 0x0f;
16757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if ((toc & 3) != 0
1689a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber                || (mIsWide && FT > 9 && FT != 15)
1699a023f1f8e27dc9cae9066bd94a417e15e42b270Andreas Huber                || (!mIsWide && FT > 8 && FT != 15)) {
17057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            queue->erase(queue->begin());
17157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            ++mNextExpectedSeqNo;
17257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
1736e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber            LOGV("Illegal TOC entry.");
17457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
17557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return MALFORMED_PACKET;
17657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
17757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
17857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f);
17957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
18057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        tableOfContents.push(toc);
18157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
18257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (0 == (toc & 0x80)) {
18357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            break;
18457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
18557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
18657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
18757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    sp<ABuffer> accessUnit = new ABuffer(totalSize);
188eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    CopyTimes(accessUnit, buffer);
18957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
19057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    size_t dstOffset = 0;
19157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    for (size_t i = 0; i < tableOfContents.size(); ++i) {
19257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        uint8_t toc = tableOfContents[i];
19357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
19457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f);
19557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
19657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (offset + frameSize - 1 > buffer->size()) {
19757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            queue->erase(queue->begin());
19857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            ++mNextExpectedSeqNo;
19957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
2006e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber            LOGV("AMR packet too short.");
20157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
20257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return MALFORMED_PACKET;
20357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
20457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
20557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        accessUnit->data()[dstOffset++] = toc;
20657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        memcpy(accessUnit->data() + dstOffset,
20757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber               buffer->data() + offset, frameSize - 1);
20857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
20957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        offset += frameSize - 1;
21057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        dstOffset += frameSize - 1;
21157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    }
21257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
21357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    sp<AMessage> msg = mNotifyMsg->dup();
21457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    msg->setObject("access-unit", accessUnit);
21557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    msg->post();
21657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
21757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    queue->erase(queue->begin());
21857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    ++mNextExpectedSeqNo;
21957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
22057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    return OK;
22157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
22257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
22357648e4eec7dd2593af467877bc7cce4aa654759Andreas Hubervoid AAMRAssembler::packetLost() {
22457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    CHECK(mNextExpectedSeqNoValid);
22557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    ++mNextExpectedSeqNo;
22657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
22757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
22857648e4eec7dd2593af467877bc7cce4aa654759Andreas Hubervoid AAMRAssembler::onByeReceived() {
22957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    sp<AMessage> msg = mNotifyMsg->dup();
23057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    msg->setInt32("eos", true);
23157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber    msg->post();
23257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}
23357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
23457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber}  // namespace android
235