Skip to content

Commit 5216b4d

Browse files
author
droidfang(房伟)
committed
init project
1 parent 5005378 commit 5216b4d

File tree

1,275 files changed

+480423
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,275 files changed

+480423
-2
lines changed

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/caches/build_file_checksums.ser
5+
/.idea/libraries
6+
/.idea/modules.xml
7+
/.idea/workspace.xml
8+
.DS_Store
9+
/build
10+
/captures
11+
.externalNativeBuild

README.md

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,23 @@
1-
# AirplayServer
2-
Android server for Airplay2
1+
# 简介
2+
3+
`Airplay2`是apple在`iOS11.3`中新加的特性,用作视频和音频的局域网投放
4+
5+
`AirplayServer`作为接收端,可以接收来自支持`Airplay2`设备的数据
6+
7+
`AirplayServer`可运行在`Android`设备,代码99%是C语言编写,方便移植
8+
9+
# 功能
10+
11+
1. mDNS发布服务
12+
2. 握手协议
13+
3. 接收镜像数据
14+
4. MediaCodec硬解与展示
15+
5. 接收音频数据
16+
6. fdk-aac音频解码
17+
7. AudioTrack播放PCM音乐
18+
19+
# 演示截图
20+
21+
下图是一次屏幕数据和音乐的投放演示,其中`iPhone`的系统是`iOS12`
22+
23+
![](https://ww1.sinaimg.cn/large/007rAy9hgy1g0l65hwvg7j30u01o0juj.jpg)

app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

app/CMakeLists.txt

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
cmake_minimum_required(VERSION 3.4.1)
2+
3+
add_subdirectory(src/main/cpp/lib/crypto)
4+
add_subdirectory(src/main/cpp/lib/curve25519)
5+
add_subdirectory(src/main/cpp/lib/ed25519)
6+
add_subdirectory(src/main/cpp/lib/playfair)
7+
add_subdirectory(src/main/cpp/lib/plist)
8+
add_subdirectory(src/main/cpp/lib/fdk-aac)
9+
add_subdirectory(src/main/cpp/lib)
10+
11+
include_directories(lib
12+
lib/fdk-aac/libAACdec/include
13+
lib/fdk-aac/libAACenc/include
14+
lib/fdk-aac/libFDK/include
15+
lib/fdk-aac/libMpegTPDec/include
16+
lib/fdk-aac/libMpegTPEnc/include
17+
lib/fdk-aac/libPCMutils/include
18+
lib/fdk-aac/libSBRdec/include
19+
lib/fdk-aac/libSBRenc/include
20+
lib/fdk-aac/libSYS/include
21+
22+
lib/fdk-aac/libArithCoding/include
23+
lib/fdk-aac/libDRCdec/include
24+
lib/fdk-aac/libSACdec/include
25+
lib/fdk-aac/libSACenc/include)
26+
add_library( raop_server
27+
SHARED
28+
src/main/cpp/jni_raop_server.cpp )
29+
add_subdirectory(src/main/cpp/mDNSResponder)
30+
find_library( log-lib
31+
log )
32+
33+
target_link_libraries( raop_server
34+
${log-lib}
35+
play-lib
36+
jdns_sd
37+
ed25519
38+
fdk-aac)

app/build.gradle

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
compileSdkVersion 27
5+
defaultConfig {
6+
applicationId "com.fang.myapplication"
7+
minSdkVersion 22
8+
targetSdkVersion 27
9+
versionCode 1
10+
versionName "1.0"
11+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12+
externalNativeBuild {
13+
cmake {
14+
abiFilters "armeabi-v7a"
15+
cppFlags ""
16+
}
17+
}
18+
ndk {
19+
abiFilters "armeabi-v7a"
20+
}
21+
}
22+
buildTypes {
23+
release {
24+
minifyEnabled false
25+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26+
}
27+
}
28+
externalNativeBuild {
29+
cmake {
30+
path "CMakeLists.txt"
31+
}
32+
}
33+
sourceSets {
34+
main {
35+
jni.srcDirs = []
36+
jniLibs.srcDirs = ['libs']
37+
}
38+
}
39+
40+
}
41+
42+
dependencies {
43+
implementation fileTree(dir: 'libs', include: ['*.jar'])
44+
testImplementation 'junit:junit:4.12'
45+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
46+
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
47+
}

app/proguard-rules.pro

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.fang.myapplication;
2+
3+
import android.content.Context;
4+
import android.support.test.InstrumentationRegistry;
5+
import android.support.test.runner.AndroidJUnit4;
6+
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
10+
import static org.junit.Assert.*;
11+
12+
/**
13+
* Instrumented test, which will execute on an Android device.
14+
*
15+
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
16+
*/
17+
@RunWith(AndroidJUnit4.class)
18+
public class ExampleInstrumentedTest {
19+
@Test
20+
public void useAppContext() {
21+
// Context of the app under test.
22+
Context appContext = InstrumentationRegistry.getTargetContext();
23+
24+
assertEquals("com.fang.myapplication", appContext.getPackageName());
25+
}
26+
}

app/src/main/AndroidManifest.xml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.fang.myapplication">
4+
5+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
6+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
7+
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
8+
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
9+
<uses-permission android:name="android.permission.INTERNET"/>
10+
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
11+
12+
<application
13+
android:allowBackup="true"
14+
android:icon="@mipmap/ic_launcher"
15+
android:label="@string/app_name"
16+
android:roundIcon="@mipmap/ic_launcher_round"
17+
android:supportsRtl="true"
18+
android:theme="@style/AppTheme">
19+
<activity android:name=".MainActivity">
20+
<intent-filter>
21+
<action android:name="android.intent.action.MAIN" />
22+
23+
<category android:name="android.intent.category.LAUNCHER" />
24+
</intent-filter>
25+
</activity>
26+
</application>
27+
28+
</manifest>

app/src/main/cpp/jni_raop_server.cpp

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//
2+
// Created by Administrator on 2019/1/29/029.
3+
//
4+
5+
#include <jni.h>
6+
#include <stddef.h>
7+
#include "lib/raop.h"
8+
#include "log.h"
9+
#include "lib/stream.h"
10+
#include "lib/logger.h"
11+
#include <malloc.h>
12+
#include <cstring>
13+
14+
static JavaVM* g_JavaVM;
15+
16+
void OnRecvAudioData(void *observer, pcm_data_struct *data) {
17+
jobject obj = (jobject) observer;
18+
JNIEnv* jniEnv = NULL;
19+
g_JavaVM->AttachCurrentThread(&jniEnv, NULL);
20+
jclass cls = jniEnv->GetObjectClass(obj);
21+
jmethodID onRecvVideoDataM = jniEnv->GetMethodID(cls, "onRecvAudioData", "([SJ)V");
22+
jniEnv->DeleteLocalRef(cls);
23+
jshortArray sarr = jniEnv->NewShortArray(data->data_len);
24+
if (sarr == NULL) return;
25+
jniEnv->SetShortArrayRegion(sarr, (jint) 0, data->data_len, (jshort *) data->data);
26+
jniEnv->CallVoidMethod(obj, onRecvVideoDataM, sarr, data->pts);
27+
jniEnv->DeleteLocalRef(sarr);
28+
g_JavaVM->DetachCurrentThread();
29+
}
30+
31+
32+
void OnRecvVideoData(void *observer, h264_decode_struct *data) {
33+
jobject obj = (jobject) observer;
34+
JNIEnv* jniEnv = NULL;
35+
g_JavaVM->AttachCurrentThread(&jniEnv, NULL);
36+
jclass cls = jniEnv->GetObjectClass(obj);
37+
jmethodID onRecvVideoDataM = jniEnv->GetMethodID(cls, "onRecvVideoData", "([BIJJ)V");
38+
jniEnv->DeleteLocalRef(cls);
39+
jbyteArray barr = jniEnv->NewByteArray(data->data_len);
40+
if (barr == NULL) return;
41+
jniEnv->SetByteArrayRegion(barr, (jint) 0, data->data_len, (jbyte *) data->data);
42+
jniEnv->CallVoidMethod(obj, onRecvVideoDataM, barr, data->frame_type,
43+
data->pts, data->pts);
44+
jniEnv->DeleteLocalRef(barr);
45+
g_JavaVM->DetachCurrentThread();
46+
}
47+
48+
extern "C" void
49+
audio_process(void *cls, pcm_data_struct *data)
50+
{
51+
OnRecvAudioData(cls, data);
52+
}
53+
54+
extern "C" void
55+
audio_set_volume(void *cls, void *opaque, float volume)
56+
{
57+
58+
}
59+
60+
extern "C" void
61+
video_process(void *cls, h264_decode_struct *data)
62+
{
63+
OnRecvVideoData(cls, data);
64+
}
65+
66+
extern "C" void
67+
log_callback(void *cls, int level, const char *msg) {
68+
switch (level) {
69+
case LOGGER_DEBUG: {
70+
LOGD("%s", msg);
71+
break;
72+
}
73+
case LOGGER_WARNING: {
74+
LOGW("%s", msg);
75+
break;
76+
}
77+
case LOGGER_INFO: {
78+
LOGI("%s", msg);
79+
break;
80+
}
81+
case LOGGER_ERR: {
82+
LOGE("%s", msg);
83+
break;
84+
}
85+
default:break;
86+
}
87+
88+
}
89+
90+
extern "C" JNIEXPORT jint JNICALL
91+
JNI_OnLoad(JavaVM* vm, void* reserved) {
92+
g_JavaVM = vm;
93+
return JNI_VERSION_1_6;
94+
}
95+
96+
extern "C" JNIEXPORT jlong JNICALL
97+
Java_com_fang_myapplication_RaopServer_start(JNIEnv* env, jobject object) {
98+
raop_t *raop;
99+
raop_callbacks_t raop_cbs;
100+
memset(&raop_cbs, 0, sizeof(raop_cbs));
101+
raop_cbs.cls = (void *) env->NewGlobalRef(object);;
102+
raop_cbs.audio_process = audio_process;
103+
raop_cbs.audio_set_volume = audio_set_volume;
104+
raop_cbs.video_process = video_process;
105+
raop = raop_init(10, &raop_cbs);
106+
if (raop == NULL) {
107+
LOGE("raop = NULL");
108+
return 0;
109+
} else {
110+
LOGD("raop init success");
111+
}
112+
113+
raop_set_log_callback(raop, log_callback, NULL);
114+
raop_set_log_level(raop, RAOP_LOG_DEBUG);
115+
116+
unsigned short port = 0;
117+
raop_start(raop, &port);
118+
raop_set_port(raop, port);
119+
LOGD("raop port = % d", raop_get_port(raop));
120+
return (jlong) (void *) raop;
121+
}
122+
123+
extern "C" JNIEXPORT jint JNICALL
124+
Java_com_fang_myapplication_RaopServer_getPort(JNIEnv* env, jobject object, jlong opaque) {
125+
raop_t *raop = (raop_t *) (void *) opaque;
126+
return raop_get_port(raop);
127+
}
128+
129+
extern "C" JNIEXPORT void JNICALL
130+
Java_com_fang_myapplication_RaopServer_stop(JNIEnv* env, jobject object, jlong opaque) {
131+
raop_t *raop = (raop_t *) (void *) opaque;
132+
jobject obj = (jobject) raop_get_callback_cls(raop);
133+
raop_destroy(raop);
134+
env->DeleteGlobalRef(obj);
135+
136+
}

app/src/main/cpp/lib/CMakeLists.txt

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
cmake_minimum_required(VERSION 3.4.1)
2+
include_directories(crypto curve25519 ed25519 playfair plist/plist
3+
fdk-aac/libAACdec/include
4+
fdk-aac/libAACenc/include
5+
fdk-aac/libFDK/include
6+
fdk-aac/libMpegTPDec/include
7+
fdk-aac/libMpegTPEnc/include
8+
fdk-aac/libPCMutils/include
9+
fdk-aac/libSBRdec/include
10+
fdk-aac/libSBRenc/include
11+
fdk-aac/libSYS/include
12+
#fdk-aac/libArithCoding/include
13+
#fdk-aac/libDRCdec/include
14+
#fdk-aac/libSACdec/include
15+
#fdk-aac/libSACenc/include
16+
)
17+
18+
19+
aux_source_directory(. play_src)
20+
set(DIR_SRCS ${play_src})
21+
22+
add_library( play-lib
23+
SHARED
24+
${DIR_SRCS}
25+
)
26+
find_library( log-lib
27+
log )
28+
target_link_libraries( play-lib
29+
crypto
30+
curve25519
31+
ed25519
32+
playfair
33+
plist
34+
fdk-aac
35+
${log-lib})

0 commit comments

Comments
 (0)