blob: 81d4dfc2c1b916364898866a3f4a62be8078601c [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:
Chung-yih Wangbd229422010-09-23 23:23:11 +080089 bool isNatAddress(struct sockaddr_storage *addr);
90
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080091 enum {
92 NORMAL = 0,
93 SEND_ONLY = 1,
94 RECEIVE_ONLY = 2,
95 LAST_MODE = 2,
96 };
97
98 int mMode;
99 int mSocket;
100 sockaddr_storage mRemote;
101 AudioCodec *mCodec;
102 uint32_t mCodecMagic;
103 uint32_t mDtmfMagic;
104
105 int mTick;
106 int mSampleRate;
107 int mSampleCount;
108 int mInterval;
repo sync7a69aef2010-09-23 05:46:01 +0800109 int mLogThrottle;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800110
111 int16_t *mBuffer;
112 int mBufferMask;
113 int mBufferHead;
114 int mBufferTail;
115 int mLatencyScore;
116
117 uint16_t mSequence;
118 uint32_t mTimestamp;
119 uint32_t mSsrc;
120
121 int mDtmfEvent;
122 int mDtmfStart;
123
124 AudioStream *mNext;
125
126 friend class AudioGroup;
127};
128
129AudioStream::AudioStream()
130{
131 mSocket = -1;
132 mCodec = NULL;
133 mBuffer = NULL;
134 mNext = NULL;
135}
136
137AudioStream::~AudioStream()
138{
139 close(mSocket);
140 delete mCodec;
141 delete [] mBuffer;
142 LOGD("stream[%d] is dead", mSocket);
143}
144
145bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800146 AudioCodec *codec, int sampleRate, int sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800147 int codecType, int dtmfType)
148{
149 if (mode < 0 || mode > LAST_MODE) {
150 return false;
151 }
152 mMode = mode;
153
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800154 mCodecMagic = (0x8000 | codecType) << 16;
155 mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
156
157 mTick = elapsedRealtime();
158 mSampleRate = sampleRate / 1000;
159 mSampleCount = sampleCount;
160 mInterval = mSampleCount / mSampleRate;
161
162 // Allocate jitter buffer.
163 for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1);
164 mBufferMask >>= 2;
165 mBuffer = new int16_t[mBufferMask];
166 --mBufferMask;
167 mBufferHead = 0;
168 mBufferTail = 0;
169 mLatencyScore = 0;
170
171 // Initialize random bits.
172 read(gRandom, &mSequence, sizeof(mSequence));
173 read(gRandom, &mTimestamp, sizeof(mTimestamp));
174 read(gRandom, &mSsrc, sizeof(mSsrc));
175
176 mDtmfEvent = -1;
177 mDtmfStart = 0;
178
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800179 // Only take over these things when succeeded.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800180 mSocket = socket;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800181 if (codec) {
182 mRemote = *remote;
183 mCodec = codec;
184 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800185
186 LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800187 (codec ? codec->name : "RAW"), mSampleRate, mInterval);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800188 return true;
189}
190
191void AudioStream::sendDtmf(int event)
192{
193 if (mDtmfMagic != 0) {
194 mDtmfEvent = event << 24;
195 mDtmfStart = mTimestamp + mSampleCount;
196 }
197}
198
199bool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
200{
201 if (mMode == SEND_ONLY) {
202 return false;
203 }
204
205 if (head - mBufferHead < 0) {
206 head = mBufferHead;
207 }
208 if (tail - mBufferTail > 0) {
209 tail = mBufferTail;
210 }
211 if (tail - head <= 0) {
212 return false;
213 }
214
215 head *= mSampleRate;
216 tail *= mSampleRate;
217
218 if (sampleRate == mSampleRate) {
219 for (int i = head; i - tail < 0; ++i) {
220 output[i - head] += mBuffer[i & mBufferMask];
221 }
222 } else {
223 // TODO: implement resampling.
224 return false;
225 }
226 return true;
227}
228
229void AudioStream::encode(int tick, AudioStream *chain)
230{
231 if (tick - mTick >= mInterval) {
232 // We just missed the train. Pretend that packets in between are lost.
233 int skipped = (tick - mTick) / mInterval;
234 mTick += skipped * mInterval;
235 mSequence += skipped;
236 mTimestamp += skipped * mSampleCount;
237 LOGD("stream[%d] skips %d packets", mSocket, skipped);
238 }
239
240 tick = mTick;
241 mTick += mInterval;
242 ++mSequence;
243 mTimestamp += mSampleCount;
244
245 if (mMode == RECEIVE_ONLY) {
246 return;
247 }
248
249 // If there is an ongoing DTMF event, send it now.
250 if (mDtmfEvent != -1) {
251 int duration = mTimestamp - mDtmfStart;
252 // Make sure duration is reasonable.
253 if (duration >= 0 && duration < mSampleRate * 100) {
254 duration += mSampleCount;
255 int32_t buffer[4] = {
256 htonl(mDtmfMagic | mSequence),
257 htonl(mDtmfStart),
258 mSsrc,
259 htonl(mDtmfEvent | duration),
260 };
261 if (duration >= mSampleRate * 100) {
262 buffer[3] |= htonl(1 << 23);
263 mDtmfEvent = -1;
264 }
265 sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
266 (sockaddr *)&mRemote, sizeof(mRemote));
267 return;
268 }
269 mDtmfEvent = -1;
270 }
271
272 // It is time to mix streams.
273 bool mixed = false;
274 int32_t buffer[mSampleCount + 3];
275 memset(buffer, 0, sizeof(buffer));
276 while (chain) {
277 if (chain != this &&
278 chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
279 mixed = true;
280 }
281 chain = chain->mNext;
282 }
283 if (!mixed) {
repo sync7a69aef2010-09-23 05:46:01 +0800284 if ((mTick ^ mLogThrottle) >> 10) {
285 mLogThrottle = mTick;
286 LOGD("stream[%d] no data", mSocket);
287 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800288 return;
289 }
290
291 // Cook the packet and send it out.
292 int16_t samples[mSampleCount];
293 for (int i = 0; i < mSampleCount; ++i) {
294 int32_t sample = buffer[i];
295 if (sample < -32768) {
296 sample = -32768;
297 }
298 if (sample > 32767) {
299 sample = 32767;
300 }
301 samples[i] = sample;
302 }
303 if (!mCodec) {
304 // Special case for device stream.
305 send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
306 return;
307 }
308
309 buffer[0] = htonl(mCodecMagic | mSequence);
310 buffer[1] = htonl(mTimestamp);
311 buffer[2] = mSsrc;
312 int length = mCodec->encode(&buffer[3], samples);
313 if (length <= 0) {
314 LOGD("stream[%d] encoder error", mSocket);
315 return;
316 }
317 sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
318 sizeof(mRemote));
319}
320
Chung-yih Wangbd229422010-09-23 23:23:11 +0800321bool AudioStream::isNatAddress(struct sockaddr_storage *addr) {
322 if (addr->ss_family != AF_INET) return false;
323 struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
324 unsigned char *d = (unsigned char *) &s4->sin_addr;
325 if ((d[0] == 10)
326 || ((d[0] == 172) && (d[1] & 0x10))
327 || ((d[0] == 192) && (d[1] == 168))) return true;
328 return false;
329}
330
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800331void AudioStream::decode(int tick)
332{
333 char c;
334 if (mMode == SEND_ONLY) {
335 recv(mSocket, &c, 1, MSG_DONTWAIT);
336 return;
337 }
338
339 // Make sure mBufferHead and mBufferTail are reasonable.
340 if ((unsigned int)(tick + 256 - mBufferHead) > 1024) {
341 mBufferHead = tick - 64;
342 mBufferTail = mBufferHead;
343 }
344
345 if (tick - mBufferHead > 64) {
346 // Throw away outdated samples.
347 mBufferHead = tick - 64;
348 if (mBufferTail - mBufferHead < 0) {
349 mBufferTail = mBufferHead;
350 }
351 }
352
353 if (mBufferTail - tick <= 80) {
354 mLatencyScore = tick;
355 } else if (tick - mLatencyScore >= 5000) {
356 // Reset the jitter buffer to 40ms if the latency keeps larger than 80ms
357 // in the past 5s. This rarely happens, so let us just keep it simple.
358 LOGD("stream[%d] latency control", mSocket);
359 mBufferTail = tick + 40;
360 }
361
362 if (mBufferTail - mBufferHead > 256 - mInterval) {
363 // Buffer overflow. Drop the packet.
364 LOGD("stream[%d] buffer overflow", mSocket);
365 recv(mSocket, &c, 1, MSG_DONTWAIT);
366 return;
367 }
368
369 // Receive the packet and decode it.
370 int16_t samples[mSampleCount];
371 int length = 0;
372 if (!mCodec) {
373 // Special case for device stream.
374 length = recv(mSocket, samples, sizeof(samples),
375 MSG_TRUNC | MSG_DONTWAIT) >> 1;
376 } else {
377 __attribute__((aligned(4))) uint8_t buffer[2048];
Chung-yih Wangbd229422010-09-23 23:23:11 +0800378 struct sockaddr_storage src_addr;
379 socklen_t addrlen;
380 length = recvfrom(mSocket, buffer, sizeof(buffer),
381 MSG_TRUNC|MSG_DONTWAIT, (sockaddr*)&src_addr, &addrlen);
382
383 // The following if clause is for fixing the target address if
384 // proxy server did not replace the NAT address with its media
385 // port in SDP. Although it is proxy server's responsibility for
386 // replacing the connection address with correct one, we will change
387 // the target address as we detect the difference for now until we
388 // know the best way to get rid of this issue.
389 if ((memcmp((void*)&src_addr, (void*)&mRemote, addrlen) != 0) &&
390 isNatAddress(&mRemote)) {
391 memcpy((void*)&mRemote, (void*)&src_addr, addrlen);
392 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800393
394 // Do we need to check SSRC, sequence, and timestamp? They are not
Chia-chi Yehb8790322010-08-19 18:26:53 +0800395 // reliable but at least they can be used to identify duplicates?
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800396 if (length < 12 || length > (int)sizeof(buffer) ||
397 (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
398 LOGD("stream[%d] malformed packet", mSocket);
399 return;
400 }
401 int offset = 12 + ((buffer[0] & 0x0F) << 2);
402 if ((buffer[0] & 0x10) != 0) {
403 offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
404 }
405 if ((buffer[0] & 0x20) != 0) {
406 length -= buffer[length - 1];
407 }
408 length -= offset;
409 if (length >= 0) {
410 length = mCodec->decode(samples, &buffer[offset], length);
411 }
412 }
413 if (length != mSampleCount) {
414 LOGD("stream[%d] decoder error", mSocket);
415 return;
416 }
417
418 if (tick - mBufferTail > 0) {
419 // Buffer underrun. Reset the jitter buffer to 40ms.
420 LOGD("stream[%d] buffer underrun", mSocket);
421 if (mBufferTail - mBufferHead <= 0) {
422 mBufferHead = tick + 40;
423 mBufferTail = mBufferHead;
424 } else {
425 int tail = (tick + 40) * mSampleRate;
426 for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
427 mBuffer[i & mBufferMask] = 0;
428 }
429 mBufferTail = tick + 40;
430 }
431 }
432
433 // Append to the jitter buffer.
434 int tail = mBufferTail * mSampleRate;
435 for (int i = 0; i < mSampleCount; ++i) {
436 mBuffer[tail & mBufferMask] = samples[i];
437 ++tail;
438 }
439 mBufferTail += mInterval;
440}
441
442//------------------------------------------------------------------------------
443
444class AudioGroup
445{
446public:
447 AudioGroup();
448 ~AudioGroup();
449 bool set(int sampleRate, int sampleCount);
450
451 bool setMode(int mode);
452 bool sendDtmf(int event);
453 bool add(AudioStream *stream);
454 bool remove(int socket);
455
456private:
457 enum {
458 ON_HOLD = 0,
459 MUTED = 1,
460 NORMAL = 2,
461 EC_ENABLED = 3,
462 LAST_MODE = 3,
463 };
464 int mMode;
465 AudioStream *mChain;
466 int mEventQueue;
467 volatile int mDtmfEvent;
468
469 int mSampleCount;
470 int mDeviceSocket;
471 AudioTrack mTrack;
472 AudioRecord mRecord;
473
474 bool networkLoop();
475 bool deviceLoop();
476
477 class NetworkThread : public Thread
478 {
479 public:
480 NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
481
482 bool start()
483 {
484 if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
485 LOGE("cannot start network thread");
486 return false;
487 }
488 return true;
489 }
490
491 private:
492 AudioGroup *mGroup;
493 bool threadLoop()
494 {
495 return mGroup->networkLoop();
496 }
497 };
498 sp<NetworkThread> mNetworkThread;
499
500 class DeviceThread : public Thread
501 {
502 public:
503 DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
504
505 bool start()
506 {
507 char c;
508 while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1);
509
510 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;
519 bool threadLoop()
520 {
521 return mGroup->deviceLoop();
522 }
523 };
524 sp<DeviceThread> mDeviceThread;
525};
526
527AudioGroup::AudioGroup()
528{
529 mMode = ON_HOLD;
530 mChain = NULL;
531 mEventQueue = -1;
532 mDtmfEvent = -1;
533 mDeviceSocket = -1;
534 mNetworkThread = new NetworkThread(this);
535 mDeviceThread = new DeviceThread(this);
536}
537
538AudioGroup::~AudioGroup()
539{
540 mNetworkThread->requestExitAndWait();
541 mDeviceThread->requestExitAndWait();
542 mTrack.stop();
543 mRecord.stop();
544 close(mEventQueue);
545 close(mDeviceSocket);
546 while (mChain) {
547 AudioStream *next = mChain->mNext;
548 delete mChain;
549 mChain = next;
550 }
551 LOGD("group[%d] is dead", mDeviceSocket);
552}
553
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800554bool AudioGroup::set(int sampleRate, int sampleCount)
555{
556 mEventQueue = epoll_create(2);
557 if (mEventQueue == -1) {
558 LOGE("epoll_create: %s", strerror(errno));
559 return false;
560 }
561
562 mSampleCount = sampleCount;
563
564 // Find out the frame count for AudioTrack and AudioRecord.
565 int output = 0;
566 int input = 0;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800567 if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
568 sampleRate) != NO_ERROR || output <= 0 ||
569 AudioRecord::getMinFrameCount(&input, sampleRate,
570 AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
571 LOGE("cannot compute frame count");
572 return false;
573 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800574 LOGD("reported frame count: output %d, input %d", output, input);
575
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800576 if (output < sampleCount * 2) {
577 output = sampleCount * 2;
578 }
579 if (input < sampleCount * 2) {
580 input = sampleCount * 2;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800581 }
582 LOGD("adjusted frame count: output %d, input %d", output, input);
583
584 // Initialize AudioTrack and AudioRecord.
585 if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
586 AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
587 mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
588 AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
589 LOGE("cannot initialize audio device");
590 return false;
591 }
592 LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
593
Chia-chi Yeh7fa7ee12010-08-26 10:33:09 +0800594 // TODO: initialize echo canceler here.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800595
596 // Create device socket.
597 int pair[2];
598 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
599 LOGE("socketpair: %s", strerror(errno));
600 return false;
601 }
602 mDeviceSocket = pair[0];
603
604 // Create device stream.
605 mChain = new AudioStream;
606 if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
607 sampleRate, sampleCount, -1, -1)) {
608 close(pair[1]);
609 LOGE("cannot initialize device stream");
610 return false;
611 }
612
613 // Give device socket a reasonable timeout and buffer size.
614 timeval tv;
615 tv.tv_sec = 0;
Chia-chi Yeh557b04d2010-09-08 09:56:02 +0800616 tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800617 if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
618 setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
619 setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
620 LOGE("setsockopt: %s", strerror(errno));
621 return false;
622 }
623
624 // Add device stream into event queue.
625 epoll_event event;
626 event.events = EPOLLIN;
627 event.data.ptr = mChain;
628 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
629 LOGE("epoll_ctl: %s", strerror(errno));
630 return false;
631 }
632
633 // Anything else?
634 LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
635 return true;
636}
637
638bool AudioGroup::setMode(int mode)
639{
640 if (mode < 0 || mode > LAST_MODE) {
641 return false;
642 }
643 if (mMode == mode) {
644 return true;
645 }
646
647 LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
648 mMode = mode;
649
650 mDeviceThread->requestExitAndWait();
651 if (mode == ON_HOLD) {
652 mTrack.stop();
653 mRecord.stop();
654 return true;
655 }
656
657 mTrack.start();
658 if (mode == MUTED) {
659 mRecord.stop();
660 } else {
661 mRecord.start();
662 }
663
664 if (!mDeviceThread->start()) {
665 mTrack.stop();
666 mRecord.stop();
667 return false;
668 }
669 return true;
670}
671
672bool AudioGroup::sendDtmf(int event)
673{
674 if (event < 0 || event > 15) {
675 return false;
676 }
677
678 // DTMF is rarely used, so we try to make it as lightweight as possible.
679 // Using volatile might be dodgy, but using a pipe or pthread primitives
680 // or stop-set-restart threads seems too heavy. Will investigate later.
681 timespec ts;
682 ts.tv_sec = 0;
683 ts.tv_nsec = 100000000;
684 for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
685 nanosleep(&ts, NULL);
686 }
687 if (mDtmfEvent != -1) {
688 return false;
689 }
690 mDtmfEvent = event;
691 nanosleep(&ts, NULL);
692 return true;
693}
694
695bool AudioGroup::add(AudioStream *stream)
696{
697 mNetworkThread->requestExitAndWait();
698
699 epoll_event event;
700 event.events = EPOLLIN;
701 event.data.ptr = stream;
702 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
703 LOGE("epoll_ctl: %s", strerror(errno));
704 return false;
705 }
706
707 stream->mNext = mChain->mNext;
708 mChain->mNext = stream;
709 if (!mNetworkThread->start()) {
710 // Only take over the stream when succeeded.
711 mChain->mNext = stream->mNext;
712 return false;
713 }
714
715 LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
716 return true;
717}
718
719bool AudioGroup::remove(int socket)
720{
721 mNetworkThread->requestExitAndWait();
722
723 for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
724 AudioStream *target = stream->mNext;
725 if (target->mSocket == socket) {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800726 if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
727 LOGE("epoll_ctl: %s", strerror(errno));
728 return false;
729 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800730 stream->mNext = target->mNext;
731 LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
732 delete target;
733 break;
734 }
735 }
736
737 // Do not start network thread if there is only one stream.
738 if (!mChain->mNext || !mNetworkThread->start()) {
739 return false;
740 }
741 return true;
742}
743
744bool AudioGroup::networkLoop()
745{
746 int tick = elapsedRealtime();
747 int deadline = tick + 10;
748 int count = 0;
749
750 for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
751 if (!stream->mTick || tick - stream->mTick >= 0) {
752 stream->encode(tick, mChain);
753 }
754 if (deadline - stream->mTick > 0) {
755 deadline = stream->mTick;
756 }
757 ++count;
758 }
759
760 if (mDtmfEvent != -1) {
761 int event = mDtmfEvent;
762 for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
763 stream->sendDtmf(event);
764 }
765 mDtmfEvent = -1;
766 }
767
768 deadline -= tick;
769 if (deadline < 1) {
770 deadline = 1;
771 }
772
773 epoll_event events[count];
774 count = epoll_wait(mEventQueue, events, count, deadline);
775 if (count == -1) {
776 LOGE("epoll_wait: %s", strerror(errno));
777 return false;
778 }
779 for (int i = 0; i < count; ++i) {
780 ((AudioStream *)events[i].data.ptr)->decode(tick);
781 }
782
783 return true;
784}
785
786bool AudioGroup::deviceLoop()
787{
788 int16_t output[mSampleCount];
789
790 if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
791 memset(output, 0, sizeof(output));
792 }
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800793
794 int16_t input[mSampleCount];
795 int toWrite = mSampleCount;
796 int toRead = (mMode == MUTED) ? 0 : mSampleCount;
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 = mTrack.obtainBuffer(&buffer, 1);
805 if (status == NO_ERROR) {
806 memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
807 toWrite -= buffer.frameCount;
808 mTrack.releaseBuffer(&buffer);
809 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
810 LOGE("cannot write to AudioTrack");
811 return false;
812 }
813 }
814
815 if (toRead > 0) {
816 AudioRecord::Buffer buffer;
817 buffer.frameCount = mRecord.frameCount();
818
819 status_t status = mRecord.obtainBuffer(&buffer, 1);
820 if (status == NO_ERROR) {
Chia-chi Yeh557b04d2010-09-08 09:56:02 +0800821 int count = ((int)buffer.frameCount < toRead) ?
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800822 buffer.frameCount : toRead;
823 memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
824 toRead -= count;
825 if (buffer.frameCount < mRecord.frameCount()) {
826 buffer.frameCount = count;
827 }
828 mRecord.releaseBuffer(&buffer);
829 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
830 LOGE("cannot read from AudioRecord");
831 return false;
832 }
833 }
834 }
835
836 if (!chances) {
837 LOGE("device loop timeout");
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800838 return false;
839 }
840
841 if (mMode != MUTED) {
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800842 if (mMode == NORMAL) {
843 send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800844 } else {
Chia-chi Yeh7fa7ee12010-08-26 10:33:09 +0800845 // TODO: Echo canceller runs here.
846 send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800847 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800848 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800849 return true;
850}
851
852//------------------------------------------------------------------------------
853
854static jfieldID gNative;
855static jfieldID gMode;
856
Chia-chi Yehb8790322010-08-19 18:26:53 +0800857void add(JNIEnv *env, jobject thiz, jint mode,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800858 jint socket, jstring jRemoteAddress, jint remotePort,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800859 jstring jCodecSpec, jint dtmfType)
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800860{
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800861 AudioCodec *codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800862 AudioStream *stream = NULL;
863 AudioGroup *group = NULL;
864
865 // Sanity check.
866 sockaddr_storage remote;
867 if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
868 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800869 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800870 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800871 if (!jCodecSpec) {
872 jniThrowNullPointerException(env, "codecSpec");
873 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800874 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800875 const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
876 if (!codecSpec) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800877 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800878 return;
879 }
880
881 // Create audio codec.
882 int codecType = -1;
883 char codecName[16];
884 int sampleRate = -1;
885 sscanf(codecSpec, "%d %[^/]%*c%d", &codecType, codecName, &sampleRate);
886 codec = newAudioCodec(codecName);
887 int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
888 env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
889 if (sampleCount <= 0) {
890 jniThrowException(env, "java/lang/IllegalStateException",
891 "cannot initialize audio codec");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800892 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800893 }
894
895 // Create audio stream.
896 stream = new AudioStream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800897 if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800898 codecType, dtmfType)) {
899 jniThrowException(env, "java/lang/IllegalStateException",
900 "cannot initialize audio stream");
901 goto error;
902 }
903 socket = -1;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800904 codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800905
906 // Create audio group.
907 group = (AudioGroup *)env->GetIntField(thiz, gNative);
908 if (!group) {
909 int mode = env->GetIntField(thiz, gMode);
910 group = new AudioGroup;
911 if (!group->set(8000, 256) || !group->setMode(mode)) {
912 jniThrowException(env, "java/lang/IllegalStateException",
913 "cannot initialize audio group");
914 goto error;
915 }
916 }
917
918 // Add audio stream into audio group.
919 if (!group->add(stream)) {
920 jniThrowException(env, "java/lang/IllegalStateException",
921 "cannot add audio stream");
922 goto error;
923 }
924
925 // Succeed.
926 env->SetIntField(thiz, gNative, (int)group);
Chia-chi Yehb8790322010-08-19 18:26:53 +0800927 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800928
929error:
930 delete group;
931 delete stream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800932 delete codec;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800933 close(socket);
934 env->SetIntField(thiz, gNative, NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800935}
936
937void remove(JNIEnv *env, jobject thiz, jint socket)
938{
939 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
940 if (group) {
941 if (socket == -1 || !group->remove(socket)) {
942 delete group;
943 env->SetIntField(thiz, gNative, NULL);
944 }
945 }
946}
947
948void setMode(JNIEnv *env, jobject thiz, jint mode)
949{
950 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
951 if (group && !group->setMode(mode)) {
952 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
953 return;
954 }
955 env->SetIntField(thiz, gMode, mode);
956}
957
958void sendDtmf(JNIEnv *env, jobject thiz, jint event)
959{
960 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
961 if (group && !group->sendDtmf(event)) {
962 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
963 }
964}
965
966JNINativeMethod gMethods[] = {
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800967 {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800968 {"remove", "(I)V", (void *)remove},
969 {"setMode", "(I)V", (void *)setMode},
970 {"sendDtmf", "(I)V", (void *)sendDtmf},
971};
972
973} // namespace
974
975int registerAudioGroup(JNIEnv *env)
976{
977 gRandom = open("/dev/urandom", O_RDONLY);
978 if (gRandom == -1) {
979 LOGE("urandom: %s", strerror(errno));
980 return -1;
981 }
982
983 jclass clazz;
984 if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
985 (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
986 (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
987 env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
988 LOGE("JNI registration failed");
989 return -1;
990 }
991 return 0;
992}