RTP: move into frameworks.

Change-Id: Ic9c17b460448c746b21526ac10b647f281ae48e9
This commit is contained in:
Chia-chi Yeh
2010-08-06 14:12:05 +08:00
parent 1d62c7737c
commit 4c5d28cee0
7 changed files with 1464 additions and 0 deletions

44
voip/jni/rtp/Android.mk Normal file
View File

@@ -0,0 +1,44 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := librtp_jni
LOCAL_SRC_FILES := \
AudioCodec.cpp \
AudioGroup.cpp \
RtpStream.cpp \
util.cpp \
rtp_jni.cpp
LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
libmedia
LOCAL_STATIC_LIBRARIES :=
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)

161
voip/jni/rtp/AudioCodec.cpp Normal file
View File

@@ -0,0 +1,161 @@
/*
* Copyrightm (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "AudioCodec.h"
namespace {
int8_t gExponents[128] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
};
//------------------------------------------------------------------------------
class UlawCodec : public AudioCodec
{
public:
bool set(int sampleRate, int sampleCount) {
mSampleCount = sampleCount;
return sampleCount > 0;
}
int encode(void *payload, int16_t *samples);
int decode(int16_t *samples, void *payload, int length);
private:
int mSampleCount;
};
int UlawCodec::encode(void *payload, int16_t *samples)
{
int8_t *ulaws = (int8_t *)payload;
for (int i = 0; i < mSampleCount; ++i) {
int sample = samples[i];
int sign = (sample >> 8) & 0x80;
if (sample < 0) {
sample = -sample;
}
sample += 132;
if (sample > 32767) {
sample = 32767;
}
int exponent = gExponents[sample >> 8];
int mantissa = (sample >> (exponent + 3)) & 0x0F;
ulaws[i] = ~(sign | (exponent << 4) | mantissa);
}
return mSampleCount;
}
int UlawCodec::decode(int16_t *samples, void *payload, int length)
{
int8_t *ulaws = (int8_t *)payload;
for (int i = 0; i < length; ++i) {
int ulaw = ~ulaws[i];
int exponent = (ulaw >> 4) & 0x07;
int mantissa = ulaw & 0x0F;
int sample = (((mantissa << 3) + 132) << exponent) - 132;
samples[i] = (ulaw < 0 ? -sample : sample);
}
return length;
}
AudioCodec *newUlawCodec()
{
return new UlawCodec;
}
//------------------------------------------------------------------------------
class AlawCodec : public AudioCodec
{
public:
bool set(int sampleRate, int sampleCount) {
mSampleCount = sampleCount;
return sampleCount > 0;
}
int encode(void *payload, int16_t *samples);
int decode(int16_t *samples, void *payload, int length);
private:
int mSampleCount;
};
int AlawCodec::encode(void *payload, int16_t *samples)
{
int8_t *alaws = (int8_t *)payload;
for (int i = 0; i < mSampleCount; ++i) {
int sample = samples[i];
int sign = (sample >> 8) & 0x80;
if (sample < 0) {
sample = -sample;
}
if (sample > 32767) {
sample = 32767;
}
int exponent = gExponents[sample >> 8];
int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F;
alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5;
}
return mSampleCount;
}
int AlawCodec::decode(int16_t *samples, void *payload, int length)
{
int8_t *alaws = (int8_t *)payload;
for (int i = 0; i < length; ++i) {
int alaw = alaws[i] ^ 0x55;
int exponent = (alaw >> 4) & 0x07;
int mantissa = alaw & 0x0F;
int sample = (exponent == 0 ? (mantissa << 4) + 8 :
((mantissa << 3) + 132) << exponent);
samples[i] = (alaw < 0 ? sample : -sample);
}
return length;
}
AudioCodec *newAlawCodec()
{
return new AlawCodec;
}
struct AudioCodecType {
const char *name;
AudioCodec *(*create)();
} gAudioCodecTypes[] = {
{"PCMA", newAlawCodec},
{"PCMU", newUlawCodec},
{NULL, NULL},
};
} // namespace
AudioCodec *newAudioCodec(const char *codecName)
{
AudioCodecType *type = gAudioCodecTypes;
while (type->name != NULL) {
if (strcmp(codecName, type->name) == 0) {
return type->create();
}
++type;
}
return NULL;
}

36
voip/jni/rtp/AudioCodec.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyrightm (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#ifndef __AUDIO_CODEC_H__
#define __AUDIO_CODEC_H__
class AudioCodec
{
public:
virtual ~AudioCodec() {}
// Returns true if initialization succeeds.
virtual bool set(int sampleRate, int sampleCount) = 0;
// Returns the length of payload in bytes.
virtual int encode(void *payload, int16_t *samples) = 0;
// Returns the number of decoded samples.
virtual int decode(int16_t *samples, void *payload, int length) = 0;
};
AudioCodec *newAudioCodec(const char *codecName);
#endif

1004
voip/jni/rtp/AudioGroup.cpp Normal file

File diff suppressed because it is too large Load Diff

126
voip/jni/rtp/RtpStream.cpp Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define LOG_TAG "RtpStream"
#include <utils/Log.h>
#include "jni.h"
#include "JNIHelp.h"
extern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
namespace {
jfieldID gNative;
jint create(JNIEnv *env, jobject thiz, jstring jAddress)
{
env->SetIntField(thiz, gNative, -1);
sockaddr_storage ss;
if (parse(env, jAddress, 0, &ss) < 0) {
// Exception already thrown.
return -1;
}
int socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
socklen_t len = sizeof(ss);
if (socket == -1 || bind(socket, (sockaddr *)&ss, sizeof(ss)) != 0 ||
getsockname(socket, (sockaddr *)&ss, &len) != 0) {
jniThrowException(env, "java/net/SocketException", strerror(errno));
::close(socket);
return -1;
}
uint16_t *p = (ss.ss_family == AF_INET) ?
&((sockaddr_in *)&ss)->sin_port : &((sockaddr_in6 *)&ss)->sin6_port;
uint16_t port = ntohs(*p);
if ((port & 1) == 0) {
env->SetIntField(thiz, gNative, socket);
return port;
}
::close(socket);
socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
if (socket != -1) {
uint16_t delta = port << 1;
++port;
for (int i = 0; i < 1000; ++i) {
do {
port += delta;
} while (port < 1024);
*p = htons(port);
if (bind(socket, (sockaddr *)&ss, sizeof(ss)) == 0) {
env->SetIntField(thiz, gNative, socket);
return port;
}
}
}
jniThrowException(env, "java/net/SocketException", strerror(errno));
::close(socket);
return -1;
}
jint dup(JNIEnv *env, jobject thiz)
{
int socket1 = env->GetIntField(thiz, gNative);
int socket2 = ::dup(socket1);
if (socket2 == -1) {
jniThrowException(env, "java/lang/IllegalStateException", strerror(errno));
}
LOGD("dup %d to %d", socket1, socket2);
return socket2;
}
void close(JNIEnv *env, jobject thiz)
{
int socket = env->GetIntField(thiz, gNative);
::close(socket);
env->SetIntField(thiz, gNative, -1);
LOGD("close %d", socket);
}
JNINativeMethod gMethods[] = {
{"create", "(Ljava/lang/String;)I", (void *)create},
{"dup", "()I", (void *)dup},
{"close", "()V", (void *)close},
};
} // namespace
int registerRtpStream(JNIEnv *env)
{
jclass clazz;
if ((clazz = env->FindClass("android/net/rtp/RtpStream")) == NULL ||
(gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
LOGE("JNI registration failed");
return -1;
}
return 0;
}

32
voip/jni/rtp/rtp_jni.cpp Normal file
View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "jni.h"
extern int registerRtpStream(JNIEnv *env);
extern int registerAudioGroup(JNIEnv *env);
__attribute__((visibility("default"))) jint JNI_OnLoad(JavaVM *vm, void *unused)
{
JNIEnv *env = NULL;
if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK ||
registerRtpStream(env) < 0 || registerAudioGroup(env) < 0) {
return -1;
}
return JNI_VERSION_1_4;
}

61
voip/jni/rtp/util.cpp Normal file
View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "jni.h"
#include "JNIHelp.h"
int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss)
{
if (!jAddress) {
jniThrowNullPointerException(env, "address");
return -1;
}
if (port < 0 || port > 65535) {
jniThrowException(env, "java/lang/IllegalArgumentException", "port");
return -1;
}
const char *address = env->GetStringUTFChars(jAddress, NULL);
if (!address) {
// Exception already thrown.
return -1;
}
memset(ss, 0, sizeof(*ss));
sockaddr_in *sin = (sockaddr_in *)ss;
if (inet_pton(AF_INET, address, &(sin->sin_addr)) > 0) {
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
env->ReleaseStringUTFChars(jAddress, address);
return 0;
}
sockaddr_in6 *sin6 = (sockaddr_in6 *)ss;
if (inet_pton(AF_INET6, address, &(sin6->sin6_addr)) > 0) {
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
env->ReleaseStringUTFChars(jAddress, address);
return 0;
}
env->ReleaseStringUTFChars(jAddress, address);
jniThrowException(env, "java/lang/IllegalArgumentException", "address");
return -1;
}