AudioGroup.cpp revision ea7bed2487a9460ad2c01cda9ded8035e0b0c945
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, 800d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh AudioCodec *codec, 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; 107ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync int mLogThrottle; 10873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 10973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int16_t *mBuffer; 11073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mBufferMask; 11173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mBufferHead; 11273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mBufferTail; 11373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mLatencyScore; 11473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 11573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh uint16_t mSequence; 11673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh uint32_t mTimestamp; 11773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh uint32_t mSsrc; 11873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 11973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mDtmfEvent; 12073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mDtmfStart; 12173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 12273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh AudioStream *mNext; 12373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 12473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh friend class AudioGroup; 12573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}; 12673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 12773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::AudioStream() 12873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 12973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mSocket = -1; 13073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mCodec = NULL; 13173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mBuffer = NULL; 13273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mNext = NULL; 13373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 13473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 13573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehAudioStream::~AudioStream() 13673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 13773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh close(mSocket); 13873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh delete mCodec; 13973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh delete [] mBuffer; 14073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh LOGD("stream[%d] is dead", mSocket); 14173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 14273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 14373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::set(int mode, int socket, sockaddr_storage *remote, 1440d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh AudioCodec *codec, int sampleRate, int sampleCount, 14573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int codecType, int dtmfType) 14673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 14773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (mode < 0 || mode > LAST_MODE) { 14873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return false; 14973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 15073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mMode = mode; 15173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 15273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mCodecMagic = (0x8000 | codecType) << 16; 15373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16; 15473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 15573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mTick = elapsedRealtime(); 15673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mSampleRate = sampleRate / 1000; 15773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mSampleCount = sampleCount; 15873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mInterval = mSampleCount / mSampleRate; 15973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 16073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Allocate jitter buffer. 16173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1); 16273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mBufferMask >>= 2; 16373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mBuffer = new int16_t[mBufferMask]; 16473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh --mBufferMask; 16573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mBufferHead = 0; 16673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mBufferTail = 0; 16773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mLatencyScore = 0; 16873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 16973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Initialize random bits. 17073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh read(gRandom, &mSequence, sizeof(mSequence)); 17173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh read(gRandom, &mTimestamp, sizeof(mTimestamp)); 17273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh read(gRandom, &mSsrc, sizeof(mSsrc)); 17373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 17473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfEvent = -1; 17573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfStart = 0; 17673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 1770d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh // Only take over these things when succeeded. 17873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mSocket = socket; 1790d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh if (codec) { 1800d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh mRemote = *remote; 1810d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh mCodec = codec; 1820d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh } 18373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 18473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket, 1850d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh (codec ? codec->name : "RAW"), mSampleRate, mInterval); 18673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return true; 18773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 18873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 18973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::sendDtmf(int event) 19073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 19173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (mDtmfMagic != 0) { 19273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfEvent = event << 24; 19373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfStart = mTimestamp + mSampleCount; 19473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 19573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 19673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 19773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehbool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate) 19873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 19973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (mMode == SEND_ONLY) { 20073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return false; 20173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 20273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 20373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (head - mBufferHead < 0) { 20473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh head = mBufferHead; 20573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 20673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (tail - mBufferTail > 0) { 20773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh tail = mBufferTail; 20873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 20973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (tail - head <= 0) { 21073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return false; 21173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 21273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 21373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh head *= mSampleRate; 21473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh tail *= mSampleRate; 21573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 21673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (sampleRate == mSampleRate) { 21773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh for (int i = head; i - tail < 0; ++i) { 21873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh output[i - head] += mBuffer[i & mBufferMask]; 21973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 22073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } else { 22173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // TODO: implement resampling. 22273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return false; 22373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 22473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return true; 22573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 22673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 22773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid AudioStream::encode(int tick, AudioStream *chain) 22873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 22973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (tick - mTick >= mInterval) { 23073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // We just missed the train. Pretend that packets in between are lost. 23173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int skipped = (tick - mTick) / mInterval; 23273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mTick += skipped * mInterval; 23373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mSequence += skipped; 23473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mTimestamp += skipped * mSampleCount; 23573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh LOGD("stream[%d] skips %d packets", mSocket, skipped); 23673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 23773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 23873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh tick = mTick; 23973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mTick += mInterval; 24073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh ++mSequence; 24173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mTimestamp += mSampleCount; 24273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 24373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (mMode == RECEIVE_ONLY) { 24473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return; 24573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 24673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 24773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // If there is an ongoing DTMF event, send it now. 24873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (mDtmfEvent != -1) { 24973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int duration = mTimestamp - mDtmfStart; 25073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Make sure duration is reasonable. 25173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (duration >= 0 && duration < mSampleRate * 100) { 25273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh duration += mSampleCount; 25373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int32_t buffer[4] = { 25473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh htonl(mDtmfMagic | mSequence), 25573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh htonl(mDtmfStart), 25673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mSsrc, 25773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh htonl(mDtmfEvent | duration), 25873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh }; 25973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (duration >= mSampleRate * 100) { 26073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh buffer[3] |= htonl(1 << 23); 26173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfEvent = -1; 26273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 26373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT, 26473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh (sockaddr *)&mRemote, sizeof(mRemote)); 26573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return; 26673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 26773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mDtmfEvent = -1; 26873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 26973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 27073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // It is time to mix streams. 27173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh bool mixed = false; 27273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int32_t buffer[mSampleCount + 3]; 27373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh memset(buffer, 0, sizeof(buffer)); 27473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh while (chain) { 27573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (chain != this && 27673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh chain->mix(buffer, tick - mInterval, tick, mSampleRate)) { 27773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh mixed = true; 27873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 27973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh chain = chain->mNext; 28073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 28173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (!mixed) { 282ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync if ((mTick ^ mLogThrottle) >> 10) { 283ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync mLogThrottle = mTick; 284ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync LOGD("stream[%d] no data", mSocket); 285ea7bed2487a9460ad2c01cda9ded8035e0b0c945repo sync } 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, 8340d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh jstring jCodecSpec, jint dtmfType) 83573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 8360d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh AudioCodec *codec = NULL; 83773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh AudioStream *stream = NULL; 83873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh AudioGroup *group = NULL; 83973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 84073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Sanity check. 84173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh sockaddr_storage remote; 84273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (parse(env, jRemoteAddress, remotePort, &remote) < 0) { 84373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Exception already thrown. 8440d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh return; 84573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 8460d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh if (!jCodecSpec) { 8470d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh jniThrowNullPointerException(env, "codecSpec"); 8480d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh return; 84973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 8500d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL); 8510d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh if (!codecSpec) { 85273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Exception already thrown. 8530d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh return; 8540d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh } 8550d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh 8560d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh // Create audio codec. 8570d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh int codecType = -1; 8580d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh char codecName[16]; 8590d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh int sampleRate = -1; 8600d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh sscanf(codecSpec, "%d %[^/]%*c%d", &codecType, codecName, &sampleRate); 8610d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh codec = newAudioCodec(codecName); 8620d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1); 8630d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh env->ReleaseStringUTFChars(jCodecSpec, codecSpec); 8640d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh if (sampleCount <= 0) { 8650d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh jniThrowException(env, "java/lang/IllegalStateException", 8660d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh "cannot initialize audio codec"); 86719f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh goto error; 86873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 86973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 87073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Create audio stream. 87173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh stream = new AudioStream; 8720d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount, 87373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh codecType, dtmfType)) { 87473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh jniThrowException(env, "java/lang/IllegalStateException", 87573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh "cannot initialize audio stream"); 87673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh goto error; 87773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 87873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh socket = -1; 8790d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh codec = NULL; 88073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 88173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Create audio group. 88273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh group = (AudioGroup *)env->GetIntField(thiz, gNative); 88373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (!group) { 88473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh int mode = env->GetIntField(thiz, gMode); 88573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh group = new AudioGroup; 88673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (!group->set(8000, 256) || !group->setMode(mode)) { 88773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh jniThrowException(env, "java/lang/IllegalStateException", 88873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh "cannot initialize audio group"); 88973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh goto error; 89073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 89173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 89273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 89373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Add audio stream into audio group. 89473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (!group->add(stream)) { 89573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh jniThrowException(env, "java/lang/IllegalStateException", 89673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh "cannot add audio stream"); 89773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh goto error; 89873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 89973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 90073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh // Succeed. 90173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh env->SetIntField(thiz, gNative, (int)group); 90219f94d0256b9d50fe2656dc5c27ee56a24f92247Chia-chi Yeh return; 90373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 90473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeherror: 90573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh delete group; 90673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh delete stream; 9070d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh delete codec; 90873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh close(socket); 90973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh env->SetIntField(thiz, gNative, NULL); 91073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 91173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 91273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid remove(JNIEnv *env, jobject thiz, jint socket) 91373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 91473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative); 91573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (group) { 91673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (socket == -1 || !group->remove(socket)) { 91773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh delete group; 91873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh env->SetIntField(thiz, gNative, NULL); 91973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 92073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 92173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 92273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 92373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid setMode(JNIEnv *env, jobject thiz, jint mode) 92473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 92573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative); 92673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (group && !group->setMode(mode)) { 92773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 92873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return; 92973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 93073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh env->SetIntField(thiz, gMode, mode); 93173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 93273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 93373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid sendDtmf(JNIEnv *env, jobject thiz, jint event) 93473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 93573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative); 93673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (group && !group->sendDtmf(event)) { 93773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 93873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 93973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 94073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 94173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehJNINativeMethod gMethods[] = { 9420d2c37c274f1db29f51f1d078f240be13b784bf2Chia-chi Yeh {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add}, 94373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh {"remove", "(I)V", (void *)remove}, 94473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh {"setMode", "(I)V", (void *)setMode}, 94573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh {"sendDtmf", "(I)V", (void *)sendDtmf}, 94673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}; 94773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 94873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} // namespace 94973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 95073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint registerAudioGroup(JNIEnv *env) 95173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{ 95273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh gRandom = open("/dev/urandom", O_RDONLY); 95373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if (gRandom == -1) { 95473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh LOGE("urandom: %s", strerror(errno)); 95573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return -1; 95673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 95773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh 95873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh jclass clazz; 95973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL || 96073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL || 96173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL || 96273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) { 96373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh LOGE("JNI registration failed"); 96473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return -1; 96573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh } 96673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh return 0; 96773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} 968