blob: 521451850503579d8823a278b5379b79c74256bc [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>
33#include <utils/Log.h>
34#include <utils/Errors.h>
35#include <utils/RefBase.h>
36#include <utils/threads.h>
37#include <utils/SystemClock.h>
38#include <media/AudioSystem.h>
39#include <media/AudioRecord.h>
40#include <media/AudioTrack.h>
41#include <media/mediarecorder.h>
42
43#include "jni.h"
44#include "JNIHelp.h"
45
46#include "AudioCodec.h"
47
48extern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
49
50namespace {
51
52using namespace android;
53
54int gRandom = -1;
55
56// We use a circular array to implement jitter buffer. The simplest way is doing
57// a modulo operation on the index while accessing the array. However modulo can
58// be expensive on some platforms, such as ARM. Thus we round up the size of the
59// array to the nearest power of 2 and then use bitwise-and instead of modulo.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +080060// Currently we make it 512ms long and assume packet interval is 40ms or less.
61// The first 80ms is the place where samples get mixed. The rest 432ms is the
62// real jitter buffer. For a stream at 8000Hz it takes 8192 bytes. These numbers
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080063// are chosen by experiments and each of them can be adjusted as needed.
64
65// Other notes:
66// + We use elapsedRealtime() to get the time. Since we use 32bit variables
67// instead of 64bit ones, comparison must be done by subtraction.
68// + Sampling rate must be multiple of 1000Hz, and packet length must be in
69// milliseconds. No floating points.
70// + If we cannot get enough CPU, we drop samples and simulate packet loss.
71// + Resampling is not done yet, so streams in one group must use the same rate.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +080072// For the first release only 8000Hz is supported.
73
74#define BUFFER_SIZE 512
75#define HISTORY_SIZE 80
76#define MEASURE_PERIOD 2000
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080077
78class AudioStream
79{
80public:
81 AudioStream();
82 ~AudioStream();
83 bool set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +080084 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080085 int codecType, int dtmfType);
86
87 void sendDtmf(int event);
88 bool mix(int32_t *output, int head, int tail, int sampleRate);
89 void encode(int tick, AudioStream *chain);
90 void decode(int tick);
91
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080092 enum {
93 NORMAL = 0,
94 SEND_ONLY = 1,
95 RECEIVE_ONLY = 2,
96 LAST_MODE = 2,
97 };
98
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +080099private:
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800100 int mMode;
101 int mSocket;
102 sockaddr_storage mRemote;
103 AudioCodec *mCodec;
104 uint32_t mCodecMagic;
105 uint32_t mDtmfMagic;
Chia-chi Yehfe529892010-09-30 02:42:27 +0800106 bool mFixRemote;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800107
108 int mTick;
109 int mSampleRate;
110 int mSampleCount;
111 int mInterval;
repo sync7a69aef2010-09-23 05:46:01 +0800112 int mLogThrottle;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800113
114 int16_t *mBuffer;
115 int mBufferMask;
116 int mBufferHead;
117 int mBufferTail;
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800118 int mLatencyTimer;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800119 int mLatencyScore;
120
121 uint16_t mSequence;
122 uint32_t mTimestamp;
123 uint32_t mSsrc;
124
125 int mDtmfEvent;
126 int mDtmfStart;
127
128 AudioStream *mNext;
129
130 friend class AudioGroup;
131};
132
133AudioStream::AudioStream()
134{
135 mSocket = -1;
136 mCodec = NULL;
137 mBuffer = NULL;
138 mNext = NULL;
139}
140
141AudioStream::~AudioStream()
142{
143 close(mSocket);
144 delete mCodec;
145 delete [] mBuffer;
146 LOGD("stream[%d] is dead", mSocket);
147}
148
149bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800150 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800151 int codecType, int dtmfType)
152{
153 if (mode < 0 || mode > LAST_MODE) {
154 return false;
155 }
156 mMode = mode;
157
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800158 mCodecMagic = (0x8000 | codecType) << 16;
159 mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
160
161 mTick = elapsedRealtime();
162 mSampleRate = sampleRate / 1000;
163 mSampleCount = sampleCount;
164 mInterval = mSampleCount / mSampleRate;
165
166 // Allocate jitter buffer.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800167 for (mBufferMask = 8; mBufferMask < mSampleRate; mBufferMask <<= 1);
168 mBufferMask *= BUFFER_SIZE;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800169 mBuffer = new int16_t[mBufferMask];
170 --mBufferMask;
171 mBufferHead = 0;
172 mBufferTail = 0;
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800173 mLatencyTimer = 0;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800174 mLatencyScore = 0;
175
176 // Initialize random bits.
177 read(gRandom, &mSequence, sizeof(mSequence));
178 read(gRandom, &mTimestamp, sizeof(mTimestamp));
179 read(gRandom, &mSsrc, sizeof(mSsrc));
180
181 mDtmfEvent = -1;
182 mDtmfStart = 0;
183
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800184 // Only take over these things when succeeded.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800185 mSocket = socket;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800186 if (codec) {
187 mRemote = *remote;
188 mCodec = codec;
Chia-chi Yehfe529892010-09-30 02:42:27 +0800189
190 // Here we should never get an private address, but some buggy proxy
191 // servers do give us one. To solve this, we replace the address when
192 // the first time we successfully decode an incoming packet.
193 mFixRemote = false;
194 if (remote->ss_family == AF_INET) {
195 unsigned char *address =
196 (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
197 if (address[0] == 10 ||
198 (address[0] == 172 && (address[1] >> 4) == 1) ||
199 (address[0] == 192 && address[1] == 168)) {
200 mFixRemote = true;
201 }
202 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800203 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800204
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800205 LOGD("stream[%d] is configured as %s %dkHz %dms mode %d", mSocket,
206 (codec ? codec->name : "RAW"), mSampleRate, mInterval, mMode);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800207 return true;
208}
209
210void AudioStream::sendDtmf(int event)
211{
212 if (mDtmfMagic != 0) {
213 mDtmfEvent = event << 24;
214 mDtmfStart = mTimestamp + mSampleCount;
215 }
216}
217
218bool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
219{
220 if (mMode == SEND_ONLY) {
221 return false;
222 }
223
224 if (head - mBufferHead < 0) {
225 head = mBufferHead;
226 }
227 if (tail - mBufferTail > 0) {
228 tail = mBufferTail;
229 }
230 if (tail - head <= 0) {
231 return false;
232 }
233
234 head *= mSampleRate;
235 tail *= mSampleRate;
236
237 if (sampleRate == mSampleRate) {
238 for (int i = head; i - tail < 0; ++i) {
239 output[i - head] += mBuffer[i & mBufferMask];
240 }
241 } else {
242 // TODO: implement resampling.
243 return false;
244 }
245 return true;
246}
247
248void AudioStream::encode(int tick, AudioStream *chain)
249{
250 if (tick - mTick >= mInterval) {
251 // We just missed the train. Pretend that packets in between are lost.
252 int skipped = (tick - mTick) / mInterval;
253 mTick += skipped * mInterval;
254 mSequence += skipped;
255 mTimestamp += skipped * mSampleCount;
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800256 LOGV("stream[%d] skips %d packets", mSocket, skipped);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800257 }
258
259 tick = mTick;
260 mTick += mInterval;
261 ++mSequence;
262 mTimestamp += mSampleCount;
263
264 if (mMode == RECEIVE_ONLY) {
265 return;
266 }
267
268 // If there is an ongoing DTMF event, send it now.
269 if (mDtmfEvent != -1) {
270 int duration = mTimestamp - mDtmfStart;
271 // Make sure duration is reasonable.
272 if (duration >= 0 && duration < mSampleRate * 100) {
273 duration += mSampleCount;
274 int32_t buffer[4] = {
275 htonl(mDtmfMagic | mSequence),
276 htonl(mDtmfStart),
277 mSsrc,
278 htonl(mDtmfEvent | duration),
279 };
280 if (duration >= mSampleRate * 100) {
281 buffer[3] |= htonl(1 << 23);
282 mDtmfEvent = -1;
283 }
284 sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
285 (sockaddr *)&mRemote, sizeof(mRemote));
286 return;
287 }
288 mDtmfEvent = -1;
289 }
290
291 // It is time to mix streams.
292 bool mixed = false;
293 int32_t buffer[mSampleCount + 3];
294 memset(buffer, 0, sizeof(buffer));
295 while (chain) {
296 if (chain != this &&
297 chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
298 mixed = true;
299 }
300 chain = chain->mNext;
301 }
302 if (!mixed) {
repo sync7a69aef2010-09-23 05:46:01 +0800303 if ((mTick ^ mLogThrottle) >> 10) {
304 mLogThrottle = mTick;
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800305 LOGV("stream[%d] no data", mSocket);
repo sync7a69aef2010-09-23 05:46:01 +0800306 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800307 return;
308 }
309
310 // Cook the packet and send it out.
311 int16_t samples[mSampleCount];
312 for (int i = 0; i < mSampleCount; ++i) {
313 int32_t sample = buffer[i];
314 if (sample < -32768) {
315 sample = -32768;
316 }
317 if (sample > 32767) {
318 sample = 32767;
319 }
320 samples[i] = sample;
321 }
322 if (!mCodec) {
323 // Special case for device stream.
324 send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
325 return;
326 }
327
328 buffer[0] = htonl(mCodecMagic | mSequence);
329 buffer[1] = htonl(mTimestamp);
330 buffer[2] = mSsrc;
331 int length = mCodec->encode(&buffer[3], samples);
332 if (length <= 0) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800333 LOGV("stream[%d] encoder error", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800334 return;
335 }
336 sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
337 sizeof(mRemote));
338}
339
340void AudioStream::decode(int tick)
341{
342 char c;
343 if (mMode == SEND_ONLY) {
344 recv(mSocket, &c, 1, MSG_DONTWAIT);
345 return;
346 }
347
348 // Make sure mBufferHead and mBufferTail are reasonable.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800349 if ((unsigned int)(tick + BUFFER_SIZE - mBufferHead) > BUFFER_SIZE * 2) {
350 mBufferHead = tick - HISTORY_SIZE;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800351 mBufferTail = mBufferHead;
352 }
353
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800354 if (tick - mBufferHead > HISTORY_SIZE) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800355 // Throw away outdated samples.
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800356 mBufferHead = tick - HISTORY_SIZE;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800357 if (mBufferTail - mBufferHead < 0) {
358 mBufferTail = mBufferHead;
359 }
360 }
361
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800362 // Adjust the jitter buffer if the latency keeps larger than two times of the
363 // packet interval in the past two seconds.
364 int score = mBufferTail - tick - mInterval * 2;
365 if (mLatencyScore > score) {
366 mLatencyScore = score;
367 }
368 if (mLatencyScore <= 0) {
369 mLatencyTimer = tick;
370 mLatencyScore = score;
371 } else if (tick - mLatencyTimer >= MEASURE_PERIOD) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800372 LOGV("stream[%d] reduces latency of %dms", mSocket, mLatencyScore);
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800373 mBufferTail -= mLatencyScore;
374 mLatencyTimer = tick;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800375 }
376
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800377 if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800378 // Buffer overflow. Drop the packet.
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800379 LOGV("stream[%d] buffer overflow", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800380 recv(mSocket, &c, 1, MSG_DONTWAIT);
381 return;
382 }
383
384 // Receive the packet and decode it.
385 int16_t samples[mSampleCount];
386 int length = 0;
387 if (!mCodec) {
388 // Special case for device stream.
389 length = recv(mSocket, samples, sizeof(samples),
390 MSG_TRUNC | MSG_DONTWAIT) >> 1;
391 } else {
392 __attribute__((aligned(4))) uint8_t buffer[2048];
Chia-chi Yehfe529892010-09-30 02:42:27 +0800393 sockaddr_storage remote;
394 socklen_t len = sizeof(remote);
Chung-yih Wangbd229422010-09-23 23:23:11 +0800395
Chia-chi Yehfe529892010-09-30 02:42:27 +0800396 length = recvfrom(mSocket, buffer, sizeof(buffer),
397 MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800398
399 // Do we need to check SSRC, sequence, and timestamp? They are not
Chia-chi Yehb8790322010-08-19 18:26:53 +0800400 // reliable but at least they can be used to identify duplicates?
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800401 if (length < 12 || length > (int)sizeof(buffer) ||
402 (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800403 LOGV("stream[%d] malformed packet", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800404 return;
405 }
406 int offset = 12 + ((buffer[0] & 0x0F) << 2);
407 if ((buffer[0] & 0x10) != 0) {
408 offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
409 }
410 if ((buffer[0] & 0x20) != 0) {
411 length -= buffer[length - 1];
412 }
413 length -= offset;
414 if (length >= 0) {
415 length = mCodec->decode(samples, &buffer[offset], length);
416 }
Chia-chi Yehfe529892010-09-30 02:42:27 +0800417 if (length > 0 && mFixRemote) {
418 mRemote = remote;
419 mFixRemote = false;
420 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800421 }
Chia-chi Yehfe529892010-09-30 02:42:27 +0800422 if (length <= 0) {
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800423 LOGV("stream[%d] decoder error", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800424 return;
425 }
426
427 if (tick - mBufferTail > 0) {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800428 // Buffer underrun. Reset the jitter buffer.
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800429 LOGV("stream[%d] buffer underrun", mSocket);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800430 if (mBufferTail - mBufferHead <= 0) {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800431 mBufferHead = tick + mInterval;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800432 mBufferTail = mBufferHead;
433 } else {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800434 int tail = (tick + mInterval) * mSampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800435 for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
436 mBuffer[i & mBufferMask] = 0;
437 }
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800438 mBufferTail = tick + mInterval;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800439 }
440 }
441
442 // Append to the jitter buffer.
443 int tail = mBufferTail * mSampleRate;
444 for (int i = 0; i < mSampleCount; ++i) {
445 mBuffer[tail & mBufferMask] = samples[i];
446 ++tail;
447 }
448 mBufferTail += mInterval;
449}
450
451//------------------------------------------------------------------------------
452
453class AudioGroup
454{
455public:
456 AudioGroup();
457 ~AudioGroup();
458 bool set(int sampleRate, int sampleCount);
459
460 bool setMode(int mode);
461 bool sendDtmf(int event);
462 bool add(AudioStream *stream);
463 bool remove(int socket);
464
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800465 enum {
466 ON_HOLD = 0,
467 MUTED = 1,
468 NORMAL = 2,
469 EC_ENABLED = 3,
470 LAST_MODE = 3,
471 };
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800472
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800473private:
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800474 AudioStream *mChain;
475 int mEventQueue;
476 volatile int mDtmfEvent;
477
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800478 int mMode;
479 int mSampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800480 int mSampleCount;
481 int mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800482
483 class NetworkThread : public Thread
484 {
485 public:
486 NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
487
488 bool start()
489 {
490 if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
491 LOGE("cannot start network thread");
492 return false;
493 }
494 return true;
495 }
496
497 private:
498 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800499 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800500 };
501 sp<NetworkThread> mNetworkThread;
502
503 class DeviceThread : public Thread
504 {
505 public:
506 DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
507
508 bool start()
509 {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800510 if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
511 LOGE("cannot start device thread");
512 return false;
513 }
514 return true;
515 }
516
517 private:
518 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800519 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800520 };
521 sp<DeviceThread> mDeviceThread;
522};
523
524AudioGroup::AudioGroup()
525{
526 mMode = ON_HOLD;
527 mChain = NULL;
528 mEventQueue = -1;
529 mDtmfEvent = -1;
530 mDeviceSocket = -1;
531 mNetworkThread = new NetworkThread(this);
532 mDeviceThread = new DeviceThread(this);
533}
534
535AudioGroup::~AudioGroup()
536{
537 mNetworkThread->requestExitAndWait();
538 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800539 close(mEventQueue);
540 close(mDeviceSocket);
541 while (mChain) {
542 AudioStream *next = mChain->mNext;
543 delete mChain;
544 mChain = next;
545 }
546 LOGD("group[%d] is dead", mDeviceSocket);
547}
548
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800549bool AudioGroup::set(int sampleRate, int sampleCount)
550{
551 mEventQueue = epoll_create(2);
552 if (mEventQueue == -1) {
553 LOGE("epoll_create: %s", strerror(errno));
554 return false;
555 }
556
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800557 mSampleRate = sampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800558 mSampleCount = sampleCount;
559
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800560 // Create device socket.
561 int pair[2];
562 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
563 LOGE("socketpair: %s", strerror(errno));
564 return false;
565 }
566 mDeviceSocket = pair[0];
567
568 // Create device stream.
569 mChain = new AudioStream;
570 if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
571 sampleRate, sampleCount, -1, -1)) {
572 close(pair[1]);
573 LOGE("cannot initialize device stream");
574 return false;
575 }
576
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800577 // Give device socket a reasonable timeout.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800578 timeval tv;
579 tv.tv_sec = 0;
Chia-chi Yeh557b04d2010-09-08 09:56:02 +0800580 tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800581 if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800582 LOGE("setsockopt: %s", strerror(errno));
583 return false;
584 }
585
586 // Add device stream into event queue.
587 epoll_event event;
588 event.events = EPOLLIN;
589 event.data.ptr = mChain;
590 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
591 LOGE("epoll_ctl: %s", strerror(errno));
592 return false;
593 }
594
595 // Anything else?
596 LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
597 return true;
598}
599
600bool AudioGroup::setMode(int mode)
601{
602 if (mode < 0 || mode > LAST_MODE) {
603 return false;
604 }
605 if (mMode == mode) {
606 return true;
607 }
608
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800609 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800610 LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
611 mMode = mode;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800612 return (mode == ON_HOLD) || mDeviceThread->start();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800613}
614
615bool AudioGroup::sendDtmf(int event)
616{
617 if (event < 0 || event > 15) {
618 return false;
619 }
620
621 // DTMF is rarely used, so we try to make it as lightweight as possible.
622 // Using volatile might be dodgy, but using a pipe or pthread primitives
623 // or stop-set-restart threads seems too heavy. Will investigate later.
624 timespec ts;
625 ts.tv_sec = 0;
626 ts.tv_nsec = 100000000;
627 for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
628 nanosleep(&ts, NULL);
629 }
630 if (mDtmfEvent != -1) {
631 return false;
632 }
633 mDtmfEvent = event;
634 nanosleep(&ts, NULL);
635 return true;
636}
637
638bool AudioGroup::add(AudioStream *stream)
639{
640 mNetworkThread->requestExitAndWait();
641
642 epoll_event event;
643 event.events = EPOLLIN;
644 event.data.ptr = stream;
645 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
646 LOGE("epoll_ctl: %s", strerror(errno));
647 return false;
648 }
649
650 stream->mNext = mChain->mNext;
651 mChain->mNext = stream;
652 if (!mNetworkThread->start()) {
653 // Only take over the stream when succeeded.
654 mChain->mNext = stream->mNext;
655 return false;
656 }
657
658 LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
659 return true;
660}
661
662bool AudioGroup::remove(int socket)
663{
664 mNetworkThread->requestExitAndWait();
665
666 for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
667 AudioStream *target = stream->mNext;
668 if (target->mSocket == socket) {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800669 if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
670 LOGE("epoll_ctl: %s", strerror(errno));
671 return false;
672 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800673 stream->mNext = target->mNext;
674 LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
675 delete target;
676 break;
677 }
678 }
679
680 // Do not start network thread if there is only one stream.
681 if (!mChain->mNext || !mNetworkThread->start()) {
682 return false;
683 }
684 return true;
685}
686
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800687bool AudioGroup::NetworkThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800688{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800689 AudioStream *chain = mGroup->mChain;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800690 int tick = elapsedRealtime();
691 int deadline = tick + 10;
692 int count = 0;
693
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800694 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh3520bd42010-09-30 13:48:07 +0800695 if (tick - stream->mTick >= 0) {
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800696 stream->encode(tick, chain);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800697 }
698 if (deadline - stream->mTick > 0) {
699 deadline = stream->mTick;
700 }
701 ++count;
702 }
703
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800704 int event = mGroup->mDtmfEvent;
705 if (event != -1) {
706 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800707 stream->sendDtmf(event);
708 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800709 mGroup->mDtmfEvent = -1;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800710 }
711
712 deadline -= tick;
713 if (deadline < 1) {
714 deadline = 1;
715 }
716
717 epoll_event events[count];
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800718 count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800719 if (count == -1) {
720 LOGE("epoll_wait: %s", strerror(errno));
721 return false;
722 }
723 for (int i = 0; i < count; ++i) {
724 ((AudioStream *)events[i].data.ptr)->decode(tick);
725 }
726
727 return true;
728}
729
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800730bool AudioGroup::DeviceThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800731{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800732 int mode = mGroup->mMode;
733 int sampleRate = mGroup->mSampleRate;
734 int sampleCount = mGroup->mSampleCount;
735 int deviceSocket = mGroup->mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800736
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800737 // Find out the frame count for AudioTrack and AudioRecord.
738 int output = 0;
739 int input = 0;
740 if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
741 sampleRate) != NO_ERROR || output <= 0 ||
742 AudioRecord::getMinFrameCount(&input, sampleRate,
743 AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
744 LOGE("cannot compute frame count");
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800745 return false;
746 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800747 LOGD("reported frame count: output %d, input %d", output, input);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800748
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800749 if (output < sampleCount * 2) {
750 output = sampleCount * 2;
751 }
752 if (input < sampleCount * 2) {
753 input = sampleCount * 2;
754 }
755 LOGD("adjusted frame count: output %d, input %d", output, input);
756
757 // Initialize AudioTrack and AudioRecord.
758 AudioTrack track;
759 AudioRecord record;
760 if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
761 AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
762 record.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
763 AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
764 LOGE("cannot initialize audio device");
765 return false;
766 }
767 LOGD("latency: output %d, input %d", track.latency(), record.latency());
768
769 // TODO: initialize echo canceler here.
770
771 // Give device socket a reasonable buffer size.
772 setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
773 setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
774
775 // Drain device socket.
776 char c;
777 while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
778
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800779 // Start AudioRecord before AudioTrack. This prevents AudioTrack from being
780 // disabled due to buffer underrun while waiting for AudioRecord.
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800781 if (mode != MUTED) {
782 record.start();
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800783 int16_t one;
784 record.read(&one, sizeof(one));
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800785 }
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800786 track.start();
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800787
788 while (!exitPending()) {
789 int16_t output[sampleCount];
790 if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
791 memset(output, 0, sizeof(output));
792 }
793
794 int16_t input[sampleCount];
795 int toWrite = sampleCount;
796 int toRead = (mode == MUTED) ? 0 : sampleCount;
797 int chances = 100;
798
799 while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
800 if (toWrite > 0) {
801 AudioTrack::Buffer buffer;
802 buffer.frameCount = toWrite;
803
804 status_t status = track.obtainBuffer(&buffer, 1);
805 if (status == NO_ERROR) {
806 int offset = sampleCount - toWrite;
807 memcpy(buffer.i8, &output[offset], buffer.size);
808 toWrite -= buffer.frameCount;
809 track.releaseBuffer(&buffer);
810 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
811 LOGE("cannot write to AudioTrack");
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800812 return true;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800813 }
814 }
815
816 if (toRead > 0) {
817 AudioRecord::Buffer buffer;
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800818 buffer.frameCount = toRead;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800819
820 status_t status = record.obtainBuffer(&buffer, 1);
821 if (status == NO_ERROR) {
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800822 int offset = sampleCount - toRead;
823 memcpy(&input[offset], buffer.i8, buffer.size);
824 toRead -= buffer.frameCount;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800825 record.releaseBuffer(&buffer);
826 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
827 LOGE("cannot read from AudioRecord");
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800828 return true;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800829 }
830 }
831 }
832
833 if (chances <= 0) {
Chia-chi Yeh67ecb5b2010-10-01 08:20:09 +0800834 LOGW("device loop timeout");
835 while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800836 }
837
838 if (mode != MUTED) {
839 if (mode == NORMAL) {
840 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
841 } else {
842 // TODO: Echo canceller runs here.
843 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
844 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800845 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800846 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800847 return false;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800848}
849
850//------------------------------------------------------------------------------
851
852static jfieldID gNative;
853static jfieldID gMode;
854
Chia-chi Yehb8790322010-08-19 18:26:53 +0800855void add(JNIEnv *env, jobject thiz, jint mode,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800856 jint socket, jstring jRemoteAddress, jint remotePort,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800857 jstring jCodecSpec, jint dtmfType)
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800858{
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800859 AudioCodec *codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800860 AudioStream *stream = NULL;
861 AudioGroup *group = NULL;
862
863 // Sanity check.
864 sockaddr_storage remote;
865 if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
866 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800867 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800868 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800869 if (!jCodecSpec) {
870 jniThrowNullPointerException(env, "codecSpec");
871 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800872 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800873 const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
874 if (!codecSpec) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800875 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800876 return;
877 }
878
879 // Create audio codec.
880 int codecType = -1;
881 char codecName[16];
882 int sampleRate = -1;
883 sscanf(codecSpec, "%d %[^/]%*c%d", &codecType, codecName, &sampleRate);
884 codec = newAudioCodec(codecName);
885 int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
886 env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
887 if (sampleCount <= 0) {
888 jniThrowException(env, "java/lang/IllegalStateException",
889 "cannot initialize audio codec");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800890 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800891 }
892
893 // Create audio stream.
894 stream = new AudioStream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800895 if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800896 codecType, dtmfType)) {
897 jniThrowException(env, "java/lang/IllegalStateException",
898 "cannot initialize audio stream");
899 goto error;
900 }
901 socket = -1;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800902 codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800903
904 // Create audio group.
905 group = (AudioGroup *)env->GetIntField(thiz, gNative);
906 if (!group) {
907 int mode = env->GetIntField(thiz, gMode);
908 group = new AudioGroup;
909 if (!group->set(8000, 256) || !group->setMode(mode)) {
910 jniThrowException(env, "java/lang/IllegalStateException",
911 "cannot initialize audio group");
912 goto error;
913 }
914 }
915
916 // Add audio stream into audio group.
917 if (!group->add(stream)) {
918 jniThrowException(env, "java/lang/IllegalStateException",
919 "cannot add audio stream");
920 goto error;
921 }
922
923 // Succeed.
924 env->SetIntField(thiz, gNative, (int)group);
Chia-chi Yehb8790322010-08-19 18:26:53 +0800925 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800926
927error:
928 delete group;
929 delete stream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800930 delete codec;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800931 close(socket);
932 env->SetIntField(thiz, gNative, NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800933}
934
935void remove(JNIEnv *env, jobject thiz, jint socket)
936{
937 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
938 if (group) {
939 if (socket == -1 || !group->remove(socket)) {
940 delete group;
941 env->SetIntField(thiz, gNative, NULL);
942 }
943 }
944}
945
946void setMode(JNIEnv *env, jobject thiz, jint mode)
947{
Chia-chi Yeh21ae1ad2010-09-30 16:07:44 +0800948 if (mode < 0 || mode > AudioGroup::LAST_MODE) {
949 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
950 return;
951 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800952 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
953 if (group && !group->setMode(mode)) {
954 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
955 return;
956 }
957 env->SetIntField(thiz, gMode, mode);
958}
959
960void sendDtmf(JNIEnv *env, jobject thiz, jint event)
961{
962 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
963 if (group && !group->sendDtmf(event)) {
964 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
965 }
966}
967
968JNINativeMethod gMethods[] = {
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800969 {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800970 {"remove", "(I)V", (void *)remove},
971 {"setMode", "(I)V", (void *)setMode},
972 {"sendDtmf", "(I)V", (void *)sendDtmf},
973};
974
975} // namespace
976
977int registerAudioGroup(JNIEnv *env)
978{
979 gRandom = open("/dev/urandom", O_RDONLY);
980 if (gRandom == -1) {
981 LOGE("urandom: %s", strerror(errno));
982 return -1;
983 }
984
985 jclass clazz;
986 if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
987 (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
988 (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
989 env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
990 LOGE("JNI registration failed");
991 return -1;
992 }
993 return 0;
994}