blob: 72c882bcc6167f4b93022b76cc767860548a56d8 [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 };
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800464
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800465 AudioStream *mChain;
466 int mEventQueue;
467 volatile int mDtmfEvent;
468
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800469 int mMode;
470 int mSampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800471 int mSampleCount;
472 int mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800473
474 class NetworkThread : public Thread
475 {
476 public:
477 NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
478
479 bool start()
480 {
481 if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
482 LOGE("cannot start network thread");
483 return false;
484 }
485 return true;
486 }
487
488 private:
489 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800490 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800491 };
492 sp<NetworkThread> mNetworkThread;
493
494 class DeviceThread : public Thread
495 {
496 public:
497 DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
498
499 bool start()
500 {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800501 if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
502 LOGE("cannot start device thread");
503 return false;
504 }
505 return true;
506 }
507
508 private:
509 AudioGroup *mGroup;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800510 bool threadLoop();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800511 };
512 sp<DeviceThread> mDeviceThread;
513};
514
515AudioGroup::AudioGroup()
516{
517 mMode = ON_HOLD;
518 mChain = NULL;
519 mEventQueue = -1;
520 mDtmfEvent = -1;
521 mDeviceSocket = -1;
522 mNetworkThread = new NetworkThread(this);
523 mDeviceThread = new DeviceThread(this);
524}
525
526AudioGroup::~AudioGroup()
527{
528 mNetworkThread->requestExitAndWait();
529 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800530 close(mEventQueue);
531 close(mDeviceSocket);
532 while (mChain) {
533 AudioStream *next = mChain->mNext;
534 delete mChain;
535 mChain = next;
536 }
537 LOGD("group[%d] is dead", mDeviceSocket);
538}
539
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800540bool AudioGroup::set(int sampleRate, int sampleCount)
541{
542 mEventQueue = epoll_create(2);
543 if (mEventQueue == -1) {
544 LOGE("epoll_create: %s", strerror(errno));
545 return false;
546 }
547
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800548 mSampleRate = sampleRate;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800549 mSampleCount = sampleCount;
550
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800551 // Create device socket.
552 int pair[2];
553 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
554 LOGE("socketpair: %s", strerror(errno));
555 return false;
556 }
557 mDeviceSocket = pair[0];
558
559 // Create device stream.
560 mChain = new AudioStream;
561 if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
562 sampleRate, sampleCount, -1, -1)) {
563 close(pair[1]);
564 LOGE("cannot initialize device stream");
565 return false;
566 }
567
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800568 // Give device socket a reasonable timeout.
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800569 timeval tv;
570 tv.tv_sec = 0;
Chia-chi Yeh557b04d2010-09-08 09:56:02 +0800571 tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800572 if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800573 LOGE("setsockopt: %s", strerror(errno));
574 return false;
575 }
576
577 // Add device stream into event queue.
578 epoll_event event;
579 event.events = EPOLLIN;
580 event.data.ptr = mChain;
581 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
582 LOGE("epoll_ctl: %s", strerror(errno));
583 return false;
584 }
585
586 // Anything else?
587 LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
588 return true;
589}
590
591bool AudioGroup::setMode(int mode)
592{
593 if (mode < 0 || mode > LAST_MODE) {
594 return false;
595 }
596 if (mMode == mode) {
597 return true;
598 }
599
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800600 mDeviceThread->requestExitAndWait();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800601 LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
602 mMode = mode;
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800603 return (mode == ON_HOLD) || mDeviceThread->start();
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800604}
605
606bool AudioGroup::sendDtmf(int event)
607{
608 if (event < 0 || event > 15) {
609 return false;
610 }
611
612 // DTMF is rarely used, so we try to make it as lightweight as possible.
613 // Using volatile might be dodgy, but using a pipe or pthread primitives
614 // or stop-set-restart threads seems too heavy. Will investigate later.
615 timespec ts;
616 ts.tv_sec = 0;
617 ts.tv_nsec = 100000000;
618 for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
619 nanosleep(&ts, NULL);
620 }
621 if (mDtmfEvent != -1) {
622 return false;
623 }
624 mDtmfEvent = event;
625 nanosleep(&ts, NULL);
626 return true;
627}
628
629bool AudioGroup::add(AudioStream *stream)
630{
631 mNetworkThread->requestExitAndWait();
632
633 epoll_event event;
634 event.events = EPOLLIN;
635 event.data.ptr = stream;
636 if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
637 LOGE("epoll_ctl: %s", strerror(errno));
638 return false;
639 }
640
641 stream->mNext = mChain->mNext;
642 mChain->mNext = stream;
643 if (!mNetworkThread->start()) {
644 // Only take over the stream when succeeded.
645 mChain->mNext = stream->mNext;
646 return false;
647 }
648
649 LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
650 return true;
651}
652
653bool AudioGroup::remove(int socket)
654{
655 mNetworkThread->requestExitAndWait();
656
657 for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
658 AudioStream *target = stream->mNext;
659 if (target->mSocket == socket) {
Chia-chi Yehb8790322010-08-19 18:26:53 +0800660 if (epoll_ctl(mEventQueue, EPOLL_CTL_DEL, socket, NULL)) {
661 LOGE("epoll_ctl: %s", strerror(errno));
662 return false;
663 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800664 stream->mNext = target->mNext;
665 LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
666 delete target;
667 break;
668 }
669 }
670
671 // Do not start network thread if there is only one stream.
672 if (!mChain->mNext || !mNetworkThread->start()) {
673 return false;
674 }
675 return true;
676}
677
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800678bool AudioGroup::NetworkThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800679{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800680 AudioStream *chain = mGroup->mChain;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800681 int tick = elapsedRealtime();
682 int deadline = tick + 10;
683 int count = 0;
684
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800685 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800686 if (!stream->mTick || tick - stream->mTick >= 0) {
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800687 stream->encode(tick, chain);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800688 }
689 if (deadline - stream->mTick > 0) {
690 deadline = stream->mTick;
691 }
692 ++count;
693 }
694
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800695 int event = mGroup->mDtmfEvent;
696 if (event != -1) {
697 for (AudioStream *stream = chain; stream; stream = stream->mNext) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800698 stream->sendDtmf(event);
699 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800700 mGroup->mDtmfEvent = -1;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800701 }
702
703 deadline -= tick;
704 if (deadline < 1) {
705 deadline = 1;
706 }
707
708 epoll_event events[count];
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800709 count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800710 if (count == -1) {
711 LOGE("epoll_wait: %s", strerror(errno));
712 return false;
713 }
714 for (int i = 0; i < count; ++i) {
715 ((AudioStream *)events[i].data.ptr)->decode(tick);
716 }
717
718 return true;
719}
720
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800721bool AudioGroup::DeviceThread::threadLoop()
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800722{
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800723 int mode = mGroup->mMode;
724 int sampleRate = mGroup->mSampleRate;
725 int sampleCount = mGroup->mSampleCount;
726 int deviceSocket = mGroup->mDeviceSocket;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800727
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800728 // Find out the frame count for AudioTrack and AudioRecord.
729 int output = 0;
730 int input = 0;
731 if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
732 sampleRate) != NO_ERROR || output <= 0 ||
733 AudioRecord::getMinFrameCount(&input, sampleRate,
734 AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
735 LOGE("cannot compute frame count");
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800736 return false;
737 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800738 LOGD("reported frame count: output %d, input %d", output, input);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800739
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800740 if (output < sampleCount * 2) {
741 output = sampleCount * 2;
742 }
743 if (input < sampleCount * 2) {
744 input = sampleCount * 2;
745 }
746 LOGD("adjusted frame count: output %d, input %d", output, input);
747
748 // Initialize AudioTrack and AudioRecord.
749 AudioTrack track;
750 AudioRecord record;
751 if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
752 AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
753 record.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
754 AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
755 LOGE("cannot initialize audio device");
756 return false;
757 }
758 LOGD("latency: output %d, input %d", track.latency(), record.latency());
759
760 // TODO: initialize echo canceler here.
761
762 // Give device socket a reasonable buffer size.
763 setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
764 setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
765
766 // Drain device socket.
767 char c;
768 while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
769
770 // Start your engine!
771 track.start();
772 if (mode != MUTED) {
773 record.start();
774 }
775
776 while (!exitPending()) {
777 int16_t output[sampleCount];
778 if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
779 memset(output, 0, sizeof(output));
780 }
781
782 int16_t input[sampleCount];
783 int toWrite = sampleCount;
784 int toRead = (mode == MUTED) ? 0 : sampleCount;
785 int chances = 100;
786
787 while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
788 if (toWrite > 0) {
789 AudioTrack::Buffer buffer;
790 buffer.frameCount = toWrite;
791
792 status_t status = track.obtainBuffer(&buffer, 1);
793 if (status == NO_ERROR) {
794 int offset = sampleCount - toWrite;
795 memcpy(buffer.i8, &output[offset], buffer.size);
796 toWrite -= buffer.frameCount;
797 track.releaseBuffer(&buffer);
798 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
799 LOGE("cannot write to AudioTrack");
800 break;
801 }
802 }
803
804 if (toRead > 0) {
805 AudioRecord::Buffer buffer;
806 buffer.frameCount = record.frameCount();
807
808 status_t status = record.obtainBuffer(&buffer, 1);
809 if (status == NO_ERROR) {
810 int count = ((int)buffer.frameCount < toRead) ?
811 buffer.frameCount : toRead;
812 memcpy(&input[sampleCount - toRead], buffer.i8, count * 2);
813 toRead -= count;
814 if (buffer.frameCount < record.frameCount()) {
815 buffer.frameCount = count;
816 }
817 record.releaseBuffer(&buffer);
818 } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
819 LOGE("cannot read from AudioRecord");
820 break;
821 }
822 }
823 }
824
825 if (chances <= 0) {
826 LOGE("device loop timeout");
827 break;
828 }
829
830 if (mode != MUTED) {
831 if (mode == NORMAL) {
832 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
833 } else {
834 // TODO: Echo canceller runs here.
835 send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
836 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800837 }
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800838 }
Chia-chi Yeh9083c842010-09-29 05:19:44 +0800839 return false;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800840}
841
842//------------------------------------------------------------------------------
843
844static jfieldID gNative;
845static jfieldID gMode;
846
Chia-chi Yehb8790322010-08-19 18:26:53 +0800847void add(JNIEnv *env, jobject thiz, jint mode,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800848 jint socket, jstring jRemoteAddress, jint remotePort,
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800849 jstring jCodecSpec, jint dtmfType)
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800850{
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800851 AudioCodec *codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800852 AudioStream *stream = NULL;
853 AudioGroup *group = NULL;
854
855 // Sanity check.
856 sockaddr_storage remote;
857 if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
858 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800859 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800860 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800861 if (!jCodecSpec) {
862 jniThrowNullPointerException(env, "codecSpec");
863 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800864 }
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800865 const char *codecSpec = env->GetStringUTFChars(jCodecSpec, NULL);
866 if (!codecSpec) {
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800867 // Exception already thrown.
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800868 return;
869 }
870
871 // Create audio codec.
872 int codecType = -1;
873 char codecName[16];
874 int sampleRate = -1;
875 sscanf(codecSpec, "%d %[^/]%*c%d", &codecType, codecName, &sampleRate);
876 codec = newAudioCodec(codecName);
877 int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
878 env->ReleaseStringUTFChars(jCodecSpec, codecSpec);
879 if (sampleCount <= 0) {
880 jniThrowException(env, "java/lang/IllegalStateException",
881 "cannot initialize audio codec");
Chia-chi Yehb8790322010-08-19 18:26:53 +0800882 goto error;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800883 }
884
885 // Create audio stream.
886 stream = new AudioStream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800887 if (!stream->set(mode, socket, &remote, codec, sampleRate, sampleCount,
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800888 codecType, dtmfType)) {
889 jniThrowException(env, "java/lang/IllegalStateException",
890 "cannot initialize audio stream");
891 goto error;
892 }
893 socket = -1;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800894 codec = NULL;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800895
896 // Create audio group.
897 group = (AudioGroup *)env->GetIntField(thiz, gNative);
898 if (!group) {
899 int mode = env->GetIntField(thiz, gMode);
900 group = new AudioGroup;
901 if (!group->set(8000, 256) || !group->setMode(mode)) {
902 jniThrowException(env, "java/lang/IllegalStateException",
903 "cannot initialize audio group");
904 goto error;
905 }
906 }
907
908 // Add audio stream into audio group.
909 if (!group->add(stream)) {
910 jniThrowException(env, "java/lang/IllegalStateException",
911 "cannot add audio stream");
912 goto error;
913 }
914
915 // Succeed.
916 env->SetIntField(thiz, gNative, (int)group);
Chia-chi Yehb8790322010-08-19 18:26:53 +0800917 return;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800918
919error:
920 delete group;
921 delete stream;
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800922 delete codec;
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800923 close(socket);
924 env->SetIntField(thiz, gNative, NULL);
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800925}
926
927void remove(JNIEnv *env, jobject thiz, jint socket)
928{
929 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
930 if (group) {
931 if (socket == -1 || !group->remove(socket)) {
932 delete group;
933 env->SetIntField(thiz, gNative, NULL);
934 }
935 }
936}
937
938void setMode(JNIEnv *env, jobject thiz, jint mode)
939{
940 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
941 if (group && !group->setMode(mode)) {
942 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
943 return;
944 }
945 env->SetIntField(thiz, gMode, mode);
946}
947
948void sendDtmf(JNIEnv *env, jobject thiz, jint event)
949{
950 AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
951 if (group && !group->sendDtmf(event)) {
952 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
953 }
954}
955
956JNINativeMethod gMethods[] = {
Chia-chi Yeh4033a672010-09-16 18:36:45 +0800957 {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
Chia-chi Yeh4c5d28c2010-08-06 14:12:05 +0800958 {"remove", "(I)V", (void *)remove},
959 {"setMode", "(I)V", (void *)setMode},
960 {"sendDtmf", "(I)V", (void *)sendDtmf},
961};
962
963} // namespace
964
965int registerAudioGroup(JNIEnv *env)
966{
967 gRandom = open("/dev/urandom", O_RDONLY);
968 if (gRandom == -1) {
969 LOGE("urandom: %s", strerror(errno));
970 return -1;
971 }
972
973 jclass clazz;
974 if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
975 (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
976 (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
977 env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
978 LOGE("JNI registration failed");
979 return -1;
980 }
981 return 0;
982}