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