AudioGroup.cpp revision a7f73fb2550935cc78c643b7faf25ebacf16b94f
173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh/*
273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Copyright (C) 2010 The Android Open Source Project
373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * you may not use this file except in compliance with the License.
673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * You may obtain a copy of the License at
773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
1073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
1173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
1273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * See the License for the specific language governing permissions and
1473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * limitations under the License.
1573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh */
1673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
1773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <stdio.h>
1873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <stdint.h>
1973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <string.h>
2073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <errno.h>
2173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <fcntl.h>
2273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/epoll.h>
2373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/types.h>
2473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/socket.h>
2573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/stat.h>
2673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/time.h>
2773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <time.h>
2873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <arpa/inet.h>
2973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <netinet/in.h>
3073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#define LOG_TAG "AudioGroup"
3273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <cutils/atomic.h>
3373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Log.h>
3473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Errors.h>
3573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/RefBase.h>
3673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/threads.h>
3773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/SystemClock.h>
3873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioSystem.h>
3973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioRecord.h>
4073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/AudioTrack.h>
4173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <media/mediarecorder.h>
4273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "jni.h"
4473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "JNIHelp.h"
4573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "AudioCodec.h"
4773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehextern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
4973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehnamespace {
5173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehusing namespace android;
5373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint gRandom = -1;
5573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// We use a circular array to implement jitter buffer. The simplest way is doing
5773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// a modulo operation on the index while accessing the array. However modulo can
5873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// be expensive on some platforms, such as ARM. Thus we round up the size of the
5973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// array to the nearest power of 2 and then use bitwise-and instead of modulo.
6073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// Currently we make it 256ms long and assume packet interval is 32ms or less.
6173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// The first 64ms is the place where samples get mixed. The rest 192ms is the
6273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// real jitter buffer. For a stream at 8000Hz it takes 4096 bytes. These numbers
6373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// are chosen by experiments and each of them can be adjusted as needed.
6473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
6573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// Other notes:
6673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + We use elapsedRealtime() to get the time. Since we use 32bit variables
6773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   instead of 64bit ones, comparison must be done by subtraction.
6873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + Sampling rate must be multiple of 1000Hz, and packet length must be in
6973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   milliseconds. No floating points.
7073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + If we cannot get enough CPU, we drop samples and simulate packet loss.
7173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh// + Resampling is not done yet, so streams in one group must use the same rate.
7273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//   For the first release we might only support 8kHz and 16kHz.
7373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehclass AudioStream
7573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
7673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehpublic:
7773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream();
7873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ~AudioStream();
7973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool set(int mode, int socket, sockaddr_storage *remote,
8073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        const char *codecName, int sampleRate, int sampleCount,
8173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int codecType, int dtmfType);
8273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void sendDtmf(int event);
8473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool mix(int32_t *output, int head, int tail, int sampleRate);
8573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void encode(int tick, AudioStream *chain);
8673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    void decode(int tick);
8773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehprivate:
8973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    enum {
9073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NORMAL = 0,
9173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        SEND_ONLY = 1,
9273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        RECEIVE_ONLY = 2,
9373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LAST_MODE = 2,
9473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
9573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
9673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mMode;
9773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSocket;
9873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage mRemote;
9973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioCodec *mCodec;
10073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mCodecMagic;
10173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mDtmfMagic;
10273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
10373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mTick;
10473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleRate;
10573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleCount;
10673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mInterval;
10773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
10873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t *mBuffer;
10973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferMask;
11073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferHead;
11173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mBufferTail;
11273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mLatencyScore;
11373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
11473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint16_t mSequence;
11573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mTimestamp;
11673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint32_t mSsrc;
11773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
11873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDtmfEvent;
11973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDtmfStart;
12073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
12173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *mNext;
12273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
12373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    friend class AudioGroup;
12473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
12573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
12673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::AudioStream()
12773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
12873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSocket = -1;
12973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mCodec = NULL;
13073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBuffer = NULL;
13173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNext = NULL;
13273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
13373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
13473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::~AudioStream()
13573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
13673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mSocket);
13773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete mCodec;
13873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete [] mBuffer;
13973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] is dead", mSocket);
14073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
14173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
14273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
14373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    const char *codecName, int sampleRate, int sampleCount,
14473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int codecType, int dtmfType)
14573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
14673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode < 0 || mode > LAST_MODE) {
14773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
14873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
14973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = mode;
15073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
15173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (codecName) {
15273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mRemote = *remote;
15373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mCodec = newAudioCodec(codecName);
15473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (!mCodec || !mCodec->set(sampleRate, sampleCount)) {
15573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return false;
15673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
15773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
15873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
15973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mCodecMagic = (0x8000 | codecType) << 16;
16073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
16173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
16273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTick = elapsedRealtime();
16373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleRate = sampleRate / 1000;
16473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleCount = sampleCount;
16573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mInterval = mSampleCount / mSampleRate;
16673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
16773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Allocate jitter buffer.
16873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1);
16973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferMask >>= 2;
17073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBuffer = new int16_t[mBufferMask];
17173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    --mBufferMask;
17273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferHead = 0;
17373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferTail = 0;
17473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mLatencyScore = 0;
17573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
17673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Initialize random bits.
17773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mSequence, sizeof(mSequence));
17873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mTimestamp, sizeof(mTimestamp));
17973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    read(gRandom, &mSsrc, sizeof(mSsrc));
18073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
18173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = -1;
18273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfStart = 0;
18373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
18473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Only take over the socket when succeeded.
18573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSocket = socket;
18673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
18773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
18873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        (codecName ? codecName : "RAW"), mSampleRate, mInterval);
18973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
19073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
19173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
19273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::sendDtmf(int event)
19373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
19473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfMagic != 0) {
19573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = event << 24;
19673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfStart = mTimestamp + mSampleCount;
19773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
19873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
19973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
20073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
20173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
20273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == SEND_ONLY) {
20373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
20473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
20573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
20673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (head - mBufferHead < 0) {
20773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        head = mBufferHead;
20873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
20973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tail - mBufferTail > 0) {
21073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        tail = mBufferTail;
21173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
21273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tail - head <= 0) {
21373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
21473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
21573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
21673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    head *= mSampleRate;
21773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tail *= mSampleRate;
21873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
21973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (sampleRate == mSampleRate) {
22073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        for (int i = head; i - tail < 0; ++i) {
22173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            output[i - head] += mBuffer[i & mBufferMask];
22273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
22373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
22473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // TODO: implement resampling.
22573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
22673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
22773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
22873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
22973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
23073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::encode(int tick, AudioStream *chain)
23173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
23273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mTick >= mInterval) {
23373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // We just missed the train. Pretend that packets in between are lost.
23473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int skipped = (tick - mTick) / mInterval;
23573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTick += skipped * mInterval;
23673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mSequence += skipped;
23773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTimestamp += skipped * mSampleCount;
23873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] skips %d packets", mSocket, skipped);
23973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
24073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
24173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tick = mTick;
24273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTick += mInterval;
24373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ++mSequence;
24473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTimestamp += mSampleCount;
24573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
24673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == RECEIVE_ONLY) {
24773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
24873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
24973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
25073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // If there is an ongoing DTMF event, send it now.
25173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfEvent != -1) {
25273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int duration = mTimestamp - mDtmfStart;
25373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Make sure duration is reasonable.
25473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (duration >= 0 && duration < mSampleRate * 100) {
25573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            duration += mSampleCount;
25673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            int32_t buffer[4] = {
25773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                htonl(mDtmfMagic | mSequence),
25873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                htonl(mDtmfStart),
25973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mSsrc,
26073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                htonl(mDtmfEvent | duration),
26173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            };
26273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (duration >= mSampleRate * 100) {
26373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                buffer[3] |= htonl(1 << 23);
26473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mDtmfEvent = -1;
26573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
26673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
26773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                (sockaddr *)&mRemote, sizeof(mRemote));
26873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return;
26973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
27073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = -1;
27173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
27273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
27373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // It is time to mix streams.
27473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool mixed = false;
27573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int32_t buffer[mSampleCount + 3];
27673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    memset(buffer, 0, sizeof(buffer));
27773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    while (chain) {
27873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (chain != this &&
27973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
28073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mixed = true;
28173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
28273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        chain = chain->mNext;
28373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
28473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mixed) {
28573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] no data", mSocket);
28673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
28773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
28873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
28973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Cook the packet and send it out.
29073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t samples[mSampleCount];
29173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; i < mSampleCount; ++i) {
29273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int32_t sample = buffer[i];
29373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (sample < -32768) {
29473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            sample = -32768;
29573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
29673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (sample > 32767) {
29773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            sample = 32767;
29873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
29973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        samples[i] = sample;
30073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
30173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mCodec) {
30273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Special case for device stream.
30373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
30473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
30573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
30673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
30773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[0] = htonl(mCodecMagic | mSequence);
30873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[1] = htonl(mTimestamp);
30973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    buffer[2] = mSsrc;
31073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int length = mCodec->encode(&buffer[3], samples);
31173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (length <= 0) {
31273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] encoder error", mSocket);
31373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
31473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
31573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
31673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sizeof(mRemote));
31773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
31873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
31973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::decode(int tick)
32073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
32173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    char c;
32273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == SEND_ONLY) {
32373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        recv(mSocket, &c, 1, MSG_DONTWAIT);
32473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
32573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
32673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
32773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Make sure mBufferHead and mBufferTail are reasonable.
32873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if ((unsigned int)(tick + 256 - mBufferHead) > 1024) {
32973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBufferHead = tick - 64;
33073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBufferTail = mBufferHead;
33173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
33273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
33373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mBufferHead > 64) {
33473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Throw away outdated samples.
33573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBufferHead = tick - 64;
33673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (mBufferTail - mBufferHead < 0) {
33773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = mBufferHead;
33873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
33973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
34073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
34173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mBufferTail - tick <= 80) {
34273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mLatencyScore = tick;
34373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else if (tick - mLatencyScore >= 5000) {
34473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Reset the jitter buffer to 40ms if the latency keeps larger than 80ms
34573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // in the past 5s. This rarely happens, so let us just keep it simple.
34673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] latency control", mSocket);
34773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBufferTail = tick + 40;
34873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
34973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
35073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mBufferTail - mBufferHead > 256 - mInterval) {
35173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Buffer overflow. Drop the packet.
35273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] buffer overflow", mSocket);
35373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        recv(mSocket, &c, 1, MSG_DONTWAIT);
35473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
35573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
35673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
35773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Receive the packet and decode it.
35873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t samples[mSampleCount];
35973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int length = 0;
36073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mCodec) {
36173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Special case for device stream.
36273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        length = recv(mSocket, samples, sizeof(samples),
36373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            MSG_TRUNC | MSG_DONTWAIT) >> 1;
36473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
36573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        __attribute__((aligned(4))) uint8_t buffer[2048];
36673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        length = recv(mSocket, buffer, sizeof(buffer),
36773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            MSG_TRUNC | MSG_DONTWAIT);
36873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
36973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Do we need to check SSRC, sequence, and timestamp? They are not
37019f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        // reliable but at least they can be used to identify duplicates?
37173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (length < 12 || length > (int)sizeof(buffer) ||
37273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
37373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            LOGD("stream[%d] malformed packet", mSocket);
37473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return;
37573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
37673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int offset = 12 + ((buffer[0] & 0x0F) << 2);
37773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if ((buffer[0] & 0x10) != 0) {
37873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
37973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
38073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if ((buffer[0] & 0x20) != 0) {
38173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            length -= buffer[length - 1];
38273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
38373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        length -= offset;
38473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (length >= 0) {
38573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            length = mCodec->decode(samples, &buffer[offset], length);
38673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
38773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
38873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (length != mSampleCount) {
38973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] decoder error", mSocket);
39073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
39173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
39273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
39373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (tick - mBufferTail > 0) {
39473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Buffer underrun. Reset the jitter buffer to 40ms.
39573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGD("stream[%d] buffer underrun", mSocket);
39673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (mBufferTail - mBufferHead <= 0) {
39773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferHead = tick + 40;
39873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = mBufferHead;
39973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        } else {
40073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            int tail = (tick + 40) * mSampleRate;
40173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
40273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                mBuffer[i & mBufferMask] = 0;
40373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
40473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            mBufferTail = tick + 40;
40573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
40673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
40773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
40873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Append to the jitter buffer.
40973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int tail = mBufferTail * mSampleRate;
41073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; i < mSampleCount; ++i) {
41173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mBuffer[tail & mBufferMask] = samples[i];
41273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++tail;
41373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
41473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mBufferTail += mInterval;
41573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
41673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
41773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//------------------------------------------------------------------------------
41873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
41973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehclass AudioGroup
42073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
42173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehpublic:
42273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup();
42373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ~AudioGroup();
42473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool set(int sampleRate, int sampleCount);
42573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
42673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool setMode(int mode);
42773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool sendDtmf(int event);
42873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool add(AudioStream *stream);
42973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool remove(int socket);
43073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
43173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehprivate:
43273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    enum {
43373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ON_HOLD = 0,
43473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        MUTED = 1,
43573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NORMAL = 2,
43673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        EC_ENABLED = 3,
43773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LAST_MODE = 3,
43873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
43973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mMode;
44073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *mChain;
44173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mEventQueue;
44273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    volatile int mDtmfEvent;
44373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
44473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mSampleCount;
44573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int mDeviceSocket;
44673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioTrack mTrack;
44773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioRecord mRecord;
44873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
44973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool networkLoop();
45073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    bool deviceLoop();
45173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
45273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    class NetworkThread : public Thread
45373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {
45473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    public:
45573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
45673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
45773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool start()
45873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
45973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
46073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                LOGE("cannot start network thread");
46173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return false;
46273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
46373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return true;
46473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
46573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
46673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    private:
46773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioGroup *mGroup;
46873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool threadLoop()
46973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
47073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return mGroup->networkLoop();
47173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
47273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
47373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sp<NetworkThread> mNetworkThread;
47473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
47573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    class DeviceThread : public Thread
47673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {
47773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    public:
47873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
47973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
48073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool start()
48173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
48273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            char c;
48373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1);
48473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
48573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
48673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                LOGE("cannot start device thread");
48773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return false;
48873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
48973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return true;
49073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
49173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
49273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    private:
49373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioGroup *mGroup;
49473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        bool threadLoop()
49573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        {
49673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            return mGroup->deviceLoop();
49773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
49873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    };
49973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sp<DeviceThread> mDeviceThread;
50073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
50173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
50273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioGroup::AudioGroup()
50373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
50473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = ON_HOLD;
50573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain = NULL;
50673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mEventQueue = -1;
50773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = -1;
50873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceSocket = -1;
50973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread = new NetworkThread(this);
51073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread = new DeviceThread(this);
51173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
51273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
51373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioGroup::~AudioGroup()
51473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
51573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
51673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread->requestExitAndWait();
51773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTrack.stop();
51873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mRecord.stop();
51973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mEventQueue);
52073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(mDeviceSocket);
52173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    while (mChain) {
52273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioStream *next = mChain->mNext;
52373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        delete mChain;
52473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mChain = next;
52573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
52673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("group[%d] is dead", mDeviceSocket);
52773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
52873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
52973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::set(int sampleRate, int sampleCount)
53073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
53173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mEventQueue = epoll_create(2);
53273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mEventQueue == -1) {
53373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_create: %s", strerror(errno));
53473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
53573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
53673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
53773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mSampleCount = sampleCount;
53873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
53973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Find out the frame count for AudioTrack and AudioRecord.
54073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int output = 0;
54173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int input = 0;
54273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
54373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sampleRate) != NO_ERROR || output <= 0 ||
54473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioRecord::getMinFrameCount(&input, sampleRate,
54573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
54673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("cannot compute frame count");
54773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
54873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
54973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("reported frame count: output %d, input %d", output, input);
55073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5517dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    if (output < sampleCount * 2) {
5527dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        output = sampleCount * 2;
5537dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    }
5547dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    if (input < sampleCount * 2) {
5557dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        input = sampleCount * 2;
55673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
55773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("adjusted frame count: output %d, input %d", output, input);
55873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
55973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Initialize AudioTrack and AudioRecord.
56073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
56173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
56273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
56373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
56473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("cannot initialize audio device");
56573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
56673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
56773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
56873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
569ac2e214d6a09850cf61de8a482032dc0e0ccdde0Chia-chi Yeh    // TODO: initialize echo canceler here.
57073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
57173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create device socket.
57273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int pair[2];
57373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
57473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("socketpair: %s", strerror(errno));
57573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
57673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
57773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceSocket = pair[0];
57873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
57973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create device stream.
58073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain = new AudioStream;
58173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
58273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        sampleRate, sampleCount, -1, -1)) {
58373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        close(pair[1]);
58473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("cannot initialize device stream");
58573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
58673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
58773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
58873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Give device socket a reasonable timeout and buffer size.
58973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    timeval tv;
59073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    tv.tv_sec = 0;
591a7f73fb2550935cc78c643b7faf25ebacf16b94fChia-chi Yeh    tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
59273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
59373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
59473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
59573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("setsockopt: %s", strerror(errno));
59673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
59773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
59873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
59973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Add device stream into event queue.
60073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event event;
60173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.events = EPOLLIN;
60273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.data.ptr = mChain;
60373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
60473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_ctl: %s", strerror(errno));
60573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
60673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
60773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
60873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Anything else?
60973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
61073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
61173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
61273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
61373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::setMode(int mode)
61473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
61573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode < 0 || mode > LAST_MODE) {
61673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
61773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
61873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mMode == mode) {
61973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return true;
62073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
62173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
62273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
62373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mMode = mode;
62473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
62573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDeviceThread->requestExitAndWait();
62673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode == ON_HOLD) {
62773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTrack.stop();
62873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mRecord.stop();
62973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return true;
63073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
63173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
63273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mTrack.start();
63373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mode == MUTED) {
63473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mRecord.stop();
63573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    } else {
63673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mRecord.start();
63773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
63873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
63973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mDeviceThread->start()) {
64073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mTrack.stop();
64173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mRecord.stop();
64273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
64373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
64473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
64573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
64673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
64773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::sendDtmf(int event)
64873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
64973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (event < 0 || event > 15) {
65073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
65173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
65273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
65373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // DTMF is rarely used, so we try to make it as lightweight as possible.
65473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Using volatile might be dodgy, but using a pipe or pthread primitives
65573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // or stop-set-restart threads seems too heavy. Will investigate later.
65673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    timespec ts;
65773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ts.tv_sec = 0;
65873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ts.tv_nsec = 100000000;
65973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
66073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        nanosleep(&ts, NULL);
66173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
66273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfEvent != -1) {
66373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
66473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
66573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mDtmfEvent = event;
66673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    nanosleep(&ts, NULL);
66773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
66873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
66973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
67073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::add(AudioStream *stream)
67173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
67273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
67373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
67473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event event;
67573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.events = EPOLLIN;
67673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    event.data.ptr = stream;
67773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
67873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_ctl: %s", strerror(errno));
67973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
68073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
68173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
68273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    stream->mNext = mChain->mNext;
68373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mChain->mNext = stream;
68473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mNetworkThread->start()) {
68573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Only take over the stream when succeeded.
68673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mChain->mNext = stream->mNext;
68773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
68873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
68973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
69073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
69173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
69273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
69373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
69473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::remove(int socket)
69573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
69673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    mNetworkThread->requestExitAndWait();
69773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
69873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
69973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        AudioStream *target = stream->mNext;
70073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (target->mSocket == socket) {
70119f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh            if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
70219f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh                LOGE("epoll_ctl: %s", strerror(errno));
70319f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh                return false;
70419f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh            }
70573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            stream->mNext = target->mNext;
70673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
70773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            delete target;
70873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            break;
70973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
71073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
71173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
71273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Do not start network thread if there is only one stream.
71373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!mChain->mNext || !mNetworkThread->start()) {
71473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
71573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
71673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
71773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
71873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
71973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::networkLoop()
72073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
72173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int tick = elapsedRealtime();
72273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int deadline = tick + 10;
72373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int count = 0;
72473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
72573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
72673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (!stream->mTick || tick - stream->mTick >= 0) {
72773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            stream->encode(tick, mChain);
72873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
72973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (deadline - stream->mTick > 0) {
73073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            deadline = stream->mTick;
73173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
73273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++count;
73373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
73473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
73573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (mDtmfEvent != -1) {
73673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int event = mDtmfEvent;
73773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
73873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            stream->sendDtmf(event);
73973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
74073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        mDtmfEvent = -1;
74173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
74273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
74373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    deadline -= tick;
74473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (deadline < 1) {
74573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        deadline = 1;
74673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
74773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
74873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    epoll_event events[count];
74973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    count = epoll_wait(mEventQueue, events, count, deadline);
75073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (count == -1) {
75173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("epoll_wait: %s", strerror(errno));
75273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return false;
75373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
75473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    for (int i = 0; i < count; ++i) {
75573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ((AudioStream *)events[i].data.ptr)->decode(tick);
75673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
75773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
75873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
75973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
76073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
76173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioGroup::deviceLoop()
76273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
76373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int16_t output[mSampleCount];
76473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
76573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
76673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        memset(output, 0, sizeof(output));
76773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
76873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7697dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    int16_t input[mSampleCount];
7707dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    int toWrite = mSampleCount;
7717dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    int toRead = (mMode == MUTED) ? 0 : mSampleCount;
7727dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    int chances = 100;
77373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7747dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
7757dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        if (toWrite > 0) {
7767dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            AudioTrack::Buffer buffer;
7777dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            buffer.frameCount = toWrite;
77873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7797dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            status_t status = mTrack.obtainBuffer(&buffer, 1);
7807dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            if (status == NO_ERROR) {
7817dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
7827dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                toWrite -= buffer.frameCount;
7837dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                mTrack.releaseBuffer(&buffer);
7847dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
7857dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                LOGE("cannot write to AudioTrack");
7867dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                return false;
78773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
7887dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        }
7897dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh
7907dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        if (toRead > 0) {
7917dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            AudioRecord::Buffer buffer;
7927dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            buffer.frameCount = mRecord.frameCount();
7937dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh
7947dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            status_t status = mRecord.obtainBuffer(&buffer, 1);
7957dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            if (status == NO_ERROR) {
796a7f73fb2550935cc78c643b7faf25ebacf16b94fChia-chi Yeh                int count = ((int)buffer.frameCount < toRead) ?
7977dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                        buffer.frameCount : toRead;
7987dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
7997dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                toRead -= count;
8007dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                if (buffer.frameCount < mRecord.frameCount()) {
8017dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                    buffer.frameCount = count;
8027dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                }
8037dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                mRecord.releaseBuffer(&buffer);
8047dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
8057dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                LOGE("cannot read from AudioRecord");
8067dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh                return false;
80773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
80873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
8097dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    }
81073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8117dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    if (!chances) {
8127dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        LOGE("device loop timeout");
8137dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        return false;
81473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
81573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8167dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    if (mMode != MUTED) {
8177dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        if (mMode == NORMAL) {
8187dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh            send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
8197dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        } else {
820ac2e214d6a09850cf61de8a482032dc0e0ccdde0Chia-chi Yeh            // TODO: Echo canceller runs here.
821ac2e214d6a09850cf61de8a482032dc0e0ccdde0Chia-chi Yeh            send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
8227dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh        }
8237dab0dc564087a4b8f90621cdfc8d730288fb201Chia-chi Yeh    }
82473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return true;
82573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
82673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
82773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh//------------------------------------------------------------------------------
82873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
82973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehstatic jfieldID gNative;
83073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehstatic jfieldID gMode;
83173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
83219f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yehvoid add(JNIEnv *env, jobject thiz, jint mode,
83373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jint socket, jstring jRemoteAddress, jint remotePort,
83473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jstring jCodecName, jint sampleRate, jint sampleCount,
83573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jint codecType, jint dtmfType)
83673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
83773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    const char *codecName = NULL;
83873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioStream *stream = NULL;
83973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = NULL;
84073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
84173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Sanity check.
84273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage remote;
84373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
84473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
84519f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        goto error;
84673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
84773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (sampleRate < 0 || sampleCount < 0 || codecType < 0 || codecType > 127) {
84873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
84973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
85073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
85173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!jCodecName) {
85273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowNullPointerException(env, "codecName");
85319f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        goto error;
85473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
85573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    codecName = env->GetStringUTFChars(jCodecName, NULL);
85673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!codecName) {
85773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
85819f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        goto error;
85973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
86073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
86173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create audio stream.
86273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    stream = new AudioStream;
86373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!stream->set(mode, socket, &remote, codecName, sampleRate, sampleCount,
86473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        codecType, dtmfType)) {
86573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
86673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            "cannot initialize audio stream");
86719f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh        env->ReleaseStringUTFChars(jCodecName, codecName);
86873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
86973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
87019f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh    env->ReleaseStringUTFChars(jCodecName, codecName);
87173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    socket = -1;
87273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
87373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Create audio group.
87473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    group = (AudioGroup *)env->GetIntField(thiz, gNative);
87573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!group) {
87673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        int mode = env->GetIntField(thiz, gMode);
87773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        group = new AudioGroup;
87873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (!group->set(8000, 256) || !group->setMode(mode)) {
87973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            jniThrowException(env, "java/lang/IllegalStateException",
88073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                "cannot initialize audio group");
88173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            goto error;
88273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
88373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
88473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
88573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Add audio stream into audio group.
88673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (!group->add(stream)) {
88773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException",
88873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            "cannot add audio stream");
88973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        goto error;
89073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
89173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
89273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    // Succeed.
89373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    env->SetIntField(thiz, gNative, (int)group);
89419f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh    return;
89573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
89673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeherror:
89773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete group;
89873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    delete stream;
89973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    close(socket);
90073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    env->SetIntField(thiz, gNative, NULL);
90173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
90273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
90373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid remove(JNIEnv *env, jobject thiz, jint socket)
90473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
90573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
90673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group) {
90773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        if (socket == -1 || !group->remove(socket)) {
90873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            delete group;
90973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            env->SetIntField(thiz, gNative, NULL);
91073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
91173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
91273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
91373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
91473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid setMode(JNIEnv *env, jobject thiz, jint mode)
91573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
91673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
91773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group && !group->setMode(mode)) {
91873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
91973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return;
92073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
92173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    env->SetIntField(thiz, gMode, mode);
92273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
92373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
92473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid sendDtmf(JNIEnv *env, jobject thiz, jint event)
92573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
92673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
92773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (group && !group->sendDtmf(event)) {
92873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
92973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
93073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
93173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
93273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehJNINativeMethod gMethods[] = {
93319f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh    {"add", "(IILjava/lang/String;ILjava/lang/String;IIII)V", (void *)add},
93473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {"remove", "(I)V", (void *)remove},
93573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {"setMode", "(I)V", (void *)setMode},
93673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {"sendDtmf", "(I)V", (void *)sendDtmf},
93773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
93873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
93973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} // namespace
94073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
94173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint registerAudioGroup(JNIEnv *env)
94273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
94373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    gRandom = open("/dev/urandom", O_RDONLY);
94473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (gRandom == -1) {
94573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("urandom: %s", strerror(errno));
94673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
94773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
94873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
94973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jclass clazz;
95073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
95173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
95273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
95373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
95473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        LOGE("JNI registration failed");
95573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
95673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
95773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return 0;
95873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
959