AudioGroup.cpp revision 04fcfe3ce9fdc5d3487c9760092649afc2de2dc8
173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh/*
273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Copyright (C) 2010 The Android Open Source Project
373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * you may not use this file except in compliance with the License.
673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * You may obtain a copy of the License at
773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
1073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
1173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
1273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * See the License for the specific language governing permissions and
1473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * limitations under the License.
1573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh */
1673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
1773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <stdio.h>
1873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <stdint.h>
1973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <string.h>
2073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <errno.h>
2173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <fcntl.h>
2273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/epoll.h>
2373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/types.h>
2473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/socket.h>
2573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/stat.h>
2673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/time.h>
2773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <time.h>
2873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <arpa/inet.h>
2973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <netinet/in.h>
3073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#define LOG_TAG "AudioGroup"
3273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <cutils/atomic.h>
3373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Log.h>
3473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Errors.h>
3573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/RefBase.h>
3673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/threads.h>
3773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/SystemClock.h>
3873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioSystem.h>
3973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioRecord.h>
4073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioTrack.h>
4173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/mediarecorder.h>
4273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "jni.h"
4473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "JNIHelp.h"
4573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "AudioCodec.h"
47c7092775516e15983053a58b3b43ff3eb58ac46fChia-chi Yeh#include "EchoSuppressor.h"
4873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehextern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
5073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehnamespace {
5273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehusing namespace android;
5473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint gRandom = -1;
5673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// We use a circular array to implement jitter buffer. The simplest way is doing
5873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// a modulo operation on the index while accessing the array. However modulo can
5973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// be expensive on some platforms, such as ARM. Thus we round up the size of the
6073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// array to the nearest power of 2 and then use bitwise-and instead of modulo.
61b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh// Currently we make it 512ms long and assume packet interval is 40ms or less.
62b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh// The first 80ms is the place where samples get mixed. The rest 432ms is the
63b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh// real jitter buffer. For a stream at 8000Hz it takes 8192 bytes. These numbers
6473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// are chosen by experiments and each of them can be adjusted as needed.
6573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
669795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// Originally a stream does not send packets when it is receive-only or there is
679795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// nothing to mix. However, this causes some problems with certain firewalls and
689795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// proxies. A firewall might remove a port mapping when there is no outgoing
699795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// packet for a preiod of time, and a proxy might wait for incoming packets from
709795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// both sides before start forwarding. To solve these problems, we send out a
719795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// silence packet on the stream for every second. It should be good enough to
729795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// keep the stream alive with relatively low resources.
739795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh
7473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// Other notes:
7573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + We use elapsedRealtime() to get the time. Since we use 32bit variables
7673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   instead of 64bit ones, comparison must be done by subtraction.
7773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + Sampling rate must be multiple of 1000Hz, and packet length must be in
7873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   milliseconds. No floating points.
7973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + If we cannot get enough CPU, we drop samples and simulate packet loss.
8073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + Resampling is not done yet, so streams in one group must use the same rate.
81b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh//   For the first release only 8000Hz is supported.
82b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh
83b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh#define BUFFER_SIZE     512
84b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh#define HISTORY_SIZE    80
85b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh#define MEASURE_PERIOD  2000
8673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehclass AudioStream
8873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
8973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehpublic:
9073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream();
9173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ~AudioStream();
9273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool set(int mode, int socket, sockaddr_storage *remote,
930d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        AudioCodec *codec, int sampleRate, int sampleCount,
9473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int codecType, int dtmfType);
9573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
9673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void sendDtmf(int event);
9773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool mix(int32_t *output, int head, int tail, int sampleRate);
9873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void encode(int tick, AudioStream *chain);
9973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void decode(int tick);
10073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
101a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yehprivate:
10273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    enum {
10373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NORMAL = 0,
10473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        SEND_ONLY = 1,
10573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        RECEIVE_ONLY = 2,
10673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LAST_MODE = 2,
10773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
10873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
10973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mMode;
11073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSocket;
11173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage mRemote;
11273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioCodec *mCodec;
11373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mCodecMagic;
11473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mDtmfMagic;
115f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh    bool mFixRemote;
11673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
11773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mTick;
11873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleRate;
11973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleCount;
12073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mInterval;
1219795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    int mKeepAlive;
12273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
12373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t *mBuffer;
12473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferMask;
12573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferHead;
12673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferTail;
127b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    int mLatencyTimer;
12873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mLatencyScore;
12973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint16_t mSequence;
13173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mTimestamp;
13273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mSsrc;
13373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDtmfEvent;
13573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDtmfStart;
13673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *mNext;
13873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    friend class AudioGroup;
14073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
14173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
14273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::AudioStream()
14373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
14473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSocket = -1;
14573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mCodec = NULL;
14673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBuffer = NULL;
14773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNext = NULL;
14873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
14973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
15073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::~AudioStream()
15173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
15273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mSocket);
15373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete mCodec;
15473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete [] mBuffer;
15573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] is dead", mSocket);
15673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
15773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
15873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
1590d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    AudioCodec *codec, int sampleRate, int sampleCount,
16073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int codecType, int dtmfType)
16173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
16273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode < 0 || mode > LAST_MODE) {
16373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
16473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
16573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = mode;
16673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
16773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mCodecMagic = (0x8000 | codecType) << 16;
16873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
16973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
17073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTick = elapsedRealtime();
17173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleRate = sampleRate / 1000;
17273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleCount = sampleCount;
17373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mInterval = mSampleCount / mSampleRate;
17473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
17573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Allocate jitter buffer.
176b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    for (mBufferMask = 8; mBufferMask < mSampleRate; mBufferMask <<= 1);
177b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    mBufferMask *= BUFFER_SIZE;
17873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBuffer = new int16_t[mBufferMask];
17973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    --mBufferMask;
18073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferHead = 0;
18173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferTail = 0;
182b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    mLatencyTimer = 0;
18373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mLatencyScore = 0;
18473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
18573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Initialize random bits.
18673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mSequence, sizeof(mSequence));
18773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mTimestamp, sizeof(mTimestamp));
18873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mSsrc, sizeof(mSsrc));
18973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
19073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = -1;
19173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfStart = 0;
19273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
1930d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    // Only take over these things when succeeded.
19473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSocket = socket;
1950d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (codec) {
1960d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        mRemote = *remote;
1970d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        mCodec = codec;
198f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh
199f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        // Here we should never get an private address, but some buggy proxy
200f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        // servers do give us one. To solve this, we replace the address when
201f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        // the first time we successfully decode an incoming packet.
202f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        mFixRemote = false;
203f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        if (remote->ss_family == AF_INET) {
204f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            unsigned char *address =
205f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
206f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            if (address[0] == 10 ||
207f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                (address[0] == 172 && (address[1] >> 4) == 1) ||
208f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                (address[0] == 192 && address[1] == 168)) {
209f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                mFixRemote = true;
210f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            }
211f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        }
2120d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    }
21373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
214d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh    LOGD("stream[%d] is configured as %s %dkHz %dms mode %d", mSocket,
215d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        (codec ? codec->name : "RAW"), mSampleRate, mInterval, mMode);
21673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
21773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
21873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
21973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::sendDtmf(int event)
22073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
22173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfMagic != 0) {
22273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = event << 24;
22373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfStart = mTimestamp + mSampleCount;
22473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
22573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
22673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
22773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
22873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
22973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == SEND_ONLY) {
23073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
23173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
23273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
23373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (head - mBufferHead < 0) {
23473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        head = mBufferHead;
23573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
23673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tail - mBufferTail > 0) {
23773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        tail = mBufferTail;
23873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
23973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tail - head <= 0) {
24073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
24173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
24273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
24373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    head *= mSampleRate;
24473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tail *= mSampleRate;
24573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
24673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (sampleRate == mSampleRate) {
24773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        for (int i = head; i - tail < 0; ++i) {
24873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            output[i - head] += mBuffer[i & mBufferMask];
24973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
25073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
25173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // TODO: implement resampling.
25273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
25373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
25473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
25573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
25673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
25773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::encode(int tick, AudioStream *chain)
25873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
25973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mTick >= mInterval) {
26073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // We just missed the train. Pretend that packets in between are lost.
26173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int skipped = (tick - mTick) / mInterval;
26273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTick += skipped * mInterval;
26373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mSequence += skipped;
26473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTimestamp += skipped * mSampleCount;
265d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        LOGV("stream[%d] skips %d packets", mSocket, skipped);
26673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
26773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
26873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tick = mTick;
26973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTick += mInterval;
27073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ++mSequence;
27173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTimestamp += mSampleCount;
27273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
27373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // If there is an ongoing DTMF event, send it now.
2749795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    if (mMode != RECEIVE_ONLY && mDtmfEvent != -1) {
27573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int duration = mTimestamp - mDtmfStart;
27673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Make sure duration is reasonable.
27773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (duration >= 0 && duration < mSampleRate * 100) {
27873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            duration += mSampleCount;
27973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            int32_t buffer[4] = {
28073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                htonl(mDtmfMagic | mSequence),
28173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                htonl(mDtmfStart),
28273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mSsrc,
28373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                htonl(mDtmfEvent | duration),
28473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            };
28573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (duration >= mSampleRate * 100) {
28673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                buffer[3] |= htonl(1 << 23);
28773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mDtmfEvent = -1;
28873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
28973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
29073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                (sockaddr *)&mRemote, sizeof(mRemote));
29173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return;
29273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
29373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = -1;
29473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
29573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
29673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int32_t buffer[mSampleCount + 3];
2979795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    int16_t samples[mSampleCount];
2989795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    if (mMode == RECEIVE_ONLY) {
2999795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        if ((mTick ^ mKeepAlive) >> 10 == 0) {
3009795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            return;
30173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
3029795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        mKeepAlive = mTick;
3039795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        memset(samples, 0, sizeof(samples));
3049795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    } else {
3059795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        // Mix all other streams.
3069795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        bool mixed = false;
3079795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        memset(buffer, 0, sizeof(buffer));
3089795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        while (chain) {
3099795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            if (chain != this &&
3109795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
3119795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                mixed = true;
3129795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            }
3139795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            chain = chain->mNext;
314ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync        }
31573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3169795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        if (mixed) {
3179795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            // Saturate into 16 bits.
3189795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            for (int i = 0; i < mSampleCount; ++i) {
3199795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                int32_t sample = buffer[i];
3209795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                if (sample < -32768) {
3219795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                    sample = -32768;
3229795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                }
3239795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                if (sample > 32767) {
3249795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                    sample = 32767;
3259795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                }
3269795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                samples[i] = sample;
3279795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            }
3289795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        } else {
3299795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            if ((mTick ^ mKeepAlive) >> 10 == 0) {
3309795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh                return;
3319795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            }
3329795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            mKeepAlive = mTick;
3339795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            memset(samples, 0, sizeof(samples));
3349795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            LOGV("stream[%d] no data", mSocket);
33573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
33673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
3379795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh
33873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mCodec) {
33973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Special case for device stream.
34073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
34173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
34273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
34373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3449795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    // Cook the packet and send it out.
34573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[0] = htonl(mCodecMagic | mSequence);
34673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[1] = htonl(mTimestamp);
34773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[2] = mSsrc;
34873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int length = mCodec->encode(&buffer[3], samples);
34973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (length <= 0) {
350d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        LOGV("stream[%d] encoder error", mSocket);
35173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
35273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
35373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
35473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sizeof(mRemote));
35573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
35673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
35773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::decode(int tick)
35873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
35973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    char c;
36073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == SEND_ONLY) {
36173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        recv(mSocket, &c, 1, MSG_DONTWAIT);
36273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
36373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
36473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
36573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Make sure mBufferHead and mBufferTail are reasonable.
366b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if ((unsigned int)(tick + BUFFER_SIZE - mBufferHead) > BUFFER_SIZE * 2) {
367b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mBufferHead = tick - HISTORY_SIZE;
36873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBufferTail = mBufferHead;
36973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
37073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
371b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if (tick - mBufferHead > HISTORY_SIZE) {
37273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Throw away outdated samples.
373b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mBufferHead = tick - HISTORY_SIZE;
37473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (mBufferTail - mBufferHead < 0) {
37573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = mBufferHead;
37673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
37773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
37873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
379b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    // Adjust the jitter buffer if the latency keeps larger than two times of the
380b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    // packet interval in the past two seconds.
381b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    int score = mBufferTail - tick - mInterval * 2;
382b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if (mLatencyScore > score) {
383b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mLatencyScore = score;
384b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    }
385b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if (mLatencyScore <= 0) {
386b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mLatencyTimer = tick;
387b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mLatencyScore = score;
388b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    } else if (tick - mLatencyTimer >= MEASURE_PERIOD) {
389d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        LOGV("stream[%d] reduces latency of %dms", mSocket, mLatencyScore);
390b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mBufferTail -= mLatencyScore;
391b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mLatencyTimer = tick;
39273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
39373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
394b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
39573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Buffer overflow. Drop the packet.
396d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        LOGV("stream[%d] buffer overflow", mSocket);
39773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        recv(mSocket, &c, 1, MSG_DONTWAIT);
39873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
39973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
40073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
40173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Receive the packet and decode it.
40273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t samples[mSampleCount];
40373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int length = 0;
40473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mCodec) {
40573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Special case for device stream.
40673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        length = recv(mSocket, samples, sizeof(samples),
40773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            MSG_TRUNC | MSG_DONTWAIT) >> 1;
40873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
40973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        __attribute__((aligned(4))) uint8_t buffer[2048];
410f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        sockaddr_storage remote;
411f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        socklen_t len = sizeof(remote);
412f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh
41364d2d433d0f4d37fccf2d98109d22f768c71f0dcChung-yih Wang        length = recvfrom(mSocket, buffer, sizeof(buffer),
414f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
41573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
41673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Do we need to check SSRC, sequence, and timestamp? They are not
41719f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        // reliable but at least they can be used to identify duplicates?
41873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (length < 12 || length > (int)sizeof(buffer) ||
41973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
420d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh            LOGV("stream[%d] malformed packet", mSocket);
42173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return;
42273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
42373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int offset = 12 + ((buffer[0] & 0x0F) << 2);
42473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if ((buffer[0] & 0x10) != 0) {
42573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
42673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
42773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if ((buffer[0] & 0x20) != 0) {
42873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            length -= buffer[length - 1];
42973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
43073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        length -= offset;
43173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (length >= 0) {
43273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            length = mCodec->decode(samples, &buffer[offset], length);
43373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
434f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        if (length > 0 && mFixRemote) {
435f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            mRemote = remote;
436f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            mFixRemote = false;
437f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        }
43873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
439f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh    if (length <= 0) {
440d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        LOGV("stream[%d] decoder error", mSocket);
44173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
44273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
44373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
44473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mBufferTail > 0) {
445b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        // Buffer underrun. Reset the jitter buffer.
446d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        LOGV("stream[%d] buffer underrun", mSocket);
44773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (mBufferTail - mBufferHead <= 0) {
448b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh            mBufferHead = tick + mInterval;
44973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = mBufferHead;
45073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        } else {
451b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh            int tail = (tick + mInterval) * mSampleRate;
45273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
45373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mBuffer[i & mBufferMask] = 0;
45473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
455b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh            mBufferTail = tick + mInterval;
45673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
45773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
45873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
45973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Append to the jitter buffer.
46073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int tail = mBufferTail * mSampleRate;
46173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; i < mSampleCount; ++i) {
46273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBuffer[tail & mBufferMask] = samples[i];
46373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++tail;
46473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
46573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferTail += mInterval;
46673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
46773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
46873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//------------------------------------------------------------------------------
46973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
47073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehclass AudioGroup
47173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
47273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehpublic:
47373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup();
47473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ~AudioGroup();
47573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool set(int sampleRate, int sampleCount);
47673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
47773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool setMode(int mode);
47873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool sendDtmf(int event);
47973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool add(AudioStream *stream);
48073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool remove(int socket);
48173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
482a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yehprivate:
48373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    enum {
48473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ON_HOLD = 0,
48573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        MUTED = 1,
48673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NORMAL = 2,
48704fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh        ECHO_SUPPRESSION = 3,
48873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LAST_MODE = 3,
48973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
490d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
49173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *mChain;
49273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mEventQueue;
49373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    volatile int mDtmfEvent;
49473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
495d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int mMode;
496d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int mSampleRate;
49773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleCount;
49873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDeviceSocket;
49973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
50073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    class NetworkThread : public Thread
50173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {
50273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    public:
50373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
50473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
50573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool start()
50673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
50773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
50873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                LOGE("cannot start network thread");
50973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return false;
51073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
51173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return true;
51273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
51373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
51473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    private:
51573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioGroup *mGroup;
516d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        bool threadLoop();
51773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
51873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sp<NetworkThread> mNetworkThread;
51973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
52073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    class DeviceThread : public Thread
52173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {
52273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    public:
52373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
52473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
52573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool start()
52673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
52773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
52873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                LOGE("cannot start device thread");
52973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return false;
53073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
53173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return true;
53273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
53373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
53473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    private:
53573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioGroup *mGroup;
536d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        bool threadLoop();
53773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
53873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sp<DeviceThread> mDeviceThread;
53973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
54073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
54173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioGroup::AudioGroup()
54273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
54373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = ON_HOLD;
54473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain = NULL;
54573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mEventQueue = -1;
54673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = -1;
54773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceSocket = -1;
54873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread = new NetworkThread(this);
54973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread = new DeviceThread(this);
55073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
55173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
55273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioGroup::~AudioGroup()
55373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
55473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
55573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread->requestExitAndWait();
55673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mEventQueue);
55773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mDeviceSocket);
55873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    while (mChain) {
55973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioStream *next = mChain->mNext;
56073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        delete mChain;
56173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mChain = next;
56273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
56373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("group[%d] is dead", mDeviceSocket);
56473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
56573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
56673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::set(int sampleRate, int sampleCount)
56773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
56873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mEventQueue = epoll_create(2);
56973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mEventQueue == -1) {
57073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_create: %s", strerror(errno));
57173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
57273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
57373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
574d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    mSampleRate = sampleRate;
57573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleCount = sampleCount;
57673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
57773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create device socket.
57873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int pair[2];
57973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
58073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("socketpair: %s", strerror(errno));
58173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
58273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
58373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceSocket = pair[0];
58473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
58573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create device stream.
58673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain = new AudioStream;
58773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
58873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sampleRate, sampleCount, -1, -1)) {
58973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        close(pair[1]);
59073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("cannot initialize device stream");
59173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
59273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
59373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
594d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Give device socket a reasonable timeout.
59573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    timeval tv;
59673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tv.tv_sec = 0;
597a7f73fb2550935cc78c643b7faf25ebacf16b94fChia-chi Yeh    tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
598d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
59973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("setsockopt: %s", strerror(errno));
60073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
60173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
60273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
60373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Add device stream into event queue.
60473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event event;
60573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.events = EPOLLIN;
60673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.data.ptr = mChain;
60773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
60873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_ctl: %s", strerror(errno));
60973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
61073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
61173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
61273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Anything else?
61373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
61473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
61573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
61673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
61773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::setMode(int mode)
61873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
61973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode < 0 || mode > LAST_MODE) {
62073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
62173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
62204fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh    if (mode == ECHO_SUPPRESSION && AudioSystem::getParameters(
62304fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh        0, String8("ec_supported")) == "ec_supported=yes") {
62404fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh        mode = NORMAL;
62504fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh    }
62673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == mode) {
62773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return true;
62873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
62973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
630d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    mDeviceThread->requestExitAndWait();
63173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
63273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = mode;
633d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    return (mode == ON_HOLD) || mDeviceThread->start();
63473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
63573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
63673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::sendDtmf(int event)
63773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
63873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (event < 0 || event > 15) {
63973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
64073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
64173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
64273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // DTMF is rarely used, so we try to make it as lightweight as possible.
64373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Using volatile might be dodgy, but using a pipe or pthread primitives
64473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // or stop-set-restart threads seems too heavy. Will investigate later.
64573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    timespec ts;
64673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ts.tv_sec = 0;
64773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ts.tv_nsec = 100000000;
64873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
64973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        nanosleep(&ts, NULL);
65073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
65173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfEvent != -1) {
65273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
65373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
65473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = event;
65573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    nanosleep(&ts, NULL);
65673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
65773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
65873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
65973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::add(AudioStream *stream)
66073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
66173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
66273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
66373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event event;
66473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.events = EPOLLIN;
66573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.data.ptr = stream;
66673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
66773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_ctl: %s", strerror(errno));
66873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
66973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
67073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
67173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    stream->mNext = mChain->mNext;
67273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain->mNext = stream;
67373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mNetworkThread->start()) {
67473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Only take over the stream when succeeded.
67573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mChain->mNext = stream->mNext;
67673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
67773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
67873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
67973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
68073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
68173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
68273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
68373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::remove(int socket)
68473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
68573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
68673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
68773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
68873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioStream *target = stream->mNext;
68973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (target->mSocket == socket) {
69019f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh            if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
69119f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh                LOGE("epoll_ctl: %s", strerror(errno));
69219f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh                return false;
69319f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh            }
69473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            stream->mNext = target->mNext;
69573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
69673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            delete target;
69773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            break;
69873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
69973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
70073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
70173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Do not start network thread if there is only one stream.
70273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mChain->mNext || !mNetworkThread->start()) {
70373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
70473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
70573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
70673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
70773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
708d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yehbool AudioGroup::NetworkThread::threadLoop()
70973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
710d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    AudioStream *chain = mGroup->mChain;
71173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int tick = elapsedRealtime();
71273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int deadline = tick + 10;
71373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int count = 0;
71473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
715d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    for (AudioStream *stream = chain; stream; stream = stream->mNext) {
716b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        if (tick - stream->mTick >= 0) {
717d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            stream->encode(tick, chain);
71873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
71973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (deadline - stream->mTick > 0) {
72073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            deadline = stream->mTick;
72173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
72273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++count;
72373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
72473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
725d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int event = mGroup->mDtmfEvent;
726d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (event != -1) {
727d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        for (AudioStream *stream = chain; stream; stream = stream->mNext) {
72873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            stream->sendDtmf(event);
72973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
730d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        mGroup->mDtmfEvent = -1;
73173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
73273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
73373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    deadline -= tick;
73473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (deadline < 1) {
73573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        deadline = 1;
73673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
73773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
73873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event events[count];
739d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
74073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (count == -1) {
74173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_wait: %s", strerror(errno));
74273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
74373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
74473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; i < count; ++i) {
74573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ((AudioStream *)events[i].data.ptr)->decode(tick);
74673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
74773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
74873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
74973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
75073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
751d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yehbool AudioGroup::DeviceThread::threadLoop()
75273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
753d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int mode = mGroup->mMode;
754d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int sampleRate = mGroup->mSampleRate;
755d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int sampleCount = mGroup->mSampleCount;
756d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int deviceSocket = mGroup->mDeviceSocket;
75773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
758d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Find out the frame count for AudioTrack and AudioRecord.
759d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int output = 0;
760d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int input = 0;
761d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
762d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        sampleRate) != NO_ERROR || output <= 0 ||
763d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        AudioRecord::getMinFrameCount(&input, sampleRate,
764d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
765d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        LOGE("cannot compute frame count");
766d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        return false;
76773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
768d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    LOGD("reported frame count: output %d, input %d", output, input);
76973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
770d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (output < sampleCount * 2) {
771d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        output = sampleCount * 2;
772d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
773d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (input < sampleCount * 2) {
774d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        input = sampleCount * 2;
775d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
776d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    LOGD("adjusted frame count: output %d, input %d", output, input);
77773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
778d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Initialize AudioTrack and AudioRecord.
779d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    AudioTrack track;
780d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    AudioRecord record;
781d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
78204fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh        AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR || record.set(
78304fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh        AUDIO_SOURCE_VOICE_COMMUNICATION, sampleRate, AudioSystem::PCM_16_BIT,
784d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
785d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        LOGE("cannot initialize audio device");
786d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        return false;
787d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
788d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    LOGD("latency: output %d, input %d", track.latency(), record.latency());
78973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
790c7092775516e15983053a58b3b43ff3eb58ac46fChia-chi Yeh    // Initialize echo canceler.
7912e85359f74a5280ee733d35ff5f63b3943140632Chia-chi Yeh    EchoSuppressor echo(sampleCount,
792c7092775516e15983053a58b3b43ff3eb58ac46fChia-chi Yeh        (track.latency() + record.latency()) * sampleRate / 1000);
793d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
794d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Give device socket a reasonable buffer size.
795d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
796d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
797d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
798d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Drain device socket.
799d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    char c;
800d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
801d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
8020ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh    // Start AudioRecord before AudioTrack. This prevents AudioTrack from being
8030ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh    // disabled due to buffer underrun while waiting for AudioRecord.
804d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (mode != MUTED) {
805d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        record.start();
8060ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh        int16_t one;
8070ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh        record.read(&one, sizeof(one));
808d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
8090ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh    track.start();
810d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
811d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    while (!exitPending()) {
812d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int16_t output[sampleCount];
813d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
814d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            memset(output, 0, sizeof(output));
8157dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        }
8167dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh
817d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int16_t input[sampleCount];
818d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int toWrite = sampleCount;
819d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int toRead = (mode == MUTED) ? 0 : sampleCount;
820d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int chances = 100;
821d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
822d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
823d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            if (toWrite > 0) {
824d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                AudioTrack::Buffer buffer;
825d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                buffer.frameCount = toWrite;
826d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
827d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                status_t status = track.obtainBuffer(&buffer, 1);
828d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                if (status == NO_ERROR) {
829d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    int offset = sampleCount - toWrite;
830d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    memcpy(buffer.i8, &output[offset], buffer.size);
831d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    toWrite -= buffer.frameCount;
832d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    track.releaseBuffer(&buffer);
833d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
834d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    LOGE("cannot write to AudioTrack");
8350ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    return true;
836d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                }
837d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            }
838d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
839d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            if (toRead > 0) {
840d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                AudioRecord::Buffer buffer;
8410ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                buffer.frameCount = toRead;
842d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
843d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                status_t status = record.obtainBuffer(&buffer, 1);
844d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                if (status == NO_ERROR) {
8450ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    int offset = sampleCount - toRead;
8460ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    memcpy(&input[offset], buffer.i8, buffer.size);
8470ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    toRead -= buffer.frameCount;
848d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    record.releaseBuffer(&buffer);
849d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
850d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    LOGE("cannot read from AudioRecord");
8510ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    return true;
8527dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                }
85373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
85473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
85573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
856d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        if (chances <= 0) {
8570ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh            LOGW("device loop timeout");
8580ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh            while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
859d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        }
86073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
861d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        if (mode != MUTED) {
862d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            if (mode == NORMAL) {
863d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
864d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            } else {
865c7092775516e15983053a58b3b43ff3eb58ac46fChia-chi Yeh                echo.run(output, input);
866d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
867d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            }
8687dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        }
8697dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    }
870d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    return false;
87173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
87273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
87373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//------------------------------------------------------------------------------
87473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
87573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehstatic jfieldID gNative;
87673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehstatic jfieldID gMode;
87773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
87819f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yehvoid add(JNIEnv *env, jobject thiz, jint mode,
87973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jint socket, jstring jRemoteAddress, jint remotePort,
8800d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    jstring jCodecSpec, jint dtmfType)
88173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
8820d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    AudioCodec *codec = NULL;
88373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *stream = NULL;
88473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = NULL;
88573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
88673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Sanity check.
88773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage remote;
88873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
88973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
8900d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        return;
89173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
8920d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (!jCodecSpec) {
8930d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        jniThrowNullPointerException(env, "codecSpec");
8940d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        return;
89573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
8960d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
8970d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (!codecSpec) {
89873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
8990d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        return;
9000d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    }
9010d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh
9020d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    // Create audio codec.
9030d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    int codecType = -1;
9040d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    char codecName[16];
9050d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    int sampleRate = -1;
9069795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    sscanf(codecSpec, "%d %15[^/]%*c%d", &codecType, codecName, &sampleRate);
9070d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    codec = newAudioCodec(codecName);
9080d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
9090d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
9100d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (sampleCount <= 0) {
9110d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
9120d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh            "cannot initialize audio codec");
91319f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        goto error;
91473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
91573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
91673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create audio stream.
91773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    stream = new AudioStream;
9180d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
91973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        codecType, dtmfType)) {
92073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
92173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            "cannot initialize audio stream");
92273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
92373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
92473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    socket = -1;
9250d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    codec = NULL;
92673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
92773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create audio group.
92873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    group = (AudioGroup *)env->GetIntField(thiz, gNative);
92973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!group) {
93073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int mode = env->GetIntField(thiz, gMode);
93173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        group = new AudioGroup;
93273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (!group->set(8000, 256) || !group->setMode(mode)) {
93373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            jniThrowException(env, "java/lang/IllegalStateException",
93473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                "cannot initialize audio group");
93573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            goto error;
93673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
93773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
93873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
93973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Add audio stream into audio group.
94073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!group->add(stream)) {
94173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
94273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            "cannot add audio stream");
94373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
94473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
94573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
94673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Succeed.
94773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    env->SetIntField(thiz, gNative, (int)group);
94819f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh    return;
94973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
95073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeherror:
95173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete group;
95273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete stream;
9530d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    delete codec;
95473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(socket);
95573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    env->SetIntField(thiz, gNative, NULL);
95673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
95773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
95873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid remove(JNIEnv *env, jobject thiz, jint socket)
95973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
96073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
96173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group) {
96273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (socket == -1 || !group->remove(socket)) {
96373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            delete group;
96473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            env->SetIntField(thiz, gNative, NULL);
96573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
96673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
96773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
96873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
96973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid setMode(JNIEnv *env, jobject thiz, jint mode)
97073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
97173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
97273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group && !group->setMode(mode)) {
97373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
97473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
97573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
97673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
97773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid sendDtmf(JNIEnv *env, jobject thiz, jint event)
97873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
97973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
98073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group && !group->sendDtmf(event)) {
98173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
98273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
98373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
98473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
98573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehJNINativeMethod gMethods[] = {
986a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    {"nativeAdd", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
987a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    {"nativeRemove", "(I)V", (void *)remove},
988a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    {"nativeSetMode", "(I)V", (void *)setMode},
989a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    {"nativeSendDtmf", "(I)V", (void *)sendDtmf},
99073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
99173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
99273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} // namespace
99373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
99473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint registerAudioGroup(JNIEnv *env)
99573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
99673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    gRandom = open("/dev/urandom", O_RDONLY);
99773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (gRandom == -1) {
99873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("urandom: %s", strerror(errno));
99973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
100073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
100173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
100273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jclass clazz;
100373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
100473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
100573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
100673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
100773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("JNI registration failed");
100873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
100973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
101073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return 0;
101173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
1012