RtpStream.cpp revision e66950506c473e660f2e5762d7a71e13808be387
14c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh/*
24c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * Copyright (C) 2010 The Android Open Source Project
34c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh *
44c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
54c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * you may not use this file except in compliance with the License.
64c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * You may obtain a copy of the License at
74c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh *
84c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
94c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh *
104c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
114c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
124c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * See the License for the specific language governing permissions and
144c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh * limitations under the License.
154c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh */
164c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
174c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <stdio.h>
184c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <stdint.h>
194c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <string.h>
204c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <errno.h>
214c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <sys/types.h>
224c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <sys/socket.h>
234c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <arpa/inet.h>
244c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <netinet/in.h>
254c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
264c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#define LOG_TAG "RtpStream"
274c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include <utils/Log.h>
284c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
294c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include "jni.h"
304c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh#include "JNIHelp.h"
314c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
324c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yehextern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
334c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
344c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yehnamespace {
354c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
36e66950506c473e660f2e5762d7a71e13808be387Chia-chi YehjfieldID gSocket;
374c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
384c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yehjint create(JNIEnv *env, jobject thiz, jstring jAddress)
394c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh{
40e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh    env->SetIntField(thiz, gSocket, -1);
414c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
424c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    sockaddr_storage ss;
434c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    if (parse(env, jAddress, 0, &ss) < 0) {
444c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        // Exception already thrown.
454c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        return -1;
464c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    }
474c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
484c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    int socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
494c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    socklen_t len = sizeof(ss);
504c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    if (socket == -1 || bind(socket, (sockaddr *)&ss, sizeof(ss)) != 0 ||
514c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        getsockname(socket, (sockaddr *)&ss, &len) != 0) {
524c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        jniThrowException(env, "java/net/SocketException", strerror(errno));
534c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        ::close(socket);
544c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        return -1;
554c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    }
564c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
574c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    uint16_t *p = (ss.ss_family == AF_INET) ?
584c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        &((sockaddr_in *)&ss)->sin_port : &((sockaddr_in6 *)&ss)->sin6_port;
594c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    uint16_t port = ntohs(*p);
604c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    if ((port & 1) == 0) {
61e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh        env->SetIntField(thiz, gSocket, socket);
624c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        return port;
634c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    }
644c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    ::close(socket);
654c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
664c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
674c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    if (socket != -1) {
684c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        uint16_t delta = port << 1;
694c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        ++port;
704c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
714c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        for (int i = 0; i < 1000; ++i) {
724c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh            do {
734c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh                port += delta;
744c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh            } while (port < 1024);
754c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh            *p = htons(port);
764c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
774c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh            if (bind(socket, (sockaddr *)&ss, sizeof(ss)) == 0) {
78e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh                env->SetIntField(thiz, gSocket, socket);
794c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh                return port;
804c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh            }
814c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        }
824c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    }
834c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
844c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    jniThrowException(env, "java/net/SocketException", strerror(errno));
854c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    ::close(socket);
864c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    return -1;
874c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh}
884c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
894c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yehvoid close(JNIEnv *env, jobject thiz)
904c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh{
91e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh    int socket = env->GetIntField(thiz, gSocket);
924c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    ::close(socket);
93e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh    env->SetIntField(thiz, gSocket, -1);
944c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh}
954c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
964c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi YehJNINativeMethod gMethods[] = {
974c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    {"create", "(Ljava/lang/String;)I", (void *)create},
984c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    {"close", "()V", (void *)close},
994c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh};
1004c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
1014c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh} // namespace
1024c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh
1034c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yehint registerRtpStream(JNIEnv *env)
1044c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh{
1054c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    jclass clazz;
1064c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    if ((clazz = env->FindClass("android/net/rtp/RtpStream")) == NULL ||
107e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh        (gSocket = env->GetFieldID(clazz, "mSocket", "I")) == NULL ||
1084c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
1093762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("JNI registration failed");
1104c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh        return -1;
1114c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    }
1124c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh    return 0;
1134c5d28cee0537c83ff0e5bc0daaae78f68dfc7c8Chia-chi Yeh}
114