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
317bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh// #define LOG_NDEBUG 0
3273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#define LOG_TAG "AudioGroup"
3373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <cutils/atomic.h>
3481b8e1b53a6035d0950309dc24d1500c5acf7f37Eric Laurent#include <cutils/properties.h>
3573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Log.h>
3673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Errors.h>
3773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/RefBase.h>
3873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/threads.h>
3973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/SystemClock.h>
4073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioSystem.h>
4173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioRecord.h>
4273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioTrack.h>
4373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/mediarecorder.h>
44ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent#include <media/AudioEffect.h>
452ad970981d31000e468f835de8286fa46f07c5e1Mikhail Naganov#include <system/audio_effects/effect_aec.h>
4636daedc9bcdadecc3065b2783553804e81a78dcdDima Zavin#include <system/audio.h>
4731a824ddf74276c6f571079fe6afbb71c13bf965Dima Zavin
489443bd615da130dbaf6aa2971fc5dcbd798b8b9dSteven Moreland#include <nativehelper/ScopedUtfChars.h>
49c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov
5073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "jni.h"
519443bd615da130dbaf6aa2971fc5dcbd798b8b9dSteven Moreland#include <nativehelper/JNIHelp.h>
5273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "AudioCodec.h"
54c7092775516e15983053a58b3b43ff3eb58ac46fChia-chi Yeh#include "EchoSuppressor.h"
5573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehextern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
5773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehnamespace {
5973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
6073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehusing namespace android;
6173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
6273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint gRandom = -1;
6373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
6473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// We use a circular array to implement jitter buffer. The simplest way is doing
6573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// a modulo operation on the index while accessing the array. However modulo can
6673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// be expensive on some platforms, such as ARM. Thus we round up the size of the
6773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// array to the nearest power of 2 and then use bitwise-and instead of modulo.
687bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh// Currently we make it 2048ms long and assume packet interval is 50ms or less.
697bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh// The first 100ms is the place where samples get mixed. The rest is the real
707bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh// jitter buffer. For a stream at 8000Hz it takes 32 kilobytes. These numbers
7173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// are chosen by experiments and each of them can be adjusted as needed.
7273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
739795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// Originally a stream does not send packets when it is receive-only or there is
749795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// nothing to mix. However, this causes some problems with certain firewalls and
759795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// proxies. A firewall might remove a port mapping when there is no outgoing
769795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// packet for a preiod of time, and a proxy might wait for incoming packets from
779795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// both sides before start forwarding. To solve these problems, we send out a
789795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// silence packet on the stream for every second. It should be good enough to
799795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh// keep the stream alive with relatively low resources.
809795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh
8173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// Other notes:
8273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + We use elapsedRealtime() to get the time. Since we use 32bit variables
8373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   instead of 64bit ones, comparison must be done by subtraction.
8473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + Sampling rate must be multiple of 1000Hz, and packet length must be in
8573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   milliseconds. No floating points.
8673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + If we cannot get enough CPU, we drop samples and simulate packet loss.
8773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + Resampling is not done yet, so streams in one group must use the same rate.
88b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh//   For the first release only 8000Hz is supported.
89b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh
907bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh#define BUFFER_SIZE     2048
917bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh#define HISTORY_SIZE    100
927bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh#define MEASURE_BASE    100
937bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh#define MEASURE_PERIOD  5000
947bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh#define DTMF_PERIOD     200
9573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
9673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehclass AudioStream
9773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
9873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehpublic:
9973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream();
10073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ~AudioStream();
10173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool set(int mode, int socket, sockaddr_storage *remote,
1020d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        AudioCodec *codec, int sampleRate, int sampleCount,
10373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int codecType, int dtmfType);
10473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
10573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void sendDtmf(int event);
10673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool mix(int32_t *output, int head, int tail, int sampleRate);
10773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void encode(int tick, AudioStream *chain);
10873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void decode(int tick);
10973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
110a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yehprivate:
11173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    enum {
11273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NORMAL = 0,
11373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        SEND_ONLY = 1,
11473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        RECEIVE_ONLY = 2,
11573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LAST_MODE = 2,
11673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
11773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
11873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mMode;
11973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSocket;
12073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage mRemote;
12173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioCodec *mCodec;
12273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mCodecMagic;
12373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mDtmfMagic;
124f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh    bool mFixRemote;
12573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
12673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mTick;
12773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleRate;
12873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleCount;
12973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mInterval;
1309795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    int mKeepAlive;
13173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t *mBuffer;
13373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferMask;
13473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferHead;
13573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferTail;
136b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    int mLatencyTimer;
13773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mLatencyScore;
13873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint16_t mSequence;
14073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mTimestamp;
14173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mSsrc;
14273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
14373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDtmfEvent;
14473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDtmfStart;
14573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
14673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *mNext;
14773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
14873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    friend class AudioGroup;
14973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
15073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
15173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::AudioStream()
15273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
15373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSocket = -1;
15473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mCodec = NULL;
15573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBuffer = NULL;
15673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNext = NULL;
15773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
15873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
15973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::~AudioStream()
16073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
16173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mSocket);
16273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete mCodec;
16373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete [] mBuffer;
164faae32cc919d4418612e6f9200d2682c0dc6d36aSteve Block    ALOGD("stream[%d] is dead", mSocket);
16573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
16673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
16773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
1680d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    AudioCodec *codec, int sampleRate, int sampleCount,
16973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int codecType, int dtmfType)
17073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
17173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode < 0 || mode > LAST_MODE) {
17273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
17373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
17473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = mode;
17573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
17673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mCodecMagic = (0x8000 | codecType) << 16;
17773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
17873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
17973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTick = elapsedRealtime();
18073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleRate = sampleRate / 1000;
18173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleCount = sampleCount;
18273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mInterval = mSampleCount / mSampleRate;
18373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
18473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Allocate jitter buffer.
185b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    for (mBufferMask = 8; mBufferMask < mSampleRate; mBufferMask <<= 1);
186b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    mBufferMask *= BUFFER_SIZE;
18773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBuffer = new int16_t[mBufferMask];
18873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    --mBufferMask;
18973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferHead = 0;
19073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferTail = 0;
191b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    mLatencyTimer = 0;
19273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mLatencyScore = 0;
19373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
19473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Initialize random bits.
19573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mSequence, sizeof(mSequence));
19673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mTimestamp, sizeof(mTimestamp));
19773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mSsrc, sizeof(mSsrc));
19873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
19973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = -1;
20073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfStart = 0;
20173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
2020d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    // Only take over these things when succeeded.
20373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSocket = socket;
2040d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (codec) {
2050d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        mRemote = *remote;
2060d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        mCodec = codec;
207f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh
208f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        // Here we should never get an private address, but some buggy proxy
209f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        // servers do give us one. To solve this, we replace the address when
210f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        // the first time we successfully decode an incoming packet.
211f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        mFixRemote = false;
212f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        if (remote->ss_family == AF_INET) {
213f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            unsigned char *address =
214f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
215f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            if (address[0] == 10 ||
216f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                (address[0] == 172 && (address[1] >> 4) == 1) ||
217f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                (address[0] == 192 && address[1] == 168)) {
218f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh                mFixRemote = true;
219f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            }
220f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        }
2210d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    }
22273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
223faae32cc919d4418612e6f9200d2682c0dc6d36aSteve Block    ALOGD("stream[%d] is configured as %s %dkHz %dms mode %d", mSocket,
224d85beac45c12a65076a1c157681de9a5b03bdec7Chia-chi Yeh        (codec ? codec->name : "RAW"), mSampleRate, mInterval, mMode);
22573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
22673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
22773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
22873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::sendDtmf(int event)
22973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
23073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfMagic != 0) {
23173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = event << 24;
23273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfStart = mTimestamp + mSampleCount;
23373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
23473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
23573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
23673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
23773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
23873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == SEND_ONLY) {
23973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
24073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
24173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
24273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (head - mBufferHead < 0) {
24373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        head = mBufferHead;
24473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
24573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tail - mBufferTail > 0) {
24673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        tail = mBufferTail;
24773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
24873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tail - head <= 0) {
24973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
25073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
25173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
25273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    head *= mSampleRate;
25373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tail *= mSampleRate;
25473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
25573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (sampleRate == mSampleRate) {
25673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        for (int i = head; i - tail < 0; ++i) {
25773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            output[i - head] += mBuffer[i & mBufferMask];
25873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
25973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
26073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // TODO: implement resampling.
26173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
26273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
26373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
26473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
26573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
26673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::encode(int tick, AudioStream *chain)
26773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
26873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mTick >= mInterval) {
26973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // We just missed the train. Pretend that packets in between are lost.
27073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int skipped = (tick - mTick) / mInterval;
27173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTick += skipped * mInterval;
27273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mSequence += skipped;
27373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTimestamp += skipped * mSampleCount;
274a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block        ALOGV("stream[%d] skips %d packets", mSocket, skipped);
27573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
27673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
27773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tick = mTick;
27873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTick += mInterval;
27973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ++mSequence;
28073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTimestamp += mSampleCount;
28173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
28273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // If there is an ongoing DTMF event, send it now.
2839795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    if (mMode != RECEIVE_ONLY && mDtmfEvent != -1) {
28473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int duration = mTimestamp - mDtmfStart;
28573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Make sure duration is reasonable.
2867bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        if (duration >= 0 && duration < mSampleRate * DTMF_PERIOD) {
28773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            duration += mSampleCount;
28873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            int32_t buffer[4] = {
289b73cce87638ee104a0411418bd0245b8cc803c79synergy dev                static_cast<int32_t>(htonl(mDtmfMagic | mSequence)),
290b73cce87638ee104a0411418bd0245b8cc803c79synergy dev                static_cast<int32_t>(htonl(mDtmfStart)),
291b73cce87638ee104a0411418bd0245b8cc803c79synergy dev                static_cast<int32_t>(mSsrc),
292b73cce87638ee104a0411418bd0245b8cc803c79synergy dev                static_cast<int32_t>(htonl(mDtmfEvent | duration)),
29373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            };
2947bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            if (duration >= mSampleRate * DTMF_PERIOD) {
29573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                buffer[3] |= htonl(1 << 23);
29673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mDtmfEvent = -1;
29773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
29873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
29973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                (sockaddr *)&mRemote, sizeof(mRemote));
30073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return;
30173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
30273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = -1;
30373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
30473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
30573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int32_t buffer[mSampleCount + 3];
3067bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    bool data = false;
3077bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    if (mMode != RECEIVE_ONLY) {
3089795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        // Mix all other streams.
3099795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        memset(buffer, 0, sizeof(buffer));
3109795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh        while (chain) {
3117bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            if (chain != this) {
3127bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh                data |= chain->mix(buffer, tick - mInterval, tick, mSampleRate);
3139795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            }
3149795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            chain = chain->mNext;
315ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync        }
3167bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    }
31773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3187bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    int16_t samples[mSampleCount];
3197bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    if (data) {
3207bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        // Saturate into 16 bits.
3217bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        for (int i = 0; i < mSampleCount; ++i) {
3227bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            int32_t sample = buffer[i];
3237bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            if (sample < -32768) {
3247bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh                sample = -32768;
3259795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            }
3267bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            if (sample > 32767) {
3277bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh                sample = 32767;
3289795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh            }
3297bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            samples[i] = sample;
3307bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        }
3317bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    } else {
3327bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        if ((mTick ^ mKeepAlive) >> 10 == 0) {
3337bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh            return;
3347bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        }
3357bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        mKeepAlive = mTick;
3367bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        memset(samples, 0, sizeof(samples));
3377bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh
3387bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        if (mMode != RECEIVE_ONLY) {
339a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block            ALOGV("stream[%d] no data", mSocket);
34073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
34173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
3429795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh
34373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mCodec) {
34473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Special case for device stream.
34573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
34673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
34773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
34873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3499795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    // Cook the packet and send it out.
35073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[0] = htonl(mCodecMagic | mSequence);
35173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[1] = htonl(mTimestamp);
35273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[2] = mSsrc;
35373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int length = mCodec->encode(&buffer[3], samples);
35473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (length <= 0) {
355a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block        ALOGV("stream[%d] encoder error", mSocket);
35673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
35773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
35873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
35973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sizeof(mRemote));
36073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
36173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
36273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::decode(int tick)
36373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
36473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    char c;
36573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == SEND_ONLY) {
36673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        recv(mSocket, &c, 1, MSG_DONTWAIT);
36773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
36873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
36973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
37073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Make sure mBufferHead and mBufferTail are reasonable.
371b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if ((unsigned int)(tick + BUFFER_SIZE - mBufferHead) > BUFFER_SIZE * 2) {
372b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mBufferHead = tick - HISTORY_SIZE;
37373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBufferTail = mBufferHead;
37473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
37573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
376b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    if (tick - mBufferHead > HISTORY_SIZE) {
37773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Throw away outdated samples.
378b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mBufferHead = tick - HISTORY_SIZE;
37973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (mBufferTail - mBufferHead < 0) {
38073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = mBufferHead;
38173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
38273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
38373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3847bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    // Adjust the jitter buffer if the latency keeps larger than the threshold
3857bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    // in the measurement period.
3867bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    int score = mBufferTail - tick - MEASURE_BASE;
3877bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh    if (mLatencyScore > score || mLatencyScore <= 0) {
388b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mLatencyScore = score;
389b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mLatencyTimer = tick;
390b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh    } else if (tick - mLatencyTimer >= MEASURE_PERIOD) {
391a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block        ALOGV("stream[%d] reduces latency of %dms", mSocket, mLatencyScore);
392b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        mBufferTail -= mLatencyScore;
3937bece4e883db6abfa8e907c43bf031a209c66de9Chia-chi Yeh        mLatencyScore = -1;
39473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
39573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
396418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    int count = (BUFFER_SIZE - (mBufferTail - mBufferHead)) * mSampleRate;
397418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    if (count < mSampleCount) {
39873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Buffer overflow. Drop the packet.
399a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block        ALOGV("stream[%d] buffer overflow", mSocket);
40073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        recv(mSocket, &c, 1, MSG_DONTWAIT);
40173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
40273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
40373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
40473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Receive the packet and decode it.
405418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    int16_t samples[count];
40673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mCodec) {
40773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Special case for device stream.
408418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        count = recv(mSocket, samples, sizeof(samples),
40973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            MSG_TRUNC | MSG_DONTWAIT) >> 1;
41073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
41173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        __attribute__((aligned(4))) uint8_t buffer[2048];
412f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        sockaddr_storage remote;
413418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        socklen_t addrlen = sizeof(remote);
414f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh
415418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        int length = recvfrom(mSocket, buffer, sizeof(buffer),
416418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &addrlen);
41773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
41873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Do we need to check SSRC, sequence, and timestamp? They are not
41919f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        // reliable but at least they can be used to identify duplicates?
42073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (length < 12 || length > (int)sizeof(buffer) ||
42173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
422a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block            ALOGV("stream[%d] malformed packet", mSocket);
42373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return;
42473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
42573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int offset = 12 + ((buffer[0] & 0x0F) << 2);
42673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if ((buffer[0] & 0x10) != 0) {
42773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
42873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
42973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if ((buffer[0] & 0x20) != 0) {
43073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            length -= buffer[length - 1];
43173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
43273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        length -= offset;
43373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (length >= 0) {
434418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh            length = mCodec->decode(samples, count, &buffer[offset], length);
43573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
436f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        if (length > 0 && mFixRemote) {
437f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            mRemote = remote;
438f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh            mFixRemote = false;
439f703412e867486aef60daf3f025d03794c19821fChia-chi Yeh        }
440418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        count = length;
44173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
442418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    if (count <= 0) {
443a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block        ALOGV("stream[%d] decoder error", mSocket);
44473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
44573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
44673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
44773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mBufferTail > 0) {
448b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        // Buffer underrun. Reset the jitter buffer.
449a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block        ALOGV("stream[%d] buffer underrun", mSocket);
45073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (mBufferTail - mBufferHead <= 0) {
451b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh            mBufferHead = tick + mInterval;
45273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = mBufferHead;
45373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        } else {
454b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh            int tail = (tick + mInterval) * mSampleRate;
45573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
45673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mBuffer[i & mBufferMask] = 0;
45773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
458b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh            mBufferTail = tick + mInterval;
45973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
46073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
46173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
46273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Append to the jitter buffer.
46373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int tail = mBufferTail * mSampleRate;
464418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    for (int i = 0; i < count; ++i) {
46573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBuffer[tail & mBufferMask] = samples[i];
46673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++tail;
46773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
46873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferTail += mInterval;
46973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
47073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
47173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//------------------------------------------------------------------------------
47273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
47373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehclass AudioGroup
47473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
47573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehpublic:
4761d45b11337494fb076a3a63b86484f6c829a61c9Chih-Hung Hsieh    explicit AudioGroup(const String16 &opPackageName);
47773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ~AudioGroup();
47873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool set(int sampleRate, int sampleCount);
47973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
48073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool setMode(int mode);
48173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool sendDtmf(int event);
48273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool add(AudioStream *stream);
4832bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    bool remove(AudioStream *stream);
484ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    bool platformHasAec() { return mPlatformHasAec; }
48573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
486a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yehprivate:
48773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    enum {
48873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ON_HOLD = 0,
48973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        MUTED = 1,
49073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NORMAL = 2,
49104fcfe3ce9fdc5d3487c9760092649afc2de2dc8Chia-chi Yeh        ECHO_SUPPRESSION = 3,
49273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LAST_MODE = 3,
49373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
494d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
495ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    bool checkPlatformAec();
496ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent
49773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *mChain;
49873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mEventQueue;
49973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    volatile int mDtmfEvent;
50073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
501c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov    String16 mOpPackageName;
502c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov
503d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int mMode;
504d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int mSampleRate;
50514ef3fc99b6b2f62e93bd5bbc9a240cd59201af0Aurimas Liutikas    size_t mSampleCount;
50673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDeviceSocket;
507ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    bool mPlatformHasAec;
50873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
50973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    class NetworkThread : public Thread
51073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {
51173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    public:
5121d45b11337494fb076a3a63b86484f6c829a61c9Chih-Hung Hsieh        explicit NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
51373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
51473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool start()
51573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
51673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
5178913af783fc2cf197ef55449792bb8416a356263Steve Block                ALOGE("cannot start network thread");
51873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return false;
51973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
52073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return true;
52173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
52273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
52373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    private:
52473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioGroup *mGroup;
525d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        bool threadLoop();
52673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
52773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sp<NetworkThread> mNetworkThread;
52873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
52973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    class DeviceThread : public Thread
53073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {
53173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    public:
5321d45b11337494fb076a3a63b86484f6c829a61c9Chih-Hung Hsieh        explicit DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
53373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
53473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool start()
53573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
53673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
5378913af783fc2cf197ef55449792bb8416a356263Steve Block                ALOGE("cannot start device thread");
53873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return false;
53973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
54073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return true;
54173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
54273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
54373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    private:
54473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioGroup *mGroup;
545d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        bool threadLoop();
54673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
54773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sp<DeviceThread> mDeviceThread;
54873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
54973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
550c2d55f13a21fe6a288601deab6832c704c998781Svet GanovAudioGroup::AudioGroup(const String16 &opPackageName)
55173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
552c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov    mOpPackageName = opPackageName;
55373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = ON_HOLD;
55473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain = NULL;
55573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mEventQueue = -1;
55673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = -1;
55773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceSocket = -1;
55873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread = new NetworkThread(this);
55973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread = new DeviceThread(this);
560ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    mPlatformHasAec = checkPlatformAec();
56173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
56273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
56373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioGroup::~AudioGroup()
56473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
56573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
56673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread->requestExitAndWait();
56773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mEventQueue);
56873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mDeviceSocket);
56973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    while (mChain) {
57073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioStream *next = mChain->mNext;
57173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        delete mChain;
57273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mChain = next;
57373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
574faae32cc919d4418612e6f9200d2682c0dc6d36aSteve Block    ALOGD("group[%d] is dead", mDeviceSocket);
57573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
57673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
57773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::set(int sampleRate, int sampleCount)
57873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
57973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mEventQueue = epoll_create(2);
58073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mEventQueue == -1) {
5818913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("epoll_create: %s", strerror(errno));
58273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
58373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
58473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
585d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    mSampleRate = sampleRate;
58673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleCount = sampleCount;
58773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
58873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create device socket.
58973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int pair[2];
59073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
5918913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("socketpair: %s", strerror(errno));
59273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
59373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
59473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceSocket = pair[0];
59573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
59673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create device stream.
59773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain = new AudioStream;
59873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
59973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sampleRate, sampleCount, -1, -1)) {
60073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        close(pair[1]);
6018913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("cannot initialize device stream");
60273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
60373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
60473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
605d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Give device socket a reasonable timeout.
60673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    timeval tv;
60773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tv.tv_sec = 0;
608a7f73fb2550935cc78c643b7faf25ebacf16b94fChia-chi Yeh    tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
609d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
6108913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("setsockopt: %s", strerror(errno));
61173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
61273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
61373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
61473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Add device stream into event queue.
61573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event event;
61673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.events = EPOLLIN;
61773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.data.ptr = mChain;
61873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
6198913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("epoll_ctl: %s", strerror(errno));
62073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
62173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
62273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
62373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Anything else?
624faae32cc919d4418612e6f9200d2682c0dc6d36aSteve Block    ALOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
62573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
62673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
62773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
62873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::setMode(int mode)
62973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
63073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode < 0 || mode > LAST_MODE) {
63173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
63273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
6336089a999b71162cd94ed2322670d7a2090b7d094Eric Laurent    // FIXME: temporary code to overcome echo and mic gain issues on herring and tuna boards.
6346089a999b71162cd94ed2322670d7a2090b7d094Eric Laurent    // Must be modified/removed when the root cause of the issue is fixed in the hardware or
6356089a999b71162cd94ed2322670d7a2090b7d094Eric Laurent    // driver
63681b8e1b53a6035d0950309dc24d1500c5acf7f37Eric Laurent    char value[PROPERTY_VALUE_MAX];
63781b8e1b53a6035d0950309dc24d1500c5acf7f37Eric Laurent    property_get("ro.product.board", value, "");
6386089a999b71162cd94ed2322670d7a2090b7d094Eric Laurent    if (mode == NORMAL &&
6396089a999b71162cd94ed2322670d7a2090b7d094Eric Laurent            (!strcmp(value, "herring") || !strcmp(value, "tuna"))) {
64081b8e1b53a6035d0950309dc24d1500c5acf7f37Eric Laurent        mode = ECHO_SUPPRESSION;
64181b8e1b53a6035d0950309dc24d1500c5acf7f37Eric Laurent    }
64273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == mode) {
64373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return true;
64473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
64573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
646d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    mDeviceThread->requestExitAndWait();
647faae32cc919d4418612e6f9200d2682c0dc6d36aSteve Block    ALOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
64873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = mode;
649d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    return (mode == ON_HOLD) || mDeviceThread->start();
65073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
65173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
65273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::sendDtmf(int event)
65373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
65473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (event < 0 || event > 15) {
65573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
65673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
65773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
65873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // DTMF is rarely used, so we try to make it as lightweight as possible.
65973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Using volatile might be dodgy, but using a pipe or pthread primitives
66073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // or stop-set-restart threads seems too heavy. Will investigate later.
66173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    timespec ts;
66273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ts.tv_sec = 0;
66373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ts.tv_nsec = 100000000;
66473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
66573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        nanosleep(&ts, NULL);
66673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
66773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfEvent != -1) {
66873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
66973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
67073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = event;
67173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    nanosleep(&ts, NULL);
67273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
67373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
67473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
67573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::add(AudioStream *stream)
67673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
67773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
67873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
67973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event event;
68073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.events = EPOLLIN;
68173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.data.ptr = stream;
68273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
6838913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("epoll_ctl: %s", strerror(errno));
68473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
68573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
68673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
68773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    stream->mNext = mChain->mNext;
68873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain->mNext = stream;
68973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mNetworkThread->start()) {
69073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Only take over the stream when succeeded.
69173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mChain->mNext = stream->mNext;
69273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
69373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
69473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
695faae32cc919d4418612e6f9200d2682c0dc6d36aSteve Block    ALOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
69673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
69773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
69873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
6992bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yehbool AudioGroup::remove(AudioStream *stream)
70073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
70173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
70273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7032bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    for (AudioStream *chain = mChain; chain->mNext; chain = chain->mNext) {
7042bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        if (chain->mNext == stream) {
7052bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh            if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, stream->mSocket, NULL)) {
7068913af783fc2cf197ef55449792bb8416a356263Steve Block                ALOGE("epoll_ctl: %s", strerror(errno));
70719f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh                return false;
70819f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh            }
7092bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh            chain->mNext = stream->mNext;
7102bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh            ALOGD("stream[%d] leaves group[%d]", stream->mSocket, mDeviceSocket);
7112bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh            delete stream;
71273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            break;
71373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
71473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
71573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
71673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Do not start network thread if there is only one stream.
71773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mChain->mNext || !mNetworkThread->start()) {
71873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
71973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
72073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
72173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
72273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
723d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yehbool AudioGroup::NetworkThread::threadLoop()
72473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
725d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    AudioStream *chain = mGroup->mChain;
72673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int tick = elapsedRealtime();
72773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int deadline = tick + 10;
72873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int count = 0;
72973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
730d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    for (AudioStream *stream = chain; stream; stream = stream->mNext) {
731b727dc4e022dd5a64301dffc527db92e023bf156Chia-chi Yeh        if (tick - stream->mTick >= 0) {
732d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            stream->encode(tick, chain);
73373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
73473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (deadline - stream->mTick > 0) {
73573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            deadline = stream->mTick;
73673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
73773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++count;
73873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
73973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
740d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int event = mGroup->mDtmfEvent;
741d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (event != -1) {
742d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        for (AudioStream *stream = chain; stream; stream = stream->mNext) {
74373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            stream->sendDtmf(event);
74473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
745d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        mGroup->mDtmfEvent = -1;
74673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
74773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
74873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    deadline -= tick;
74973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (deadline < 1) {
75073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        deadline = 1;
75173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
75273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
75373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event events[count];
754d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
75573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (count == -1) {
7568913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("epoll_wait: %s", strerror(errno));
75773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
75873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
75973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; i < count; ++i) {
76073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ((AudioStream *)events[i].data.ptr)->decode(tick);
76173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
76273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
76373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
76473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
76573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
766ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurentbool AudioGroup::checkPlatformAec()
767ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent{
768ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    effect_descriptor_t fxDesc;
769ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    uint32_t numFx;
770ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent
771ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    if (AudioEffect::queryNumberEffects(&numFx) != NO_ERROR) {
772ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        return false;
773ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    }
774ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    for (uint32_t i = 0; i < numFx; i++) {
775ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        if (AudioEffect::queryEffect(i, &fxDesc) != NO_ERROR) {
776ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            continue;
777ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        }
778ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        if (memcmp(&fxDesc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
779ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            return true;
780ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        }
781ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    }
782ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    return false;
783ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent}
784ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent
785d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yehbool AudioGroup::DeviceThread::threadLoop()
78673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
787d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int mode = mGroup->mMode;
788d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int sampleRate = mGroup->mSampleRate;
78914ef3fc99b6b2f62e93bd5bbc9a240cd59201af0Aurimas Liutikas    size_t sampleCount = mGroup->mSampleCount;
790d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    int deviceSocket = mGroup->mDeviceSocket;
79173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
792d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Find out the frame count for AudioTrack and AudioRecord.
79386d1860a1d9c905bf8ee8328bcee4537cd02fcd6Glenn Kasten    size_t output = 0;
79486d1860a1d9c905bf8ee8328bcee4537cd02fcd6Glenn Kasten    size_t input = 0;
79531a824ddf74276c6f571079fe6afbb71c13bf965Dima Zavin    if (AudioTrack::getMinFrameCount(&output, AUDIO_STREAM_VOICE_CALL,
796d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        sampleRate) != NO_ERROR || output <= 0 ||
797d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        AudioRecord::getMinFrameCount(&input, sampleRate,
798f29ac10f0f3649c16a6e44bac961401cd3874fd4Glenn Kasten        AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO) != NO_ERROR || input <= 0) {
7998913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("cannot compute frame count");
800d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        return false;
80173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
80214ef3fc99b6b2f62e93bd5bbc9a240cd59201af0Aurimas Liutikas    ALOGD("reported frame count: output %zu, input %zu", output, input);
80373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
804d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (output < sampleCount * 2) {
805d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        output = sampleCount * 2;
806d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
807d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (input < sampleCount * 2) {
808d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        input = sampleCount * 2;
809d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
81014ef3fc99b6b2f62e93bd5bbc9a240cd59201af0Aurimas Liutikas    ALOGD("adjusted frame count: output %zu, input %zu", output, input);
81173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
812d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Initialize AudioTrack and AudioRecord.
81335b37b5e24f6a852fd7b5c5843146497b566d90eGlenn Kasten    sp<AudioTrack> track = new AudioTrack();
814c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov    sp<AudioRecord> record = new AudioRecord(mGroup->mOpPackageName);
81535b37b5e24f6a852fd7b5c5843146497b566d90eGlenn Kasten    if (track->set(AUDIO_STREAM_VOICE_CALL, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
816b0d67543d9926be60ca1198b02a1d644646f6e4eGlenn Kasten                AUDIO_CHANNEL_OUT_MONO, output, AUDIO_OUTPUT_FLAG_NONE, NULL /*callback_t*/,
817b0d67543d9926be60ca1198b02a1d644646f6e4eGlenn Kasten                NULL /*user*/, 0 /*notificationFrames*/, 0 /*sharedBuffer*/,
8185dc85971e22d4150db5c42508a58b2a9d2ec934aGlenn Kasten                false /*threadCanCallJava*/, AUDIO_SESSION_ALLOCATE,
819b0d67543d9926be60ca1198b02a1d644646f6e4eGlenn Kasten                AudioTrack::TRANSFER_OBTAIN) != NO_ERROR ||
820b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten            record->set(AUDIO_SOURCE_VOICE_COMMUNICATION, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
821b0d67543d9926be60ca1198b02a1d644646f6e4eGlenn Kasten                AUDIO_CHANNEL_IN_MONO, input, NULL /*callback_t*/, NULL /*user*/,
8225dc85971e22d4150db5c42508a58b2a9d2ec934aGlenn Kasten                0 /*notificationFrames*/, false /*threadCanCallJava*/, AUDIO_SESSION_ALLOCATE,
823b0d67543d9926be60ca1198b02a1d644646f6e4eGlenn Kasten                AudioRecord::TRANSFER_OBTAIN) != NO_ERROR) {
8248913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("cannot initialize audio device");
825d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        return false;
826d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
827b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten    ALOGD("latency: output %d, input %d", track->latency(), record->latency());
82873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
829d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Give device socket a reasonable buffer size.
830d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
831d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
832d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
833d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    // Drain device socket.
834d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    char c;
835d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
836d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
837ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    // check if platform supports echo cancellation and do not active local echo suppression in
838ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    // this case
839ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    EchoSuppressor *echo = NULL;
840cb6c06ce98be1742683574b697b69313002cdd1bEric Laurent    sp<AudioEffect> aec;
841ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    if (mode == ECHO_SUPPRESSION) {
842ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        if (mGroup->platformHasAec()) {
843ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            aec = new AudioEffect(FX_IID_AEC,
844c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov                                    mGroup->mOpPackageName,
845ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                                    NULL,
846ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                                    0,
847ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                                    0,
848ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                                    0,
849b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten                                    record->getSessionId(),
850b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten                                    record->getInput());
851ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            status_t status = aec->initCheck();
852ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            if (status == NO_ERROR || status == ALREADY_EXISTS) {
853ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                aec->setEnabled(true);
854ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            } else {
855cb6c06ce98be1742683574b697b69313002cdd1bEric Laurent                aec.clear();
856ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            }
857ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        }
858ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        // Create local echo suppressor if platform AEC cannot be used.
859cb6c06ce98be1742683574b697b69313002cdd1bEric Laurent        if (aec == 0) {
860ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent             echo = new EchoSuppressor(sampleCount,
861b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten                                       (track->latency() + record->latency()) * sampleRate / 1000);
862ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent        }
863ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    }
8640ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh    // Start AudioRecord before AudioTrack. This prevents AudioTrack from being
8650ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh    // disabled due to buffer underrun while waiting for AudioRecord.
866d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    if (mode != MUTED) {
867b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten        record->start();
8680ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh        int16_t one;
869b0d67543d9926be60ca1198b02a1d644646f6e4eGlenn Kasten        // FIXME this may not work any more
870b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten        record->read(&one, sizeof(one));
871d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    }
87235b37b5e24f6a852fd7b5c5843146497b566d90eGlenn Kasten    track->start();
873d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
874d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh    while (!exitPending()) {
875d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int16_t output[sampleCount];
876d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
877d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            memset(output, 0, sizeof(output));
8787dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        }
8797dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh
880d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int16_t input[sampleCount];
881d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int toWrite = sampleCount;
882d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int toRead = (mode == MUTED) ? 0 : sampleCount;
883d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        int chances = 100;
884d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
885d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
886d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            if (toWrite > 0) {
887d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                AudioTrack::Buffer buffer;
888d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                buffer.frameCount = toWrite;
889d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
89035b37b5e24f6a852fd7b5c5843146497b566d90eGlenn Kasten                status_t status = track->obtainBuffer(&buffer, 1);
891d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                if (status == NO_ERROR) {
892d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    int offset = sampleCount - toWrite;
893d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    memcpy(buffer.i8, &output[offset], buffer.size);
894d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                    toWrite -= buffer.frameCount;
89535b37b5e24f6a852fd7b5c5843146497b566d90eGlenn Kasten                    track->releaseBuffer(&buffer);
896d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
8978913af783fc2cf197ef55449792bb8416a356263Steve Block                    ALOGE("cannot write to AudioTrack");
898ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                    goto exit;
899d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                }
900d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            }
901d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
902d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            if (toRead > 0) {
903d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                AudioRecord::Buffer buffer;
9040ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                buffer.frameCount = toRead;
905d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh
906b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten                status_t status = record->obtainBuffer(&buffer, 1);
907d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                if (status == NO_ERROR) {
9080ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    int offset = sampleCount - toRead;
9090ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    memcpy(&input[offset], buffer.i8, buffer.size);
9100ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh                    toRead -= buffer.frameCount;
911b51ed34abbb70994da221c545678d9dc5fe88141Glenn Kasten                    record->releaseBuffer(&buffer);
912d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh                } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
9138913af783fc2cf197ef55449792bb8416a356263Steve Block                    ALOGE("cannot read from AudioRecord");
914ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                    goto exit;
9157dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                }
91673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
91773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
91873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
919d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        if (chances <= 0) {
920f2b555a7c96aea30bf5ef4076ee41d8572be6fd2Steve Block            ALOGW("device loop timeout");
9210ec517b89eef54d900ed1c49c2611707d2406d3bChia-chi Yeh            while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
922d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        }
92373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
924d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh        if (mode != MUTED) {
925ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            if (echo != NULL) {
926a0ee529927ab5cb2762994fc865df09179bdcda8Steve Block                ALOGV("echo->run()");
927ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent                echo->run(output, input);
928d3cd43211e94d0cd1dbb7d0c35b01412eea4b5b8Chia-chi Yeh            }
929ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent            send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
9307dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        }
9317dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    }
932ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent
933ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurentexit:
934ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    delete echo;
935ff0c3ac9f0e9aa22c0d4cc2b1ca051e1974287eaEric Laurent    return true;
93673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
93773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
93873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//------------------------------------------------------------------------------
93973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
94073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehstatic jfieldID gNative;
94173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehstatic jfieldID gMode;
94273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
943ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhatjlong add(JNIEnv *env, jobject thiz, jint mode,
94473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jint socket, jstring jRemoteAddress, jint remotePort,
945c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov    jstring jCodecSpec, jint dtmfType, jstring opPackageNameStr)
94673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
9470d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    AudioCodec *codec = NULL;
94873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *stream = NULL;
94973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = NULL;
95073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
95173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Sanity check.
95273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage remote;
95373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
95473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
9552bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        return 0;
95673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
9570d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (!jCodecSpec) {
9580d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        jniThrowNullPointerException(env, "codecSpec");
9592bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        return 0;
96073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
9610d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
9620d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (!codecSpec) {
96373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
9642bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        return 0;
9652bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    }
9662bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    socket = dup(socket);
9672bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    if (socket == -1) {
9682bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
9692bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh            "cannot get stream socket");
9702bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        return 0;
9710d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    }
9720d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh
973c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov    ScopedUtfChars opPackageName(env, opPackageNameStr);
974c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov
9750d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    // Create audio codec.
9760d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    int codecType = -1;
9770d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    char codecName[16];
9780d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    int sampleRate = -1;
9799795c258778208fd96a072b7a91028285aafbc32Chia-chi Yeh    sscanf(codecSpec, "%d %15[^/]%*c%d", &codecType, codecName, &sampleRate);
9800d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    codec = newAudioCodec(codecName);
9810d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
9820d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
9830d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (sampleCount <= 0) {
9840d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
9850d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh            "cannot initialize audio codec");
98619f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        goto error;
98773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
98873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
98973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create audio stream.
99073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    stream = new AudioStream;
9910d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
99273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        codecType, dtmfType)) {
99373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
99473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            "cannot initialize audio stream");
99573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
99673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
99773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    socket = -1;
9980d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    codec = NULL;
99973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
100073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create audio group.
1001ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    group = (AudioGroup *)env->GetLongField(thiz, gNative);
100273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!group) {
100373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int mode = env->GetIntField(thiz, gMode);
1004c2d55f13a21fe6a288601deab6832c704c998781Svet Ganov        group = new AudioGroup(String16(opPackageName.c_str()));
100573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (!group->set(8000, 256) || !group->setMode(mode)) {
100673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            jniThrowException(env, "java/lang/IllegalStateException",
100773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                "cannot initialize audio group");
100873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            goto error;
100973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
101073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
101173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
101273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Add audio stream into audio group.
101373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!group->add(stream)) {
101473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
101573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            "cannot add audio stream");
101673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
101773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
101873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
101973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Succeed.
1020ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    env->SetLongField(thiz, gNative, (jlong)group);
1021ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    return (jlong)stream;
102273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
102373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeherror:
102473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete group;
102573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete stream;
10260d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh    delete codec;
102773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(socket);
1028ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    env->SetLongField(thiz, gNative, 0);
10292bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    return 0;
103073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
103173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
1032ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhatvoid remove(JNIEnv *env, jobject thiz, jlong stream)
103373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
1034ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    AudioGroup *group = (AudioGroup *)env->GetLongField(thiz, gNative);
103573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group) {
10362bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        if (!stream || !group->remove((AudioStream *)stream)) {
103773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            delete group;
1038ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat            env->SetLongField(thiz, gNative, 0);
103973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
104073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
104173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
104273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
104373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid setMode(JNIEnv *env, jobject thiz, jint mode)
104473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
1045ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    AudioGroup *group = (AudioGroup *)env->GetLongField(thiz, gNative);
104673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group && !group->setMode(mode)) {
104773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
104873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
104973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
105073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
105173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid sendDtmf(JNIEnv *env, jobject thiz, jint event)
105273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
1053ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    AudioGroup *group = (AudioGroup *)env->GetLongField(thiz, gNative);
105473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group && !group->sendDtmf(event)) {
105573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
105673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
105773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
105873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
105973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehJNINativeMethod gMethods[] = {
10605a4b1c96e2722a57a4b33519a0a0015e70c9420eSvetoslav    {"nativeAdd", "(IILjava/lang/String;ILjava/lang/String;ILjava/lang/String;)J", (void *)add},
1061ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat    {"nativeRemove", "(J)V", (void *)remove},
1062a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    {"nativeSetMode", "(I)V", (void *)setMode},
1063a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    {"nativeSendDtmf", "(I)V", (void *)sendDtmf},
106473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
106573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
106673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} // namespace
106773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
106873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint registerAudioGroup(JNIEnv *env)
106973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
107073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    gRandom = open("/dev/urandom", O_RDONLY);
107173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (gRandom == -1) {
10728913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("urandom: %s", strerror(errno));
107373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
107473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
107573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
107673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jclass clazz;
107773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
1078ae710cd10213c0a89e9daea945f3efa9f90b188eAshok Bhat        (gNative = env->GetFieldID(clazz, "mNative", "J")) == NULL ||
107973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
108073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
10818913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("JNI registration failed");
108273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
108373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
108473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return 0;
108573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
1086