blob: b5a4e22599fc8365333c57e9b497bb592cc4ffd0 [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
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +080043#include <speex/speex_echo.h>
44
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +080045#include "jni.h"
46#include "JNIHelp.h"
47
48#include "AudioCodec.h"
49
50extern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
51
52namespace {
53
54using namespace android;
55
56int gRandom = -1;
57
58// We use a circular array to implement jitter buffer. The simplest way is doing
59// a modulo operation on the index while accessing the array. However modulo can
60// be expensive on some platforms, such as ARM. Thus we round up the size of the
61// array to the nearest power of 2 and then use bitwise-and instead of modulo.
62// Currently we make it 256ms long and assume packet interval is 32ms or less.
63// The first 64ms is the place where samples get mixed. The rest 192ms is the
64// real jitter buffer. For a stream at 8000Hz it takes 4096 bytes. These numbers
65// are chosen by experiments and each of them can be adjusted as needed.
66
67// Other notes:
68// + We use elapsedRealtime() to get the time. Since we use 32bit variables
69// instead of 64bit ones, comparison must be done by subtraction.
70// + Sampling rate must be multiple of 1000Hz, and packet length must be in
71// milliseconds. No floating points.
72// + If we cannot get enough CPU, we drop samples and simulate packet loss.
73// + Resampling is not done yet, so streams in one group must use the same rate.
74// For the first release we might only support 8kHz and 16kHz.
75
76class AudioStream
77{
78public:
79 AudioStream();
80 ~AudioStream();
81 bool set(int mode, int socket, sockaddr_storage *remote,
82 const char *codecName, int sampleRate, int sampleCount,
83 int codecType, int dtmfType);
84
85 void sendDtmf(int event);
86 bool mix(int32_t *output, int head, int tail, int sampleRate);
87 void encode(int tick, AudioStream *chain);
88 void decode(int tick);
89
90private:
91 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;
109
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,
145 const char *codecName, int sampleRate, int sampleCount,
146 int codecType, int dtmfType)
147{
148 if (mode < 0 || mode > LAST_MODE) {
149 return false;
150 }
151 mMode = mode;
152
153 if (codecName) {
154 mRemote = *remote;
155 mCodec = newAudioCodec(codecName);
156 if (!mCodec || !mCodec->set(sampleRate, sampleCount)) {
157 return false;
158 }
159 }
160
161 mCodecMagic = (0x8000 | codecType) << 16;
162 mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
163
164 mTick = elapsedRealtime();
165 mSampleRate = sampleRate / 1000;
166 mSampleCount = sampleCount;
167 mInterval = mSampleCount / mSampleRate;
168
169 // Allocate jitter buffer.
170 for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1);
171 mBufferMask >>= 2;
172 mBuffer = new int16_t[mBufferMask];
173 --mBufferMask;
174 mBufferHead = 0;
175 mBufferTail = 0;
176 mLatencyScore = 0;
177
178 // Initialize random bits.
179 read(gRandom, &mSequence, sizeof(mSequence));
180 read(gRandom, &mTimestamp, sizeof(mTimestamp));
181 read(gRandom, &mSsrc, sizeof(mSsrc));
182
183 mDtmfEvent = -1;
184 mDtmfStart = 0;
185
186 // Only take over the socket when succeeded.
187 mSocket = socket;
188
189 LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
190 (codecName ? codecName : "RAW"), mSampleRate, mInterval);
191 return true;
192}
193
194void AudioStream::sendDtmf(int event)
195{
196 if (mDtmfMagic != 0) {
197 mDtmfEvent = event << 24;
198 mDtmfStart = mTimestamp + mSampleCount;
199 }
200}
201
202bool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
203{
204 if (mMode == SEND_ONLY) {
205 return false;
206 }
207
208 if (head - mBufferHead < 0) {
209 head = mBufferHead;
210 }
211 if (tail - mBufferTail > 0) {
212 tail = mBufferTail;
213 }
214 if (tail - head <= 0) {
215 return false;
216 }
217
218 head *= mSampleRate;
219 tail *= mSampleRate;
220
221 if (sampleRate == mSampleRate) {
222 for (int i = head; i - tail < 0; ++i) {
223 output[i - head] += mBuffer[i & mBufferMask];
224 }
225 } else {
226 // TODO: implement resampling.
227 return false;
228 }
229 return true;
230}
231
232void AudioStream::encode(int tick, AudioStream *chain)
233{
234 if (tick - mTick >= mInterval) {
235 // We just missed the train. Pretend that packets in between are lost.
236 int skipped = (tick - mTick) / mInterval;
237 mTick += skipped * mInterval;
238 mSequence += skipped;
239 mTimestamp += skipped * mSampleCount;
240 LOGD("stream[%d] skips %d packets", mSocket, skipped);
241 }
242
243 tick = mTick;
244 mTick += mInterval;
245 ++mSequence;
246 mTimestamp += mSampleCount;
247
248 if (mMode == RECEIVE_ONLY) {
249 return;
250 }
251
252 // If there is an ongoing DTMF event, send it now.
253 if (mDtmfEvent != -1) {
254 int duration = mTimestamp - mDtmfStart;
255 // Make sure duration is reasonable.
256 if (duration >= 0 && duration < mSampleRate * 100) {
257 duration += mSampleCount;
258 int32_t buffer[4] = {
259 htonl(mDtmfMagic | mSequence),
260 htonl(mDtmfStart),
261 mSsrc,
262 htonl(mDtmfEvent | duration),
263 };
264 if (duration >= mSampleRate * 100) {
265 buffer[3] |= htonl(1 << 23);
266 mDtmfEvent = -1;
267 }
268 sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
269 (sockaddr *)&mRemote, sizeof(mRemote));
270 return;
271 }
272 mDtmfEvent = -1;
273 }
274
275 // It is time to mix streams.
276 bool mixed = false;
277 int32_t buffer[mSampleCount + 3];
278 memset(buffer, 0, sizeof(buffer));
279 while (chain) {
280 if (chain != this &&
281 chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
282 mixed = true;
283 }
284 chain = chain->mNext;
285 }
286 if (!mixed) {
287 LOGD("stream[%d] no data", mSocket);
288 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
321void AudioStream::decode(int tick)
322{
323 char c;
324 if (mMode == SEND_ONLY) {
325 recv(mSocket, &c, 1, MSG_DONTWAIT);
326 return;
327 }
328
329 // Make sure mBufferHead and mBufferTail are reasonable.
330 if ((unsigned int)(tick + 256 - mBufferHead) > 1024) {
331 mBufferHead = tick - 64;
332 mBufferTail = mBufferHead;
333 }
334
335 if (tick - mBufferHead > 64) {
336 // Throw away outdated samples.
337 mBufferHead = tick - 64;
338 if (mBufferTail - mBufferHead < 0) {
339 mBufferTail = mBufferHead;
340 }
341 }
342
343 if (mBufferTail - tick <= 80) {
344 mLatencyScore = tick;
345 } else if (tick - mLatencyScore >= 5000) {
346 // Reset the jitter buffer to 40ms if the latency keeps larger than 80ms
347 // in the past 5s. This rarely happens, so let us just keep it simple.
348 LOGD("stream[%d] latency control", mSocket);
349 mBufferTail = tick + 40;
350 }
351
352 if (mBufferTail - mBufferHead > 256 - mInterval) {
353 // Buffer overflow. Drop the packet.
354 LOGD("stream[%d] buffer overflow", mSocket);
355 recv(mSocket, &c, 1, MSG_DONTWAIT);
356 return;
357 }
358
359 // Receive the packet and decode it.
360 int16_t samples[mSampleCount];
361 int length = 0;
362 if (!mCodec) {
363 // Special case for device stream.
364 length = recv(mSocket, samples, sizeof(samples),
365 MSG_TRUNC | MSG_DONTWAIT) >> 1;
366 } else {
367 __attribute__((aligned(4))) uint8_t buffer[2048];
368 length = recv(mSocket, buffer, sizeof(buffer),
369 MSG_TRUNC | MSG_DONTWAIT);
370
371 // Do we need to check SSRC, sequence, and timestamp? They are not
Chia-chi Yehb8790322010-08-19 18:26:53 +0800372 // reliable but at least they can be used to identify duplicates?
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800373 if (length < 12 || length > (int)sizeof(buffer) ||
374 (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
375 LOGD("stream[%d] malformed packet", mSocket);
376 return;
377 }
378 int offset = 12 + ((buffer[0] & 0x0F) << 2);
379 if ((buffer[0] & 0x10) != 0) {
380 offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
381 }
382 if ((buffer[0] & 0x20) != 0) {
383 length -= buffer[length - 1];
384 }
385 length -= offset;
386 if (length >= 0) {
387 length = mCodec->decode(samples, &buffer[offset], length);
388 }
389 }
390 if (length != mSampleCount) {
391 LOGD("stream[%d] decoder error", mSocket);
392 return;
393 }
394
395 if (tick - mBufferTail > 0) {
396 // Buffer underrun. Reset the jitter buffer to 40ms.
397 LOGD("stream[%d] buffer underrun", mSocket);
398 if (mBufferTail - mBufferHead <= 0) {
399 mBufferHead = tick + 40;
400 mBufferTail = mBufferHead;
401 } else {
402 int tail = (tick + 40) * mSampleRate;
403 for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
404 mBuffer[i & mBufferMask] = 0;
405 }
406 mBufferTail = tick + 40;
407 }
408 }
409
410 // Append to the jitter buffer.
411 int tail = mBufferTail * mSampleRate;
412 for (int i = 0; i < mSampleCount; ++i) {
413 mBuffer[tail & mBufferMask] = samples[i];
414 ++tail;
415 }
416 mBufferTail += mInterval;
417}
418
419//------------------------------------------------------------------------------
420
421class AudioGroup
422{
423public:
424 AudioGroup();
425 ~AudioGroup();
426 bool set(int sampleRate, int sampleCount);
427
428 bool setMode(int mode);
429 bool sendDtmf(int event);
430 bool add(AudioStream *stream);
431 bool remove(int socket);
432
433private:
434 enum {
435 ON_HOLD = 0,
436 MUTED = 1,
437 NORMAL = 2,
438 EC_ENABLED = 3,
439 LAST_MODE = 3,
440 };
441 int mMode;
442 AudioStream *mChain;
443 int mEventQueue;
444 volatile int mDtmfEvent;
445
446 int mSampleCount;
447 int mDeviceSocket;
448 AudioTrack mTrack;
449 AudioRecord mRecord;
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800450
451 SpeexEchoState *mEchoState;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800452
453 bool networkLoop();
454 bool deviceLoop();
455
456 class NetworkThread : public Thread
457 {
458 public:
459 NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
460
461 bool start()
462 {
463 if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
464 LOGE("cannot start network thread");
465 return false;
466 }
467 return true;
468 }
469
470 private:
471 AudioGroup *mGroup;
472 bool threadLoop()
473 {
474 return mGroup->networkLoop();
475 }
476 };
477 sp<NetworkThread> mNetworkThread;
478
479 class DeviceThread : public Thread
480 {
481 public:
482 DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
483
484 bool start()
485 {
486 char c;
487 while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1);
488
489 if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
490 LOGE("cannot start device thread");
491 return false;
492 }
493 return true;
494 }
495
496 private:
497 AudioGroup *mGroup;
498 bool threadLoop()
499 {
500 return mGroup->deviceLoop();
501 }
502 };
503 sp<DeviceThread> mDeviceThread;
504};
505
506AudioGroup::AudioGroup()
507{
508 mMode = ON_HOLD;
509 mChain = NULL;
510 mEventQueue = -1;
511 mDtmfEvent = -1;
512 mDeviceSocket = -1;
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800513 mEchoState = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800514 mNetworkThread = new NetworkThread(this);
515 mDeviceThread = new DeviceThread(this);
516}
517
518AudioGroup::~AudioGroup()
519{
520 mNetworkThread->requestExitAndWait();
521 mDeviceThread->requestExitAndWait();
522 mTrack.stop();
523 mRecord.stop();
524 close(mEventQueue);
525 close(mDeviceSocket);
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800526 if (mEchoState) {
527 speex_echo_state_destroy(mEchoState);
528 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800529 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
545 mSampleCount = sampleCount;
546
547 // Find out the frame count for AudioTrack and AudioRecord.
548 int output = 0;
549 int input = 0;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800550 if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
551 sampleRate) != NO_ERROR || output <= 0 ||
552 AudioRecord::getMinFrameCount(&input, sampleRate,
553 AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
554 LOGE("cannot compute frame count");
555 return false;
556 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800557 LOGD("reported frame count: output %d, input %d", output, input);
558
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800559 if (output < sampleCount * 2) {
560 output = sampleCount * 2;
561 }
562 if (input < sampleCount * 2) {
563 input = sampleCount * 2;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800564 }
565 LOGD("adjusted frame count: output %d, input %d", output, input);
566
567 // Initialize AudioTrack and AudioRecord.
568 if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
569 AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
570 mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
571 AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
572 LOGE("cannot initialize audio device");
573 return false;
574 }
575 LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
576
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800577 // Initialize echo canceller.
578 mEchoState = speex_echo_state_init(sampleCount, sampleRate);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800579
580 // Create device socket.
581 int pair[2];
582 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
583 LOGE("socketpair: %s", strerror(errno));
584 return false;
585 }
586 mDeviceSocket = pair[0];
587
588 // Create device stream.
589 mChain = new AudioStream;
590 if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
591 sampleRate, sampleCount, -1, -1)) {
592 close(pair[1]);
593 LOGE("cannot initialize device stream");
594 return false;
595 }
596
597 // Give device socket a reasonable timeout and buffer size.
598 timeval tv;
599 tv.tv_sec = 0;
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800600 tv.tv_usec = 1000 * sampleCount / sampleRate * 1000;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800601 if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
602 setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
603 setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
604 LOGE("setsockopt: %s", strerror(errno));
605 return false;
606 }
607
608 // Add device stream into event queue.
609 epoll_event event;
610 event.events = EPOLLIN;
611 event.data.ptr = mChain;
612 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
613 LOGE("epoll_ctl: %s", strerror(errno));
614 return false;
615 }
616
617 // Anything else?
618 LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
619 return true;
620}
621
622bool AudioGroup::setMode(int mode)
623{
624 if (mode < 0 || mode > LAST_MODE) {
625 return false;
626 }
627 if (mMode == mode) {
628 return true;
629 }
630
631 LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
632 mMode = mode;
633
634 mDeviceThread->requestExitAndWait();
635 if (mode == ON_HOLD) {
636 mTrack.stop();
637 mRecord.stop();
638 return true;
639 }
640
641 mTrack.start();
642 if (mode == MUTED) {
643 mRecord.stop();
644 } else {
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800645 speex_echo_state_reset(mEchoState);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800646 mRecord.start();
647 }
648
649 if (!mDeviceThread->start()) {
650 mTrack.stop();
651 mRecord.stop();
652 return false;
653 }
654 return true;
655}
656
657bool AudioGroup::sendDtmf(int event)
658{
659 if (event < 0 || event > 15) {
660 return false;
661 }
662
663 // DTMF is rarely used, so we try to make it as lightweight as possible.
664 // Using volatile might be dodgy, but using a pipe or pthread primitives
665 // or stop-set-restart threads seems too heavy. Will investigate later.
666 timespec ts;
667 ts.tv_sec = 0;
668 ts.tv_nsec = 100000000;
669 for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
670 nanosleep(&ts, NULL);
671 }
672 if (mDtmfEvent != -1) {
673 return false;
674 }
675 mDtmfEvent = event;
676 nanosleep(&ts, NULL);
677 return true;
678}
679
680bool AudioGroup::add(AudioStream *stream)
681{
682 mNetworkThread->requestExitAndWait();
683
684 epoll_event event;
685 event.events = EPOLLIN;
686 event.data.ptr = stream;
687 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
688 LOGE("epoll_ctl: %s", strerror(errno));
689 return false;
690 }
691
692 stream->mNext = mChain->mNext;
693 mChain->mNext = stream;
694 if (!mNetworkThread->start()) {
695 // Only take over the stream when succeeded.
696 mChain->mNext = stream->mNext;
697 return false;
698 }
699
700 LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
701 return true;
702}
703
704bool AudioGroup::remove(int socket)
705{
706 mNetworkThread->requestExitAndWait();
707
708 for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
709 AudioStream *target = stream->mNext;
710 if (target->mSocket == socket) {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800711 if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
712 LOGE("epoll_ctl: %s", strerror(errno));
713 return false;
714 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800715 stream->mNext = target->mNext;
716 LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
717 delete target;
718 break;
719 }
720 }
721
722 // Do not start network thread if there is only one stream.
723 if (!mChain->mNext || !mNetworkThread->start()) {
724 return false;
725 }
726 return true;
727}
728
729bool AudioGroup::networkLoop()
730{
731 int tick = elapsedRealtime();
732 int deadline = tick + 10;
733 int count = 0;
734
735 for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
736 if (!stream->mTick || tick - stream->mTick >= 0) {
737 stream->encode(tick, mChain);
738 }
739 if (deadline - stream->mTick > 0) {
740 deadline = stream->mTick;
741 }
742 ++count;
743 }
744
745 if (mDtmfEvent != -1) {
746 int event = mDtmfEvent;
747 for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
748 stream->sendDtmf(event);
749 }
750 mDtmfEvent = -1;
751 }
752
753 deadline -= tick;
754 if (deadline < 1) {
755 deadline = 1;
756 }
757
758 epoll_event events[count];
759 count = epoll_wait(mEventQueue, events, count, deadline);
760 if (count == -1) {
761 LOGE("epoll_wait: %s", strerror(errno));
762 return false;
763 }
764 for (int i = 0; i < count; ++i) {
765 ((AudioStream *)events[i].data.ptr)->decode(tick);
766 }
767
768 return true;
769}
770
771bool AudioGroup::deviceLoop()
772{
773 int16_t output[mSampleCount];
774
775 if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
776 memset(output, 0, sizeof(output));
777 }
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800778
779 int16_t input[mSampleCount];
780 int toWrite = mSampleCount;
781 int toRead = (mMode == MUTED) ? 0 : mSampleCount;
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 = mTrack.obtainBuffer(&buffer, 1);
790 if (status == NO_ERROR) {
791 memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
792 toWrite -= buffer.frameCount;
793 mTrack.releaseBuffer(&buffer);
794 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
795 LOGE("cannot write to AudioTrack");
796 return false;
797 }
798 }
799
800 if (toRead > 0) {
801 AudioRecord::Buffer buffer;
802 buffer.frameCount = mRecord.frameCount();
803
804 status_t status = mRecord.obtainBuffer(&buffer, 1);
805 if (status == NO_ERROR) {
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800806 int count = ((int)buffer.frameCount < toRead) ?
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800807 buffer.frameCount : toRead;
808 memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
809 toRead -= count;
810 if (buffer.frameCount < mRecord.frameCount()) {
811 buffer.frameCount = count;
812 }
813 mRecord.releaseBuffer(&buffer);
814 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
815 LOGE("cannot read from AudioRecord");
816 return false;
817 }
818 }
819 }
820
821 if (!chances) {
822 LOGE("device loop timeout");
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800823 return false;
824 }
825
826 if (mMode != MUTED) {
Chia-chi Yeh2880ef82010-08-24 13:58:12 +0800827 if (mMode == NORMAL) {
828 send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800829 } else {
Chia-chi Yeh4ae6ec42010-08-24 16:00:32 +0800830 int16_t result[mSampleCount];
831 speex_echo_cancellation(mEchoState, input, output, result);
832 send(mDeviceSocket, result, sizeof(result), MSG_DONTWAIT);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800833 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800834 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800835 return true;
836}
837
838//------------------------------------------------------------------------------
839
840static jfieldID gNative;
841static jfieldID gMode;
842
Chia-chi Yehb8790322010-08-19 18:26:53 +0800843void add(JNIEnv *env, jobject thiz, jint mode,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800844 jint socket, jstring jRemoteAddress, jint remotePort,
845 jstring jCodecName, jint sampleRate, jint sampleCount,
846 jint codecType, jint dtmfType)
847{
848 const char *codecName = NULL;
849 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 Yehb8790322010-08-19 18:26:53 +0800856 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800857 }
858 if (sampleRate < 0 || sampleCount < 0 || codecType < 0 || codecType > 127) {
859 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
860 goto error;
861 }
862 if (!jCodecName) {
863 jniThrowNullPointerException(env, "codecName");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800864 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800865 }
866 codecName = env->GetStringUTFChars(jCodecName, NULL);
867 if (!codecName) {
868 // Exception already thrown.
Chia-chi Yehb8790322010-08-19 18:26:53 +0800869 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800870 }
871
872 // Create audio stream.
873 stream = new AudioStream;
874 if (!stream->set(mode, socket, &remote, codecName, sampleRate, sampleCount,
875 codecType, dtmfType)) {
876 jniThrowException(env, "java/lang/IllegalStateException",
877 "cannot initialize audio stream");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800878 env->ReleaseStringUTFChars(jCodecName, codecName);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800879 goto error;
880 }
Chia-chi Yehb8790322010-08-19 18:26:53 +0800881 env->ReleaseStringUTFChars(jCodecName, codecName);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800882 socket = -1;
883
884 // Create audio group.
885 group = (AudioGroup *)env->GetIntField(thiz, gNative);
886 if (!group) {
887 int mode = env->GetIntField(thiz, gMode);
888 group = new AudioGroup;
889 if (!group->set(8000, 256) || !group->setMode(mode)) {
890 jniThrowException(env, "java/lang/IllegalStateException",
891 "cannot initialize audio group");
892 goto error;
893 }
894 }
895
896 // Add audio stream into audio group.
897 if (!group->add(stream)) {
898 jniThrowException(env, "java/lang/IllegalStateException",
899 "cannot add audio stream");
900 goto error;
901 }
902
903 // Succeed.
904 env->SetIntField(thiz, gNative, (int)group);
Chia-chi Yehb8790322010-08-19 18:26:53 +0800905 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800906
907error:
908 delete group;
909 delete stream;
910 close(socket);
911 env->SetIntField(thiz, gNative, NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800912}
913
914void remove(JNIEnv *env, jobject thiz, jint socket)
915{
916 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
917 if (group) {
918 if (socket == -1 || !group->remove(socket)) {
919 delete group;
920 env->SetIntField(thiz, gNative, NULL);
921 }
922 }
923}
924
925void setMode(JNIEnv *env, jobject thiz, jint mode)
926{
927 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
928 if (group && !group->setMode(mode)) {
929 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
930 return;
931 }
932 env->SetIntField(thiz, gMode, mode);
933}
934
935void sendDtmf(JNIEnv *env, jobject thiz, jint event)
936{
937 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
938 if (group && !group->sendDtmf(event)) {
939 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
940 }
941}
942
943JNINativeMethod gMethods[] = {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800944 {"add", "(IILjava/lang/String;ILjava/lang/String;IIII)V", (void *)add},
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800945 {"remove", "(I)V", (void *)remove},
946 {"setMode", "(I)V", (void *)setMode},
947 {"sendDtmf", "(I)V", (void *)sendDtmf},
948};
949
950} // namespace
951
952int registerAudioGroup(JNIEnv *env)
953{
954 gRandom = open("/dev/urandom", O_RDONLY);
955 if (gRandom == -1) {
956 LOGE("urandom: %s", strerror(errno));
957 return -1;
958 }
959
960 jclass clazz;
961 if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
962 (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
963 (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
964 env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
965 LOGE("JNI registration failed");
966 return -1;
967 }
968 return 0;
969}