blob: 41fedcee1f4cfadd9d7b4572fcb6ccba7ed0a4c1 [file] [log] [blame]
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdint.h>
19#include <string.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <sys/epoll.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <sys/stat.h>
26#include <sys/time.h>
27#include <time.h>
28#include <arpa/inet.h>
29#include <netinet/in.h>
30
31#define LOG_TAG "AudioGroup"
32#include <cutils/atomic.h>
Eric Laurentd7a724e2011-03-29 18:22:57 -070033#include <cutils/properties.h>
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080034#include <utils/Log.h>
35#include <utils/Errors.h>
36#include <utils/RefBase.h>
37#include <utils/threads.h>
38#include <utils/SystemClock.h>
39#include <media/AudioSystem.h>
40#include <media/AudioRecord.h>
41#include <media/AudioTrack.h>
42#include <media/mediarecorder.h>
43
44#include "jni.h"
45#include "JNIHelp.h"
46
47#include "AudioCodec.h"
Chia-chi Yeha8a10092010-10-05 01:17:13 +080048#include "EchoSuppressor.h"
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080049
50extern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
51
52namespace {
53
54using namespace android;
55
56int gRandom = -1;
57
58// We use a circular array to implement jitter buffer. The simplest way is doing
59// a modulo operation on the index while accessing the array. However modulo can
60// be expensive on some platforms, such as ARM. Thus we round up the size of the
61// array to the nearest power of 2 and then use bitwise-and instead of modulo.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +080062// Currently we make it 512ms long and assume packet interval is 40ms or less.
63// The first 80ms is the place where samples get mixed. The rest 432ms is the
64// real jitter buffer. For a stream at 8000Hz it takes 8192 bytes. These numbers
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080065// are chosen by experiments and each of them can be adjusted as needed.
66
Chia-chi Yeh3cf71372011-01-04 19:10:06 +080067// Originally a stream does not send packets when it is receive-only or there is
68// nothing to mix. However, this causes some problems with certain firewalls and
69// proxies. A firewall might remove a port mapping when there is no outgoing
70// packet for a preiod of time, and a proxy might wait for incoming packets from
71// both sides before start forwarding. To solve these problems, we send out a
72// silence packet on the stream for every second. It should be good enough to
73// keep the stream alive with relatively low resources.
74
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080075// Other notes:
76// + We use elapsedRealtime() to get the time. Since we use 32bit variables
77// instead of 64bit ones, comparison must be done by subtraction.
78// + Sampling rate must be multiple of 1000Hz, and packet length must be in
79// milliseconds. No floating points.
80// + If we cannot get enough CPU, we drop samples and simulate packet loss.
81// + Resampling is not done yet, so streams in one group must use the same rate.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +080082// For the first release only 8000Hz is supported.
83
84#define BUFFER_SIZE 512
85#define HISTORY_SIZE 80
86#define MEASURE_PERIOD 2000
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080087
88class AudioStream
89{
90public:
91 AudioStream();
92 ~AudioStream();
93 bool set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +080094 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080095 int codecType, int dtmfType);
96
97 void sendDtmf(int event);
98 bool mix(int32_t *output, int head, int tail, int sampleRate);
99 void encode(int tick, AudioStream *chain);
100 void decode(int tick);
101
Chia-chi Yeh53aa6ef2010-11-30 13:10:31 +0800102private:
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800103 enum {
104 NORMAL = 0,
105 SEND_ONLY = 1,
106 RECEIVE_ONLY = 2,
107 LAST_MODE = 2,
108 };
109
110 int mMode;
111 int mSocket;
112 sockaddr_storage mRemote;
113 AudioCodec *mCodec;
114 uint32_t mCodecMagic;
115 uint32_t mDtmfMagic;
Chia-chi Yehfe529892010-09-30 02:42:27 +0800116 bool mFixRemote;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800117
118 int mTick;
119 int mSampleRate;
120 int mSampleCount;
121 int mInterval;
Chia-chi Yeh3cf71372011-01-04 19:10:06 +0800122 int mKeepAlive;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800123
124 int16_t *mBuffer;
125 int mBufferMask;
126 int mBufferHead;
127 int mBufferTail;
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800128 int mLatencyTimer;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800129 int mLatencyScore;
130
131 uint16_t mSequence;
132 uint32_t mTimestamp;
133 uint32_t mSsrc;
134
135 int mDtmfEvent;
136 int mDtmfStart;
137
138 AudioStream *mNext;
139
140 friend class AudioGroup;
141};
142
143AudioStream::AudioStream()
144{
145 mSocket = -1;
146 mCodec = NULL;
147 mBuffer = NULL;
148 mNext = NULL;
149}
150
151AudioStream::~AudioStream()
152{
153 close(mSocket);
154 delete mCodec;
155 delete [] mBuffer;
156 LOGD("stream[%d] is dead", mSocket);
157}
158
159bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800160 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800161 int codecType, int dtmfType)
162{
163 if (mode < 0 || mode > LAST_MODE) {
164 return false;
165 }
166 mMode = mode;
167
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800168 mCodecMagic = (0x8000 | codecType) << 16;
169 mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
170
171 mTick = elapsedRealtime();
172 mSampleRate = sampleRate / 1000;
173 mSampleCount = sampleCount;
174 mInterval = mSampleCount / mSampleRate;
175
176 // Allocate jitter buffer.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800177 for (mBufferMask = 8; mBufferMask < mSampleRate; mBufferMask <<= 1);
178 mBufferMask *= BUFFER_SIZE;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800179 mBuffer = new int16_t[mBufferMask];
180 --mBufferMask;
181 mBufferHead = 0;
182 mBufferTail = 0;
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800183 mLatencyTimer = 0;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800184 mLatencyScore = 0;
185
186 // Initialize random bits.
187 read(gRandom, &mSequence, sizeof(mSequence));
188 read(gRandom, &mTimestamp, sizeof(mTimestamp));
189 read(gRandom, &mSsrc, sizeof(mSsrc));
190
191 mDtmfEvent = -1;
192 mDtmfStart = 0;
193
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800194 // Only take over these things when succeeded.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800195 mSocket = socket;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800196 if (codec) {
197 mRemote = *remote;
198 mCodec = codec;
Chia-chi Yehfe529892010-09-30 02:42:27 +0800199
200 // Here we should never get an private address, but some buggy proxy
201 // servers do give us one. To solve this, we replace the address when
202 // the first time we successfully decode an incoming packet.
203 mFixRemote = false;
204 if (remote->ss_family == AF_INET) {
205 unsigned char *address =
206 (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
207 if (address[0] == 10 ||
208 (address[0] == 172 && (address[1] >> 4) == 1) ||
209 (address[0] == 192 && address[1] == 168)) {
210 mFixRemote = true;
211 }
212 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800213 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800214
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800215 LOGD("stream[%d] is configured as %s %dkHz %dms mode %d", mSocket,
216 (codec ? codec->name : "RAW"), mSampleRate, mInterval, mMode);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800217 return true;
218}
219
220void AudioStream::sendDtmf(int event)
221{
222 if (mDtmfMagic != 0) {
223 mDtmfEvent = event << 24;
224 mDtmfStart = mTimestamp + mSampleCount;
225 }
226}
227
228bool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
229{
230 if (mMode == SEND_ONLY) {
231 return false;
232 }
233
234 if (head - mBufferHead < 0) {
235 head = mBufferHead;
236 }
237 if (tail - mBufferTail > 0) {
238 tail = mBufferTail;
239 }
240 if (tail - head <= 0) {
241 return false;
242 }
243
244 head *= mSampleRate;
245 tail *= mSampleRate;
246
247 if (sampleRate == mSampleRate) {
248 for (int i = head; i - tail < 0; ++i) {
249 output[i - head] += mBuffer[i & mBufferMask];
250 }
251 } else {
252 // TODO: implement resampling.
253 return false;
254 }
255 return true;
256}
257
258void AudioStream::encode(int tick, AudioStream *chain)
259{
260 if (tick - mTick >= mInterval) {
261 // We just missed the train. Pretend that packets in between are lost.
262 int skipped = (tick - mTick) / mInterval;
263 mTick += skipped * mInterval;
264 mSequence += skipped;
265 mTimestamp += skipped * mSampleCount;
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800266 LOGV("stream[%d] skips %d packets", mSocket, skipped);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800267 }
268
269 tick = mTick;
270 mTick += mInterval;
271 ++mSequence;
272 mTimestamp += mSampleCount;
273
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800274 // If there is an ongoing DTMF event, send it now.
Chia-chi Yeh3cf71372011-01-04 19:10:06 +0800275 if (mMode != RECEIVE_ONLY && mDtmfEvent != -1) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800276 int duration = mTimestamp - mDtmfStart;
277 // Make sure duration is reasonable.
278 if (duration >= 0 && duration < mSampleRate * 100) {
279 duration += mSampleCount;
280 int32_t buffer[4] = {
281 htonl(mDtmfMagic | mSequence),
282 htonl(mDtmfStart),
283 mSsrc,
284 htonl(mDtmfEvent | duration),
285 };
286 if (duration >= mSampleRate * 100) {
287 buffer[3] |= htonl(1 << 23);
288 mDtmfEvent = -1;
289 }
290 sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
291 (sockaddr *)&mRemote, sizeof(mRemote));
292 return;
293 }
294 mDtmfEvent = -1;
295 }
296
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800297 int32_t buffer[mSampleCount + 3];
Chia-chi Yeh3cf71372011-01-04 19:10:06 +0800298 int16_t samples[mSampleCount];
299 if (mMode == RECEIVE_ONLY) {
300 if ((mTick ^ mKeepAlive) >> 10 == 0) {
301 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800302 }
Chia-chi Yeh3cf71372011-01-04 19:10:06 +0800303 mKeepAlive = mTick;
304 memset(samples, 0, sizeof(samples));
305 } else {
306 // Mix all other streams.
307 bool mixed = false;
308 memset(buffer, 0, sizeof(buffer));
309 while (chain) {
310 if (chain != this &&
311 chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
312 mixed = true;
313 }
314 chain = chain->mNext;
315 }
316
317 if (mixed) {
318 // Saturate into 16 bits.
319 for (int i = 0; i < mSampleCount; ++i) {
320 int32_t sample = buffer[i];
321 if (sample < -32768) {
322 sample = -32768;
323 }
324 if (sample > 32767) {
325 sample = 32767;
326 }
327 samples[i] = sample;
328 }
329 } else {
330 if ((mTick ^ mKeepAlive) >> 10 == 0) {
331 return;
332 }
333 mKeepAlive = mTick;
334 memset(samples, 0, sizeof(samples));
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800335 LOGV("stream[%d] no data", mSocket);
repo sync7a69aef2010-09-23 05:46:01 +0800336 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800337 }
338
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800339 if (!mCodec) {
340 // Special case for device stream.
341 send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
342 return;
343 }
344
Chia-chi Yeh3cf71372011-01-04 19:10:06 +0800345 // Cook the packet and send it out.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800346 buffer[0] = htonl(mCodecMagic | mSequence);
347 buffer[1] = htonl(mTimestamp);
348 buffer[2] = mSsrc;
349 int length = mCodec->encode(&buffer[3], samples);
350 if (length <= 0) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800351 LOGV("stream[%d] encoder error", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800352 return;
353 }
354 sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
355 sizeof(mRemote));
356}
357
358void AudioStream::decode(int tick)
359{
360 char c;
361 if (mMode == SEND_ONLY) {
362 recv(mSocket, &c, 1, MSG_DONTWAIT);
363 return;
364 }
365
366 // Make sure mBufferHead and mBufferTail are reasonable.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800367 if ((unsigned int)(tick + BUFFER_SIZE - mBufferHead) > BUFFER_SIZE * 2) {
368 mBufferHead = tick - HISTORY_SIZE;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800369 mBufferTail = mBufferHead;
370 }
371
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800372 if (tick - mBufferHead > HISTORY_SIZE) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800373 // Throw away outdated samples.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800374 mBufferHead = tick - HISTORY_SIZE;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800375 if (mBufferTail - mBufferHead < 0) {
376 mBufferTail = mBufferHead;
377 }
378 }
379
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800380 // Adjust the jitter buffer if the latency keeps larger than two times of the
381 // packet interval in the past two seconds.
382 int score = mBufferTail - tick - mInterval * 2;
383 if (mLatencyScore > score) {
384 mLatencyScore = score;
385 }
386 if (mLatencyScore <= 0) {
387 mLatencyTimer = tick;
388 mLatencyScore = score;
389 } else if (tick - mLatencyTimer >= MEASURE_PERIOD) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800390 LOGV("stream[%d] reduces latency of %dms", mSocket, mLatencyScore);
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800391 mBufferTail -= mLatencyScore;
392 mLatencyTimer = tick;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800393 }
394
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800395 if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800396 // Buffer overflow. Drop the packet.
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800397 LOGV("stream[%d] buffer overflow", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800398 recv(mSocket, &c, 1, MSG_DONTWAIT);
399 return;
400 }
401
402 // Receive the packet and decode it.
403 int16_t samples[mSampleCount];
404 int length = 0;
405 if (!mCodec) {
406 // Special case for device stream.
407 length = recv(mSocket, samples, sizeof(samples),
408 MSG_TRUNC | MSG_DONTWAIT) >> 1;
409 } else {
410 __attribute__((aligned(4))) uint8_t buffer[2048];
Chia-chi Yehfe529892010-09-30 02:42:27 +0800411 sockaddr_storage remote;
412 socklen_t len = sizeof(remote);
Chung-yih Wangbd229422010-09-23 23:23:11 +0800413
Chia-chi Yehfe529892010-09-30 02:42:27 +0800414 length = recvfrom(mSocket, buffer, sizeof(buffer),
415 MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800416
417 // Do we need to check SSRC, sequence, and timestamp? They are not
Chia-chi Yehb8790322010-08-19 18:26:53 +0800418 // reliable but at least they can be used to identify duplicates?
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800419 if (length < 12 || length > (int)sizeof(buffer) ||
420 (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800421 LOGV("stream[%d] malformed packet", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800422 return;
423 }
424 int offset = 12 + ((buffer[0] & 0x0F) << 2);
425 if ((buffer[0] & 0x10) != 0) {
426 offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
427 }
428 if ((buffer[0] & 0x20) != 0) {
429 length -= buffer[length - 1];
430 }
431 length -= offset;
432 if (length >= 0) {
433 length = mCodec->decode(samples, &buffer[offset], length);
434 }
Chia-chi Yehfe529892010-09-30 02:42:27 +0800435 if (length > 0 && mFixRemote) {
436 mRemote = remote;
437 mFixRemote = false;
438 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800439 }
Chia-chi Yehfe529892010-09-30 02:42:27 +0800440 if (length <= 0) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800441 LOGV("stream[%d] decoder error", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800442 return;
443 }
444
445 if (tick - mBufferTail > 0) {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800446 // Buffer underrun. Reset the jitter buffer.
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800447 LOGV("stream[%d] buffer underrun", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800448 if (mBufferTail - mBufferHead <= 0) {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800449 mBufferHead = tick + mInterval;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800450 mBufferTail = mBufferHead;
451 } else {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800452 int tail = (tick + mInterval) * mSampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800453 for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
454 mBuffer[i & mBufferMask] = 0;
455 }
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800456 mBufferTail = tick + mInterval;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800457 }
458 }
459
460 // Append to the jitter buffer.
461 int tail = mBufferTail * mSampleRate;
462 for (int i = 0; i < mSampleCount; ++i) {
463 mBuffer[tail & mBufferMask] = samples[i];
464 ++tail;
465 }
466 mBufferTail += mInterval;
467}
468
469//------------------------------------------------------------------------------
470
471class AudioGroup
472{
473public:
474 AudioGroup();
475 ~AudioGroup();
476 bool set(int sampleRate, int sampleCount);
477
478 bool setMode(int mode);
479 bool sendDtmf(int event);
480 bool add(AudioStream *stream);
481 bool remove(int socket);
482
Chia-chi Yeh53aa6ef2010-11-30 13:10:31 +0800483private:
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800484 enum {
485 ON_HOLD = 0,
486 MUTED = 1,
487 NORMAL = 2,
Chia-chi Yehd87be272011-01-06 17:43:24 +0800488 ECHO_SUPPRESSION = 3,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800489 LAST_MODE = 3,
490 };
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800491
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800492 AudioStream *mChain;
493 int mEventQueue;
494 volatile int mDtmfEvent;
495
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800496 int mMode;
497 int mSampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800498 int mSampleCount;
499 int mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800500
501 class NetworkThread : public Thread
502 {
503 public:
504 NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
505
506 bool start()
507 {
508 if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
509 LOGE("cannot start network thread");
510 return false;
511 }
512 return true;
513 }
514
515 private:
516 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800517 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800518 };
519 sp<NetworkThread> mNetworkThread;
520
521 class DeviceThread : public Thread
522 {
523 public:
524 DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
525
526 bool start()
527 {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800528 if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
529 LOGE("cannot start device thread");
530 return false;
531 }
532 return true;
533 }
534
535 private:
536 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800537 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800538 };
539 sp<DeviceThread> mDeviceThread;
540};
541
542AudioGroup::AudioGroup()
543{
544 mMode = ON_HOLD;
545 mChain = NULL;
546 mEventQueue = -1;
547 mDtmfEvent = -1;
548 mDeviceSocket = -1;
549 mNetworkThread = new NetworkThread(this);
550 mDeviceThread = new DeviceThread(this);
551}
552
553AudioGroup::~AudioGroup()
554{
555 mNetworkThread->requestExitAndWait();
556 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800557 close(mEventQueue);
558 close(mDeviceSocket);
559 while (mChain) {
560 AudioStream *next = mChain->mNext;
561 delete mChain;
562 mChain = next;
563 }
564 LOGD("group[%d] is dead", mDeviceSocket);
565}
566
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800567bool AudioGroup::set(int sampleRate, int sampleCount)
568{
569 mEventQueue = epoll_create(2);
570 if (mEventQueue == -1) {
571 LOGE("epoll_create: %s", strerror(errno));
572 return false;
573 }
574
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800575 mSampleRate = sampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800576 mSampleCount = sampleCount;
577
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800578 // Create device socket.
579 int pair[2];
580 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
581 LOGE("socketpair: %s", strerror(errno));
582 return false;
583 }
584 mDeviceSocket = pair[0];
585
586 // Create device stream.
587 mChain = new AudioStream;
588 if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
589 sampleRate, sampleCount, -1, -1)) {
590 close(pair[1]);
591 LOGE("cannot initialize device stream");
592 return false;
593 }
594
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800595 // Give device socket a reasonable timeout.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800596 timeval tv;
597 tv.tv_sec = 0;
Chia-chi Yeh557b04d2010-09-08 09:56:02 +0800598 tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800599 if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800600 LOGE("setsockopt: %s", strerror(errno));
601 return false;
602 }
603
604 // Add device stream into event queue.
605 epoll_event event;
606 event.events = EPOLLIN;
607 event.data.ptr = mChain;
608 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
609 LOGE("epoll_ctl: %s", strerror(errno));
610 return false;
611 }
612
613 // Anything else?
614 LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
615 return true;
616}
617
618bool AudioGroup::setMode(int mode)
619{
620 if (mode < 0 || mode > LAST_MODE) {
621 return false;
622 }
Eric Laurentd7a724e2011-03-29 18:22:57 -0700623 //FIXME: temporary code to overcome echo and mic gain issues on herring board.
624 // Must be modified/removed when proper support for voice processing query and control
625 // is included in audio framework
626 char value[PROPERTY_VALUE_MAX];
627 property_get("ro.product.board", value, "");
628 if (mode == NORMAL && !strcmp(value, "herring")) {
629 mode = ECHO_SUPPRESSION;
630 }
Chia-chi Yehd87be272011-01-06 17:43:24 +0800631 if (mode == ECHO_SUPPRESSION && AudioSystem::getParameters(
632 0, String8("ec_supported")) == "ec_supported=yes") {
633 mode = NORMAL;
634 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800635 if (mMode == mode) {
636 return true;
637 }
638
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800639 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800640 LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
641 mMode = mode;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800642 return (mode == ON_HOLD) || mDeviceThread->start();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800643}
644
645bool AudioGroup::sendDtmf(int event)
646{
647 if (event < 0 || event > 15) {
648 return false;
649 }
650
651 // DTMF is rarely used, so we try to make it as lightweight as possible.
652 // Using volatile might be dodgy, but using a pipe or pthread primitives
653 // or stop-set-restart threads seems too heavy. Will investigate later.
654 timespec ts;
655 ts.tv_sec = 0;
656 ts.tv_nsec = 100000000;
657 for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
658 nanosleep(&ts, NULL);
659 }
660 if (mDtmfEvent != -1) {
661 return false;
662 }
663 mDtmfEvent = event;
664 nanosleep(&ts, NULL);
665 return true;
666}
667
668bool AudioGroup::add(AudioStream *stream)
669{
670 mNetworkThread->requestExitAndWait();
671
672 epoll_event event;
673 event.events = EPOLLIN;
674 event.data.ptr = stream;
675 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
676 LOGE("epoll_ctl: %s", strerror(errno));
677 return false;
678 }
679
680 stream->mNext = mChain->mNext;
681 mChain->mNext = stream;
682 if (!mNetworkThread->start()) {
683 // Only take over the stream when succeeded.
684 mChain->mNext = stream->mNext;
685 return false;
686 }
687
688 LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
689 return true;
690}
691
692bool AudioGroup::remove(int socket)
693{
694 mNetworkThread->requestExitAndWait();
695
696 for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
697 AudioStream *target = stream->mNext;
698 if (target->mSocket == socket) {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800699 if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
700 LOGE("epoll_ctl: %s", strerror(errno));
701 return false;
702 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800703 stream->mNext = target->mNext;
704 LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
705 delete target;
706 break;
707 }
708 }
709
710 // Do not start network thread if there is only one stream.
711 if (!mChain->mNext || !mNetworkThread->start()) {
712 return false;
713 }
714 return true;
715}
716
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800717bool AudioGroup::NetworkThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800718{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800719 AudioStream *chain = mGroup->mChain;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800720 int tick = elapsedRealtime();
721 int deadline = tick + 10;
722 int count = 0;
723
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800724 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800725 if (tick - stream->mTick >= 0) {
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800726 stream->encode(tick, chain);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800727 }
728 if (deadline - stream->mTick > 0) {
729 deadline = stream->mTick;
730 }
731 ++count;
732 }
733
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800734 int event = mGroup->mDtmfEvent;
735 if (event != -1) {
736 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800737 stream->sendDtmf(event);
738 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800739 mGroup->mDtmfEvent = -1;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800740 }
741
742 deadline -= tick;
743 if (deadline < 1) {
744 deadline = 1;
745 }
746
747 epoll_event events[count];
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800748 count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800749 if (count == -1) {
750 LOGE("epoll_wait: %s", strerror(errno));
751 return false;
752 }
753 for (int i = 0; i < count; ++i) {
754 ((AudioStream *)events[i].data.ptr)->decode(tick);
755 }
756
757 return true;
758}
759
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800760bool AudioGroup::DeviceThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800761{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800762 int mode = mGroup->mMode;
763 int sampleRate = mGroup->mSampleRate;
764 int sampleCount = mGroup->mSampleCount;
765 int deviceSocket = mGroup->mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800766
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800767 // Find out the frame count for AudioTrack and AudioRecord.
768 int output = 0;
769 int input = 0;
770 if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
771 sampleRate) != NO_ERROR || output <= 0 ||
772 AudioRecord::getMinFrameCount(&input, sampleRate,
773 AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
774 LOGE("cannot compute frame count");
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800775 return false;
776 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800777 LOGD("reported frame count: output %d, input %d", output, input);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800778
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800779 if (output < sampleCount * 2) {
780 output = sampleCount * 2;
781 }
782 if (input < sampleCount * 2) {
783 input = sampleCount * 2;
784 }
785 LOGD("adjusted frame count: output %d, input %d", output, input);
786
787 // Initialize AudioTrack and AudioRecord.
788 AudioTrack track;
789 AudioRecord record;
790 if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
Chia-chi Yehd87be272011-01-06 17:43:24 +0800791 AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR || record.set(
792 AUDIO_SOURCE_VOICE_COMMUNICATION, sampleRate, AudioSystem::PCM_16_BIT,
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800793 AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
794 LOGE("cannot initialize audio device");
795 return false;
796 }
797 LOGD("latency: output %d, input %d", track.latency(), record.latency());
798
Chia-chi Yeha8a10092010-10-05 01:17:13 +0800799 // Initialize echo canceler.
Chia-chi Yeh8a68b522010-10-21 23:39:35 +0800800 EchoSuppressor echo(sampleCount,
Chia-chi Yeha8a10092010-10-05 01:17:13 +0800801 (track.latency() + record.latency()) * sampleRate / 1000);
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800802
803 // Give device socket a reasonable buffer size.
804 setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
805 setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
806
807 // Drain device socket.
808 char c;
809 while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
810
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800811 // Start AudioRecord before AudioTrack. This prevents AudioTrack from being
812 // disabled due to buffer underrun while waiting for AudioRecord.
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800813 if (mode != MUTED) {
814 record.start();
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800815 int16_t one;
816 record.read(&one, sizeof(one));
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800817 }
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800818 track.start();
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800819
820 while (!exitPending()) {
821 int16_t output[sampleCount];
822 if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
823 memset(output, 0, sizeof(output));
824 }
825
826 int16_t input[sampleCount];
827 int toWrite = sampleCount;
828 int toRead = (mode == MUTED) ? 0 : sampleCount;
829 int chances = 100;
830
831 while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
832 if (toWrite > 0) {
833 AudioTrack::Buffer buffer;
834 buffer.frameCount = toWrite;
835
836 status_t status = track.obtainBuffer(&buffer, 1);
837 if (status == NO_ERROR) {
838 int offset = sampleCount - toWrite;
839 memcpy(buffer.i8, &output[offset], buffer.size);
840 toWrite -= buffer.frameCount;
841 track.releaseBuffer(&buffer);
842 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
843 LOGE("cannot write to AudioTrack");
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800844 return true;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800845 }
846 }
847
848 if (toRead > 0) {
849 AudioRecord::Buffer buffer;
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800850 buffer.frameCount = toRead;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800851
852 status_t status = record.obtainBuffer(&buffer, 1);
853 if (status == NO_ERROR) {
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800854 int offset = sampleCount - toRead;
855 memcpy(&input[offset], buffer.i8, buffer.size);
856 toRead -= buffer.frameCount;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800857 record.releaseBuffer(&buffer);
858 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
859 LOGE("cannot read from AudioRecord");
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800860 return true;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800861 }
862 }
863 }
864
865 if (chances <= 0) {
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800866 LOGW("device loop timeout");
867 while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800868 }
869
870 if (mode != MUTED) {
871 if (mode == NORMAL) {
872 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
873 } else {
Chia-chi Yeha8a10092010-10-05 01:17:13 +0800874 echo.run(output, input);
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800875 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
876 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800877 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800878 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800879 return false;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800880}
881
882//------------------------------------------------------------------------------
883
884static jfieldID gNative;
885static jfieldID gMode;
886
Chia-chi Yehb8790322010-08-19 18:26:53 +0800887void add(JNIEnv *env, jobject thiz, jint mode,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800888 jint socket, jstring jRemoteAddress, jint remotePort,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800889 jstring jCodecSpec, jint dtmfType)
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800890{
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800891 AudioCodec *codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800892 AudioStream *stream = NULL;
893 AudioGroup *group = NULL;
894
895 // Sanity check.
896 sockaddr_storage remote;
897 if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
898 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800899 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800900 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800901 if (!jCodecSpec) {
902 jniThrowNullPointerException(env, "codecSpec");
903 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800904 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800905 const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
906 if (!codecSpec) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800907 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800908 return;
909 }
910
911 // Create audio codec.
912 int codecType = -1;
913 char codecName[16];
914 int sampleRate = -1;
Chia-chi Yeh3cf71372011-01-04 19:10:06 +0800915 sscanf(codecSpec, "%d %15[^/]%*c%d", &codecType, codecName, &sampleRate);
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800916 codec = newAudioCodec(codecName);
917 int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
918 env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
919 if (sampleCount <= 0) {
920 jniThrowException(env, "java/lang/IllegalStateException",
921 "cannot initialize audio codec");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800922 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800923 }
924
925 // Create audio stream.
926 stream = new AudioStream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800927 if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800928 codecType, dtmfType)) {
929 jniThrowException(env, "java/lang/IllegalStateException",
930 "cannot initialize audio stream");
931 goto error;
932 }
933 socket = -1;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800934 codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800935
936 // Create audio group.
937 group = (AudioGroup *)env->GetIntField(thiz, gNative);
938 if (!group) {
939 int mode = env->GetIntField(thiz, gMode);
940 group = new AudioGroup;
941 if (!group->set(8000, 256) || !group->setMode(mode)) {
942 jniThrowException(env, "java/lang/IllegalStateException",
943 "cannot initialize audio group");
944 goto error;
945 }
946 }
947
948 // Add audio stream into audio group.
949 if (!group->add(stream)) {
950 jniThrowException(env, "java/lang/IllegalStateException",
951 "cannot add audio stream");
952 goto error;
953 }
954
955 // Succeed.
956 env->SetIntField(thiz, gNative, (int)group);
Chia-chi Yehb8790322010-08-19 18:26:53 +0800957 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800958
959error:
960 delete group;
961 delete stream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800962 delete codec;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800963 close(socket);
964 env->SetIntField(thiz, gNative, NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800965}
966
967void remove(JNIEnv *env, jobject thiz, jint socket)
968{
969 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
970 if (group) {
971 if (socket == -1 || !group->remove(socket)) {
972 delete group;
973 env->SetIntField(thiz, gNative, NULL);
974 }
975 }
976}
977
978void setMode(JNIEnv *env, jobject thiz, jint mode)
979{
980 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
981 if (group && !group->setMode(mode)) {
982 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800983 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800984}
985
986void sendDtmf(JNIEnv *env, jobject thiz, jint event)
987{
988 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
989 if (group && !group->sendDtmf(event)) {
990 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
991 }
992}
993
994JNINativeMethod gMethods[] = {
Chia-chi Yeh53aa6ef2010-11-30 13:10:31 +0800995 {"nativeAdd", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
996 {"nativeRemove", "(I)V", (void *)remove},
997 {"nativeSetMode", "(I)V", (void *)setMode},
998 {"nativeSendDtmf", "(I)V", (void *)sendDtmf},
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800999};
1000
1001} // namespace
1002
1003int registerAudioGroup(JNIEnv *env)
1004{
1005 gRandom = open("/dev/urandom", O_RDONLY);
1006 if (gRandom == -1) {
1007 LOGE("urandom: %s", strerror(errno));
1008 return -1;
1009 }
1010
1011 jclass clazz;
1012 if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
1013 (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
1014 (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
1015 env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
1016 LOGE("JNI registration failed");
1017 return -1;
1018 }
1019 return 0;
1020}