blob: f09edb6907a9b3ac5b41f68c8d9ae3cc5040623a [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.
60// Currently we make it 256ms long and assume packet interval is 32ms or less.
61// The first 64ms is the place where samples get mixed. The rest 192ms is the
62// real jitter buffer. For a stream at 8000Hz it takes 4096 bytes. These numbers
63// 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.
72// For the first release we might only support 8kHz and 16kHz.
73
74class AudioStream
75{
76public:
77 AudioStream();
78 ~AudioStream();
79 bool set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +080080 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080081 int codecType, int dtmfType);
82
83 void sendDtmf(int event);
84 bool mix(int32_t *output, int head, int tail, int sampleRate);
85 void encode(int tick, AudioStream *chain);
86 void decode(int tick);
87
88private:
89 enum {
90 NORMAL = 0,
91 SEND_ONLY = 1,
92 RECEIVE_ONLY = 2,
93 LAST_MODE = 2,
94 };
95
96 int mMode;
97 int mSocket;
98 sockaddr_storage mRemote;
99 AudioCodec *mCodec;
100 uint32_t mCodecMagic;
101 uint32_t mDtmfMagic;
Chia-chi Yehfe529892010-09-30 02:42:27 +0800102 bool mFixRemote;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800103
104 int mTick;
105 int mSampleRate;
106 int mSampleCount;
107 int mInterval;
repo sync7a69aef2010-09-23 05:46:01 +0800108 int mLogThrottle;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800109
110 int16_t *mBuffer;
111 int mBufferMask;
112 int mBufferHead;
113 int mBufferTail;
114 int mLatencyScore;
115
116 uint16_t mSequence;
117 uint32_t mTimestamp;
118 uint32_t mSsrc;
119
120 int mDtmfEvent;
121 int mDtmfStart;
122
123 AudioStream *mNext;
124
125 friend class AudioGroup;
126};
127
128AudioStream::AudioStream()
129{
130 mSocket = -1;
131 mCodec = NULL;
132 mBuffer = NULL;
133 mNext = NULL;
134}
135
136AudioStream::~AudioStream()
137{
138 close(mSocket);
139 delete mCodec;
140 delete [] mBuffer;
141 LOGD("stream[%d] is dead", mSocket);
142}
143
144bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800145 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800146 int codecType, int dtmfType)
147{
148 if (mode < 0 || mode > LAST_MODE) {
149 return false;
150 }
151 mMode = mode;
152
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800153 mCodecMagic = (0x8000 | codecType) << 16;
154 mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
155
156 mTick = elapsedRealtime();
157 mSampleRate = sampleRate / 1000;
158 mSampleCount = sampleCount;
159 mInterval = mSampleCount / mSampleRate;
160
161 // Allocate jitter buffer.
162 for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1);
163 mBufferMask >>= 2;
164 mBuffer = new int16_t[mBufferMask];
165 --mBufferMask;
166 mBufferHead = 0;
167 mBufferTail = 0;
168 mLatencyScore = 0;
169
170 // Initialize random bits.
171 read(gRandom, &mSequence, sizeof(mSequence));
172 read(gRandom, &mTimestamp, sizeof(mTimestamp));
173 read(gRandom, &mSsrc, sizeof(mSsrc));
174
175 mDtmfEvent = -1;
176 mDtmfStart = 0;
177
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800178 // Only take over these things when succeeded.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800179 mSocket = socket;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800180 if (codec) {
181 mRemote = *remote;
182 mCodec = codec;
Chia-chi Yehfe529892010-09-30 02:42:27 +0800183
184 // Here we should never get an private address, but some buggy proxy
185 // servers do give us one. To solve this, we replace the address when
186 // the first time we successfully decode an incoming packet.
187 mFixRemote = false;
188 if (remote->ss_family == AF_INET) {
189 unsigned char *address =
190 (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
191 if (address[0] == 10 ||
192 (address[0] == 172 && (address[1] >> 4) == 1) ||
193 (address[0] == 192 && address[1] == 168)) {
194 mFixRemote = true;
195 }
196 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800197 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800198
199 LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800200 (codec ? codec->name : "RAW"), mSampleRate, mInterval);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800201 return true;
202}
203
204void AudioStream::sendDtmf(int event)
205{
206 if (mDtmfMagic != 0) {
207 mDtmfEvent = event << 24;
208 mDtmfStart = mTimestamp + mSampleCount;
209 }
210}
211
212bool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
213{
214 if (mMode == SEND_ONLY) {
215 return false;
216 }
217
218 if (head - mBufferHead < 0) {
219 head = mBufferHead;
220 }
221 if (tail - mBufferTail > 0) {
222 tail = mBufferTail;
223 }
224 if (tail - head <= 0) {
225 return false;
226 }
227
228 head *= mSampleRate;
229 tail *= mSampleRate;
230
231 if (sampleRate == mSampleRate) {
232 for (int i = head; i - tail < 0; ++i) {
233 output[i - head] += mBuffer[i & mBufferMask];
234 }
235 } else {
236 // TODO: implement resampling.
237 return false;
238 }
239 return true;
240}
241
242void AudioStream::encode(int tick, AudioStream *chain)
243{
244 if (tick - mTick >= mInterval) {
245 // We just missed the train. Pretend that packets in between are lost.
246 int skipped = (tick - mTick) / mInterval;
247 mTick += skipped * mInterval;
248 mSequence += skipped;
249 mTimestamp += skipped * mSampleCount;
250 LOGD("stream[%d] skips %d packets", mSocket, skipped);
251 }
252
253 tick = mTick;
254 mTick += mInterval;
255 ++mSequence;
256 mTimestamp += mSampleCount;
257
258 if (mMode == RECEIVE_ONLY) {
259 return;
260 }
261
262 // If there is an ongoing DTMF event, send it now.
263 if (mDtmfEvent != -1) {
264 int duration = mTimestamp - mDtmfStart;
265 // Make sure duration is reasonable.
266 if (duration >= 0 && duration < mSampleRate * 100) {
267 duration += mSampleCount;
268 int32_t buffer[4] = {
269 htonl(mDtmfMagic | mSequence),
270 htonl(mDtmfStart),
271 mSsrc,
272 htonl(mDtmfEvent | duration),
273 };
274 if (duration >= mSampleRate * 100) {
275 buffer[3] |= htonl(1 << 23);
276 mDtmfEvent = -1;
277 }
278 sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
279 (sockaddr *)&mRemote, sizeof(mRemote));
280 return;
281 }
282 mDtmfEvent = -1;
283 }
284
285 // It is time to mix streams.
286 bool mixed = false;
287 int32_t buffer[mSampleCount + 3];
288 memset(buffer, 0, sizeof(buffer));
289 while (chain) {
290 if (chain != this &&
291 chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
292 mixed = true;
293 }
294 chain = chain->mNext;
295 }
296 if (!mixed) {
repo sync7a69aef2010-09-23 05:46:01 +0800297 if ((mTick ^ mLogThrottle) >> 10) {
298 mLogThrottle = mTick;
299 LOGD("stream[%d] no data", mSocket);
300 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800301 return;
302 }
303
304 // Cook the packet and send it out.
305 int16_t samples[mSampleCount];
306 for (int i = 0; i < mSampleCount; ++i) {
307 int32_t sample = buffer[i];
308 if (sample < -32768) {
309 sample = -32768;
310 }
311 if (sample > 32767) {
312 sample = 32767;
313 }
314 samples[i] = sample;
315 }
316 if (!mCodec) {
317 // Special case for device stream.
318 send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
319 return;
320 }
321
322 buffer[0] = htonl(mCodecMagic | mSequence);
323 buffer[1] = htonl(mTimestamp);
324 buffer[2] = mSsrc;
325 int length = mCodec->encode(&buffer[3], samples);
326 if (length <= 0) {
327 LOGD("stream[%d] encoder error", mSocket);
328 return;
329 }
330 sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
331 sizeof(mRemote));
332}
333
334void AudioStream::decode(int tick)
335{
336 char c;
337 if (mMode == SEND_ONLY) {
338 recv(mSocket, &c, 1, MSG_DONTWAIT);
339 return;
340 }
341
342 // Make sure mBufferHead and mBufferTail are reasonable.
343 if ((unsigned int)(tick + 256 - mBufferHead) > 1024) {
344 mBufferHead = tick - 64;
345 mBufferTail = mBufferHead;
346 }
347
348 if (tick - mBufferHead > 64) {
349 // Throw away outdated samples.
350 mBufferHead = tick - 64;
351 if (mBufferTail - mBufferHead < 0) {
352 mBufferTail = mBufferHead;
353 }
354 }
355
356 if (mBufferTail - tick <= 80) {
357 mLatencyScore = tick;
358 } else if (tick - mLatencyScore >= 5000) {
359 // Reset the jitter buffer to 40ms if the latency keeps larger than 80ms
360 // in the past 5s. This rarely happens, so let us just keep it simple.
361 LOGD("stream[%d] latency control", mSocket);
362 mBufferTail = tick + 40;
363 }
364
365 if (mBufferTail - mBufferHead > 256 - mInterval) {
366 // Buffer overflow. Drop the packet.
367 LOGD("stream[%d] buffer overflow", mSocket);
368 recv(mSocket, &c, 1, MSG_DONTWAIT);
369 return;
370 }
371
372 // Receive the packet and decode it.
373 int16_t samples[mSampleCount];
374 int length = 0;
375 if (!mCodec) {
376 // Special case for device stream.
377 length = recv(mSocket, samples, sizeof(samples),
378 MSG_TRUNC | MSG_DONTWAIT) >> 1;
379 } else {
380 __attribute__((aligned(4))) uint8_t buffer[2048];
Chia-chi Yehfe529892010-09-30 02:42:27 +0800381 sockaddr_storage remote;
382 socklen_t len = sizeof(remote);
Chung-yih Wangbd229422010-09-23 23:23:11 +0800383
Chia-chi Yehfe529892010-09-30 02:42:27 +0800384 length = recvfrom(mSocket, buffer, sizeof(buffer),
385 MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800386
387 // Do we need to check SSRC, sequence, and timestamp? They are not
Chia-chi Yehb8790322010-08-19 18:26:53 +0800388 // reliable but at least they can be used to identify duplicates?
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800389 if (length < 12 || length > (int)sizeof(buffer) ||
390 (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
391 LOGD("stream[%d] malformed packet", mSocket);
392 return;
393 }
394 int offset = 12 + ((buffer[0] & 0x0F) << 2);
395 if ((buffer[0] & 0x10) != 0) {
396 offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
397 }
398 if ((buffer[0] & 0x20) != 0) {
399 length -= buffer[length - 1];
400 }
401 length -= offset;
402 if (length >= 0) {
403 length = mCodec->decode(samples, &buffer[offset], length);
404 }
Chia-chi Yehfe529892010-09-30 02:42:27 +0800405 if (length > 0 && mFixRemote) {
406 mRemote = remote;
407 mFixRemote = false;
408 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800409 }
Chia-chi Yehfe529892010-09-30 02:42:27 +0800410 if (length <= 0) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800411 LOGD("stream[%d] decoder error", mSocket);
412 return;
413 }
414
415 if (tick - mBufferTail > 0) {
416 // Buffer underrun. Reset the jitter buffer to 40ms.
417 LOGD("stream[%d] buffer underrun", mSocket);
418 if (mBufferTail - mBufferHead <= 0) {
419 mBufferHead = tick + 40;
420 mBufferTail = mBufferHead;
421 } else {
422 int tail = (tick + 40) * mSampleRate;
423 for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
424 mBuffer[i & mBufferMask] = 0;
425 }
426 mBufferTail = tick + 40;
427 }
428 }
429
430 // Append to the jitter buffer.
431 int tail = mBufferTail * mSampleRate;
432 for (int i = 0; i < mSampleCount; ++i) {
433 mBuffer[tail & mBufferMask] = samples[i];
434 ++tail;
435 }
436 mBufferTail += mInterval;
437}
438
439//------------------------------------------------------------------------------
440
441class AudioGroup
442{
443public:
444 AudioGroup();
445 ~AudioGroup();
446 bool set(int sampleRate, int sampleCount);
447
448 bool setMode(int mode);
449 bool sendDtmf(int event);
450 bool add(AudioStream *stream);
451 bool remove(int socket);
452
453private:
454 enum {
455 ON_HOLD = 0,
456 MUTED = 1,
457 NORMAL = 2,
458 EC_ENABLED = 3,
459 LAST_MODE = 3,
460 };
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800461
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800462 AudioStream *mChain;
463 int mEventQueue;
464 volatile int mDtmfEvent;
465
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800466 int mMode;
467 int mSampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800468 int mSampleCount;
469 int mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800470
471 class NetworkThread : public Thread
472 {
473 public:
474 NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
475
476 bool start()
477 {
478 if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
479 LOGE("cannot start network thread");
480 return false;
481 }
482 return true;
483 }
484
485 private:
486 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800487 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800488 };
489 sp<NetworkThread> mNetworkThread;
490
491 class DeviceThread : public Thread
492 {
493 public:
494 DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
495
496 bool start()
497 {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800498 if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
499 LOGE("cannot start device thread");
500 return false;
501 }
502 return true;
503 }
504
505 private:
506 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800507 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800508 };
509 sp<DeviceThread> mDeviceThread;
510};
511
512AudioGroup::AudioGroup()
513{
514 mMode = ON_HOLD;
515 mChain = NULL;
516 mEventQueue = -1;
517 mDtmfEvent = -1;
518 mDeviceSocket = -1;
519 mNetworkThread = new NetworkThread(this);
520 mDeviceThread = new DeviceThread(this);
521}
522
523AudioGroup::~AudioGroup()
524{
525 mNetworkThread->requestExitAndWait();
526 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800527 close(mEventQueue);
528 close(mDeviceSocket);
529 while (mChain) {
530 AudioStream *next = mChain->mNext;
531 delete mChain;
532 mChain = next;
533 }
534 LOGD("group[%d] is dead", mDeviceSocket);
535}
536
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800537bool AudioGroup::set(int sampleRate, int sampleCount)
538{
539 mEventQueue = epoll_create(2);
540 if (mEventQueue == -1) {
541 LOGE("epoll_create: %s", strerror(errno));
542 return false;
543 }
544
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800545 mSampleRate = sampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800546 mSampleCount = sampleCount;
547
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800548 // Create device socket.
549 int pair[2];
550 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
551 LOGE("socketpair: %s", strerror(errno));
552 return false;
553 }
554 mDeviceSocket = pair[0];
555
556 // Create device stream.
557 mChain = new AudioStream;
558 if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
559 sampleRate, sampleCount, -1, -1)) {
560 close(pair[1]);
561 LOGE("cannot initialize device stream");
562 return false;
563 }
564
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800565 // Give device socket a reasonable timeout.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800566 timeval tv;
567 tv.tv_sec = 0;
Chia-chi Yeh557b04d2010-09-08 09:56:02 +0800568 tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800569 if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800570 LOGE("setsockopt: %s", strerror(errno));
571 return false;
572 }
573
574 // Add device stream into event queue.
575 epoll_event event;
576 event.events = EPOLLIN;
577 event.data.ptr = mChain;
578 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
579 LOGE("epoll_ctl: %s", strerror(errno));
580 return false;
581 }
582
583 // Anything else?
584 LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
585 return true;
586}
587
588bool AudioGroup::setMode(int mode)
589{
590 if (mode < 0 || mode > LAST_MODE) {
591 return false;
592 }
593 if (mMode == mode) {
594 return true;
595 }
596
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800597 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800598 LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
599 mMode = mode;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800600 return (mode == ON_HOLD) || mDeviceThread->start();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800601}
602
603bool AudioGroup::sendDtmf(int event)
604{
605 if (event < 0 || event > 15) {
606 return false;
607 }
608
609 // DTMF is rarely used, so we try to make it as lightweight as possible.
610 // Using volatile might be dodgy, but using a pipe or pthread primitives
611 // or stop-set-restart threads seems too heavy. Will investigate later.
612 timespec ts;
613 ts.tv_sec = 0;
614 ts.tv_nsec = 100000000;
615 for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
616 nanosleep(&ts, NULL);
617 }
618 if (mDtmfEvent != -1) {
619 return false;
620 }
621 mDtmfEvent = event;
622 nanosleep(&ts, NULL);
623 return true;
624}
625
626bool AudioGroup::add(AudioStream *stream)
627{
628 mNetworkThread->requestExitAndWait();
629
630 epoll_event event;
631 event.events = EPOLLIN;
632 event.data.ptr = stream;
633 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
634 LOGE("epoll_ctl: %s", strerror(errno));
635 return false;
636 }
637
638 stream->mNext = mChain->mNext;
639 mChain->mNext = stream;
640 if (!mNetworkThread->start()) {
641 // Only take over the stream when succeeded.
642 mChain->mNext = stream->mNext;
643 return false;
644 }
645
646 LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
647 return true;
648}
649
650bool AudioGroup::remove(int socket)
651{
652 mNetworkThread->requestExitAndWait();
653
654 for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
655 AudioStream *target = stream->mNext;
656 if (target->mSocket == socket) {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800657 if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
658 LOGE("epoll_ctl: %s", strerror(errno));
659 return false;
660 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800661 stream->mNext = target->mNext;
662 LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
663 delete target;
664 break;
665 }
666 }
667
668 // Do not start network thread if there is only one stream.
669 if (!mChain->mNext || !mNetworkThread->start()) {
670 return false;
671 }
672 return true;
673}
674
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800675bool AudioGroup::NetworkThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800676{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800677 AudioStream *chain = mGroup->mChain;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800678 int tick = elapsedRealtime();
679 int deadline = tick + 10;
680 int count = 0;
681
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800682 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800683 if (!stream->mTick || tick - stream->mTick >= 0) {
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800684 stream->encode(tick, chain);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800685 }
686 if (deadline - stream->mTick > 0) {
687 deadline = stream->mTick;
688 }
689 ++count;
690 }
691
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800692 int event = mGroup->mDtmfEvent;
693 if (event != -1) {
694 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800695 stream->sendDtmf(event);
696 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800697 mGroup->mDtmfEvent = -1;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800698 }
699
700 deadline -= tick;
701 if (deadline < 1) {
702 deadline = 1;
703 }
704
705 epoll_event events[count];
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800706 count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800707 if (count == -1) {
708 LOGE("epoll_wait: %s", strerror(errno));
709 return false;
710 }
711 for (int i = 0; i < count; ++i) {
712 ((AudioStream *)events[i].data.ptr)->decode(tick);
713 }
714
715 return true;
716}
717
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800718bool AudioGroup::DeviceThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800719{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800720 int mode = mGroup->mMode;
721 int sampleRate = mGroup->mSampleRate;
722 int sampleCount = mGroup->mSampleCount;
723 int deviceSocket = mGroup->mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800724
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800725 // Find out the frame count for AudioTrack and AudioRecord.
726 int output = 0;
727 int input = 0;
728 if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
729 sampleRate) != NO_ERROR || output <= 0 ||
730 AudioRecord::getMinFrameCount(&input, sampleRate,
731 AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
732 LOGE("cannot compute frame count");
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800733 return false;
734 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800735 LOGD("reported frame count: output %d, input %d", output, input);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800736
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800737 if (output < sampleCount * 2) {
738 output = sampleCount * 2;
739 }
740 if (input < sampleCount * 2) {
741 input = sampleCount * 2;
742 }
743 LOGD("adjusted frame count: output %d, input %d", output, input);
744
745 // Initialize AudioTrack and AudioRecord.
746 AudioTrack track;
747 AudioRecord record;
748 if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
749 AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
750 record.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
751 AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
752 LOGE("cannot initialize audio device");
753 return false;
754 }
755 LOGD("latency: output %d, input %d", track.latency(), record.latency());
756
757 // TODO: initialize echo canceler here.
758
759 // Give device socket a reasonable buffer size.
760 setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
761 setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
762
763 // Drain device socket.
764 char c;
765 while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
766
767 // Start your engine!
768 track.start();
769 if (mode != MUTED) {
770 record.start();
771 }
772
773 while (!exitPending()) {
774 int16_t output[sampleCount];
775 if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
776 memset(output, 0, sizeof(output));
777 }
778
779 int16_t input[sampleCount];
780 int toWrite = sampleCount;
781 int toRead = (mode == MUTED) ? 0 : sampleCount;
782 int chances = 100;
783
784 while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
785 if (toWrite > 0) {
786 AudioTrack::Buffer buffer;
787 buffer.frameCount = toWrite;
788
789 status_t status = track.obtainBuffer(&buffer, 1);
790 if (status == NO_ERROR) {
791 int offset = sampleCount - toWrite;
792 memcpy(buffer.i8, &output[offset], buffer.size);
793 toWrite -= buffer.frameCount;
794 track.releaseBuffer(&buffer);
795 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
796 LOGE("cannot write to AudioTrack");
797 break;
798 }
799 }
800
801 if (toRead > 0) {
802 AudioRecord::Buffer buffer;
803 buffer.frameCount = record.frameCount();
804
805 status_t status = record.obtainBuffer(&buffer, 1);
806 if (status == NO_ERROR) {
807 int count = ((int)buffer.frameCount < toRead) ?
808 buffer.frameCount : toRead;
809 memcpy(&input[sampleCount - toRead], buffer.i8, count * 2);
810 toRead -= count;
811 if (buffer.frameCount < record.frameCount()) {
812 buffer.frameCount = count;
813 }
814 record.releaseBuffer(&buffer);
815 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
816 LOGE("cannot read from AudioRecord");
817 break;
818 }
819 }
820 }
821
822 if (chances <= 0) {
823 LOGE("device loop timeout");
824 break;
825 }
826
827 if (mode != MUTED) {
828 if (mode == NORMAL) {
829 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
830 } else {
831 // TODO: Echo canceller runs here.
832 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
833 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800834 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800835 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800836 return false;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800837}
838
839//------------------------------------------------------------------------------
840
841static jfieldID gNative;
842static jfieldID gMode;
843
Chia-chi Yehb8790322010-08-19 18:26:53 +0800844void add(JNIEnv *env, jobject thiz, jint mode,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800845 jint socket, jstring jRemoteAddress, jint remotePort,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800846 jstring jCodecSpec, jint dtmfType)
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800847{
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800848 AudioCodec *codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800849 AudioStream *stream = NULL;
850 AudioGroup *group = NULL;
851
852 // Sanity check.
853 sockaddr_storage remote;
854 if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
855 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800856 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800857 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800858 if (!jCodecSpec) {
859 jniThrowNullPointerException(env, "codecSpec");
860 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800861 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800862 const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
863 if (!codecSpec) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800864 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800865 return;
866 }
867
868 // Create audio codec.
869 int codecType = -1;
870 char codecName[16];
871 int sampleRate = -1;
872 sscanf(codecSpec, "%d %[^/]%*c%d", &codecType, codecName, &sampleRate);
873 codec = newAudioCodec(codecName);
874 int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
875 env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
876 if (sampleCount <= 0) {
877 jniThrowException(env, "java/lang/IllegalStateException",
878 "cannot initialize audio codec");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800879 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800880 }
881
882 // Create audio stream.
883 stream = new AudioStream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800884 if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800885 codecType, dtmfType)) {
886 jniThrowException(env, "java/lang/IllegalStateException",
887 "cannot initialize audio stream");
888 goto error;
889 }
890 socket = -1;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800891 codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800892
893 // Create audio group.
894 group = (AudioGroup *)env->GetIntField(thiz, gNative);
895 if (!group) {
896 int mode = env->GetIntField(thiz, gMode);
897 group = new AudioGroup;
898 if (!group->set(8000, 256) || !group->setMode(mode)) {
899 jniThrowException(env, "java/lang/IllegalStateException",
900 "cannot initialize audio group");
901 goto error;
902 }
903 }
904
905 // Add audio stream into audio group.
906 if (!group->add(stream)) {
907 jniThrowException(env, "java/lang/IllegalStateException",
908 "cannot add audio stream");
909 goto error;
910 }
911
912 // Succeed.
913 env->SetIntField(thiz, gNative, (int)group);
Chia-chi Yehb8790322010-08-19 18:26:53 +0800914 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800915
916error:
917 delete group;
918 delete stream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800919 delete codec;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800920 close(socket);
921 env->SetIntField(thiz, gNative, NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800922}
923
924void remove(JNIEnv *env, jobject thiz, jint socket)
925{
926 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
927 if (group) {
928 if (socket == -1 || !group->remove(socket)) {
929 delete group;
930 env->SetIntField(thiz, gNative, NULL);
931 }
932 }
933}
934
935void setMode(JNIEnv *env, jobject thiz, jint mode)
936{
937 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
938 if (group && !group->setMode(mode)) {
939 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
940 return;
941 }
942 env->SetIntField(thiz, gMode, mode);
943}
944
945void sendDtmf(JNIEnv *env, jobject thiz, jint event)
946{
947 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
948 if (group && !group->sendDtmf(event)) {
949 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
950 }
951}
952
953JNINativeMethod gMethods[] = {
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800954 {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800955 {"remove", "(I)V", (void *)remove},
956 {"setMode", "(I)V", (void *)setMode},
957 {"sendDtmf", "(I)V", (void *)sendDtmf},
958};
959
960} // namespace
961
962int registerAudioGroup(JNIEnv *env)
963{
964 gRandom = open("/dev/urandom", O_RDONLY);
965 if (gRandom == -1) {
966 LOGE("urandom: %s", strerror(errno));
967 return -1;
968 }
969
970 jclass clazz;
971 if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
972 (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
973 (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
974 env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
975 LOGE("JNI registration failed");
976 return -1;
977 }
978 return 0;
979}